diff --git a/.editorconfig b/.editorconfig index 5a751aad..95f2c7dd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,6 +8,3 @@ root = true end_of_line = lf insert_final_newline = true charset = utf-8 - -[*.{php,t}] -indent_style = tab diff --git a/.env b/.env index 22846cb4..bf6c48c4 100644 --- a/.env +++ b/.env @@ -1,7 +1,6 @@ FASTAPI_BACKEND="uvicorn" FASTAPI_WORKERS=2 MARIADB_SOCKET_DIR="/var/run/mysqld/" -AURWEB_PHP_PREFIX=https://localhost:8443 AURWEB_FASTAPI_PREFIX=https://localhost:8444 AURWEB_SSHD_PREFIX=ssh://aur@localhost:2222 GIT_DATA_DIR="./aur.git/" diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index af722d99..10dd1787 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -71,7 +71,6 @@ deploy: variables: FASTAPI_BACKEND: gunicorn FASTAPI_WORKERS: 5 - AURWEB_PHP_PREFIX: https://aur-dev.archlinux.org AURWEB_FASTAPI_PREFIX: https://aur-dev.archlinux.org AURWEB_SSHD_PREFIX: ssh://aur@aur-dev.archlinux.org:2222 COMMIT_HASH: $CI_COMMIT_SHA diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c8d4f90d..a91e3eec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,7 +91,6 @@ browser if desired. Accessible services (on the host): - https://localhost:8444 (python via nginx) -- https://localhost:8443 (php via nginx) - localhost:13306 (mariadb) - localhost:16379 (redis) diff --git a/INSTALL b/INSTALL index 03459726..107fab4b 100644 --- a/INSTALL +++ b/INSTALL @@ -14,8 +14,7 @@ read the instructions below. $ cd aurweb $ poetry install -2) Setup a web server with PHP and MySQL. Configure the web server to redirect - all URLs to /index.php/foo/bar/. The following block can be used with nginx: +2) Setup a web server with MySQL. The following block can be used with nginx: server { # https is preferred and can be done easily with LetsEncrypt diff --git a/README.md b/README.md index 2741efa2..4d732bb2 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,6 @@ Directory Layout * `schema`: schema for the SQL database * `test`: test suite and test cases * `upgrading`: instructions for upgrading setups from one release to another -* `web`: PHP-based web interface for the AUR Documentation ------------- diff --git a/TESTING b/TESTING index cb34c0e9..078d330b 100644 --- a/TESTING +++ b/TESTING @@ -29,7 +29,6 @@ docker-compose 4) Browse to local aurweb development server. Python: https://localhost:8444/ - PHP: https://localhost:8443/ 5) [Optionally] populate the database with dummy data: diff --git a/aurweb/db.py b/aurweb/db.py index ab0f80b8..8311f2be 100644 --- a/aurweb/db.py +++ b/aurweb/db.py @@ -364,7 +364,7 @@ class ConnectionExecutor: def execute(self, query, params=()): # pragma: no cover # TODO: SQLite support has been removed in FastAPI. It remains - # here to fund its support for PHP until it is removed. + # here to fund its support for the Sharness testsuite. if self._paramstyle in ("format", "pyformat"): query = query.replace("%", "%%").replace("?", "%s") elif self._paramstyle == "qmark": @@ -410,7 +410,7 @@ class Connection: ) elif aur_db_backend == "sqlite": # pragma: no cover # TODO: SQLite support has been removed in FastAPI. It remains - # here to fund its support for PHP until it is removed. + # here to fund its support for Sharness testsuite. import math import sqlite3 diff --git a/aurweb/spawn.py b/aurweb/spawn.py index 29162f33..442d89a9 100644 --- a/aurweb/spawn.py +++ b/aurweb/spawn.py @@ -20,7 +20,6 @@ from typing import Iterable import aurweb.config import aurweb.schema -from aurweb.exceptions import AurwebException children = [] temporary_dir = None @@ -28,9 +27,6 @@ verbosity = 0 asgi_backend = "" workers = 1 -PHP_BINARY = os.environ.get("PHP_BINARY", "php") -PHP_MODULES = ["pdo_mysql", "pdo_sqlite"] -PHP_NGINX_PORT = int(os.environ.get("PHP_NGINX_PORT", 8001)) FASTAPI_NGINX_PORT = int(os.environ.get("FASTAPI_NGINX_PORT", 8002)) @@ -47,42 +43,12 @@ class ProcessExceptions(Exception): super().__init__("\n- ".join(messages)) -def validate_php_config() -> None: - """ - Perform a validation check against PHP_BINARY's configuration. - - AurwebException is raised here if checks fail to pass. We require - the 'pdo_mysql' and 'pdo_sqlite' modules to be enabled. - - :raises: AurwebException - :return: None - """ - try: - proc = subprocess.Popen( - [PHP_BINARY, "-m"], stdout=subprocess.PIPE, stderr=subprocess.PIPE - ) - out, _ = proc.communicate() - except FileNotFoundError: - raise AurwebException(f"Unable to locate the '{PHP_BINARY}' " "executable.") - - assert proc.returncode == 0, ( - "Received non-zero error code " f"{proc.returncode} from '{PHP_BINARY}'." - ) - - modules = out.decode().splitlines() - for module in PHP_MODULES: - if module not in modules: - raise AurwebException(f"PHP does not have the '{module}' module enabled.") - - def generate_nginx_config(): """ Generate an nginx configuration based on aurweb's configuration. The file is generated under `temporary_dir`. Returns the path to the created configuration file. """ - php_bind = aurweb.config.get("php", "bind_address") - php_host = php_bind.split(":")[0] fastapi_bind = aurweb.config.get("fastapi", "bind_address") fastapi_host = fastapi_bind.split(":")[0] config_path = os.path.join(temporary_dir, "nginx.conf") @@ -101,12 +67,6 @@ def generate_nginx_config(): fastcgi_temp_path {os.path.join(temporary_dir, "fastcgi")}1 2; uwsgi_temp_path {os.path.join(temporary_dir, "uwsgi")}; scgi_temp_path {os.path.join(temporary_dir, "scgi")}; - server {{ - listen {php_host}:{PHP_NGINX_PORT}; - location / {{ - proxy_pass http://{php_bind}; - }} - }} server {{ listen {fastapi_host}:{FASTAPI_NGINX_PORT}; location / {{ @@ -154,7 +114,7 @@ def start(): terminal_width = 80 print( "{ruler}\n" - "Spawing PHP and FastAPI, then nginx as a reverse proxy.\n" + "Spawing FastAPI, then nginx as a reverse proxy.\n" "Check out {aur_location}\n" "Hit ^C to terminate everything.\n" "{ruler}".format( @@ -163,12 +123,6 @@ def start(): ) ) - # PHP - php_address = aurweb.config.get("php", "bind_address") - php_host = php_address.split(":")[0] - htmldir = aurweb.config.get("php", "htmldir") - spawn_child(["php", "-S", php_address, "-t", htmldir]) - # FastAPI fastapi_host, fastapi_port = aurweb.config.get("fastapi", "bind_address").rsplit( ":", 1 @@ -210,10 +164,7 @@ def start(): f""" > Started nginx. > - > PHP backend: http://{php_address} - > FastAPI backend: http://{fastapi_host}:{fastapi_port} - > - > PHP frontend: http://{php_host}:{PHP_NGINX_PORT} + > FastAPI backend: http://{fastapi_host}:{fastapi_port} > FastAPI frontend: http://{fastapi_host}:{FASTAPI_NGINX_PORT} > > Frontends are hosted via nginx and should be preferred. @@ -307,12 +258,6 @@ if __name__ == "__main__": ) args = parser.parse_args() - try: - validate_php_config() - except AurwebException as exc: - print(f"error: {str(exc)}") - sys.exit(1) - verbosity = args.verbose asgi_backend = args.backend workers = args.workers diff --git a/conf/config.defaults b/conf/config.defaults index 06e73afe..0cd4b9d4 100644 --- a/conf/config.defaults +++ b/conf/config.defaults @@ -38,11 +38,9 @@ enable-maintenance = 1 maintenance-exceptions = 127.0.0.1 render-comment-cmd = /usr/bin/aurweb-rendercomment localedir = /srv/http/aurweb/web/locale/ -; memcache, apc, or redis -; memcache/apc are supported in PHP, redis is supported in Python. +; cache: redis is supported in Python. cache = none cache_pkginfo_ttl = 86400 -memcache_servers = 127.0.0.1:11211 salt_rounds = 12 redis_address = redis://localhost ; Toggles traceback display in templates/errors/500.html. @@ -125,12 +123,12 @@ sync-dbs = core extra community multilib testing community-testing server = https://mirrors.kernel.org/archlinux/%s/os/x86_64 [mkpkglists] -archivedir = /srv/http/aurweb/web/html -packagesfile = /srv/http/aurweb/web/html/packages.gz -packagesmetafile = /srv/http/aurweb/web/html/packages-meta-v1.json.gz -packagesmetaextfile = /srv/http/aurweb/web/html/packages-meta-ext-v1.json.gz -pkgbasefile = /srv/http/aurweb/web/html/pkgbase.gz -userfile = /srv/http/aurweb/web/html/users.gz +archivedir = /srv/http/aurweb/archives +packagesfile = /srv/http/aurweb/archives/packages.gz +packagesmetafile = /srv/http/aurweb/archives/packages-meta-v1.json.gz +packagesmetaextfile = /srv/http/aurweb/archives/packages-meta-ext-v1.json.gz +pkgbasefile = /srv/http/aurweb/archives/pkgbase.gz +userfile = /srv/http/aurweb/archives/users.gz [git-archive] author = git_archive.py diff --git a/conf/config.dev b/conf/config.dev index b36bfe77..f3b0ee21 100644 --- a/conf/config.dev +++ b/conf/config.dev @@ -6,7 +6,6 @@ ; development-specific options too. [database] -; PHP options: mysql, sqlite. ; FastAPI options: mysql. backend = mysql @@ -31,9 +30,6 @@ localedir = YOUR_AUR_ROOT/web/locale salt_rounds = 4 ; See config.defaults comment about cache. cache = none -; In docker, the memcached host is available. On a user's system, -; this should be set to localhost (most likely). -memcache_servers = memcached:11211 ; If cache = 'redis' this address is used to connect to Redis. redis_address = redis://127.0.0.1 aur_request_ml = aur-requests@localhost @@ -51,13 +47,6 @@ openid_configuration = http://127.0.0.1:8083/auth/realms/aurweb/.well-known/open client_id = aurweb client_secret = -[php] -; Address PHP should bind when spawned in development mode by aurweb.spawn. -bind_address = 127.0.0.1:8081 - -; Directory containing aurweb's PHP code, required by aurweb.spawn. -htmldir = YOUR_AUR_ROOT/web/html - [fastapi] ; Address uvicorn should bind when spawned in development mode by aurweb.spawn. bind_address = 127.0.0.1:8082 diff --git a/doc/docker.md b/doc/docker.md index 22505f7a..c54184b8 100644 --- a/doc/docker.md +++ b/doc/docker.md @@ -65,12 +65,9 @@ Services | [mariadb](#mariadb) | 127.0.0.1:13306 | | [git](#git) | 127.0.0.1:2222 | | redis | 127.0.0.1:16379 | -| [php-fpm](#php-fpm) | 127.0.0.1:19000 | -| cgit-php | | | [fastapi](#fastapi) | 127.0.0.1:18000 | | cgit-fastapi | | | [nginx](#nginx) (fastapi) | 127.0.0.1:8444 | -| [nginx](#nginx) (php) | 127.0.0.1:8443 | There are more services which have not been referred to here; the services listed above encompass all notable services. Some @@ -113,16 +110,6 @@ to be used for the AUR. This service will perform setup in either case if the repository is not yet initialized. -#### php-fpm - -When running any services which use the _php-fpm_ backend or other -php-related services, users should define: - -- `AURWEB_PHP_PREFIX` - - Default: `https://localhost:8443` -- `AURWEB_SSHD_PREFIX` - - Default: `ssh://aur@localhost:2222` - #### fastapi The _fastapi_ service hosts a `gunicorn`, `uvicorn` or `hypercorn` @@ -145,20 +132,17 @@ backend or other fastapi-related services, users should define: #### nginx -The _nginx_ service binds to two host endpoints: 127.0.0.1:8444 (fastapi) -and 127.0.0.1:8443 (php). Each instance is available over the `https` +The _nginx_ service binds to host endpoint: 127.0.0.1:8444 (fastapi). +The instance is available over the `https` protocol as noted in the table below. | Impl | Host Binding | URL | |--------|----------------|------------------------| | Python | 127.0.0.1:8444 | https://localhost:8444 | -| PHP | 127.0.0.1:8443 | https://localhost:8443 | When running this service, the following variables should be defined: - `AURWEB_FASTAPI_PREFIX` - Default: `https://localhost:8444` -- `AURWEB_PHP_PREFIX` - - Default: `https://localhost:8443` - `AURWEB_SSHD_PREFIX` - Default: `ssh://aur@localhost:2222` diff --git a/doc/maintenance.txt b/doc/maintenance.txt index dacf2b60..39642f21 100644 --- a/doc/maintenance.txt +++ b/doc/maintenance.txt @@ -21,7 +21,7 @@ The RPC interface can be used to query package information via HTTP. Installation ------------ -The web backend requires a web server with PHP and an SQL database. The Git/SSH +The web backend requires a web server and an SQL database. The Git/SSH interface requires Python, several Python modules and an up-to-date version of Git. APCu or memcached can be used to reduce load on the database server. diff --git a/docker-compose.aur-dev.yml b/docker-compose.aur-dev.yml index 0b91dd93..1763f427 100644 --- a/docker-compose.aur-dev.yml +++ b/docker-compose.aur-dev.yml @@ -6,9 +6,6 @@ services: - data:/data - step:/root/.step - memcached: - restart: always - redis: restart: always @@ -32,11 +29,6 @@ services: - data:/data - smartgit_run:/var/run/smartgit - cgit-php: - restart: always - volumes: - - ${GIT_DATA_DIR}:/aurweb/aur.git - cgit-fastapi: restart: always volumes: @@ -48,14 +40,6 @@ services: - mariadb_run:/var/run/mysqld - archives:/var/lib/aurweb/archives - php-fpm: - restart: always - environment: - - AURWEB_PHP_PREFIX=${AURWEB_PHP_PREFIX} - - AURWEB_SSHD_PREFIX=${AURWEB_SSHD_PREFIX} - volumes: - - data:/data - fastapi: restart: always environment: diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 1e466730..6580de30 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -25,26 +25,12 @@ services: mariadb: condition: service_healthy - php-fpm: - volumes: - - ./data:/data - - ./aurweb:/aurweb/aurweb - - ./migrations:/aurweb/migrations - - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - - ./templates:/aurweb/templates - fastapi: volumes: - ./data:/data - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates nginx: diff --git a/docker-compose.yml b/docker-compose.yml index a1c2bb42..0973fc0e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,11 +10,9 @@ # - `ca` - Certificate Authority generation # - `git` - `port 2222` - Git over SSH server # - `fastapi` - hypercorn service for aurweb's FastAPI app -# - `php-fpm` - Execution server for PHP aurweb -# - `nginx` - `ports 8444 (FastAPI), 8443 (PHP)` - Everything -# - You can reach `nginx` via FastAPI at `https://localhost:8444/` -# or via PHP at `https://localhost:8443/`. CGit can be reached -# via the `/cgit/` request uri on either server. +# - `nginx` - `port 8444 (FastAPI) +# - You can reach `nginx` via FastAPI at `https://localhost:8444/`. +# CGit can be reached via the `/cgit/` request uri on either server. # # Copyright (C) 2021 aurweb Development # All Rights Reserved. @@ -36,14 +34,6 @@ services: volumes: - step:/root/.step - memcached: - image: aurweb:latest - init: true - command: /docker/scripts/run-memcached.sh - healthcheck: - test: "bash /docker/health/memcached.sh" - interval: 3s - redis: image: aurweb:latest init: true @@ -133,26 +123,6 @@ services: test: "bash /docker/health/smartgit.sh" interval: 3s - cgit-php: - image: aurweb:latest - init: true - environment: - - AUR_CONFIG=/aurweb/conf/config - - CGIT_CLONE_PREFIX=${AURWEB_PHP_PREFIX} - - CGIT_CSS=/css/cgit.css - entrypoint: /docker/cgit-entrypoint.sh - command: /docker/scripts/run-cgit.sh 3000 - healthcheck: - test: "bash /docker/health/cgit.sh 3000" - interval: 3s - depends_on: - git: - condition: service_healthy - ports: - - "127.0.0.1:13000:3000" - volumes: - - git_data:/aurweb/aur.git - cgit-fastapi: image: aurweb:latest init: true @@ -189,32 +159,6 @@ services: - mariadb_run:/var/run/mysqld - archives:/var/lib/aurweb/archives - php-fpm: - image: aurweb:latest - init: true - environment: - - AUR_CONFIG=/aurweb/conf/config - - AURWEB_PHP_PREFIX=${AURWEB_PHP_PREFIX} - - AURWEB_SSHD_PREFIX=${AURWEB_SSHD_PREFIX} - - AUR_CONFIG_IMMUTABLE=${AUR_CONFIG_IMMUTABLE:-0} - entrypoint: /docker/php-entrypoint.sh - command: /docker/scripts/run-php.sh - healthcheck: - test: "bash /docker/health/php.sh" - interval: 3s - depends_on: - git: - condition: service_healthy - memcached: - condition: service_healthy - cron: - condition: service_started - volumes: - - mariadb_run:/var/run/mysqld - - archives:/var/lib/aurweb/archives - ports: - - "127.0.0.1:19000:9000" - fastapi: image: aurweb:latest init: true @@ -252,7 +196,6 @@ services: entrypoint: /docker/nginx-entrypoint.sh command: /docker/scripts/run-nginx.sh ports: - - "127.0.0.1:8443:8443" # PHP - "127.0.0.1:8444:8444" # FastAPI healthcheck: test: "bash /docker/health/nginx.sh" @@ -260,16 +203,12 @@ services: depends_on: ca: condition: service_healthy - cgit-php: - condition: service_healthy cgit-fastapi: condition: service_healthy smartgit: condition: service_healthy fastapi: condition: service_healthy - php-fpm: - condition: service_healthy sharness: image: aurweb:latest @@ -290,9 +229,6 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates pytest-mysql: @@ -319,9 +255,6 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates test: @@ -346,9 +279,6 @@ services: - ./aurweb:/aurweb/aurweb - ./migrations:/aurweb/migrations - ./test:/aurweb/test - - ./web/html:/aurweb/web/html - - ./web/template:/aurweb/web/template - - ./web/lib:/aurweb/web/lib - ./templates:/aurweb/templates volumes: diff --git a/docker/README.md b/docker/README.md index cc1f5df0..51e485f6 100644 --- a/docker/README.md +++ b/docker/README.md @@ -55,8 +55,7 @@ can proceed. ### Querying the RPC -The Fast (Python) API runs on Port 8444, while the legacy PHP version runs -on 8443. You can query one like so: +The Fast (Python) API runs on Port 8444. You can query one like so: ```sh curl -k "https://localhost:8444/rpc/?v=5&type=search&arg=python" diff --git a/docker/config/nginx.conf b/docker/config/nginx.conf index 99804d1d..9b167553 100644 --- a/docker/config/nginx.conf +++ b/docker/config/nginx.conf @@ -27,10 +27,6 @@ http { server fastapi:8000; } - upstream cgit-php { - server cgit-php:3000; - } - upstream cgit-fastapi { server cgit-fastapi:3000; } @@ -39,54 +35,6 @@ http { server unix:/var/run/smartgit/smartgit.sock; } - server { - listen 8443 ssl http2; - server_name localhost default_server; - - ssl_certificate /etc/ssl/certs/web.cert.pem; - ssl_certificate_key /etc/ssl/private/web.key.pem; - - root /aurweb/web/html; - index index.php; - - location ~ "^/([a-z0-9][a-z0-9.+_-]*?)(\.git)?/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$" { - include uwsgi_params; - uwsgi_pass smartgit; - uwsgi_modifier1 9; - uwsgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend; - uwsgi_param PATH_INFO /aur.git/$3; - uwsgi_param GIT_HTTP_EXPORT_ALL ""; - uwsgi_param GIT_NAMESPACE $1; - uwsgi_param GIT_PROJECT_ROOT /aurweb; - } - - location ~ ^/cgit { - include uwsgi_params; - rewrite ^/cgit/([^?/]+/[^?]*)?(?:\?(.*))?$ /cgit.cgi?url=$1&$2 last; - uwsgi_modifier1 9; - uwsgi_param CGIT_CONFIG /etc/cgitrc; - uwsgi_pass uwsgi://cgit-php; - } - - location ~ ^/[^/]+\.php($|/) { - fastcgi_pass php-fpm:9000; - fastcgi_index index.php; - fastcgi_split_path_info ^(/[^/]+\.php)(/.*)$; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - include fastcgi_params; - } - - location ~ .+\.(css|js?|jpe?g|png|svg|ico)/?$ { - try_files $uri =404; - } - - location ~ .* { - rewrite ^/(.*)$ /index.php/$1 last; - } - - } - server { listen 8444 ssl http2; server_name localhost default_server; diff --git a/docker/health/memcached.sh b/docker/health/memcached.sh deleted file mode 100755 index 00f8cd98..00000000 --- a/docker/health/memcached.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec pgrep memcached diff --git a/docker/health/php.sh b/docker/health/php.sh deleted file mode 100755 index 7325946b..00000000 --- a/docker/health/php.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec printf "" >>/dev/tcp/127.0.0.1/9000 diff --git a/docker/mariadb-entrypoint.sh b/docker/mariadb-entrypoint.sh index a00f6106..a6fb9a76 100755 --- a/docker/mariadb-entrypoint.sh +++ b/docker/mariadb-entrypoint.sh @@ -12,7 +12,7 @@ while ! mysqladmin ping 2>/dev/null; do done # Configure databases. -DATABASE="aurweb" # Persistent database for fastapi/php-fpm. +DATABASE="aurweb" # Persistent database for fastapi. echo "Taking care of primary database '${DATABASE}'..." mysql -u root -e "CREATE USER IF NOT EXISTS 'aur'@'localhost' IDENTIFIED BY 'aur';" diff --git a/docker/php-entrypoint.sh b/docker/php-entrypoint.sh deleted file mode 100755 index dc1a91de..00000000 --- a/docker/php-entrypoint.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -set -eou pipefail - -for archive in packages pkgbase users packages-meta-v1.json packages-meta-ext-v1.json; do - ln -vsf /var/lib/aurweb/archives/${archive}.gz /aurweb/web/html/${archive}.gz -done - -# Setup database. -NO_INITDB=1 /docker/mariadb-init-entrypoint.sh - -# Setup some other options. -aurweb-config set options cache 'memcache' -aurweb-config set options aur_location "$AURWEB_PHP_PREFIX" -aurweb-config set options git_clone_uri_anon "${AURWEB_PHP_PREFIX}/%s.git" -aurweb-config set options git_clone_uri_priv "${AURWEB_SSHD_PREFIX}/%s.git" - -# Listen on :9000. -sed -ri 's/^(listen).*/\1 = 0.0.0.0:9000/' /etc/php/php-fpm.d/www.conf -sed -ri 's/^;?(clear_env).*/\1 = no/' /etc/php/php-fpm.d/www.conf - -# Log to stderr. View logs via `docker-compose logs php-fpm`. -sed -ri 's|^(error_log) = .*$|\1 = /proc/self/fd/2|g' /etc/php/php-fpm.conf -sed -ri 's|^;?(access\.log) = .*$|\1 = /proc/self/fd/2|g' \ - /etc/php/php-fpm.d/www.conf - -sed -ri 's/^;?(extension=pdo_mysql)/\1/' /etc/php/php.ini -sed -ri 's/^;?(open_basedir).*$/\1 = \//' /etc/php/php.ini - -# Use the sqlite3 extension line for memcached. -sed -ri 's/^;(extension)=sqlite3$/\1=memcached/' /etc/php/php.ini - -exec "$@" diff --git a/docker/scripts/install-deps.sh b/docker/scripts/install-deps.sh index 85403969..7aa225fa 100755 --- a/docker/scripts/install-deps.sh +++ b/docker/scripts/install-deps.sh @@ -15,9 +15,8 @@ pacman -Sy --noconfirm --noprogressbar archlinux-keyring pacman -Syu --noconfirm --noprogressbar \ --cachedir .pkg-cache git gpgme nginx redis openssh \ mariadb mariadb-libs cgit-aurweb uwsgi uwsgi-plugin-cgi \ - php php-fpm memcached php-memcached python-pip pyalpm \ - python-srcinfo curl libeatmydata cronie python-poetry \ - python-poetry-core step-cli step-ca asciidoc \ + python-pip pyalpm python-srcinfo curl libeatmydata cronie \ + python-poetry python-poetry-core step-cli step-ca asciidoc \ python-virtualenv python-pre-commit exec "$@" diff --git a/docker/scripts/run-memcached.sh b/docker/scripts/run-memcached.sh deleted file mode 100755 index 90784b0f..00000000 --- a/docker/scripts/run-memcached.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec /usr/bin/memcached -u memcached -m 64 -c 1024 -l 0.0.0.0 diff --git a/docker/scripts/run-nginx.sh b/docker/scripts/run-nginx.sh index 6ece3303..e976f67d 100755 --- a/docker/scripts/run-nginx.sh +++ b/docker/scripts/run-nginx.sh @@ -5,8 +5,6 @@ echo echo " Services:" echo " - FastAPI : https://localhost:8444/" echo " (cgit) : https://localhost:8444/cgit/" -echo " - PHP : https://localhost:8443/" -echo " (cgit) : https://localhost:8443/cgit/" echo echo " Note: Copy root CA (./data/ca.root.pem) to ca-certificates or browser." echo diff --git a/docker/scripts/run-php.sh b/docker/scripts/run-php.sh deleted file mode 100755 index b86f8ce5..00000000 --- a/docker/scripts/run-php.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -eou pipefail - -exec php-fpm --fpm-config /etc/php/php-fpm.conf --nodaemonize diff --git a/po/Makefile b/po/Makefile index 0b579f48..8fd17515 100644 --- a/po/Makefile +++ b/po/Makefile @@ -48,20 +48,12 @@ all: ${MOFILES} lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ msgmerge -U --no-location --lang="$$lang" $< aurweb.pot -POTFILES-php: - find ../web -type f -name '*.php' -printf '%P\n' | sort >POTFILES-php - POTFILES-py: find ../aurweb -type f -name '*.py' -printf '%P\n' | sort >POTFILES-py -update-pot: POTFILES-php POTFILES-py +update-pot: POTFILES-py pkgname=AURWEB; \ - pkgver=`sed -n 's/.*"AURWEB_VERSION", "\(.*\)".*/\1/p' ../web/lib/version.inc.php`; \ - xgettext --default-domain=aurweb -L php --keyword=__ --keyword=_n:1,2 \ - --add-location=file --add-comments=TRANSLATORS: \ - --package-name="$$pkgname" --package-version="$$pkgver" \ - --msgid-bugs-address='${MSGID_BUGS_ADDRESS}' \ - --directory ../web --files-from POTFILES-php -o aurweb.pot; \ + pkgver=`sed -n 's/version\s*=\s*"\(.*\)"/\1/p' ../pyproject.toml`; \ xgettext --default-domain=aurweb -L python --join-existing \ --keyword=translate \ --add-location=file --add-comments=TRANSLATORS: \ @@ -73,7 +65,7 @@ update-po: ${MAKE} ${UPDATEPOFILES} clean: - rm -f *.mo *.po\~ POTFILES-php POTFILES-py + rm -f *.mo *.po\~ POTFILES-py install: all for l in ${LOCALES}; do mkdir -p ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/; done @@ -82,4 +74,4 @@ install: all uninstall: for l in ${LOCALES}; do rm -rf ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/; done -.PHONY: all update-pot update-po clean install uninstall POTFILES-php POTFILES-py +.PHONY: all update-pot update-po clean install uninstall POTFILES-py diff --git a/test/test_spawn.py b/test/test_spawn.py index 25b9ebfc..c57c9b52 100644 --- a/test/test_spawn.py +++ b/test/test_spawn.py @@ -7,10 +7,9 @@ import pytest import aurweb.config import aurweb.spawn -from aurweb.exceptions import AurwebException # Some os.environ overrides we use in this suite. -TEST_ENVIRONMENT = {"PHP_NGINX_PORT": "8001", "FASTAPI_NGINX_PORT": "8002"} +TEST_ENVIRONMENT = {"FASTAPI_NGINX_PORT": "8002"} class FakeProcess: @@ -49,34 +48,6 @@ class MockFakeProcess: return proc -@mock.patch("aurweb.spawn.PHP_BINARY", "does-not-exist") -def test_spawn(): - match = r"^Unable to locate the '.*' executable\.$" - with pytest.raises(AurwebException, match=match): - aurweb.spawn.validate_php_config() - - -@mock.patch("subprocess.Popen", side_effect=MockFakeProcess(1).process) -def test_spawn_non_zero_php_binary(fake_process: FakeProcess): - match = r"^Received non-zero error code.*$" - with pytest.raises(AssertionError, match=match): - aurweb.spawn.validate_php_config() - - -def test_spawn_missing_modules(): - side_effect = MockFakeProcess(stdout=b"pdo_sqlite").process - with mock.patch("subprocess.Popen", side_effect=side_effect): - match = r"PHP does not have the 'pdo_mysql' module enabled\.$" - with pytest.raises(AurwebException, match=match): - aurweb.spawn.validate_php_config() - - side_effect = MockFakeProcess(stdout=b"pdo_mysql").process - with mock.patch("subprocess.Popen", side_effect=side_effect): - match = r"PHP does not have the 'pdo_sqlite' module enabled\.$" - with pytest.raises(AurwebException, match=match): - aurweb.spawn.validate_php_config() - - @mock.patch.dict("os.environ", TEST_ENVIRONMENT) def test_spawn_generate_nginx_config(): ctx = tempfile.TemporaryDirectory() @@ -86,13 +57,9 @@ def test_spawn_generate_nginx_config(): with open(nginx_config_path) as f: nginx_config = f.read().rstrip() - php_address = aurweb.config.get("php", "bind_address") - php_host = php_address.split(":")[0] fastapi_address = aurweb.config.get("fastapi", "bind_address") fastapi_host = fastapi_address.split(":")[0] expected_content = [ - f'listen {php_host}:{TEST_ENVIRONMENT.get("PHP_NGINX_PORT")}', - f"proxy_pass http://{php_address}", f'listen {fastapi_host}:{TEST_ENVIRONMENT.get("FASTAPI_NGINX_PORT")}', f"proxy_pass http://{fastapi_address}", ] diff --git a/web/html/404.php b/web/html/404.php deleted file mode 100644 index 9f81d115..00000000 --- a/web/html/404.php +++ /dev/null @@ -1,47 +0,0 @@ - - -
-

404 -

-

- - - -
- - - -
-

503 -

-

-
- -\n"; -echo "

".__("Accounts")."

\n"; - -if (isset($_COOKIE["AURSID"])) { - if ($action == "SearchAccounts") { - - # security check - # - if (has_credential(CRED_ACCOUNT_SEARCH)) { - # the user has entered search criteria, find any matching accounts - # - search_results_page(in_request("O"), in_request("SB"), - in_request("U"), in_request("T"), in_request("S"), - in_request("E"), in_request("R"), in_request("I"), - in_request("K")); - - } else { - # a non-privileged user is trying to access the search page - # - print __("You are not allowed to access this area.")."
\n"; - } - - } elseif ($action == "DisplayAccount") { - # the user has clicked 'edit', display the account details in a form - # - if (empty($row)) { - print __("Could not retrieve information for the specified user."); - } else { - /* Verify user has permission to edit the account */ - if (can_edit_account($row)) { - display_account_form("UpdateAccount", - $row["Username"], - $row["AccountTypeID"], - $row["Suspended"], - $row["Email"], - $row["BackupEmail"], - $row["HideEmail"], - "", - "", - $row["RealName"], - $row["LangPreference"], - $row["Timezone"], - $row["Homepage"], - $row["IRCNick"], - $row["PGPKey"], - $PK, - $row["InactivityTS"] ? 1 : 0, - $row["CommentNotify"], - $row["UpdateNotify"], - $row["OwnershipNotify"], - $row["ID"], - $row["Username"]); - } else { - print __("You do not have permission to edit this account."); - } - } - - } elseif ($action == "DeleteAccount") { - /* Details for account being deleted. */ - if ($row && can_edit_account($row)) { - $uid_removal = $row['ID']; - $uid_session = uid_from_sid($_COOKIE['AURSID']); - $username = $row['Username']; - - if (in_request('confirm') && check_token()) { - if (check_passwd($uid_session, $_REQUEST['passwd']) == 1) { - user_delete($uid_removal); - header('Location: /'); - } else { - echo ""; - include("account_delete.php"); - } - } else { - include("account_delete.php"); - } - } else { - print __("You do not have permission to edit this account."); - } - } elseif ($action == "AccountInfo") { - # no editing, just looking up user info - # - if (empty($row)) { - print __("Could not retrieve information for the specified user."); - } else { - include("account_details.php"); - } - - } elseif ($action == "UpdateAccount") { - print $update_account_message; - - if ($row && !$success) { - display_account_form("UpdateAccount", - in_request("U"), - in_request("T"), - in_request("S"), - in_request("E"), - in_request("BE"), - in_request("H"), - in_request("P"), - in_request("C"), - in_request("R"), - in_request("L"), - in_request("TZ"), - in_request("HP"), - in_request("I"), - in_request("K"), - in_request("PK"), - in_request("J"), - in_request("CN"), - in_request("UN"), - in_request("ON"), - in_request("ID"), - $row["Username"]); - } - - } elseif ($action == "ListComments") { - if ($row && has_credential(CRED_ACCOUNT_LIST_COMMENTS, array($row["ID"]))) { - # display the comment list if they're a TU/dev - - $total_comment_count = account_comments_count($row["ID"]); - list($pagination_templs, $per_page, $offset) = calculate_pagination($total_comment_count); - - $username = $row["Username"]; - $uid = $row["ID"]; - $comments = account_comments($uid, $per_page, $offset); - - $comment_section = "account"; - include('pkg_comments.php'); - - } else { - print __("You are not allowed to access this area."); - } - - } else { - if (has_credential(CRED_ACCOUNT_SEARCH)) { - # display the search page if they're a TU/dev - # - print __("Use this form to search existing accounts.")."
\n"; - include('search_accounts_form.php'); - - } else { - print __("You are not allowed to access this area."); - } - } - -} else { - # visitor is not logged in - # - print __("You must log in to view user information."); -} - -echo ""; - -html_footer(AURWEB_VERSION); - -?> diff --git a/web/html/addvote.php b/web/html/addvote.php deleted file mode 100644 index 4b52a3bb..00000000 --- a/web/html/addvote.php +++ /dev/null @@ -1,116 +0,0 @@ -" . __("New proposal submitted.") . "

\n"; - } else { -?> - - -

- - -
-

- -
-

- - - -

-

- - -

-

-
-
- - - " /> -

-
-
- a.headerlink { - visibility: visible; -} - -/* headings */ -h2 { - font-size: 1.5em; - margin-bottom: 0.5em; - border-bottom: 1px solid #888; -} - -h3 { - font-size: 1.25em; - margin-top: .5em; -} - -h4 { - font-size: 1.15em; - margin-top: 1em; -} - -h5 { - font-size: 1em; - margin-top: 1em; -} - -/* general layout */ -[dir="rtl"] #content { - text-align: right; -} - -#content { - width: 95%; - margin: 0 auto; - text-align: left; -} - -[dir="rtl"] #content-left-wrapper { - float: right; -} - -#content-left-wrapper { - float: left; - width: 100%; /* req to keep content above sidebar in source code */ -} - -[dir="rtl"] #content-left { - margin: 0 0 0 340px; -} - -#content-left { - margin: 0 340px 0 0; -} - -[dir="rtl"] #content-right { - float: right; - margin-right: -300px; -} - -#content-right { - float: left; - width: 300px; - margin-left: -300px; -} - -div.box { - margin-bottom: 1.5em; - padding: 0.65em; - background: #ecf2f5; - border: 1px solid #bcd; -} - -#footer { - clear: both; - margin: 2em 0 1em; -} - - #footer p { - margin: 0; - text-align: center; - font-size: 0.85em; - } - -/* alignment */ -div.center, -table.center, -img.center { - width: auto; - margin-left: auto; - margin-right: auto; -} - -p.center, -td.center, -th.center { - text-align: center; -} - -/* table generics */ -table { - width: 100%; - border-collapse: collapse; -} - - table .wrap { - white-space: normal; - } - -[dir="rtl"] th, -[dir="rtl"] td { - text-align: right; -} - -th, -td { - white-space: nowrap; - text-align: left; -} - - th { - vertical-align: middle; - font-weight: bold; - } - - td { - vertical-align: top; - } - -/* table pretty styles */ -table.pretty2 { - width: auto; - margin-top: 0.25em; - margin-bottom: 0.5em; - border-collapse: collapse; - border: 1px solid #bbb; -} - - .pretty2 th { - padding: 0.35em; - background: #eee; - border: 1px solid #bbb; - } - - .pretty2 td { - padding: 0.35em; - border: 1px dotted #bbb; - } - -table.compact { - width: auto; -} - - .compact td { - padding: 0.25em 0 0.25em 1.5em; - } - - -/* definition lists */ -dl { - clear: both; -} - - dl dt, - dl dd { - margin-bottom: 4px; - padding: 8px 0 4px; - font-weight: bold; - border-top: 1px dotted #bbb; - } - - [dir="rtl"] dl dt { - float: right; - padding-left: 15px; - } - dl dt { - color: #333; - float: left; - padding-right: 15px; - } - -/* forms and input styling */ -form p { - margin: 0.5em 0; -} - -fieldset { - border: 0; -} - -label { - width: 12em; - vertical-align: top; - display: inline-block; - font-weight: bold; -} - -input[type=text], -input[type=password], -input[type=email], -textarea { - padding: 0.10em; -} - -form.general-form label, -form.general-form .form-help { - width: 10em; - vertical-align: top; - display: inline-block; -} - -form.general-form input[type=text], -form.general-form textarea { - width: 45%; -} - -/* archdev navbar */ -#archdev-navbar { - margin: 1.5em 0; -} - - #archdev-navbar ul { - list-style: none; - margin: -0.5em 0; - padding: 0; - } - - #archdev-navbar li { - display: inline; - margin: 0; - padding: 0; - font-size: 0.9em; - } - - #archdev-navbar li a { - padding: 0 0.5em; - color: #07b; - } - -/* error/info messages (x pkg is already flagged out-of-date, etc) */ -#sys-message { - width: 35em; - text-align: center; - margin: 1em auto; - padding: 0.5em; - background: #fff; - border: 1px solid #f00; -} - - #sys-message p { - margin: 0; - } - -ul.errorlist { - color: red; -} - -form ul.errorlist { - margin: 0.5em 0; -} - -/* JS sorting via tablesorter */ -[dir="rtl"] table th.tablesorter-header { - padding-left: 20px; - background-position: center left ; -} -table th.tablesorter-header { - padding-right: 20px; - background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); - background-repeat: no-repeat; - background-position: center right; - cursor: pointer; -} - -table thead th.tablesorter-headerAsc { - background-color: #e4eeff; - background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); -} - -table thead th.tablesorter-headerDesc { - background-color: #e4eeff; - background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); -} - -table thead th.sorter-false { - background-image: none; - cursor: default; -} - -.tablesorter-header:focus { - outline: none; -} - -/** - * PAGE SPECIFIC STYLES - */ - -/* home: introduction */ -[dir="rtl"] #intro p.readmore { - text-align: left; -} -#intro p.readmore { - margin: -0.5em 0 0 0; - font-size: .9em; - text-align: right; -} - -/* home: news */ -#news { - margin-top: 1.5em; -} - - [dir="rtl"] #news h3 { - float: right; - } - #news h3 { - float: left; - padding-bottom: .5em - } - - #news div { - margin-bottom: 1em; - } - - #news div p { - margin-bottom: 0.5em; - } - - #news .more { - font-weight: normal; - } - [dir="rtl"] #news .rss-icon { - float: left; - } - #news .rss-icon { - float: right; - margin-top: 1em; - } - - #news h4 { - clear: both; - font-size: 1em; - margin-top: 1.5em; - border-bottom: 1px dotted #bbb; - } - [dir="rtl"] #news .timestamp { - float: left; - margin: -1.8em 0 0 0.5em; - } - #news .timestamp { - float: right; - font-size: 0.85em; - margin: -1.8em 0.5em 0 0; - } - -/* home: arrowed headings */ -#news h3 a { - display: block; - background: #1794D1; - font-size: 15px; - padding: 2px 10px; - color: white; -} - - #news a:active { - color: white; - } - -h3 span.arrow { - display: block; - width: 0; - height: 0; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-top: 6px solid #1794D1; - margin: 0 auto; - font-size: 0; - line-height: 0px; -} - -/* home: pkgsearch box */ -#pkgsearch { - padding: 1em 0.75em; - background: #3ad; - color: #fff; - border: 1px solid #08b; -} - - #pkgsearch label { - width: auto; - padding: 0.1em 0; - } - - [dir="rtl"] #pkgsearch input { - float: left; - } - #pkgsearch input { - width: 10em; - float: right; - font-size: 1em; - color: #000; - background: #fff; - border: 1px solid #09c; - } - - [dir="rtl"] .pkgsearch-typeahead { - right: 0; - float: right; - text-align: right; - } - - .pkgsearch-typeahead { - position: absolute; - top: 100%; - left: 0; - z-index: 1000; - display: none; - float: left; - padding: 0.15em 0.1em; - margin: 0; - min-width: 10em; - font-size: 1em; - text-align: left; - list-style: none; - background-color: #f6f9fc; - border: 1px solid #09c; - } - - .pkgsearch-typeahead li a { - color: #000; - } - - .pkgsearch-typeahead li:hover a, - .pkgsearch-typeahead li.active a { - color: #07b; - } - -/* home: recent pkg updates */ -#pkg-updates h3 { - margin: 0 0 0.3em; -} - - #pkg-updates .more { - font-weight: normal; - } - [dir="rtl"] #pkg-updates .rss-icon { - float: left; - } - #pkg-updates .rss-icon { - float: right; - margin: -2em 0 0 0; - } - - [dir="rtl"] #pkg-updates .rss-icon.latest { - margin-left: 1em; - } - #pkg-updates .rss-icon.latest { - margin-right: 1em; - } - - #pkg-updates table { - margin: 0; - direction: ltr; - } - - #pkg-updates td.pkg-name { - white-space: normal; - text-align: left; - } - - [dir="rtl"] #pkg-updates td.pkg-arch { - text-align: left; - } - #pkg-updates td.pkg-arch { - text-align: right; - } - - #pkg-updates span.testing { - font-style: italic; - } - - #pkg-updates span.staging { - font-style: italic; - color: #ff8040; - } - -/* home: sidebar navigation */ -[dir="rtl"] #nav-sidebar ul { - margin: 0.5em 1em 0.5em 0; -} - -#nav-sidebar ul { - list-style: none; - margin: 0.5em 0 0.5em 1em; - padding: 0; -} - -/* home: sponsor banners */ -#arch-sponsors img { - padding: 0.3em 0; -} - -/* home: sidebar components (navlist, sponsors, pkgsearch, etc) */ -div.widget { - margin-bottom: 1.5em; -} - -/* feeds page */ -[dir="rtl"] #rss-feeds .rss { - padding-left: 20px; - background: url(rss.png) top left no-repeat; -} - -#rss-feeds .rss { - padding-right: 20px; - background: url(rss.png) top right no-repeat; -} - -/* artwork: logo images */ -#artwork img.inverted { - background: #333; - padding: 0; -} - -#artwork div.imagelist img { - display: inline; - margin: 0.75em; -} - -/* news: article list */ -[dir="rtl"] .news-nav { - float: left; -} -.news-nav { - float: right; - margin-top: -2.2em; -} - - .news-nav .prev, - .news-nav .next { - margin: 0 1em; - } - -/* news: article pages */ -div.news-article .article-info { - margin: 0; - color: #999; -} - -/* news: add/edit article */ -#newsform { - width: 60em; -} - - #newsform input[type=text], - #newsform textarea { - width: 75%; - } - -#news-preview { - display: none; -} - -/* todolists: list */ -[dir="rtl"] .todolist-nav { - float: left; -} -.todolist-nav { - float: right; - margin-top: -2.2em; -} - - .todolist-nav .prev, - .todolist-nav .next { - margin: 0 1em; - } - -/* donate: donor list */ -#donor-list ul { - width: 100%; -} - /* max 4 columns, but possibly fewer if screen size doesn't allow for more */ - [dir="rtl"] #donor-list li { - float: right; - } - #donor-list li { - float: left; - width: 25%; - min-width: 20em; - } - -/* download page */ -#arch-downloads h3 { - border-bottom: 1px dotted #bbb; -} - -/* pkglists/devlists */ -table.results { - font-size: 0.846em; - border-top: 1px dotted #999; - border-bottom: 1px dotted #999; - direction: ltr; -} - - [dir="rtl"] .results th {text-align: center; direction:rtl;} - .results th { - padding: 0.5em 1em 0.25em 0.25em; - border-bottom: 1px solid #999; - white-space: nowrap; - background-color:#fff; - } - - .results td { - padding: .3em 1em .3em 3px; - text-align: left; - } - - .results .flagged { - color: red; - } - - .results tr.empty td { - text-align: center; - } - -/* pkglist: layout */ -#pkglist-about { - margin-top: 1.5em; -} - -/* pkglist: results navigation */ -.pkglist-stats { - font-size: 0.85em; -} - -[dir="rtl"] #pkglist-results .pkglist-nav { - float: left; -} -#pkglist-results .pkglist-nav { - float: right; - margin-top: -2.2em; -} - -[dir="rtl"] .pkglist-nav .prev { - margin-left: 1em; -} - -.pkglist-nav .prev { - margin-right: 1em; -} - -[dir="rtl"] .pkglist-nav .next { - margin-left: 1em; -} -.pkglist-nav .next { - margin-right: 1em; -} - -/* search fields and other filter selections */ -.filter-criteria { - margin-bottom: 1em; -} - -.filter-criteria h3 { - font-size: 1em; - margin-top: 0; -} -[dir="rtl"] .filter-criteria div { - float: right; - margin-left: 1.65em; -} -.filter-criteria div { - float: left; - margin-right: 1.65em; - font-size: 0.85em; -} - -.filter-criteria legend { - display: none; -} - -.filter-criteria label { - width: auto; - display: block; - font-weight: normal; -} - -/* pkgdetails: details links that float on the right */ -[dir="rtl"] #pkgdetails #detailslinks { - float: left; -} -#pkgdetails #detailslinks { - float: right; -} - - #pkgdetails #detailslinks h4 { - margin-top: 0; - margin-bottom: 0.25em; - } - - #pkgdetails #detailslinks ul { - list-style: none; - padding: 0; - margin-bottom: 0; - font-size: 0.846em; - } - - #pkgdetails #detailslinks > div { - padding: 0.5em; - margin-bottom: 1em; - background: #eee; - border: 1px solid #bbb; - } - -#pkgdetails #actionlist .flagged { - color: red; - font-size: 0.9em; - font-style: italic; -} - -/* pkgdetails: pkg info */ -#pkgdetails #pkginfo { - width: auto; -} - -[dir="rtl"] #pkgdetails td { - padding: 0.25em 1.5em 0.25em 0; - } - - #pkgdetails #pkginfo td { - padding: 0.25em 0 0.25em 1.5em; - } - - #pkgdetails #pkginfo .userdata { - font-size: 0.85em; - padding: 0.5em; - } - -/* pkgdetails: flag package */ -#flag-pkg-form label { - width: 10em; -} - -#flag-pkg-form textarea, -#flag-pkg-form input[type=text] { - width: 45%; -} - -#flag-pkg-form #id_website { - display: none; -} - -/* pkgdetails: deps, required by and file lists */ -#pkgdetails #metadata { - clear: both; -} - -#pkgdetails #metadata h3 { - background: #555; - color: #fff; - font-size: 1em; - margin-bottom: 0.5em; - padding: 0.2em 0.35em; -} - -#pkgdetails #metadata ul { - list-style: none; - margin: 0; - padding: 0; -} - -[dir="rtl"] #pkgdetails #metadata li { - padding-right: 0.5em; -} - -#pkgdetails #metadata li { - padding-left: 0.5em; -} - -[dir="rtl"] #pkgdetails #metadata p { - padding-right: 0.5em; -} -#pkgdetails #metadata p { - padding-left: 0.5em; -} - -#pkgdetails #metadata .message { - font-style: italic; -} - -#pkgdetails #metadata br { - clear: both; -} - -[dir="rtl"] #pkgdetails #pkgdeps { - float: right; - width: 48%; - margin-left: 2%; - -} -#pkgdetails #pkgdeps { - float: left; - width: 48%; - margin-right: 2%; -} - -#pkgdetails #metadata .virtual-dep, -#pkgdetails #metadata .testing-dep, -#pkgdetails #metadata .staging-dep, -#pkgdetails #metadata .opt-dep, -#pkgdetails #metadata .make-dep, -#pkgdetails #metadata .check-dep, -#pkgdetails #metadata .dep-desc { - font-style: italic; -} - -[dir="rtl"] #pkgdetails #pkgreqs { - float: right; - width: 48%; -} - -#pkgdetails #pkgreqs { - float: left; - width: 50%; -} - -#pkgdetails #pkgfiles { - clear: both; - padding-top: 1em; -} - -#pkgfilelist li.d { - color: #666; -} - -#pkgfilelist li.f { -} - -/* mirror stuff */ -table td.country { - white-space: normal; -} - -#list-generator div ul { - list-style: none; - display: inline; - padding-left: 0; -} - - #list-generator div ul li { - display: inline; - } - -.visualize-mirror .axis path, -.visualize-mirror .axis line { - fill: none; - stroke: #000; - stroke-width: 3px; - shape-rendering: crispEdges; -} - -.visualize-mirror .url-dot { - stroke: #000; -} - -.visualize-mirror .url-line { - fill: none; - stroke-width: 1.5px; -} - -/* dev/TU biographies */ -#arch-bio-toc { - width: 75%; - margin: 0 auto; - text-align: center; -} - - #arch-bio-toc a { - white-space: nowrap; - } - -.arch-bio-entry { - width: 75%; - min-width: 640px; - margin: 0 auto; -} - .arch-bio-entry td.pic { - padding-left: 15px; - } - .arch-bio-entry td.pic { - vertical-align: top; - padding-right: 15px; - padding-top: 2.25em; - } - - .arch-bio-entry td.pic img { - padding: 4px; - border: 1px solid #ccc; - } - - .arch-bio-entry td h3 { - border-bottom: 1px dotted #ccc; - margin-bottom: 0.5em; - } - - .arch-bio-entry table.bio { - margin-bottom: 2em; - } - [dir="rtl"] .arch-bio-entry table.bio th { - text-align: left; - padding-left: 0.5em; - } - - .arch-bio-entry table.bio th { - color: #666; - font-weight: normal; - text-align: right; - padding-right: 0.5em; - vertical-align: top; - white-space: nowrap; - } - - .arch-bio-entry table.bio td { - width: 100%; - padding-bottom: 0.25em; - white-space: normal; - } - -/* dev: login/out */ -#dev-login { - width: auto; -} - -/* tables rows: highlight on mouse-vover */ -#article-list tr:hover, -#clocks-table tr:hover, -#dev-dashboard tr:hover, -#dev-todo-lists tr:hover, -#dev-todo-pkglist tr:hover, -#pkglist-results tr:hover, -#stats-area tr:hover { - background: #ffd; -} - -.results tr:nth-child(even), -#article-list tr:nth-child(even) { - background: #e4eeff; -} - -.results tr:nth-child(odd), -#article-list tr:nth-child(odd) { - background: #fff; -} - -/* dev dashboard: */ -table.dash-stats .key { - width: 50%; -} - -/* dev dashboard: admin actions (add news items, todo list, etc) */ -[dir="rtl"] ul.admin-actions { - float: left; -} -ul.admin-actions { - float: right; - list-style: none; - margin-top: -2.5em; -} - - ul.admin-actions li { - display: inline; - padding-left: 1.5em; - } - -/* colored yes/no type values */ -.todo-table .complete, -.signoff-yes, -#key-status .signed-yes, -#release-list .available-yes { - color: green; -} - -.todo-table .incomplete, -.signoff-no, -#key-status .signed-no, -#release-list .available-no { - color: red; -} - -.todo-table .inprogress, -.signoff-bad { - color: darkorange; -} - - -/* todo lists (public and private) */ -.todo-info { - color: #999; - border-bottom: 1px dotted #bbb; -} - -.todo-description { - margin-top: 1em; - padding-left: 2em; - max-width: 900px; -} - -.todo-pkgbases { - border-top: 1px dotted #bbb; -} - -.todo-list h4 { - margin-top: 0; - margin-bottom: 0.4em; -} - -/* dev: signoff page */ -#dev-signoffs tr:hover { - background: #ffd; -} - -ul.signoff-list { - list-style: none; - margin: 0; - padding: 0; -} - -.signoff-yes { - font-weight: bold; -} - -.signoff-disabled { - color: gray; -} - -/* highlight current website in the navbar */ -#archnavbar.anb-home ul li#anb-home a, -#archnavbar.anb-packages ul li#anb-packages a, -#archnavbar.anb-download ul li#anb-download a { - color: white !important; -} - -/* visualizations page */ -.visualize-buttons { - margin: 0.5em 0.33em; -} - -.visualize-chart { - position: relative; - height: 500px; - margin: 0.33em; -} - -#visualize-archrepo .treemap-cell { - border: solid 1px white; - overflow: hidden; - position: absolute; -} - - #visualize-archrepo .treemap-cell span { - padding: 3px; - font-size: 0.85em; - line-height: 1em; - } - -#visualize-keys svg { - width: 100%; - height: 100%; -} - -/* releases */ -#release-table th:first-of-type { - width: 30px; -} - -/* itemprops */ -.itemprop { - display: none; -} diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css deleted file mode 100644 index 64a65742..00000000 --- a/web/html/css/aurweb.css +++ /dev/null @@ -1,292 +0,0 @@ -/* aurweb-specific customizations to archweb.css */ - -#archnavbar.anb-aur ul li#anb-aur a { - color: white !important; -} - -#archnavbarlogo { - background: url('archnavbar/aurlogo.png') !important; -} - -[dir="rtl"] #lang_sub { - float: left; - } -#lang_sub { - float: right; -} - -.pkglist-nav .page { - margin: 0 .25em; -} - -#pkg-stats td.stat-desc { - white-space: normal; -} - -#actionlist form { - margin: 0; - padding: 0; -} - -.arch-bio-entry ul { - list-style: none; - padding: 0; -} - -#pkg-updates table { - table-layout: fixed; - width:100%; -} - -#pkg-updates td.pkg-name { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -[dir="rtl"] #pkg-updates td.pkg-date { - text-align:left; -} -#pkg-updates td.pkg-date { - text-align:right; -} - -[dir="rtl"] .keyword:link, .keyword:visited { - float: right; -} - -.keyword:link, .keyword:visited { - float: left; - margin: 1px .5ex 1px 0; - padding: 0 1em; - color: white; - background-color: #36a; - border: 1px solid transparent; - border-radius: 2px; -} - -.keyword:hover { - cursor: pointer; -} - -.keyword:focus { - border: 1px dotted #000; -} - -.text-button { - background: transparent; - border: none !important; - margin: 0 !important; - padding: 0 !important; - font: normal 100% sans-serif; - text-decoration: none; - color: #07b; - cursor: pointer; -} - -.text-button:hover { - text-decoration: underline; - color: #666; -} - -.text-button::-moz-focus-inner { - padding: 0; - border: none; -} - -.comment-deleted { - color: #999; -} - -.edited { - font-size: 0.9em; - color: #999; -} - -[dir="rtl"] .delete-comment-form, .undelete-comment-form, .pin-comment-form, .edit-comment { - float: left; - margin-right: 8px; -} - -.delete-comment-form, .undelete-comment-form, .pin-comment-form, .edit-comment { - float: right; - margin-left: 8px; -} - -.edit-comment { - height: 11px; - position: relative; - top: 1px; -} - -.comment-enable-notifications { - display: inline-block; - margin-left: 1em; -} - -.rss-icon, .delete-comment, .undelete-comment, .edit-comment, .pin-comment { - filter: grayscale(100%); - opacity: 0.6; -} - -.rss-icon:hover, .delete-comment:hover, .undelete-comment:hover, .edit-comment:hover, .pin-comment:hover { - filter: none; - opacity: 1; -} - -[dir="rtl"] .ajax-loader { - float: left; -} - -.ajax-loader { - float: right; - position: relative; - top: 4px; -} - -.flagged a { - color: inherit; -} - -legend { - padding: 1em 0; -} - -p.important { - font-weight: bold; -} - -span.hover-help { - border-bottom: 1px dotted black; - cursor:help; -} - -label.confirmation { - width: auto; -} - -#pkgdepslist .broken { - color: red; - font-weight: bold; -} - -.package-comments { - margin-top: 1.5em; -} - -.comments-header { - display: flex; - justify-content: space-between; - align-items: flex-start; -} - -/* arrowed headings */ -.comments-header h3 span.text { - display: block; - background: #1794D1; - font-size: 15px; - padding: 2px 10px; - color: white; -} - -.comments-header .comments-header-nav { - align-self: flex-end; -} - -.comments-footer { - display: flex; - justify-content: flex-end; -} - -.comment-header { - clear: both; - font-size: 1em; - margin-top: 1.5em; - border-bottom: 1px dotted #bbb; -} - -.comments div { - margin-bottom: 1em; -} - -.comments div p { - margin-bottom: 0.5em; -} - -.comments .more { - font-weight: normal; -} - -.error { - color: red; -} - -.article-content > div { - overflow: hidden; - transition: height 1s; -} - -.proposal.details { - margin: .33em 0 1em; -} - -button[type="submit"], -button[type="reset"] { - padding: 0 0.6em; -} - -.results tr td[align="left"] fieldset { - text-align: left; -} - -.results tr td[align="right"] fieldset { - text-align: right; -} - -input#search-action-submit { - width: 80px; -} - -.success { - color: green; -} - -/* Styling used to clone styles for a form.link button. */ -form.link, form.link button { - display: inline; - font-family: sans-serif; -} -form.link button { - padding: 0 0.5em; - color: #07b; - background: none; - border: none; - font-family: inherit; - font-size: inherit; -} -form.link button:hover { - cursor: pointer; - text-decoration: underline; -} - -/* Customize form.link when used inside of a page. */ -div.box form.link p { - margin: .33em 0 1em; -} -div.box form.link button { - padding: 0; -} - -pre.traceback { - /* https://css-tricks.com/snippets/css/make-pre-text-wrap/ */ - white-space: pre-wrap; - word-wrap: break-all; -} - -/* By default, tables use 100% width, which we do not always want. */ -table.no-width { - width: auto; -} -table.no-width > tbody > tr > td { - padding-right: 2px; -} diff --git a/web/html/css/cgit.css b/web/html/css/cgit.css deleted file mode 100644 index 429b5f54..00000000 --- a/web/html/css/cgit.css +++ /dev/null @@ -1,866 +0,0 @@ -/* - * ARCH GLOBAL NAVBAR - * We're forcing all generic selectors with !important - * to help prevent other stylesheets from interfering. - */ - -/* container for the entire bar */ -#archnavbar { height: 40px !important; padding: 10px 15px !important; background: #333 !important; border-bottom: 5px #08c solid !important; } -#archnavbarlogo { float: left !important; margin: 0 !important; padding: 0 !important; height: 40px !important; width: 190px !important; background: url('archnavbar/archlogo.png') no-repeat !important; } - -/* move the heading text offscreen */ -#archnavbarlogo h1 { margin: 0 !important; padding: 0 !important; text-indent: -9999px !important; } - -/* make the link the same size as the logo */ -#archnavbarlogo a { display: block !important; height: 40px !important; width: 190px !important; } - -/* display the list inline, float it to the right and style it */ -#archnavbarlist { display: inline !important; float: right !important; list-style: none !important; margin: 0 !important; padding: 0 !important; } -#archnavbarlist li { float: left !important; font-size: 14px !important; font-family: sans-serif !important; line-height: 45px !important; padding-right: 15px !important; padding-left: 15px !important; } - -/* style the links */ -#archnavbarlist li a { color: #999; font-weight: bold !important; text-decoration: none !important; } -#archnavbarlist li a:hover { color: white !important; text-decoration: underline !important; } - -/* END ARCH GLOBAL NAVBAR */ - -#footer { - clear: both; - margin: 0; -} - -#footer p { - margin: 1em; -} - -#archnavbar.anb-aur ul li#anb-aur a { - color: white !important; -} - -#archnavbarlogo { - background: url('archnavbar/aurlogo.png') !important; -} - -body { - padding: 0; - margin: 0; - font-family: sans-serif; - font-size: 10pt; - color: #333; - background: white; -} - -div#cgit a { - color: blue; - text-decoration: none; -} - -div#cgit a:hover { - text-decoration: underline; -} - -div#cgit table { - border-collapse: collapse; -} - -div#cgit table#header { - width: 100%; - margin-bottom: 1em; -} - -div#cgit table#header td.logo { - width: 96px; - vertical-align: top; -} - -div#cgit table#header td.main { - font-size: 250%; - padding-left: 10px; - white-space: nowrap; -} - -div#cgit table#header td.main a { - color: #000; -} - -div#cgit table#header td.form { - text-align: right; - vertical-align: bottom; - padding-right: 1em; - padding-bottom: 2px; - white-space: nowrap; -} - -div#cgit table#header td.form form, -div#cgit table#header td.form input, -div#cgit table#header td.form select { - font-size: 90%; -} - -div#cgit table#header td.sub { - color: #777; - border-top: solid 1px #ccc; - padding-left: 10px; -} - -div#cgit table.tabs { - border-bottom: solid 3px #ccc; - border-collapse: collapse; - margin-top: 2em; - margin-bottom: 0px; - width: 100%; -} - -div#cgit table.tabs td { - padding: 0px 1em; - vertical-align: bottom; -} - -div#cgit table.tabs td a { - padding: 2px 0.75em; - color: #777; - font-size: 110%; -} - -div#cgit table.tabs td a.active { - color: #000; - background-color: #ccc; -} - -div#cgit table.tabs td.form { - text-align: right; -} - -div#cgit table.tabs td.form form { - padding-bottom: 2px; - font-size: 90%; - white-space: nowrap; -} - -div#cgit table.tabs td.form input, -div#cgit table.tabs td.form select { - font-size: 90%; -} - -div#cgit div.path { - margin: 0px; - padding: 5px 2em 2px 2em; - color: #000; - background-color: #eee; -} - -div#cgit div.content { - margin: 0px; - padding: 2em; - border-bottom: solid 3px #ccc; -} - - -div#cgit table.list { - width: 100%; - border: none; - border-collapse: collapse; -} - -div#cgit table.list tr { - background: white; -} - -div#cgit table.list tr.logheader { - background: #eee; -} - -div#cgit table.list tr:hover { - background: #eee; -} - -div#cgit table.list tr.nohover:hover { - background: white; -} - -div#cgit table.list th { - font-weight: bold; - /* color: #888; - border-top: dashed 1px #888; - border-bottom: dashed 1px #888; - */ - padding: 0.1em 0.5em 0.05em 0.5em; - vertical-align: baseline; -} - -div#cgit table.list td { - border: none; - padding: 0.1em 0.5em 0.1em 0.5em; -} - -div#cgit table.list td.commitgraph { - font-family: monospace; - white-space: pre; -} - -div#cgit table.list td.commitgraph .column1 { - color: #a00; -} - -div#cgit table.list td.commitgraph .column2 { - color: #0a0; -} - -div#cgit table.list td.commitgraph .column3 { - color: #aa0; -} - -div#cgit table.list td.commitgraph .column4 { - color: #00a; -} - -div#cgit table.list td.commitgraph .column5 { - color: #a0a; -} - -div#cgit table.list td.commitgraph .column6 { - color: #0aa; -} - -div#cgit table.list td.logsubject { - font-family: monospace; - font-weight: bold; -} - -div#cgit table.list td.logmsg { - font-family: monospace; - white-space: pre; - padding: 0 0.5em; -} - -div#cgit table.list td a { - color: black; -} - -div#cgit table.list td a.ls-dir { - font-weight: bold; - color: #00f; -} - -div#cgit table.list td a:hover { - color: #00f; -} - -div#cgit img { - border: none; -} - -div#cgit input#switch-btn { - margin: 2px 0px 0px 0px; -} - -div#cgit td#sidebar input.txt { - width: 100%; - margin: 2px 0px 0px 0px; -} - -div#cgit table#grid { - margin: 0px; -} - -div#cgit td#content { - vertical-align: top; - padding: 1em 2em 1em 1em; - border: none; -} - -div#cgit div#summary { - vertical-align: top; - margin-bottom: 1em; -} - -div#cgit table#downloads { - float: right; - border-collapse: collapse; - border: solid 1px #777; - margin-left: 0.5em; - margin-bottom: 0.5em; -} - -div#cgit table#downloads th { - background-color: #ccc; -} - -div#cgit div#blob { - border: solid 1px black; -} - -div#cgit div.error { - color: red; - font-weight: bold; - margin: 1em 2em; -} - -div#cgit a.ls-blob, div#cgit a.ls-dir, div#cgit a.ls-mod { - font-family: monospace; -} - -div#cgit td.ls-size { - text-align: right; - font-family: monospace; - width: 10em; -} - -div#cgit td.ls-mode { - font-family: monospace; - width: 10em; -} - -div#cgit table.blob { - margin-top: 0.5em; - border-top: solid 1px black; -} - -div#cgit table.blob td.lines { - margin: 0; padding: 0 0 0 0.5em; - vertical-align: top; - color: black; -} - -div#cgit table.blob td.linenumbers { - margin: 0; padding: 0 0.5em 0 0.5em; - vertical-align: top; - text-align: right; - border-right: 1px solid gray; -} - -div#cgit table.blob pre { - padding: 0; margin: 0; -} - -div#cgit table.blob a.no, div#cgit table.ssdiff a.no { - color: gray; - text-align: right; - text-decoration: none; -} - -div#cgit table.blob a.no a:hover { - color: black; -} - -div#cgit table.bin-blob { - margin-top: 0.5em; - border: solid 1px black; -} - -div#cgit table.bin-blob th { - font-family: monospace; - white-space: pre; - border: solid 1px #777; - padding: 0.5em 1em; -} - -div#cgit table.bin-blob td { - font-family: monospace; - white-space: pre; - border-left: solid 1px #777; - padding: 0em 1em; -} - -div#cgit table.nowrap td { - white-space: nowrap; -} - -div#cgit table.commit-info { - border-collapse: collapse; - margin-top: 1.5em; -} - -div#cgit div.cgit-panel { - float: right; - margin-top: 1.5em; -} - -div#cgit div.cgit-panel table { - border-collapse: collapse; - border: solid 1px #aaa; - background-color: #eee; -} - -div#cgit div.cgit-panel th { - text-align: center; -} - -div#cgit div.cgit-panel td { - padding: 0.25em 0.5em; -} - -div#cgit div.cgit-panel td.label { - padding-right: 0.5em; -} - -div#cgit div.cgit-panel td.ctrl { - padding-left: 0.5em; -} - -div#cgit table.commit-info th { - text-align: left; - font-weight: normal; - padding: 0.1em 1em 0.1em 0.1em; - vertical-align: top; -} - -div#cgit table.commit-info td { - font-weight: normal; - padding: 0.1em 1em 0.1em 0.1em; -} - -div#cgit div.commit-subject { - font-weight: bold; - font-size: 125%; - margin: 1.5em 0em 0.5em 0em; - padding: 0em; -} - -div#cgit div.commit-msg { - white-space: pre; - font-family: monospace; -} - -div#cgit div.notes-header { - font-weight: bold; - padding-top: 1.5em; -} - -div#cgit div.notes { - white-space: pre; - font-family: monospace; - border: solid 1px #ee9; - background-color: #ffd; - padding: 0.3em 2em 0.3em 1em; - float: left; -} - -div#cgit div.notes-footer { - clear: left; -} - -div#cgit div.diffstat-header { - font-weight: bold; - padding-top: 1.5em; -} - -div#cgit table.diffstat { - border-collapse: collapse; - border: solid 1px #aaa; - background-color: #eee; -} - -div#cgit table.diffstat th { - font-weight: normal; - text-align: left; - text-decoration: underline; - padding: 0.1em 1em 0.1em 0.1em; - font-size: 100%; -} - -div#cgit table.diffstat td { - padding: 0.2em 0.2em 0.1em 0.1em; - font-size: 100%; - border: none; -} - -div#cgit table.diffstat td.mode { - white-space: nowrap; -} - -div#cgit table.diffstat td span.modechange { - padding-left: 1em; - color: red; -} - -div#cgit table.diffstat td.add a { - color: green; -} - -div#cgit table.diffstat td.del a { - color: red; -} - -div#cgit table.diffstat td.upd a { - color: blue; -} - -div#cgit table.diffstat td.graph { - width: 500px; - vertical-align: middle; -} - -div#cgit table.diffstat td.graph table { - border: none; -} - -div#cgit table.diffstat td.graph td { - padding: 0px; - border: 0px; - height: 7pt; -} - -div#cgit table.diffstat td.graph td.add { - background-color: #5c5; -} - -div#cgit table.diffstat td.graph td.rem { - background-color: #c55; -} - -div#cgit div.diffstat-summary { - color: #888; - padding-top: 0.5em; -} - -div#cgit table.diff { - width: 100%; -} - -div#cgit table.diff td { - font-family: monospace; - white-space: pre; -} - -div#cgit table.diff td div.head { - font-weight: bold; - margin-top: 1em; - color: black; -} - -div#cgit table.diff td div.hunk { - color: #009; -} - -div#cgit table.diff td div.add { - color: green; -} - -div#cgit table.diff td div.del { - color: red; -} - -div#cgit .sha1 { - font-family: monospace; - font-size: 90%; -} - -div#cgit .left { - text-align: left; -} - -div#cgit .right { - text-align: right; - float: none !important; - width: auto !important; - padding: 0 !important; -} - -div#cgit table.list td.reposection { - font-style: italic; - color: #888; -} - -div#cgit a.button { - font-size: 80%; - padding: 0em 0.5em; -} - -div#cgit a.primary { - font-size: 100%; -} - -div#cgit a.secondary { - font-size: 90%; -} - -div#cgit td.toplevel-repo { - -} - -div#cgit table.list td.sublevel-repo { - padding-left: 1.5em; -} - -div#cgit ul.pager { - list-style-type: none; - text-align: center; - margin: 1em 0em 0em 0em; - padding: 0; -} - -div#cgit ul.pager li { - display: inline-block; - margin: 0.25em 0.5em; -} - -div#cgit ul.pager a { - color: #777; -} - -div#cgit ul.pager .current { - font-weight: bold; -} - -div#cgit span.age-mins { - font-weight: bold; - color: #080; -} - -div#cgit span.age-hours { - color: #080; -} - -div#cgit span.age-days { - color: #040; -} - -div#cgit span.age-weeks { - color: #444; -} - -div#cgit span.age-months { - color: #888; -} - -div#cgit span.age-years { - color: #bbb; -} -div#cgit div.footer { - margin-top: 0.5em; - text-align: center; - font-size: 80%; - color: #ccc; -} -div#cgit a.branch-deco { - color: #000; - margin: 0px 0.5em; - padding: 0px 0.25em; - background-color: #88ff88; - border: solid 1px #007700; -} -div#cgit a.tag-deco { - color: #000; - margin: 0px 0.5em; - padding: 0px 0.25em; - background-color: #ffff88; - border: solid 1px #777700; -} -div#cgit a.remote-deco { - color: #000; - margin: 0px 0.5em; - padding: 0px 0.25em; - background-color: #ccccff; - border: solid 1px #000077; -} -div#cgit a.deco { - color: #000; - margin: 0px 0.5em; - padding: 0px 0.25em; - background-color: #ff8888; - border: solid 1px #770000; -} - -div#cgit div.commit-subject a.branch-deco, -div#cgit div.commit-subject a.tag-deco, -div#cgit div.commit-subject a.remote-deco, -div#cgit div.commit-subject a.deco { - margin-left: 1em; - font-size: 75%; -} - -div#cgit table.stats { - border: solid 1px black; - border-collapse: collapse; -} - -div#cgit table.stats th { - text-align: left; - padding: 1px 0.5em; - background-color: #eee; - border: solid 1px black; -} - -div#cgit table.stats td { - text-align: right; - padding: 1px 0.5em; - border: solid 1px black; -} - -div#cgit table.stats td.total { - font-weight: bold; - text-align: left; -} - -div#cgit table.stats td.sum { - color: #c00; - font-weight: bold; -/* background-color: #eee; */ -} - -div#cgit table.stats td.left { - text-align: left; -} - -div#cgit table.vgraph { - border-collapse: separate; - border: solid 1px black; - height: 200px; -} - -div#cgit table.vgraph th { - background-color: #eee; - font-weight: bold; - border: solid 1px white; - padding: 1px 0.5em; -} - -div#cgit table.vgraph td { - vertical-align: bottom; - padding: 0px 10px; -} - -div#cgit table.vgraph div.bar { - background-color: #eee; -} - -div#cgit table.hgraph { - border: solid 1px black; - width: 800px; -} - -div#cgit table.hgraph th { - background-color: #eee; - font-weight: bold; - border: solid 1px black; - padding: 1px 0.5em; -} - -div#cgit table.hgraph td { - vertical-align: middle; - padding: 2px 2px; -} - -div#cgit table.hgraph div.bar { - background-color: #eee; - height: 1em; -} - -div#cgit table.ssdiff { - width: 100%; -} - -div#cgit table.ssdiff td { - font-size: 75%; - font-family: monospace; - white-space: pre; - padding: 1px 4px 1px 4px; - border-left: solid 1px #aaa; - border-right: solid 1px #aaa; -} - -div#cgit table.ssdiff td.add { - color: black; - background: #cfc; - min-width: 50%; -} - -div#cgit table.ssdiff td.add_dark { - color: black; - background: #aca; - min-width: 50%; -} - -div#cgit table.ssdiff span.add { - background: #cfc; - font-weight: bold; -} - -div#cgit table.ssdiff td.del { - color: black; - background: #fcc; - min-width: 50%; -} - -div#cgit table.ssdiff td.del_dark { - color: black; - background: #caa; - min-width: 50%; -} - -div#cgit table.ssdiff span.del { - background: #fcc; - font-weight: bold; -} - -div#cgit table.ssdiff td.changed { - color: black; - background: #ffc; - min-width: 50%; -} - -div#cgit table.ssdiff td.changed_dark { - color: black; - background: #cca; - min-width: 50%; -} - -div#cgit table.ssdiff td.lineno { - color: black; - background: #eee; - text-align: right; - width: 3em; - min-width: 3em; -} - -div#cgit table.ssdiff td.hunk { - color: black; - background: #ccf; - border-top: solid 1px #aaa; - border-bottom: solid 1px #aaa; -} - -div#cgit table.ssdiff td.head { - border-top: solid 1px #aaa; - border-bottom: solid 1px #aaa; -} - -div#cgit table.ssdiff td.head div.head { - font-weight: bold; - color: black; -} - -div#cgit table.ssdiff td.foot { - border-top: solid 1px #aaa; - border-left: none; - border-right: none; - border-bottom: none; -} - -div#cgit table.ssdiff td.space { - border: none; -} - -div#cgit table.ssdiff td.space div { - min-height: 3em; -} - -/* - * Style definitions generated by highlight 3.14, http://www.andre-simon.de/ - * Highlighting theme: Kwrite Editor - */ -div#cgit table.blob .num { color:#b07e00; } -div#cgit table.blob .esc { color:#ff00ff; } -div#cgit table.blob .str { color:#bf0303; } -div#cgit table.blob .pps { color:#818100; } -div#cgit table.blob .slc { color:#838183; font-style:italic; } -div#cgit table.blob .com { color:#838183; font-style:italic; } -div#cgit table.blob .ppc { color:#008200; } -div#cgit table.blob .opt { color:#000000; } -div#cgit table.blob .ipl { color:#0057ae; } -div#cgit table.blob .lin { color:#555555; } -div#cgit table.blob .kwa { color:#000000; font-weight:bold; } -div#cgit table.blob .kwb { color:#0057ae; } -div#cgit table.blob .kwc { color:#000000; font-weight:bold; } -div#cgit table.blob .kwd { color:#010181; } diff --git a/web/html/home.php b/web/html/home.php deleted file mode 100644 index 5ea79ee9..00000000 --- a/web/html/home.php +++ /dev/null @@ -1,215 +0,0 @@ - - -
-
- -
-

-

- 50, - 'SeB' => 'M', - 'K' => username_from_sid($_COOKIE["AURSID"]), - 'outdated' => 'on', - 'SB' => 'l', - 'SO' => 'a' - ); - pkg_search_page($params, false, $_COOKIE["AURSID"]); - ?> -

- -
-
-

-

">

- 50, - 'SeB' => 'm', - 'K' => username_from_sid($_COOKIE["AURSID"]), - 'SB' => 'l', - 'SO' => 'd' - ); - pkg_search_page($params, false, $_COOKIE["AURSID"]); - ?> -
-
-

-

">

- 50, - 'SeB' => 'c', - 'K' => username_from_sid($_COOKIE["AURSID"]), - 'SB' => 'l', - 'SO' => 'd' - ); - pkg_search_page($params, false, $_COOKIE["AURSID"]); - ?> -
- -
-

AUR

-

- ', - '', - '', - '' - ); - ?> - ', '', - '', - '' - ); - ?> - - -

-

- : - -

-

-
-
-

-

-
-

- ', - '' - ); - ?> -

-
    -
  • :
  • -
  • :
  • -
  • :
  • -
-

- ', - '' - ); - ?> -

-
-

-
-

- ', - '' - ); - ?> -

- -

- -

-
    - $fingerprint): ?> -
  • :
  • - -
- -
-

-
-

- ', - '', - '', - '' - ); - ?> -

-
-

-
-

- ', - '', - '', - '' - ); - ?> -

-
-
- -
-
-
-
-
-
- - - " maxlength="35" autocomplete="off"/> -
-
-
-
- -
-
- -
- -
- -
- - -
- - - - - diff --git a/web/html/images/action-undo.svg b/web/html/images/action-undo.svg deleted file mode 100644 index b93ebb78..00000000 --- a/web/html/images/action-undo.svg +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/web/html/images/ajax-loader.gif b/web/html/images/ajax-loader.gif deleted file mode 100644 index df07e7ec..00000000 Binary files a/web/html/images/ajax-loader.gif and /dev/null differ diff --git a/web/html/images/favicon.ico b/web/html/images/favicon.ico deleted file mode 100644 index 55497b85..00000000 Binary files a/web/html/images/favicon.ico and /dev/null differ diff --git a/web/html/images/pencil.min.svg b/web/html/images/pencil.min.svg deleted file mode 100644 index 06125ae0..00000000 --- a/web/html/images/pencil.min.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/html/images/pencil.svg b/web/html/images/pencil.svg deleted file mode 100644 index 91f08991..00000000 --- a/web/html/images/pencil.svg +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - diff --git a/web/html/images/pin.min.svg b/web/html/images/pin.min.svg deleted file mode 100644 index ac08903d..00000000 --- a/web/html/images/pin.min.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/web/html/images/pin.svg b/web/html/images/pin.svg deleted file mode 100644 index b4ee9eb7..00000000 --- a/web/html/images/pin.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/html/images/rss.svg b/web/html/images/rss.svg deleted file mode 100644 index 3c7f6ba1..00000000 --- a/web/html/images/rss.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/html/images/unpin.min.svg b/web/html/images/unpin.min.svg deleted file mode 100644 index 3cf2413c..00000000 --- a/web/html/images/unpin.min.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/web/html/images/unpin.svg b/web/html/images/unpin.svg deleted file mode 100644 index de897152..00000000 --- a/web/html/images/unpin.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/web/html/images/x.min.svg b/web/html/images/x.min.svg deleted file mode 100644 index 833d4f22..00000000 --- a/web/html/images/x.min.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/web/html/images/x.svg b/web/html/images/x.svg deleted file mode 100644 index e323fe19..00000000 --- a/web/html/images/x.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - diff --git a/web/html/index.php b/web/html/index.php deleted file mode 100644 index dc435162..00000000 --- a/web/html/index.php +++ /dev/null @@ -1,205 +0,0 @@ - '1'); - } - } - - include get_route('/' . $tokens[1]); -} elseif (!empty($tokens[1]) && '/' . $tokens[1] == get_pkgreq_route()) { - if (!empty($tokens[2])) { - /* TODO: Create a proper data structure to pass variables from - * the routing framework to the individual pages instead of - * initializing arbitrary variables here. */ - if (!empty($tokens[3]) && $tokens[3] == 'close') { - $pkgreq_id = $tokens[2]; - } else { - $pkgreq_id = null; - } - - if (!$pkgreq_id) { - header("HTTP/1.0 404 Not Found"); - include "./404.php"; - return; - } - } - - include get_route('/' . $tokens[1]); -} elseif (!empty($tokens[1]) && '/' . $tokens[1] == get_user_route()) { - if (!empty($tokens[2])) { - $_REQUEST['ID'] = uid_from_username($tokens[2]); - - if (!$_REQUEST['ID']) { - header("HTTP/1.0 404 Not Found"); - include "./404.php"; - return; - } - - if (!empty($tokens[3])) { - if ($tokens[3] == 'edit') { - $_REQUEST['Action'] = "DisplayAccount"; - } elseif ($tokens[3] == 'update') { - $_REQUEST['Action'] = "UpdateAccount"; - } elseif ($tokens[3] == 'delete') { - $_REQUEST['Action'] = "DeleteAccount"; - } elseif ($tokens[3] == 'comments') { - $_REQUEST['Action'] = "ListComments"; - } else { - header("HTTP/1.0 404 Not Found"); - include "./404.php"; - return; - } - } else { - $_REQUEST['Action'] = "AccountInfo"; - } - } - include get_route('/' . $tokens[1]); -} elseif (get_route($path) !== NULL) { - include get_route($path); -} else { - switch ($path) { - case "/css/archweb.css": - case "/css/aurweb.css": - case "/css/cgit.css": - case "/css/archnavbar/archnavbar.css": - header("Content-Type: text/css"); - readfile("./$path"); - break; - case "/images/ajax-loader.gif": - header("Content-Type: image/gif"); - readfile("./$path"); - break; - case "/css/archnavbar/archlogo.png": - case "/css/archnavbar/aurlogo.png": - case "/images/favicon.ico": - header("Content-Type: image/png"); - readfile("./$path"); - break; - case "/images/x.min.svg": - case "/images/action-undo.min.svg": - case "/images/pencil.min.svg": - case "/images/pin.min.svg": - case "/images/unpin.min.svg": - case "/images/rss.svg": - header("Content-Type: image/svg+xml"); - readfile("./$path"); - break; - case "/js/typeahead.js": - header("Content-Type: application/javascript"); - readfile("./$path"); - break; - case "/packages.gz": - case "/packages-meta-v1.json.gz": - case "/packages-meta-ext-v1.json.gz": - case "/pkgbase.gz": - case "/users.gz": - header("Content-Type: text/plain"); - header("Content-Encoding: gzip"); - readfile("./$path"); - break; - default: - header("HTTP/1.0 404 Not Found"); - include "./404.php"; - break; - } -} diff --git a/web/html/js/comment-edit.js b/web/html/js/comment-edit.js deleted file mode 100644 index 23ffdd34..00000000 --- a/web/html/js/comment-edit.js +++ /dev/null @@ -1,61 +0,0 @@ -function add_busy_indicator(sibling) { - const img = document.createElement('img'); - img.src = "/static/images/ajax-loader.gif"; - img.classList.add('ajax-loader'); - img.style.height = 11; - img.style.width = 16; - img.alt = "Busy…"; - - sibling.insertAdjacentElement('afterend', img); -} - -function remove_busy_indicator(sibling) { - const elem = sibling.nextElementSibling; - elem.parentNode.removeChild(elem); -} - -function getParentsUntil(elem, className) { - // Limit to 10 depth - for ( ; elem && elem !== document; elem = elem.parentNode) { - if (elem.matches(className)) { - break; - } - } - - return elem; -} - -function handleEditCommentClick(event, pkgbasename) { - event.preventDefault(); - const parent_element = getParentsUntil(event.target, '.comment-header'); - const parent_id = parent_element.id; - const comment_id = parent_id.substr(parent_id.indexOf('-') + 1); - // The div class="article-content" which contains the comment - const edit_form = parent_element.nextElementSibling; - - const url = "/pkgbase/" + pkgbasename + "/comments/" + comment_id + "/form?"; - - add_busy_indicator(event.target); - - fetch(url + new URLSearchParams({ next: window.location.pathname }), { - method: 'GET', - credentials: 'same-origin' - }) - .then(function(response) { - if (!response.ok) { - throw Error(response.statusText); - } - return response.json(); - }) - .then(function(data) { - remove_busy_indicator(event.target); - edit_form.innerHTML = data.form; - edit_form.querySelector('textarea').focus(); - }) - .catch(function(error) { - remove_busy_indicator(event.target); - console.error(error); - }); - - return false; -} diff --git a/web/html/js/copy.js b/web/html/js/copy.js deleted file mode 100644 index 3b659270..00000000 --- a/web/html/js/copy.js +++ /dev/null @@ -1,9 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - let elements = document.querySelectorAll('.copy'); - elements.forEach(function(el) { - el.addEventListener('click', function(e) { - e.preventDefault(); - navigator.clipboard.writeText(e.target.text); - }); - }); -}); diff --git a/web/html/js/typeahead-home.js b/web/html/js/typeahead-home.js deleted file mode 100644 index 5af51c53..00000000 --- a/web/html/js/typeahead-home.js +++ /dev/null @@ -1,6 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - const input = document.getElementById('pkgsearch-field'); - const form = document.getElementById('pkgsearch-form'); - const type = 'suggest'; - typeahead.init(type, input, form); -}); diff --git a/web/html/js/typeahead-pkgbase-merge.js b/web/html/js/typeahead-pkgbase-merge.js deleted file mode 100644 index a8c87e4f..00000000 --- a/web/html/js/typeahead-pkgbase-merge.js +++ /dev/null @@ -1,6 +0,0 @@ -document.addEventListener('DOMContentLoaded', function() { - const input = document.getElementById('merge_into'); - const form = document.getElementById('merge-form'); - const type = "suggest-pkgbase"; - typeahead.init(type, input, form, false); -}); diff --git a/web/html/js/typeahead-pkgbase-request.js b/web/html/js/typeahead-pkgbase-request.js deleted file mode 100644 index e012d55f..00000000 --- a/web/html/js/typeahead-pkgbase-request.js +++ /dev/null @@ -1,36 +0,0 @@ -function showHideMergeSection() { - const elem = document.getElementById('id_type'); - const merge_section = document.getElementById('merge_section'); - if (elem.value == 'merge') { - merge_section.style.display = ''; - } else { - merge_section.style.display = 'none'; - } -} - -function showHideRequestHints() { - document.getElementById('deletion_hint').style.display = 'none'; - document.getElementById('merge_hint').style.display = 'none'; - document.getElementById('orphan_hint').style.display = 'none'; - - const elem = document.getElementById('id_type'); - document.getElementById(elem.value + '_hint').style.display = ''; -} - -document.addEventListener('DOMContentLoaded', function() { - showHideMergeSection(); - showHideRequestHints(); - - const input = document.getElementById('id_merge_into'); - const form = document.getElementById('request-form'); - const type = "suggest-pkgbase"; - - typeahead.init(type, input, form, false); -}); - -// Bind the change event here, otherwise we have to inline javascript, -// which angers CSP (Content Security Policy). -document.getElementById("id_type").addEventListener("change", function() { - showHideMergeSection(); - showHideRequestHints(); -}); diff --git a/web/html/js/typeahead.js b/web/html/js/typeahead.js deleted file mode 100644 index bfd3d156..00000000 --- a/web/html/js/typeahead.js +++ /dev/null @@ -1,151 +0,0 @@ -"use strict"; - -const typeahead = (function() { - var input; - var form; - var suggest_type; - var list; - var submit = true; - - function resetResults() { - if (!list) return; - list.style.display = "none"; - list.innerHTML = ""; - } - - function getCompleteList() { - if (!list) { - list = document.createElement("UL"); - list.setAttribute("class", "pkgsearch-typeahead"); - form.appendChild(list); - setListLocation(); - } - return list; - } - - function onListClick(e) { - let target = e.target; - while (!target.getAttribute('data-value')) { - target = target.parentNode; - } - input.value = target.getAttribute('data-value'); - if (submit) { - form.submit(); - } - } - - function setListLocation() { - if (!list) return; - const rects = input.getClientRects()[0]; - list.style.top = (rects.top + rects.height) + "px"; - list.style.left = rects.left + "px"; - } - - function loadData(letter, data) { - const pkgs = data.slice(0, 10); // Show maximum of 10 results - - resetResults(); - - if (pkgs.length === 0) { - return; - } - - const ul = getCompleteList(); - ul.style.display = "block"; - const fragment = document.createDocumentFragment(); - - for (let i = 0; i < pkgs.length; i++) { - const item = document.createElement("li"); - const text = pkgs[i].replace(letter, '' + letter + ''); - item.innerHTML = '' + text + ''; - item.setAttribute('data-value', pkgs[i]); - fragment.appendChild(item); - } - - ul.appendChild(fragment); - ul.addEventListener('click', onListClick); - } - - function fetchData(letter) { - const url = '/rpc?v=5&type=' + suggest_type + '&arg=' + letter; - fetch(url).then(function(response) { - return response.json(); - }).then(function(data) { - loadData(letter, data); - }); - } - - function onInputClick() { - if (input.value === "") { - resetResults(); - return; - } - fetchData(input.value); - } - - function onKeyDown(e) { - if (!list) return; - - const elem = document.querySelector(".pkgsearch-typeahead li.active"); - switch(e.keyCode) { - case 13: // enter - if (!submit) { - return; - } - if (elem) { - input.value = elem.getAttribute('data-value'); - form.submit(); - } else { - form.submit(); - } - e.preventDefault(); - break; - case 38: // up - if (elem && elem.previousElementSibling) { - elem.className = ""; - elem.previousElementSibling.className = "active"; - } - e.preventDefault(); - break; - case 40: // down - if (elem && elem.nextElementSibling) { - elem.className = ""; - elem.nextElementSibling.className = "active"; - } else if (!elem && list.childElementCount !== 0) { - list.children[0].className = "active"; - } - e.preventDefault(); - break; - } - } - - // debounce https://davidwalsh.name/javascript-debounce-function - function debounce(func, wait, immediate) { - var timeout; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) func.apply(context, args); - }; - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) func.apply(context, args); - }; - } - - return { - init: function(type, inputfield, formfield, submitdata = true) { - suggest_type = type; - input = inputfield; - form = formfield; - submit = submitdata; - - input.addEventListener("input", onInputClick); - input.addEventListener("keydown", onKeyDown); - window.addEventListener('resize', debounce(setListLocation, 150)); - document.addEventListener("click", resetResults); - } - } -}()); diff --git a/web/html/login.php b/web/html/login.php deleted file mode 100644 index 3f3d66cc..00000000 --- a/web/html/login.php +++ /dev/null @@ -1,68 +0,0 @@ - -
-

AUR

- -

- ' . username_from_sid($_COOKIE["AURSID"]) . ''); ?> - [] -

- -
-
- - -
- -

- - -

-

- - -

-

- - -

-

- " /> - [] - - [] - - - - -

-
-
- -

- ', ''); ?> -

- -
-query("SELECT SSOAccountID FROM Users WHERE ID = " . $dbh->quote($uid)) - ->fetchColumn(); - if ($sso_account_id) - $redirect_uri = '/sso/logout'; - } -} - -header("Location: $redirect_uri"); diff --git a/web/html/modified-rss.php b/web/html/modified-rss.php deleted file mode 100644 index 4c5c47e0..00000000 --- a/web/html/modified-rss.php +++ /dev/null @@ -1,62 +0,0 @@ -cssStyleSheet = false; -$rss->xslStyleSheet = false; - -# Use UTF-8 (fixes FS#10706). -$rss->encoding = "UTF-8"; - -#All the general RSS setup -$rss->title = "AUR Latest Modified Packages"; -$rss->description = "The latest modified packages in the AUR"; -$rss->link = "${protocol}://{$host}"; -$rss->syndicationURL = "{$protocol}://{$host}" . get_uri('/rss/'); -$image = new FeedImage(); -$image->title = "AUR Latest Modified Packages"; -$image->url = "{$protocol}://{$host}/css/archnavbar/aurlogo.png"; -$image->link = $rss->link; -$image->description = "AUR Latest Modified Packages Feed"; -$rss->image = $image; - -#Get the latest packages and add items for them -$packages = latest_modified_pkgs(100); - -foreach ($packages as $indx => $row) { - $item = new FeedItem(); - $item->title = $row["Name"]; - $item->link = "{$protocol}://{$host}" . get_pkg_uri($row["Name"]); - $item->description = $row["Description"]; - $item->date = intval($row["ModifiedTS"]); - $item->source = "{$protocol}://{$host}"; - $item->author = username_from_id($row["MaintainerUID"]); - $item->guidIsPermaLink = true; - $item->guid = $row["Name"] . "-" . $row["ModifiedTS"]; - $rss->addItem($item); -} - -#save it so that useCached() can find it -$feedContent = $rss->createFeed(); -set_cache_value($feed_key, $feedContent, 600); -echo $feedContent; -?> diff --git a/web/html/packages.php b/web/html/packages.php deleted file mode 100644 index 24d1f82e..00000000 --- a/web/html/packages.php +++ /dev/null @@ -1,173 +0,0 @@ - - - - -\n"; - } -} else { - if (!isset($_GET['K']) && !isset($_GET['SB'])) { - $_GET['SB'] = 'p'; - $_GET['SO'] = 'd'; - } - echo '
'; - if (isset($_COOKIE["AURSID"])) { - pkg_search_page($_GET, true, $_COOKIE["AURSID"]); - } else { - pkg_search_page($_GET, true); - } - echo '
'; -} - -html_footer(AURWEB_VERSION); diff --git a/web/html/passreset.php b/web/html/passreset.php deleted file mode 100644 index 26b9bbbb..00000000 --- a/web/html/passreset.php +++ /dev/null @@ -1,100 +0,0 @@ - - -
-

- - -

- -

- - - - -
- - - - - - - - - - - - - -
-
- -
- -

', - ''); ?>

- - - -
-

-

- -
- -
- - $i) { - $id = intval($id); - if ($id > 0) { - $ids[] = $id; - } - } -} - -/* Perform package base actions. */ -$via = isset($_POST['via']) ? $_POST['via'] : NULL; -$return_to = isset($_POST['return_to']) ? $_POST['return_to'] : NULL; -$ret = false; -$output = ""; -$fragment = ""; -if (check_token()) { - if (current_action("do_Flag")) { - list($ret, $output) = pkgbase_flag($ids, $_POST['comments']); - } elseif (current_action("do_UnFlag")) { - list($ret, $output) = pkgbase_unflag($ids); - } elseif (current_action("do_Adopt")) { - list($ret, $output) = pkgbase_adopt($ids, true, NULL); - } elseif (current_action("do_Disown")) { - if (isset($_POST['confirm'])) { - list($ret, $output) = pkgbase_adopt($ids, false, $via); - } else { - $output = __("The selected packages have not been disowned, check the confirmation checkbox."); - $ret = false; - } - } elseif (current_action("do_DisownComaintainer")) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - list($ret, $output) = pkgbase_remove_comaintainer($base_id, $uid); - } elseif (current_action("do_Vote")) { - list($ret, $output) = pkgbase_vote($ids, true); - } elseif (current_action("do_UnVote")) { - list($ret, $output) = pkgbase_vote($ids, false); - } elseif (current_action("do_Delete")) { - if (isset($_POST['confirm'])) { - if (!isset($_POST['merge_Into']) || empty($_POST['merge_Into'])) { - list($ret, $output) = pkgbase_delete($ids, NULL, $via); - unset($_GET['ID']); - unset($base_id); - } - else { - $merge_base_id = pkgbase_from_name($_POST['merge_Into']); - if (!$merge_base_id) { - $output = __("Cannot find package to merge votes and comments into."); - $ret = false; - } elseif (in_array($merge_base_id, $ids)) { - $output = __("Cannot merge a package base with itself."); - $ret = false; - } else { - list($ret, $output) = pkgbase_delete($ids, $merge_base_id, $via); - unset($_GET['ID']); - unset($base_id); - } - } - } - else { - $output = __("The selected packages have not been deleted, check the confirmation checkbox."); - $ret = false; - } - } elseif (current_action("do_Notify")) { - list($ret, $output) = pkgbase_notify($ids); - } elseif (current_action("do_UnNotify")) { - list($ret, $output) = pkgbase_notify($ids, false); - } elseif (current_action("do_DeleteComment")) { - list($ret, $output) = pkgbase_delete_comment(); - } elseif (current_action("do_UndeleteComment")) { - list($ret, $output) = pkgbase_delete_comment(true); - if ($ret && isset($_POST["comment_id"])) { - $fragment = '#comment-' . intval($_POST["comment_id"]); - } - } elseif (current_action("do_PinComment")) { - list($ret, $output) = pkgbase_pin_comment(); - } elseif (current_action("do_UnpinComment")) { - list($ret, $output) = pkgbase_pin_comment(true); - } elseif (current_action("do_SetKeywords")) { - list($ret, $output) = pkgbase_set_keywords($base_id, preg_split("/[\s,;]+/", $_POST['keywords'], -1, PREG_SPLIT_NO_EMPTY)); - } elseif (current_action("do_FileRequest")) { - list($ret, $output) = pkgreq_file($ids, $_POST['type'], $_POST['merge_into'], $_POST['comments']); - } elseif (current_action("do_CloseRequest")) { - list($ret, $output) = pkgreq_close($_POST['reqid'], $_POST['reason'], $_POST['comments']); - } elseif (current_action("do_EditComaintainers")) { - list($ret, $output) = pkgbase_set_comaintainers($base_id, explode("\n", $_POST['users'])); - } elseif (current_action("do_AddComment")) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - list($ret, $output) = pkgbase_add_comment($base_id, $uid, $_REQUEST['comment']); - if ($ret && isset($_REQUEST['enable_notifications'])) { - list($ret, $output) = pkgbase_notify(array($base_id)); - } - $fragment = '#news'; - } elseif (current_action("do_EditComment")) { - list($ret, $output) = pkgbase_edit_comment($_REQUEST['comment']); - if ($ret && isset($_POST["comment_id"])) { - $fragment = '#comment-' . intval($_POST["comment_id"]); - } - } - - if ($ret) { - if (current_action("do_CloseRequest") || - (current_action("do_Delete") && $via)) { - /* Redirect back to package request page on success. */ - header('Location: ' . get_pkgreq_route()); - exit(); - } elseif ((current_action("do_DeleteComment") || - current_action("do_UndeleteComment")) && $return_to) { - header('Location: ' . $return_to); - exit(); - } elseif (current_action("do_PinComment") && $return_to) { - header('Location: ' . $return_to); - exit(); - } elseif (isset($base_id)) { - /* Redirect back to package base page on success. */ - header('Location: ' . get_pkgbase_uri($pkgbase_name) . $fragment); - exit(); - } else { - /* Redirect back to package search page. */ - header('Location: ' . get_pkg_route()); - exit(); - } - } -} - -if (isset($base_id)) { - $pkgs = pkgbase_get_pkgnames($base_id); - if (!$output && count($pkgs) == 1) { - /* Not a split package. Redirect to the package page. */ - if (empty($_SERVER['QUERY_STRING'])) { - header('Location: ' . get_pkg_uri($pkgs[0]) . $fragment); - } else { - header('Location: ' . get_pkg_uri($pkgs[0]) . '?' . $_SERVER['QUERY_STRING'] . $fragment); - } - } - - $details = pkgbase_get_details($base_id); -} else { - $details = array(); -} -html_header($title, $details); -?> - - - -

- - - - - - -
-

:

-

- ', htmlspecialchars($pkgbase_name), ''); ?> -

- -

- - -

-
-
- - - - - - -

-

" />

-
-
-
- - -
-

:

-

- ', htmlspecialchars($pkgbase_name), ''); ?> -

- -

- - - - 0 && !has_credential(CRED_PKGBASE_DISOWN)): ?> - ', $comaintainers[0], ''); ?> - - - -

-
-
- - - - - - -

" />

-
-
-
- - $i) { - $id = intval($id); - if ($id > 0) { - $ids[] = $id; - } - } -} - -/* Perform package base actions. */ -$ret = false; -$output = ""; -if (check_token()) { - if (current_action("do_Flag")) { - list($ret, $output) = pkgbase_flag($ids, $_POST['comments']); - } - - if ($ret) { - header('Location: ' . get_pkgbase_uri($pkgbase_name)); - exit(); - } -} - -/* Get default comment. */ -$comment = ''; -if (isset($_POST['comments'])) { - $comment = $_POST['comments']; -} - -html_header(__("Flag Package Out-Of-Date")); - -if (has_credential(CRED_PKGBASE_FLAG)): ?> -
-

:

-

- ', htmlspecialchars($pkgbase_name), ''); ?> -

- - -

- This seems to be a VCS package. Please do not - flag it out-of-date if the package version in the AUR does not - match the most recent commit. Flagging this package should only - be done if the sources moved or changes in the PKGBUILD are - required because of recent upstream changes. -

- -

- ', ''); ?> - -

- - - - - -
-
- - - -

- - -

-

" />

-
-
-
- - -
-

:

-

- ', htmlspecialchars($pkgbase_name), ''); ?> - -

- -

- - - -

-
-
- - - - - - - - -

-

-

-

" />

-
-
-
- - 0) ? $_GET['PP'] : 50; - $current = ceil($first / $per_page); - $pages = ceil($total / $per_page); - $templ_pages = array(); - - if ($current > 1) { - $templ_pages['« ' . __('First')] = 0; - $templ_pages['‹ ' . __('Previous')] = ($current - 2) * $per_page; - } - - if ($current - 5 > 1) - $templ_pages["..."] = false; - - for ($i = max($current - 5, 1); $i <= min($pages, $current + 5); $i++) { - $templ_pages[$i] = ($i - 1) * $per_page; - } - - if ($current + 5 < $pages) - $templ_pages["... "] = false; - - if ($current < $pages) { - $templ_pages[__('Next') . ' ›'] = $current * $per_page; - $templ_pages[__('Last') . ' »'] = ($pages - 1) * $per_page; - } - - $SID = $_COOKIE['AURSID']; - - html_header(__("Requests")); - echo '
'; - $show_headers = true; - include('pkgreq_results.php'); - echo '
'; -} - -html_footer(AURWEB_VERSION); diff --git a/web/html/register.php b/web/html/register.php deleted file mode 100644 index fee0a68f..00000000 --- a/web/html/register.php +++ /dev/null @@ -1,87 +0,0 @@ -'; -echo '

' . __('Register') . '

'; - -if (in_request("Action") == "NewAccount") { - list($success, $message) = process_account_form( - "new", - "NewAccount", - in_request("U"), - 1, - 0, - in_request("E"), - in_request("BE"), - in_request("H"), - '', - '', - in_request("R"), - in_request("L"), - in_request("TZ"), - in_request("HP"), - in_request("I"), - in_request("K"), - in_request("PK"), - 0, - in_request("CN"), - in_request("UN"), - in_request("ON"), - 0, - "", - '', - in_request("captcha_salt"), - in_request("captcha"), - ); - - print $message; - - if (!$success) { - display_account_form("NewAccount", - in_request("U"), - 1, - 0, - in_request("E"), - in_request("BE"), - in_request("H"), - '', - '', - in_request("R"), - in_request("L"), - in_request("TZ"), - in_request("HP"), - in_request("I"), - in_request("K"), - in_request("PK"), - 0, - in_request("CN"), - in_request("UN"), - in_request("ON"), - 0, - "", - '', - in_request("captcha_salt"), - in_request("captcha") - ); - } -} else { - print '

' . __("Use this form to create an account.") . '

'; - display_account_form("NewAccount", "", "", "", "", "", "", "", "", "", $LANG); -} - -echo ''; - -html_footer(AURWEB_VERSION); - -?> diff --git a/web/html/rpc.php b/web/html/rpc.php deleted file mode 100644 index 64c95622..00000000 --- a/web/html/rpc.php +++ /dev/null @@ -1,17 +0,0 @@ -handle($_GET); -} -else { - echo file_get_contents('../../doc/rpc.html'); -} -?> diff --git a/web/html/rss.php b/web/html/rss.php deleted file mode 100644 index 1e6335cf..00000000 --- a/web/html/rss.php +++ /dev/null @@ -1,61 +0,0 @@ -cssStyleSheet = false; -$rss->xslStyleSheet = false; - -# Use UTF-8 (fixes FS#10706). -$rss->encoding = "UTF-8"; - -#All the general RSS setup -$rss->title = "AUR Newest Packages"; -$rss->description = "The latest and greatest packages in the AUR"; -$rss->link = "${protocol}://{$host}"; -$rss->syndicationURL = "{$protocol}://{$host}" . get_uri('/rss/'); -$image = new FeedImage(); -$image->title = "AUR Newest Packages"; -$image->url = "{$protocol}://{$host}/css/archnavbar/aurlogo.png"; -$image->link = $rss->link; -$image->description = "AUR Newest Packages Feed"; -$rss->image = $image; - -#Get the latest packages and add items for them -$packages = latest_pkgs(100); - -foreach ($packages as $indx => $row) { - $item = new FeedItem(); - $item->title = $row["Name"]; - $item->link = "{$protocol}://{$host}" . get_pkg_uri($row["Name"]); - $item->description = $row["Description"]; - $item->date = intval($row["SubmittedTS"]); - $item->source = "{$protocol}://{$host}"; - $item->author = username_from_id($row["MaintainerUID"]); - $item->guid = $item->link; - $rss->addItem($item); -} - -#save it so that useCached() can find it -$feedContent = $rss->createFeed(); -set_cache_value($feed_key, $feedContent, 600); -echo $feedContent; -?> diff --git a/web/html/tos.php b/web/html/tos.php deleted file mode 100644 index fc5d8765..00000000 --- a/web/html/tos.php +++ /dev/null @@ -1,50 +0,0 @@ - -
-

AUR

- -
-
-

- ' . username_from_sid($_COOKIE["AURSID"]) . ''); ?> -

-

- -

-
    - -
  • "> ()
  • - -
-

- - ]" value="" /> - - -

-

- " /> -

-
-
- -
- time() ? 1 : 0; - - # List voters of a proposal. - $whovoted = voter_list($row['ID']); - - $canvote = 1; - $hasvoted = 0; - $errorvote = ""; - if ($isrunning == 0) { - $canvote = 0; - $errorvote = __("Voting is closed for this proposal."); - } else if (!has_credential(CRED_TU_VOTE)) { - $canvote = 0; - $errorvote = __("Only Trusted Users are allowed to vote."); - } else if ($row['User'] == username_from_sid($_COOKIE["AURSID"])) { - $canvote = 0; - $errorvote = __("You cannot vote in an proposal about you."); - } - if (tu_voted($row['ID'], uid_from_sid($_COOKIE["AURSID"]))) { - $canvote = 0; - $hasvoted = 1; - if ($isrunning) { - $errorvote = __("You've already voted for this proposal."); - } - } - - if ($canvote == 1) { - if (isset($_POST['doVote']) && check_token()) { - if (isset($_POST['voteYes'])) { - $myvote = "Yes"; - } else if (isset($_POST['voteNo'])) { - $myvote = "No"; - } else if (isset($_POST['voteAbstain'])) { - $myvote = "Abstain"; - } - - cast_proposal_vote($row['ID'], uid_from_sid($_COOKIE["AURSID"]), $myvote, $row[$myvote] + 1); - - # Can't vote anymore - # - $canvote = 0; - $errorvote = __("You've already voted for this proposal."); - - # Update if they voted - if (tu_voted($row['ID'], uid_from_sid($_COOKIE["AURSID"]))) { - $hasvoted = 1; - } - $row = vote_details($_GET['id']); - } - } - include("tu_details.php"); - } - } else { - print __("Vote ID not valid."); - } - - } else { - $limit = $pp; - if (isset($_GET['off'])) - $offset = $_GET['off']; - - if (isset($_GET['by'])) - $by = $_GET['by']; - else - $by = 'desc'; - - if (!empty($offset) && is_numeric($offset)) { - if ($offset >= 1) { - $off = $offset; - } else { - $off = 0; - } - } else { - $off = 0; - } - - $order = ($by == 'asc') ? 'ASC' : 'DESC'; - $lim = ($limit > 0) ? " LIMIT $limit OFFSET $off" : ""; - $by_next = ($by == 'desc') ? 'asc' : 'desc'; - - $result = current_proposal_list($order); - $type = __("Current Votes"); - $nextresult = 0; - include("tu_list.php"); - - $result = past_proposal_list($order, $lim); - $type = __("Past Votes"); - $nextresult = proposal_count(); - include("tu_list.php"); - - $result = last_votes_list(); - include("tu_last_votes_list.php"); - } -} -else { - header('Location: /'); -} - -html_footer(AURWEB_VERSION); diff --git a/web/html/voters.php b/web/html/voters.php deleted file mode 100644 index bacbcfc8..00000000 --- a/web/html/voters.php +++ /dev/null @@ -1,34 +0,0 @@ - - -
-

Votes for

-
-
    - $row): ?> -
  • - - 0): ?> - () - -
  • - -
-
-
- -exec("SET NAMES 'utf8' COLLATE 'utf8_general_ci';"); - } else if ($backend == "sqlite") { - $dsn = $backend . - ":" . $name; - - self::$dbh = new PDO($dsn, null, null); - } else { - die("Error - " . $backend . " is not supported by aurweb"); - } - - } catch (PDOException $e) { - die('Error - Could not connect to AUR database'); - } - } - - return self::$dbh; - } -} diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php deleted file mode 100644 index 0d021f99..00000000 --- a/web/lib/acctfuncs.inc.php +++ /dev/null @@ -1,1522 +0,0 @@ -\n" - . "
  • " . __("It must be between %s and %s characters long", $length_min, $length_max) - . "
  • " - . "
  • " . __("Start and end with a letter or number") . "
  • " - . "
  • " . __("Can contain only one period, underscore or hyphen.") - . "
  • \n"; - } - - if (!$error && $P && !$C) { - $error = __("Please confirm your new password."); - } - if (!$error && $P && $P != $C) { - $error = __("Password fields do not match."); - } - if (!$error && $P != '' && !good_passwd($P)) { - $length_min = config_get_int('options', 'passwd_min_len'); - $error = __("Your password must be at least %s characters.", - $length_min); - } - - if (!$error && !valid_email($E)) { - $error = __("The email address is invalid."); - } - if (!$error && $BE && !valid_email($BE)) { - $error = __("The backup email address is invalid."); - } - - if (!$error && !empty($HP) && !valid_homepage($HP)) { - $error = __("The home page is invalid, please specify the full HTTP(s) URL."); - } - - if (!$error && $K != '' && !valid_pgp_fingerprint($K)) { - $error = __("The PGP key fingerprint is invalid."); - } - - if (!$error && !empty($PK)) { - $ssh_keys = array_filter(array_map('trim', explode("\n", $PK))); - $ssh_fingerprints = array(); - - foreach ($ssh_keys as &$ssh_key) { - if (!valid_ssh_pubkey($ssh_key)) { - $error = __("The SSH public key is invalid."); - break; - } - - $ssh_fingerprint = ssh_key_fingerprint($ssh_key); - if (!$ssh_fingerprint) { - $error = __("The SSH public key is invalid."); - break; - } - - $tokens = explode(" ", $ssh_key); - $ssh_key = $tokens[0] . " " . $tokens[1]; - - $ssh_fingerprints[] = $ssh_fingerprint; - } - - /* - * Destroy last reference to prevent accidentally overwriting - * an array element. - */ - unset($ssh_key); - } - - if (isset($_COOKIE['AURSID'])) { - $atype = account_from_sid($_COOKIE['AURSID']); - if (($atype == "User" && $T > 1) || ($atype == "Trusted User" && $T > 2)) { - $error = __("Cannot increase account permissions."); - } - } - - if (!$error && !array_key_exists($L, $SUPPORTED_LANGS)) { - $error = __("Language is not currently supported."); - } - if (!$error && !array_key_exists($TZ, generate_timezone_list())) { - $error = __("Timezone is not currently supported."); - } - if (!$error) { - /* - * Check whether the user name is available. - * TODO: Fix race condition. - */ - $q = "SELECT COUNT(*) AS CNT FROM Users "; - $q.= "WHERE Username = " . $dbh->quote($U); - if ($TYPE == "edit") { - $q.= " AND ID != ".intval($UID); - } - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row[0]) { - $error = __("The username, %s%s%s, is already in use.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - } - } - if (!$error) { - /* - * Check whether the e-mail address is available. - * TODO: Fix race condition. - */ - $q = "SELECT COUNT(*) AS CNT FROM Users "; - $q.= "WHERE Email = " . $dbh->quote($E); - if ($TYPE == "edit") { - $q.= " AND ID != ".intval($UID); - } - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row[0]) { - $error = __("The address, %s%s%s, is already in use.", - "", htmlspecialchars($E,ENT_QUOTES), ""); - } - } - if (!$error && isset($ssh_keys) && count($ssh_keys) > 0) { - /* - * Check whether any of the SSH public keys is already in use. - * TODO: Fix race condition. - */ - $q = "SELECT Fingerprint FROM SSHPubKeys "; - $q.= "WHERE Fingerprint IN ("; - $q.= implode(',', array_map(array($dbh, 'quote'), $ssh_fingerprints)); - $q.= ")"; - if ($TYPE == "edit") { - $q.= " AND UserID != " . intval($UID); - } - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - $error = __("The SSH public key, %s%s%s, is already in use.", - "", htmlspecialchars($row[0], ENT_QUOTES), ""); - } - } - - if (!$error && $TYPE == "new" && empty($captcha)) { - $error = __("The CAPTCHA is missing."); - } - - if (!$error && $TYPE == "new" && !in_array($captcha_salt, get_captcha_salts())) { - $error = __("This CAPTCHA has expired. Please try again."); - } - - if (!$error && $TYPE == "new" && $captcha != get_captcha_answer($captcha_salt)) { - $error = __("The entered CAPTCHA answer is invalid."); - } - - if ($error) { - $message = "\n"; - return array(false, $message); - } - - if ($TYPE == "new") { - /* Create an unprivileged user. */ - if (empty($P)) { - $send_resetkey = true; - $email = $E; - } else { - $send_resetkey = false; - $P = password_hash($P, PASSWORD_DEFAULT); - } - $U = $dbh->quote($U); - $E = $dbh->quote($E); - $BE = $dbh->quote($BE); - $P = $dbh->quote($P); - $R = $dbh->quote($R); - $L = $dbh->quote($L); - $TZ = $dbh->quote($TZ); - $HP = $dbh->quote($HP); - $I = $dbh->quote($I); - $K = $dbh->quote(str_replace(" ", "", $K)); - $q = "INSERT INTO Users (AccountTypeID, Suspended, "; - $q.= "InactivityTS, Username, Email, BackupEmail, Passwd , "; - $q.= "RealName, LangPreference, Timezone, Homepage, IRCNick, PGPKey) "; - $q.= "VALUES (1, 0, 0, $U, $E, $BE, $P, $R, $L, $TZ, "; - $q.= "$HP, $I, $K)"; - $result = $dbh->exec($q); - if (!$result) { - $message = __("Error trying to create account, %s%s%s.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - return array(false, $message); - } - - $uid = $dbh->lastInsertId(); - if (isset($ssh_keys) && count($ssh_keys) > 0) { - account_set_ssh_keys($uid, $ssh_keys, $ssh_fingerprints); - } - - $message = __("The account, %s%s%s, has been successfully created.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - $message .= "

    \n"; - - if ($send_resetkey) { - send_resetkey($email, true); - $message .= __("A password reset key has been sent to your e-mail address."); - $message .= "

    \n"; - } else { - $message .= __("Click on the Login link above to use your account."); - $message .= "

    \n"; - } - } else { - /* Modify an existing account. */ - $q = "SELECT InactivityTS FROM Users WHERE "; - $q.= "ID = " . intval($UID); - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - if ($row[0] && $J) { - $inactivity_ts = $row[0]; - } elseif ($J) { - $inactivity_ts = time(); - } else { - $inactivity_ts = 0; - } - - $q = "UPDATE Users SET "; - $q.= "Username = " . $dbh->quote($U); - if ($T) { - $q.= ", AccountTypeID = ".intval($T); - } - if ($S) { - /* Ensure suspended users can't keep an active session */ - delete_user_sessions($UID); - $q.= ", Suspended = 1"; - } else { - $q.= ", Suspended = 0"; - } - $q.= ", Email = " . $dbh->quote($E); - $q.= ", BackupEmail = " . $dbh->quote($BE); - if ($H) { - $q.= ", HideEmail = 1"; - } else { - $q.= ", HideEmail = 0"; - } - if ($P) { - $hash = password_hash($P, PASSWORD_DEFAULT); - $q .= ", Passwd = " . $dbh->quote($hash); - } - $q.= ", RealName = " . $dbh->quote($R); - $q.= ", LangPreference = " . $dbh->quote($L); - $q.= ", Timezone = " . $dbh->quote($TZ); - $q.= ", Homepage = " . $dbh->quote($HP); - $q.= ", IRCNick = " . $dbh->quote($I); - $q.= ", PGPKey = " . $dbh->quote(str_replace(" ", "", $K)); - $q.= ", InactivityTS = " . $inactivity_ts; - $q.= ", CommentNotify = " . ($CN ? "1" : "0"); - $q.= ", UpdateNotify = " . ($UN ? "1" : "0"); - $q.= ", OwnershipNotify = " . ($ON ? "1" : "0"); - $q.= " WHERE ID = ".intval($UID); - $result = $dbh->exec($q); - - if (isset($ssh_keys) && count($ssh_keys) > 0) { - $ssh_key_result = account_set_ssh_keys($UID, $ssh_keys, $ssh_fingerprints); - } else { - $ssh_key_result = true; - } - - if (isset($_COOKIE["AURTZ"]) && ($_COOKIE["AURTZ"] != $TZ)) { - /* set new cookie for timezone */ - $timeout = intval(config_get("options", "persistent_cookie_timeout")); - $cookie_time = time() + $timeout; - setcookie("AURTZ", $TZ, $cookie_time, "/"); - } - - if (isset($_COOKIE["AURLANG"]) && ($_COOKIE["AURLANG"] != $L)) { - /* set new cookie for language */ - $timeout = intval(config_get("options", "persistent_cookie_timeout")); - $cookie_time = time() + $timeout; - setcookie("AURLANG", $L, $cookie_time, "/"); - } - - if ($result === false || $ssh_key_result === false) { - $message = __("No changes were made to the account, %s%s%s.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - } else { - $message = __("The account, %s%s%s, has been successfully modified.", - "", htmlspecialchars($U,ENT_QUOTES), ""); - } - } - - return array(true, $message); -} - -/** - * Display the search results page - * - * @param string $O The offset for the results page - * @param string $SB The column to sort the results page by - * @param string $U The username search criteria - * @param string $T The account type search criteria - * @param string $S Whether the account is suspended search criteria - * @param string $E The e-mail address search criteria - * @param string $R The real name search criteria - * @param string $I The IRC nickname search criteria - * @param string $K The PGP key fingerprint search criteria - * - * @return void - */ -function search_results_page($O=0,$SB="",$U="",$T="", - $S="",$E="",$R="",$I="",$K="") { - - $HITS_PER_PAGE = 50; - if ($O) { - $OFFSET = intval($O); - } else { - $OFFSET = 0; - } - if ($OFFSET < 0) { - $OFFSET = 0; - } - $search_vars = array(); - - $dbh = DB::connect(); - - $q = "SELECT Users.*, AccountTypes.AccountType "; - $q.= "FROM Users, AccountTypes "; - $q.= "WHERE AccountTypes.ID = Users.AccountTypeID "; - if ($T == "u") { - $q.= "AND AccountTypes.ID = 1 "; - $search_vars[] = "T"; - } elseif ($T == "t") { - $q.= "AND AccountTypes.ID = 2 "; - $search_vars[] = "T"; - } elseif ($T == "d") { - $q.= "AND AccountTypes.ID = 3 "; - $search_vars[] = "T"; - } elseif ($T == "td") { - $q.= "AND AccountTypes.ID = 4 "; - $search_vars[] = "T"; - } - if ($S) { - $q.= "AND Users.Suspended = 1 "; - $search_vars[] = "S"; - } - if ($U) { - $U = "%" . addcslashes($U, '%_') . "%"; - $q.= "AND Username LIKE " . $dbh->quote($U) . " "; - $search_vars[] = "U"; - } - if ($E) { - $E = "%" . addcslashes($E, '%_') . "%"; - $q.= "AND Email LIKE " . $dbh->quote($E) . " "; - $search_vars[] = "E"; - } - if ($R) { - $R = "%" . addcslashes($R, '%_') . "%"; - $q.= "AND RealName LIKE " . $dbh->quote($R) . " "; - $search_vars[] = "R"; - } - if ($I) { - $I = "%" . addcslashes($I, '%_') . "%"; - $q.= "AND IRCNick LIKE " . $dbh->quote($I) . " "; - $search_vars[] = "I"; - } - if ($K) { - $K = "%" . addcslashes(str_replace(" ", "", $K), '%_') . "%"; - $q.= "AND PGPKey LIKE " . $dbh->quote($K) . " "; - $search_vars[] = "K"; - } - switch ($SB) { - case 't': - $q.= "ORDER BY AccountTypeID, Username "; - break; - case 'r': - $q.= "ORDER BY RealName, AccountTypeID "; - break; - case 'i': - $q.= "ORDER BY IRCNick, AccountTypeID "; - break; - default: - $q.= "ORDER BY Username, AccountTypeID "; - break; - } - $search_vars[] = "SB"; - $q.= "LIMIT " . $HITS_PER_PAGE . " OFFSET " . $OFFSET; - - $dbh = DB::connect(); - - $result = $dbh->query($q); - - $userinfo = array(); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $userinfo[] = $row; - } - } - - include("account_search_results.php"); - return; -} - -/** - * Attempt to login and generate a session - * - * @return array Session ID for user, error message if applicable - */ -function try_login() { - $login_error = ""; - $new_sid = ""; - $userID = null; - - if (!isset($_REQUEST['user']) && !isset($_REQUEST['passwd'])) { - return array('SID' => '', 'error' => null); - } - - if (is_ipbanned()) { - $login_error = __('The login form is currently disabled ' . - 'for your IP address, probably due ' . - 'to sustained spam attacks. Sorry for the ' . - 'inconvenience.'); - return array('SID' => '', 'error' => $login_error); - } - - $dbh = DB::connect(); - $userID = uid_from_loginname($_REQUEST['user']); - - if (user_suspended($userID)) { - $login_error = __('Account suspended'); - return array('SID' => '', 'error' => $login_error); - } - - switch (check_passwd($userID, $_REQUEST['passwd'])) { - case -1: - $login_error = __('Your password has been reset. ' . - 'If you just created a new account, please ' . - 'use the link from the confirmation email ' . - 'to set an initial password. Otherwise, ' . - 'please request a reset key on the %s' . - 'Password Reset%s page.', '', - ''); - return array('SID' => '', 'error' => $login_error); - case 0: - $login_error = __("Bad username or password."); - return array('SID' => '', 'error' => $login_error); - case 1: - break; - } - - $logged_in = 0; - $num_tries = 0; - - /* Generate a session ID and store it. */ - while (!$logged_in && $num_tries < 5) { - $new_sid = new_sid(); - $q = "INSERT INTO Sessions (UsersID, SessionID, LastUpdateTS)" - ." VALUES (" . $userID . ", '" . $new_sid . "', " . strval(time()) . ")"; - $result = $dbh->exec($q); - - /* Query will fail if $new_sid is not unique. */ - if ($result) { - $logged_in = 1; - break; - } - - $num_tries++; - } - - if (!$logged_in) { - $login_error = __('An error occurred trying to generate a user session.'); - return array('SID' => $new_sid, 'error' => $login_error); - } - - $q = "UPDATE Users SET LastLogin = " . strval(time()) . ", "; - $q.= "LastLoginIPAddress = " . $dbh->quote($_SERVER['REMOTE_ADDR']) . " "; - $q.= "WHERE ID = $userID"; - $dbh->exec($q); - - /* Set the SID cookie. */ - if (isset($_POST['remember_me']) && $_POST['remember_me'] == "on") { - /* Set cookies for 30 days. */ - $timeout = config_get_int('options', 'persistent_cookie_timeout'); - $cookie_time = time() + $timeout; - - /* Set session for 30 days. */ - $q = "UPDATE Sessions SET LastUpdateTS = $cookie_time "; - $q.= "WHERE SessionID = '$new_sid'"; - $dbh->exec($q); - } else { - $cookie_time = 0; - } - - setcookie("AURSID", $new_sid, $cookie_time, "/", null, !empty($_SERVER['HTTPS']), true); - - $referer = in_request('referer'); - if (strpos($referer, aur_location()) !== 0) { - $referer = '/'; - } - header("Location: " . get_uri($referer)); - $login_error = ""; - return array('SID' => $new_sid, 'error' => null); -} - -/** - * Determine if the user is using a banned IP address - * - * @return bool True if IP address is banned, otherwise false - */ -function is_ipbanned() { - $dbh = DB::connect(); - - $q = "SELECT * FROM Bans WHERE IPAddress = " . $dbh->quote($_SERVER['REMOTE_ADDR']); - $result = $dbh->query($q); - - return ($result->fetchColumn() ? true : false); -} - -/** - * Validate a username against a collection of rules - * - * The username must be longer or equal to the configured minimum length. It - * must be shorter or equal to the configured maximum length. It must start and - * end with either a letter or a number. It can contain one period, hypen, or - * underscore. Returns boolean of whether name is valid. - * - * @param string $user Username to validate - * - * @return bool True if username meets criteria, otherwise false - */ -function valid_username($user) { - $length_min = config_get_int('options', 'username_min_len'); - $length_max = config_get_int('options', 'username_max_len'); - - if (strlen($user) < $length_min || strlen($user) > $length_max) { - return false; - } else if (!preg_match("/^[a-z0-9]+[.\-_]?[a-z0-9]+$/Di", $user)) { - return false; - } - - return true; -} - -/** - * Determine if a user already has a proposal open about themselves - * - * @param string $user Username to checkout for open proposal - * - * @return bool True if there is an open proposal about the user, otherwise false - */ -function open_user_proposals($user) { - $dbh = DB::connect(); - $q = "SELECT * FROM TU_VoteInfo WHERE User = " . $dbh->quote($user) . " "; - $q.= "AND End > " . strval(time()); - $result = $dbh->query($q); - - return ($result->fetchColumn() ? true : false); -} - -/** - * Add a new Trusted User proposal to the database - * - * @param string $agenda The agenda of the vote - * @param string $user The use the vote is about - * @param int $votelength The length of time for the vote to last - * @param string $submitteruid The user ID of the individual who submitted the proposal - * - * @return void - */ -function add_tu_proposal($agenda, $user, $votelength, $quorum, $submitteruid) { - $dbh = DB::connect(); - - $q = "SELECT COUNT(*) FROM Users WHERE (AccountTypeID = 2 OR AccountTypeID = 4)"; - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - $active_tus = $row[0]; - - $q = "INSERT INTO TU_VoteInfo (Agenda, User, Submitted, End, Quorum, "; - $q.= "SubmitterID, ActiveTUs) VALUES "; - $q.= "(" . $dbh->quote($agenda) . ", " . $dbh->quote($user) . ", "; - $q.= strval(time()) . ", " . strval(time()) . " + " . $dbh->quote($votelength); - $q.= ", " . $dbh->quote($quorum) . ", " . $submitteruid . ", "; - $q.= $active_tus . ")"; - $result = $dbh->exec($q); -} - -/** - * Add a reset key to the database for a specified user - * - * @param string $resetkey A password reset key to be stored in database - * @param string $uid The user ID to store the reset key for - * - * @return void - */ -function create_resetkey($resetkey, $uid) { - $dbh = DB::connect(); - $q = "UPDATE Users "; - $q.= "SET ResetKey = '" . $resetkey . "' "; - $q.= "WHERE ID = " . $uid; - $dbh->exec($q); -} - -/** - * Send a reset key to a specific e-mail address - * - * @param string $user User name or email address of the user - * @param bool $welcome Whether to use the welcome message - * - * @return void - */ -function send_resetkey($user, $welcome=false) { - $uid = uid_from_loginname($user); - if ($uid == null) { - return; - } - - /* We (ab)use new_sid() to get a random 32 characters long string. */ - $resetkey = new_sid(); - create_resetkey($resetkey, $uid); - - /* Send e-mail with confirmation link. */ - notify(array($welcome ? 'welcome' : 'send-resetkey', $uid)); -} - -/** - * Change a user's password in the database if reset key and e-mail are correct - * - * @param string $password The new password - * @param string $resetkey Code e-mailed to a user to reset a password - * @param string $user User name or email address of the user - * - * @return string|void Redirect page if successful, otherwise return error message - */ -function password_reset($password, $resetkey, $user) { - $hash = password_hash($password, PASSWORD_DEFAULT); - - $dbh = DB::connect(); - $q = "UPDATE Users SET "; - $q.= "Passwd = " . $dbh->quote($hash) . ", "; - $q.= "ResetKey = '' "; - $q.= "WHERE ResetKey != '' "; - $q.= "AND ResetKey = " . $dbh->quote($resetkey) . " "; - $q.= "AND (Email = " . $dbh->quote($user) . " OR "; - $q.= "UserName = " . $dbh->quote($user) . ")"; - $result = $dbh->exec($q); - - if (!$result) { - $error = __('Invalid e-mail and reset key combination.'); - return $error; - } else { - header('Location: ' . get_uri('/passreset/') . '?step=complete'); - exit(); - } -} - -/** - * Determine if the password is longer than the minimum length - * - * @param string $passwd The password to check - * - * @return bool True if longer than minimum length, otherwise false - */ -function good_passwd($passwd) { - $length_min = config_get_int('options', 'passwd_min_len'); - return (strlen($passwd) >= $length_min); -} - -/** - * Determine if the password is correct and salt it if it hasn't been already - * - * @param int $user_id The user ID to check the password against - * @param string $passwd The password the visitor sent - * - * @return int Positive if password is correct, negative if password is unset - */ -function check_passwd($user_id, $passwd) { - $dbh = DB::connect(); - - /* Get password hash and salt. */ - $q = "SELECT Passwd, Salt FROM Users WHERE ID = " . intval($user_id); - $result = $dbh->query($q); - if (!$result) { - return 0; - } - $row = $result->fetch(PDO::FETCH_ASSOC); - if (!$row) { - return 0; - } - $hash = $row['Passwd']; - $salt = $row['Salt']; - if (!$hash) { - return -1; - } - - /* Verify the password hash. */ - if (!password_verify($passwd, $hash)) { - /* Invalid password, fall back to MD5. */ - if (md5($salt . $passwd) != $hash) { - return 0; - } - } - - /* Password correct, migrate the hash if necessary. */ - if (password_needs_rehash($hash, PASSWORD_DEFAULT)) { - $hash = password_hash($passwd, PASSWORD_DEFAULT); - - $q = "UPDATE Users SET Passwd = " . $dbh->quote($hash) . " "; - $q.= "WHERE ID = " . intval($user_id); - $dbh->query($q); - } - - return 1; -} - -/** - * Determine if the PGP key fingerprint is valid (must be 40 hexadecimal digits) - * - * @param string $fingerprint PGP fingerprint to check if valid - * - * @return bool True if the fingerprint is 40 hexadecimal digits, otherwise false - */ -function valid_pgp_fingerprint($fingerprint) { - $fingerprint = str_replace(" ", "", $fingerprint); - return (strlen($fingerprint) == 40 && ctype_xdigit($fingerprint)); -} - -/** - * Determine if the SSH public key is valid - * - * @param string $pubkey SSH public key to check - * - * @return bool True if the SSH public key is valid, otherwise false - */ -function valid_ssh_pubkey($pubkey) { - $valid_prefixes = explode(' ', config_get('auth', 'valid-keytypes')); - - $has_valid_prefix = false; - foreach ($valid_prefixes as $prefix) { - if (strpos($pubkey, $prefix . " ") === 0) { - $has_valid_prefix = true; - break; - } - } - if (!$has_valid_prefix) { - return false; - } - - $tokens = explode(" ", $pubkey); - if (empty($tokens[1])) { - return false; - } - - return (base64_encode(base64_decode($tokens[1], true)) == $tokens[1]); -} - -/** - * Determine if the user account has been suspended - * - * @param string $id The ID of user to check if suspended - * - * @return bool True if the user is suspended, otherwise false - */ -function user_suspended($id) { - $dbh = DB::connect(); - if (!$id) { - return false; - } - $q = "SELECT Suspended FROM Users WHERE ID = " . $id; - $result = $dbh->query($q); - if ($result) { - $row = $result->fetch(PDO::FETCH_NUM); - if ($row[0]) { - return true; - } - } - return false; -} - -/** - * Delete a specified user account from the database - * - * @param int $id The user ID of the account to be deleted - * - * @return void - */ -function user_delete($id) { - $dbh = DB::connect(); - $id = intval($id); - - /* - * These are normally already taken care of by propagation constraints - * but it is better to be explicit here. - */ - $fields_delete = array( - array("Sessions", "UsersID"), - array("PackageVotes", "UsersID"), - array("PackageNotifications", "UserID") - ); - - $fields_set_null = array( - array("PackageBases", "SubmitterUID"), - array("PackageBases", "MaintainerUID"), - array("PackageBases", "PackagerUID"), - array("PackageComments", "UsersID"), - array("PackageComments", "DelUsersID"), - array("PackageRequests", "UsersID"), - array("TU_VoteInfo", "SubmitterID"), - array("TU_Votes", "UserID") - ); - - foreach($fields_delete as list($table, $field)) { - $q = "DELETE FROM " . $table . " "; - $q.= "WHERE " . $field . " = " . $id; - $dbh->query($q); - } - - foreach($fields_set_null as list($table, $field)) { - $q = "UPDATE " . $table . " SET " . $field . " = NULL "; - $q.= "WHERE " . $field . " = " . $id; - $dbh->query($q); - } - - $q = "DELETE FROM Users WHERE ID = " . $id; - $dbh->query($q); - return; -} - -/** - * Remove the session from the database on logout - * - * @param string $sid User's session ID - * - * @return void - */ -function delete_session_id($sid) { - $dbh = DB::connect(); - - $q = "DELETE FROM Sessions WHERE SessionID = " . $dbh->quote($sid); - $dbh->query($q); -} - -/** - * Remove all sessions belonging to a particular user - * - * @param int $uid ID of user to remove all sessions for - * - * @return void - */ -function delete_user_sessions($uid) { - $dbh = DB::connect(); - - $q = "DELETE FROM Sessions WHERE UsersID = " . intval($uid); - $dbh->exec($q); -} - -/** - * Remove sessions from the database that have exceed the timeout - * - * @return void - */ -function clear_expired_sessions() { - $dbh = DB::connect(); - - $timeout = config_get_int('options', 'login_timeout'); - $q = "DELETE FROM Sessions WHERE LastUpdateTS < (" . strval(time()) . " - " . $timeout . ")"; - $dbh->query($q); - - return; -} - -/** - * Get account details for a specific user - * - * @param string $uid The User ID of account to get information for - * @param string $username The username of the account to get for - * - * @return array Account details for the specified user - */ -function account_details($uid, $username) { - $dbh = DB::connect(); - $q = "SELECT Users.*, AccountTypes.AccountType "; - $q.= "FROM Users, AccountTypes "; - $q.= "WHERE AccountTypes.ID = Users.AccountTypeID "; - if (!empty($uid)) { - $q.= "AND Users.ID = ".intval($uid); - } else { - $q.= "AND Users.Username = " . $dbh->quote($username); - } - $result = $dbh->query($q); - - if ($result) { - $row = $result->fetch(PDO::FETCH_ASSOC); - } - - return $row; -} - -/** - * Determine if a user has already voted on a specific proposal - * - * @param string $voteid The ID of the Trusted User proposal - * @param string $uid The ID to check if the user already voted - * - * @return bool True if the user has already voted, otherwise false - */ -function tu_voted($voteid, $uid) { - $dbh = DB::connect(); - - $q = "SELECT COUNT(*) FROM TU_Votes "; - $q.= "WHERE VoteID = " . intval($voteid) . " AND UserID = " . intval($uid); - $result = $dbh->query($q); - if ($result->fetchColumn() > 0) { - return true; - } - else { - return false; - } -} - -/** - * Get all current Trusted User proposals from the database - * - * @param string $order Ascending or descending order for the proposal listing - * - * @return array The details for all current Trusted User proposals - */ -function current_proposal_list($order) { - $dbh = DB::connect(); - - $q = "SELECT * FROM TU_VoteInfo WHERE End > " . time() . " ORDER BY Submitted " . $order; - $result = $dbh->query($q); - - $details = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $details[] = $row; - } - - return $details; -} - -/** - * Get a subset of all past Trusted User proposals from the database - * - * @param string $order Ascending or descending order for the proposal listing - * @param string $lim The number of proposals to list with the offset - * - * @return array The details for the subset of past Trusted User proposals - */ -function past_proposal_list($order, $lim) { - $dbh = DB::connect(); - - $q = "SELECT * FROM TU_VoteInfo WHERE End < " . time() . " ORDER BY Submitted " . $order . $lim; - $result = $dbh->query($q); - - $details = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $details[] = $row; - } - - return $details; -} - -/** - * Get the vote ID of the last vote of all Trusted Users - * - * @return array The vote ID of the last vote of each Trusted User - */ -function last_votes_list() { - $dbh = DB::connect(); - - $q = "SELECT UserID, MAX(VoteID) AS LastVote FROM TU_Votes, "; - $q .= "TU_VoteInfo, Users WHERE TU_VoteInfo.ID = TU_Votes.VoteID AND "; - $q .= "TU_VoteInfo.End < " . strval(time()) . " AND "; - $q .= "Users.ID = TU_Votes.UserID AND (Users.AccountTypeID = 2 OR Users.AccountTypeID = 4) "; - $q .= "GROUP BY UserID ORDER BY LastVote DESC, UserName ASC"; - $result = $dbh->query($q); - - $details = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $details[] = $row; - } - - return $details; -} - -/** - * Determine the total number of Trusted User proposals - * - * @return string The total number of Trusted User proposals - */ -function proposal_count() { - $dbh = DB::connect(); - $q = "SELECT COUNT(*) FROM TU_VoteInfo"; - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - return $row[0]; -} - -/** - * Get all details related to a specific vote from the database - * - * @param string $voteid The ID of the Trusted User proposal - * - * @return array All stored details for a specific vote - */ -function vote_details($voteid) { - $dbh = DB::connect(); - - $q = "SELECT * FROM TU_VoteInfo "; - $q.= "WHERE ID = " . intval($voteid); - - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_ASSOC); - - return $row; -} - -/** - * Get an alphabetical list of users who voted for a proposal with HTML links - * - * @param string $voteid The ID of the Trusted User proposal - * - * @return array All users who voted for a specific proposal - */ -function voter_list($voteid) { - $dbh = DB::connect(); - - $whovoted = array(); - - $q = "SELECT tv.UserID,U.Username "; - $q.= "FROM TU_Votes tv, Users U "; - $q.= "WHERE tv.VoteID = " . intval($voteid); - $q.= " AND tv.UserID = U.ID "; - $q.= "ORDER BY Username"; - - $result = $dbh->query($q); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $whovoted[] = $row['Username']; - } - } - return $whovoted; -} - -/** - * Cast a vote for a specific user proposal - * - * @param string $voteid The ID of the proposal being voted on - * @param string $uid The user ID of the individual voting - * @param string $vote Vote position, either "Yes", "No", or "Abstain" - * @param int $newtotal The total number of votes after the user has voted - * - * @return void - */ -function cast_proposal_vote($voteid, $uid, $vote, $newtotal) { - $dbh = DB::connect(); - - $q = "UPDATE TU_VoteInfo SET " . $vote . " = (" . $newtotal . ") WHERE ID = " . $voteid; - $result = $dbh->exec($q); - - $q = "INSERT INTO TU_Votes (VoteID, UserID) VALUES (" . intval($voteid) . ", " . intval($uid) . ")"; - $result = $dbh->exec($q); -} - -/** - * Verify a user has the proper permissions to edit an account - * - * @param array $acctinfo User account information for edited account - * - * @return bool True if permission to edit the account, otherwise false - */ -function can_edit_account($acctinfo) { - if ($acctinfo['AccountType'] == 'Developer' || - $acctinfo['AccountType'] == 'Trusted User & Developer') { - return has_credential(CRED_ACCOUNT_EDIT_DEV); - } - - $uid = $acctinfo['ID']; - return has_credential(CRED_ACCOUNT_EDIT, array($uid)); -} - -/* - * Compute the fingerprint of an SSH key. - * - * @param string $ssh_key The SSH public key to retrieve the fingerprint for - * - * @return string The SSH key fingerprint - */ -function ssh_key_fingerprint($ssh_key) { - $tmpfile = tempnam(sys_get_temp_dir(), "aurweb"); - file_put_contents($tmpfile, $ssh_key); - - /* - * The -l option of ssh-keygen can be used to show the fingerprint of - * the specified public key file. Expected output format: - * - * 2048 SHA256:uBBTXmCNjI2CnLfkuz9sG8F+e9/T4C+qQQwLZWIODBY user@host (RSA) - * - * ... where 2048 is the key length, the second token is the actual - * fingerprint, followed by the key comment and the key type. - */ - - $cmd = "/usr/bin/ssh-keygen -l -f " . escapeshellarg($tmpfile); - exec($cmd, $out, $ret); - if ($ret !== 0 || count($out) !== 1) { - return false; - } - - unlink($tmpfile); - - $tokens = explode(' ', $out[0]); - if (count($tokens) < 4) { - return false; - } - - $tokens = explode(':', $tokens[1]); - if (count($tokens) != 2 || $tokens[0] != 'SHA256') { - return false; - } - - return $tokens[1]; -} - -/* - * Get the SSH public keys associated with an account. - * - * @param int $uid The user ID of the account to retrieve the keys for. - * - * @return array An array representing the keys - */ -function account_get_ssh_keys($uid) { - $dbh = DB::connect(); - $q = "SELECT PubKey FROM SSHPubKeys WHERE UserID = " . intval($uid); - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - return array(); - } -} - -/* - * Set the SSH public keys associated with an account. - * - * @param int $uid The user ID of the account to assign the keys to. - * @param array $ssh_keys The SSH public keys. - * @param array $ssh_fingerprints The corresponding SSH key fingerprints. - * - * @return bool Boolean flag indicating success or failure. - */ -function account_set_ssh_keys($uid, $ssh_keys, $ssh_fingerprints) { - $dbh = DB::connect(); - - $q = sprintf("DELETE FROM SSHPubKeys WHERE UserID = %d", $uid); - $dbh->exec($q); - - $ssh_fingerprint = reset($ssh_fingerprints); - foreach ($ssh_keys as $ssh_key) { - $q = sprintf( - "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) " . - "VALUES (%d, %s, %s)", $uid, - $dbh->quote($ssh_fingerprint), $dbh->quote($ssh_key) - ); - $dbh->exec($q); - $ssh_fingerprint = next($ssh_fingerprints); - } - - return true; -} - -/* - * Invoke the email notification script. - * - * @param string $params Command line parameters for the script. - * - * @return void - */ -function notify($params) { - $cmd = config_get('notifications', 'notify-cmd'); - foreach ($params as $param) { - $cmd .= ' ' . escapeshellarg($param); - } - - $descspec = array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - ); - - $p = proc_open($cmd, $descspec, $pipes); - - if (!is_resource($p)) { - return false; - } - - fclose($pipes[0]); - fclose($pipes[1]); - - return proc_close($p); -} - -/* - * Obtain a list of terms a given user has not yet accepted. - * - * @param int $uid The ID of the user to obtain terms for. - * - * @return array A list of terms the user has not yet accepted. - */ -function fetch_updated_terms($uid) { - $dbh = DB::connect(); - - $q = "SELECT ID, Terms.Revision, Description, URL "; - $q .= "FROM Terms LEFT JOIN AcceptedTerms "; - $q .= "ON AcceptedTerms.TermsID = Terms.ID "; - $q .= "AND AcceptedTerms.UsersID = " . intval($uid) . " "; - $q .= "WHERE AcceptedTerms.Revision IS NULL OR "; - $q .= "AcceptedTerms.Revision < Terms.Revision"; - - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(); - } else { - return array(); - } -} - -/* - * Accept a list of given terms. - * - * @param int $uid The ID of the user to accept the terms. - * @param array $termrev An array mapping each term to the accepted revision. - * - * @return void - */ -function accept_terms($uid, $termrev) { - $dbh = DB::connect(); - - $q = "SELECT TermsID, Revision FROM AcceptedTerms "; - $q .= "WHERE UsersID = " . intval($uid); - - $result = $dbh->query($q); - - if (!$result) { - return; - } - - $termrev_update = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $id = $row['TermsID']; - if (!array_key_exists($id, $termrev)) { - continue; - } - if ($row['Revision'] < $termrev[$id]) { - $termrev_update[$id] = $termrev[$id]; - } - } - $termrev_add = array_diff_key($termrev, $termrev_update); - - foreach ($termrev_add as $id => $rev) { - $q = "INSERT INTO AcceptedTerms (TermsID, UsersID, Revision) "; - $q .= "VALUES (" . intval($id) . ", " . intval($uid) . ", "; - $q .= intval($rev) . ")"; - $dbh->exec($q); - } - - foreach ($termrev_update as $id => $rev) { - $q = "UPDATE AcceptedTerms "; - $q .= "SET Revision = " . intval($rev) . " "; - $q .= "WHERE TermsID = " . intval($id) . " AND "; - $q .= "UsersID = " . intval($uid); - $dbh->exec($q); - } -} - -function account_comments($uid, $limit, $offset=0) { - $dbh = DB::connect(); - $q = "SELECT PackageComments.ID, Comments, UsersID, "; - $q.= "PackageBaseId, CommentTS, DelTS, EditedTS, B.UserName AS EditUserName, "; - $q.= "PinnedTS, "; - $q.= "C.UserName as DelUserName, RenderedComment, "; - $q.= "PB.ID as PackageBaseID, PB.Name as PackageBaseName "; - $q.= "FROM PackageComments "; - $q.= "LEFT JOIN PackageBases PB ON PackageComments.PackageBaseID = PB.ID "; - $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; - $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; - $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID "; - $q.= "WHERE A.ID = " . $dbh->quote($uid) . " "; - $q.= "ORDER BY CommentTS DESC"; - - if ($limit > 0) { - $q.=" LIMIT " . intval($limit); - } - - if ($offset > 0) { - $q.=" OFFSET " . intval($offset); - } - - $result = $dbh->query($q); - if (!$result) { - return null; - } - - return $result->fetchAll(); -} - -function account_comments_count($uid) { - $dbh = DB::connect(); - $q = "SELECT COUNT(*) "; - $q.= "FROM PackageComments "; - $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; - $q.= "WHERE A.ID = " . $dbh->quote($uid); - - $result = $dbh->query($q); - return $result->fetchColumn(); -} - -/* - * Compute the list of active CAPTCHA salts. The salt changes based on the - * number of registered users. This ensures that new users always use a - * different salt and protects against hardcoding the CAPTCHA response. - * - * The first CAPTCHA in the list is the most recent one and should be used for - * new CAPTCHA challenges. The other ones are slightly outdated but may still - * be valid for recent challenges that were created before the number of users - * increased. The current implementation ensures that we can still use our - * CAPTCHA salt, even if five new users registered since the CAPTCHA challenge - * was created. - * - * @return string The list of active salts, the first being the most recent - * one. - */ -function get_captcha_salts() { - $dbh = DB::connect(); - $q = "SELECT count(*) FROM Users"; - $result = $dbh->query($q); - $user_count = $result->fetchColumn(); - - $ret = array(); - for ($i = 0; $i <= 5; $i++) { - array_push($ret, 'aurweb-' . ($user_count - $i)); - } - return $ret; -} - -/* - * Return the CAPTCHA challenge for a given salt. - * - * @param string $salt The salt to be used for the CAPTCHA computation. - * - * @return string The challenge as a string. - */ -function get_captcha_challenge($salt) { - $token = substr(md5($salt), 0, 3); - return "LC_ALL=C pacman -V|sed -r 's#[0-9]+#" . $token . "#g'|md5sum|cut -c1-6"; -} - -/* - * Compute CAPTCHA answer for a given salt. - * - * @param string $salt The salt to be used for the CAPTCHA computation. - * - * @return string The correct answer as a string. - */ -function get_captcha_answer($salt) { - $token = substr(md5($salt), 0, 3); - $text = <<quote($_COOKIE["AURSID"]); - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if (!$row) { - # Invalid SessionID - hacker alert! - # - $failed = 1; - } else { - $last_update = $row[0]; - if ($last_update + $timeout <= $row[1]) { - $failed = 2; - } - } - - if ($failed == 1) { - # clear out the hacker's cookie, and send them to a naughty page - # why do you have to be so harsh on these people!? - # - setcookie("AURSID", "", 1, "/", null, !empty($_SERVER['HTTPS']), true); - unset($_COOKIE['AURSID']); - } elseif ($failed == 2) { - # session id timeout was reached and they must login again. - # - delete_session_id($_COOKIE["AURSID"]); - - setcookie("AURSID", "", 1, "/", null, !empty($_SERVER['HTTPS']), true); - unset($_COOKIE['AURSID']); - } else { - # still logged in and haven't reached the timeout, go ahead - # and update the idle timestamp - - # Only update the timestamp if it is less than the - # current time plus $timeout. - # - # This keeps 'remembered' sessions from being - # overwritten. - if ($last_update < time() + $timeout) { - $q = "UPDATE Sessions SET LastUpdateTS = " . strval(time()) . " "; - $q.= "WHERE SessionID = " . $dbh->quote($_COOKIE["AURSID"]); - $dbh->exec($q); - } - } - } - return; -} - -/** - * Redirect user to the Terms of Service agreement if there are updated terms. - * - * @return void - */ -function check_tos() { - if (!isset($_COOKIE["AURSID"])) { - return; - } - - $path = $_SERVER['PATH_INFO']; - $route = get_route($path); - if (!$route || $route == "tos.php") { - return; - } - - if (count(fetch_updated_terms(uid_from_sid($_COOKIE["AURSID"]))) > 0) { - header('Location: ' . get_uri('/tos')); - exit(); - } -} - -/** - * Verify the supplied CSRF token matches expected token - * - * @return bool True if the CSRF token is the same as the cookie SID, otherwise false - */ -function check_token() { - if (isset($_POST['token']) && isset($_COOKIE['AURSID'])) { - return ($_POST['token'] == $_COOKIE['AURSID']); - } else { - return false; - } -} - -/** - * Verify a user supplied e-mail against RFC 3696 and DNS records - * - * @param string $addy E-mail address being validated in foo@example.com format - * - * @return bool True if e-mail passes validity checks, otherwise false - */ -function valid_email($addy) { - // check against RFC 3696 - if (filter_var($addy, FILTER_VALIDATE_EMAIL) === false) { - return false; - } - - // check dns for mx, a, aaaa records - list($local, $domain) = explode('@', $addy); - if (!(checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A') || checkdnsrr($domain, 'AAAA'))) { - return false; - } - - return true; -} - -/** - * Verify that a given URL is valid and uses the HTTP(s) protocol - * - * @param string $url URL of the home page to be validated - * - * @return bool True if URL passes validity checks, false otherwise - */ -function valid_homepage($url) { - if (filter_var($url, FILTER_VALIDATE_URL) === false) { - return false; - } - - $url_components = parse_url($url); - if (!in_array($url_components['scheme'], array('http', 'https'))) { - return false; - } - - return true; -} - -/** - * Generate a unique session ID - * - * @return string MD5 hash of the concatenated user IP, random number, and current time - */ -function new_sid() { - return md5($_SERVER['REMOTE_ADDR'] . uniqid(mt_rand(), true)); -} - -/** - * Determine the user's username in the database using a user ID - * - * @param string $id User's ID - * - * @return string Username if it exists, otherwise null - */ -function username_from_id($id) { - $id = intval($id); - - $dbh = DB::connect(); - $q = "SELECT Username FROM Users WHERE ID = " . $dbh->quote($id); - $result = $dbh->query($q); - if (!$result) { - return null; - } - - $row = $result->fetch(PDO::FETCH_NUM); - if ($row) { - return $row[0]; - } -} - -/** - * Determine the user's username in the database using a session ID - * - * @param string $sid User's session ID - * - * @return string Username of the visitor - */ -function username_from_sid($sid="") { - if (!$sid) { - return ""; - } - $dbh = DB::connect(); - $q = "SELECT Username "; - $q.= "FROM Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if (!$result) { - return ""; - } - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - return $row[0]; - } -} - -/** - * Format a user name for inclusion in HTML data - * - * @param string $username The user name to format - * - * @return string The generated HTML code for the account link - */ -function html_format_username($username) { - $username_fmt = $username ? htmlspecialchars($username, ENT_QUOTES) : __("None"); - - if ($username && isset($_COOKIE["AURSID"])) { - $link = '' . $username_fmt . ''; - return $link; - } else { - return $username_fmt; - } -} - -/** - * Format the maintainer and co-maintainers for inclusion in HTML data - * - * @param string $maintainer The user name of the maintainer - * @param array $comaintainers The list of co-maintainer user names - * - * @return string The generated HTML code for the account links - */ -function html_format_maintainers($maintainer, $comaintainers) { - $code = html_format_username($maintainer); - - if (count($comaintainers) > 0) { - $code .= ' ('; - foreach ($comaintainers as $comaintainer) { - $code .= html_format_username($comaintainer); - if ($comaintainer !== end($comaintainers)) { - $code .= ', '; - } - } - $code .= ')'; - } - - return $code; -} - -/** - * Format a link in the package actions box - * - * @param string $uri The link target - * @param string $inner The HTML code to use for the link label - * - * @return string The generated HTML code for the action link - */ -function html_action_link($uri, $inner) { - if (isset($_COOKIE["AURSID"])) { - $code = ''; - } else { - $code = ''; - } - $code .= $inner . ''; - - return $code; -} - -/** - * Format a form in the package actions box - * - * @param string $uri The link target - * @param string $action The action name (passed as HTTP POST parameter) - * @param string $inner The HTML code to use for the link label - * - * @return string The generated HTML code for the action link - */ -function html_action_form($uri, $action, $inner) { - if (isset($_COOKIE["AURSID"])) { - $code = '
    '; - $code .= ''; - $code .= '
    '; - } else { - $code = ''; - $code .= $inner . ''; - } - - return $code; -} - -/** - * Determine the user's e-mail address in the database using a session ID - * - * @param string $sid User's session ID - * - * @return string User's e-mail address as given during registration - */ -function email_from_sid($sid="") { - if (!$sid) { - return ""; - } - $dbh = DB::connect(); - $q = "SELECT Email "; - $q.= "FROM Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if (!$result) { - return ""; - } - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - return $row[0]; - } -} - -/** - * Determine the user's account type in the database using a session ID - * - * @param string $sid User's session ID - * - * @return string Account type of user ("User", "Trusted User", or "Developer") - */ -function account_from_sid($sid="") { - if (!$sid) { - return ""; - } - $dbh = DB::connect(); - $q = "SELECT AccountType "; - $q.= "FROM Users, AccountTypes, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND AccountTypes.ID = Users.AccountTypeID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if (!$result) { - return ""; - } - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - return $row[0]; - } -} - -/** - * Determine the user's ID in the database using a session ID - * - * @param string $sid User's session ID - * - * @return string|int The user's name, 0 on query failure - */ -function uid_from_sid($sid="") { - if (!$sid) { - return ""; - } - $dbh = DB::connect(); - $q = "SELECT Users.ID "; - $q.= "FROM Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if (!$result) { - return 0; - } - $row = $result->fetch(PDO::FETCH_NUM); - - if ($row) { - return $row[0]; - } -} - -/** - * Common AUR header displayed on all pages - * - * @global string $LANG Language selected by the visitor - * @global array $SUPPORTED_LANGS Languages that are supported by the AUR - * @param string $title Name of the AUR page to be displayed on browser - * - * @return void - */ -function html_header($title="", $details=array()) { - global $LANG; - global $SUPPORTED_LANGS; - - include('header.php'); - return; -} - -/** - * Common AUR footer displayed on all pages - * - * @param string $ver The AUR version - * - * @return void - */ -function html_footer($ver="") { - include('footer.php'); - return; -} - -/** - * Determine if a user has permission to submit a package - * - * @param string $name Name of the package to be submitted - * @param string $sid User's session ID - * - * @return int 0 if the user can't submit, 1 if the user can submit - */ -function can_submit_pkgbase($name="", $sid="") { - if (!$name || !$sid) {return 0;} - $dbh = DB::connect(); - $q = "SELECT MaintainerUID "; - $q.= "FROM PackageBases WHERE Name = " . $dbh->quote($name); - $result = $dbh->query($q); - $row = $result->fetch(PDO::FETCH_NUM); - - if (!$row[0]) { - return 1; - } - $my_uid = uid_from_sid($sid); - - if ($row[0] === NULL || $row[0] == $my_uid) { - return 1; - } - - return 0; -} - -/** - * Determine if a package can be overwritten by some package base - * - * @param string $name Name of the package to be submitted - * @param int $base_id The ID of the package base - * - * @return bool True if the package can be overwritten, false if not - */ -function can_submit_pkg($name, $base_id) { - $dbh = DB::connect(); - $q = "SELECT COUNT(*) FROM Packages WHERE "; - $q.= "Name = " . $dbh->quote($name) . " AND "; - $q.= "PackageBaseID <> " . intval($base_id); - $result = $dbh->query($q); - - if (!$result) return false; - return ($result->fetchColumn() == 0); -} - -/** - * Recursively delete a directory - * - * @param string $dirname Name of the directory to be removed - * - * @return void - */ -function rm_tree($dirname) { - if (empty($dirname) || !is_dir($dirname)) return; - - foreach (scandir($dirname) as $item) { - if ($item != '.' && $item != '..') { - $path = $dirname . '/' . $item; - if (is_file($path) || is_link($path)) { - unlink($path); - } - else { - rm_tree($path); - } - } - } - - rmdir($dirname); - - return; -} - - /** - * Determine the user's ID in the database using a username - * - * @param string $username The username of an account - * - * @return string Return user ID if exists for username, otherwise null - */ -function uid_from_username($username) { - $dbh = DB::connect(); - $q = "SELECT ID FROM Users WHERE Username = " . $dbh->quote($username); - $result = $dbh->query($q); - if (!$result) { - return null; - } - - $row = $result->fetch(PDO::FETCH_NUM); - if ($row) { - return $row[0]; - } -} - -/** - * Determine the user's ID in the database using a username or email address - * - * @param string $username The username or email address of an account - * - * @return string Return user ID if exists, otherwise null - */ -function uid_from_loginname($loginname) { - $uid = uid_from_username($loginname); - if (!$uid) { - $uid = uid_from_email($loginname); - } - return $uid; -} - -/** - * Determine the user's ID in the database using an e-mail address - * - * @param string $email An e-mail address in foo@example.com format - * - * @return string The user's ID - */ -function uid_from_email($email) { - $dbh = DB::connect(); - $q = "SELECT ID FROM Users WHERE Email = " . $dbh->quote($email); - $result = $dbh->query($q); - if (!$result) { - return null; - } - - $row = $result->fetch(PDO::FETCH_NUM); - if ($row) { - return $row[0]; - } -} - -/** - * Generate clean url with edited/added user values - * - * Makes a clean string of variables for use in URLs based on current $_GET and - * list of values to edit/add to that. Any empty variables are discarded. - * - * @example print "http://example.com/test.php?" . mkurl("foo=bar&bar=baz") - * - * @param string $append string of variables and values formatted as in URLs - * - * @return string clean string of variables to append to URL, urlencoded - */ -function mkurl($append) { - $get = $_GET; - $append = explode('&', $append); - $uservars = array(); - $out = ''; - - foreach ($append as $i) { - $ex = explode('=', $i); - $uservars[$ex[0]] = $ex[1]; - } - - foreach ($uservars as $k => $v) { $get[$k] = $v; } - - foreach ($get as $k => $v) { - if ($v !== '') { - $out .= '&' . urlencode($k) . '=' . urlencode($v); - } - } - - return substr($out, 5); -} - -/** - * Get a package comment - * - * @param int $comment_id The ID of the comment - * - * @return array The user ID and comment OR null, null in case of an error - */ -function comment_by_id($comment_id) { - $dbh = DB::connect(); - $q = "SELECT UsersID, Comments FROM PackageComments "; - $q.= "WHERE ID = " . intval($comment_id); - $result = $dbh->query($q); - if (!$result) { - return array(null, null); - } - - return $result->fetch(PDO::FETCH_NUM); -} - -/** - * Process submitted comments so any links can be followed - * - * @param string $comment Raw user submitted package comment - * - * @return string User comment with links printed in HTML - */ -function parse_comment($comment) { - $url_pattern = '/(\b(?:https?|ftp):\/\/[\w\/\#~:.?+=&%@!\-;,]+?' . - '(?=[.:?\-;,]*(?:[^\w\/\#~:.?+=&%@!\-;,]|$)))/iS'; - - $matches = preg_split($url_pattern, $comment, -1, - PREG_SPLIT_DELIM_CAPTURE); - - $html = ''; - for ($i = 0; $i < count($matches); $i++) { - if ($i % 2) { - # convert links - $html .= '' . htmlspecialchars($matches[$i]) . ''; - } - else { - # convert everything else - $html .= nl2br(htmlspecialchars($matches[$i])); - } - } - - return $html; -} - -/** - * Wrapper for beginning a database transaction - */ -function begin_atomic_commit() { - $dbh = DB::connect(); - $dbh->beginTransaction(); -} - -/** - * Wrapper for committing a database transaction - */ -function end_atomic_commit() { - $dbh = DB::connect(); - $dbh->commit(); -} - -/** - * Merge pkgbase and package options - * - * Merges entries of the first and the second array. If any key appears in both - * arrays and the corresponding value in the second array is either a non-array - * type or a non-empty array, the value from the second array replaces the - * value from the first array. If the value from the second array is an array - * containing a single empty string, the value in the resulting array becomes - * an empty array instead. If the value in the second array is empty, the - * resulting array contains the value from the first array. - * - * @param array $pkgbase_info Options from the pkgbase section - * @param array $section_info Options from the package section - * - * @return array Merged information from both sections - */ -function array_pkgbuild_merge($pkgbase_info, $section_info) { - $pi = $pkgbase_info; - foreach ($section_info as $opt_key => $opt_val) { - if (is_array($opt_val)) { - if ($opt_val == array('')) { - $pi[$opt_key] = array(); - } elseif (count($opt_val) > 0) { - $pi[$opt_key] = $opt_val; - } - } else { - $pi[$opt_key] = $opt_val; - } - } - return $pi; -} - -/** - * Bound an integer value between two values - * - * @param int $n Integer value to bound - * @param int $min Lower bound - * @param int $max Upper bound - * - * @return int Bounded integer value - */ -function bound($n, $min, $max) { - return min(max($n, $min), $max); -} - -/** - * Return the URL of the AUR root - * - * @return string The URL of the AUR root - */ -function aur_location() { - $location = config_get('options', 'aur_location'); - if (substr($location, -1) != '/') { - $location .= '/'; - } - return $location; -} - -/** - * Calculate pagination templates - * - * @return array The array of pagination templates, per page, and offset values - */ -function calculate_pagination($total_comment_count) { - /* Sanitize paging variables. */ - if (isset($_GET["O"])) { - $_GET["O"] = max(intval($_GET["O"]), 0); - } else { - $_GET["O"] = 0; - } - $offset = $_GET["O"]; - - if (isset($_GET["PP"])) { - $_GET["PP"] = bound(intval($_GET["PP"]), 1, 250); - } else { - $_GET["PP"] = 10; - } - $per_page = $_GET["PP"]; - - // Page offsets start at zero, so page 2 has offset 1, which means that we - // need to add 1 to the offset to get the current page. - $current_page = ceil($offset / $per_page) + 1; - $num_pages = ceil($total_comment_count / $per_page); - $pagination_templs = array(); - - if ($current_page > 1) { - $previous_page = $current_page - 1; - $previous_offset = ($previous_page - 1) * $per_page; - $pagination_templs['« ' . __('First')] = 0; - $pagination_templs['‹ ' . __('Previous')] = $previous_offset; - } - - if ($current_page - 5 > 1) { - $pagination_templs["..."] = false; - } - - for ($i = max($current_page - 5, 1); $i <= min($num_pages, $current_page + 5); $i++) { - $pagination_templs[$i] = ($i - 1) * $per_page; - } - - if ($current_page + 5 < $num_pages) - $pagination_templs["... "] = false; - - if ($current_page < $num_pages) { - $pagination_templs[__('Next') . ' ›'] = $current_page * $per_page; - $pagination_templs[__('Last') . ' »'] = ($num_pages - 1) * $per_page; - } - - return array($pagination_templs, $per_page, $offset); -} diff --git a/web/lib/aurjson.class.php b/web/lib/aurjson.class.php deleted file mode 100644 index 81c27bd9..00000000 --- a/web/lib/aurjson.class.php +++ /dev/null @@ -1,710 +0,0 @@ -version = intval($http_data['v']); - } - if ($this->version < 1 || $this->version > 6) { - return $this->json_error('Invalid version specified.'); - } - - if (!isset($http_data['type']) || !isset($http_data['arg'])) { - return $this->json_error('No request type/data specified.'); - } - if (!in_array($http_data['type'], self::$exposed_methods)) { - return $this->json_error('Incorrect request type specified.'); - } - - if (isset($http_data['search_by']) && !isset($http_data['by'])) { - $http_data['by'] = $http_data['search_by']; - } - if (isset($http_data['by']) && !in_array($http_data['by'], self::$exposed_fields)) { - return $this->json_error('Incorrect by field specified.'); - } - - $this->dbh = DB::connect(); - - if ($this->check_ratelimit($_SERVER['REMOTE_ADDR'])) { - header("HTTP/1.1 429 Too Many Requests"); - return $this->json_error('Rate limit reached'); - } - - $type = str_replace('-', '_', $http_data['type']); - if ($type == 'info' && $this->version >= 5) { - $type = 'multiinfo'; - } - $json = call_user_func(array(&$this, $type), $http_data); - - $etag = md5($json); - header("Etag: \"$etag\""); - /* - * Make sure to strip a few things off the - * if-none-match header. Stripping whitespace may not - * be required, but removing the quote on the incoming - * header is required to make the equality test. - */ - $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? - trim($_SERVER['HTTP_IF_NONE_MATCH'], "\t\n\r\" ") : false; - if ($if_none_match && $if_none_match == $etag) { - header('HTTP/1.1 304 Not Modified'); - return; - } - - if (isset($http_data['callback'])) { - $callback = $http_data['callback']; - if (!preg_match('/^[a-zA-Z0-9()_.]{1,128}$/D', $callback)) { - return $this->json_error('Invalid callback name.'); - } - header('content-type: text/javascript'); - return '/**/' . $callback . '(' . $json . ')'; - } else { - header('content-type: application/json'); - return $json; - } - } - - /* - * Check if an IP needs to be rate limited. - * - * @param $ip IP of the current request - * - * @return true if IP needs to be rate limited, false otherwise. - */ - private function check_ratelimit($ip) { - $limit = config_get("ratelimit", "request_limit"); - if ($limit == 0) { - return false; - } - - $this->update_ratelimit($ip); - - $status = false; - $value = get_cache_value('ratelimit:' . $ip, $status); - if (!$status) { - $stmt = $this->dbh->prepare(" - SELECT Requests FROM ApiRateLimit - WHERE IP = :ip"); - $stmt->bindParam(":ip", $ip); - $result = $stmt->execute(); - - if (!$result) { - return false; - } - - $row = $stmt->fetch(PDO::FETCH_ASSOC); - $value = $row['Requests']; - } - - return $value > $limit; - } - - /* - * Update a rate limit for an IP by increasing it's requests value by one. - * - * @param $ip IP of the current request - * - * @return void - */ - private function update_ratelimit($ip) { - $window_length = config_get("ratelimit", "window_length"); - $db_backend = config_get("database", "backend"); - $time = time(); - $deletion_time = $time - $window_length; - - /* Try to use the cache. */ - $status = false; - $value = get_cache_value('ratelimit-ws:' . $ip, $status); - if (!$status || ($status && $value < $deletion_time)) { - if (set_cache_value('ratelimit-ws:' . $ip, $time, $window_length) && - set_cache_value('ratelimit:' . $ip, 1, $window_length)) { - return; - } - } else { - $value = get_cache_value('ratelimit:' . $ip, $status); - if ($status && set_cache_value('ratelimit:' . $ip, $value + 1, $window_length)) - return; - } - - /* Clean up old windows. */ - $stmt = $this->dbh->prepare(" - DELETE FROM ApiRateLimit - WHERE WindowStart < :time"); - $stmt->bindParam(":time", $deletion_time); - $stmt->execute(); - - if ($db_backend == "mysql") { - $stmt = $this->dbh->prepare(" - INSERT INTO ApiRateLimit - (IP, Requests, WindowStart) - VALUES (:ip, 1, :window_start) - ON DUPLICATE KEY UPDATE Requests=Requests+1"); - $stmt->bindParam(":ip", $ip); - $stmt->bindParam(":window_start", $time); - $stmt->execute(); - } elseif ($db_backend == "sqlite") { - $stmt = $this->dbh->prepare(" - INSERT OR IGNORE INTO ApiRateLimit - (IP, Requests, WindowStart) - VALUES (:ip, 0, :window_start);"); - $stmt->bindParam(":ip", $ip); - $stmt->bindParam(":window_start", $time); - $stmt->execute(); - - $stmt = $this->dbh->prepare(" - UPDATE ApiRateLimit - SET Requests = Requests + 1 - WHERE IP = :ip"); - $stmt->bindParam(":ip", $ip); - $stmt->execute(); - } else { - throw new RuntimeException("Unknown database backend"); - } - } - - /* - * Returns a JSON formatted error string. - * - * @param $msg The error string to return - * - * @return mixed A json formatted error response. - */ - private function json_error($msg) { - header('content-type: application/json'); - if ($this->version < 3) { - return $this->json_results('error', 0, $msg, NULL); - } elseif ($this->version >= 3) { - return $this->json_results('error', 0, array(), $msg); - } - } - - /* - * Returns a JSON formatted result data. - * - * @param $type The response method type. - * @param $count The number of results to return - * @param $data The result data to return - * @param $error An error message to include in the response - * - * @return mixed A json formatted result response. - */ - private function json_results($type, $count, $data, $error) { - $json_array = array( - 'version' => $this->version, - 'type' => $type, - 'resultcount' => $count, - 'results' => $data - ); - - if ($this->version != 5) { - $json_array['warning'] = 'The use of versions lower than 5 is ' - . 'now deprecated and will soon be unsupported. To ensure ' - . 'your API client supports the change without issue, it ' - . 'should use version 5 and adjust for any changes in the ' - . 'API interface. See https://aur.archlinux.org/rpc for ' - . 'documentation related to v5.'; - } - - if ($error) { - $json_array['error'] = $error; - } - - return json_encode($json_array); - } - - /* - * Get extended package details (for info and multiinfo queries). - * - * @param $pkgid The ID of the package to retrieve details for. - * @param $base_id The ID of the package base to retrieve details for. - * - * @return array An array containing package details. - */ - private function get_extended_fields($pkgid, $base_id) { - $query = "SELECT DependencyTypes.Name AS Type, " . - "PackageDepends.DepName AS Name, " . - "PackageDepends.DepCondition AS Cond " . - "FROM PackageDepends " . - "LEFT JOIN DependencyTypes " . - "ON DependencyTypes.ID = PackageDepends.DepTypeID " . - "WHERE PackageDepends.PackageID = " . $pkgid . " " . - "UNION SELECT RelationTypes.Name AS Type, " . - "PackageRelations.RelName AS Name, " . - "PackageRelations.RelCondition AS Cond " . - "FROM PackageRelations " . - "LEFT JOIN RelationTypes " . - "ON RelationTypes.ID = PackageRelations.RelTypeID " . - "WHERE PackageRelations.PackageID = " . $pkgid . " " . - "UNION SELECT 'groups' AS Type, `Groups`.`Name`, '' AS Cond " . - "FROM `Groups` INNER JOIN PackageGroups " . - "ON PackageGroups.PackageID = " . $pkgid . " " . - "AND PackageGroups.GroupID = `Groups`.ID " . - "UNION SELECT 'license' AS Type, Licenses.Name, '' AS Cond " . - "FROM Licenses INNER JOIN PackageLicenses " . - "ON PackageLicenses.PackageID = " . $pkgid . " " . - "AND PackageLicenses.LicenseID = Licenses.ID"; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - $rows = db_cache_result($query, 'extended-fields:' . $pkgid, PDO::FETCH_ASSOC, $ttl); - - $type_map = array( - 'depends' => 'Depends', - 'makedepends' => 'MakeDepends', - 'checkdepends' => 'CheckDepends', - 'optdepends' => 'OptDepends', - 'conflicts' => 'Conflicts', - 'provides' => 'Provides', - 'replaces' => 'Replaces', - 'groups' => 'Groups', - 'license' => 'License', - ); - $data = array(); - foreach ($rows as $row) { - $type = $type_map[$row['Type']]; - $data[$type][] = $row['Name'] . $row['Cond']; - } - - if ($this->version >= 5) { - $query = "SELECT Keyword FROM PackageKeywords " . - "WHERE PackageBaseID = " . intval($base_id) . " " . - "ORDER BY Keyword ASC"; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - $rows = db_cache_result($query, 'keywords:' . intval($base_id), PDO::FETCH_NUM, $ttl); - $data['Keywords'] = array_map(function ($x) { return $x[0]; }, $rows); - } - - return $data; - } - - /* - * Retrieve package information (used in info, multiinfo, search and - * depends requests). - * - * @param $type The request type. - * @param $where_condition An SQL WHERE-condition to filter packages. - * - * @return mixed Returns an array of package matches. - */ - private function process_query($type, $where_condition) { - $max_results = config_get_int('options', 'max_rpc_results'); - - if ($this->version == 1) { - $fields = implode(',', self::$fields_v1); - $query = "SELECT {$fields} " . - "FROM Packages LEFT JOIN PackageBases " . - "ON PackageBases.ID = Packages.PackageBaseID " . - "LEFT JOIN Users " . - "ON PackageBases.MaintainerUID = Users.ID " . - "LEFT JOIN PackageLicenses " . - "ON PackageLicenses.PackageID = Packages.ID " . - "LEFT JOIN Licenses " . - "ON Licenses.ID = PackageLicenses.LicenseID " . - "WHERE ${where_condition} " . - "AND PackageBases.PackagerUID IS NOT NULL " . - "LIMIT $max_results"; - } elseif ($this->version >= 2) { - if ($this->version == 2 || $this->version == 3) { - $fields = implode(',', self::$fields_v2); - } else if ($this->version >= 4 && $this->version <= 6) { - $fields = implode(',', self::$fields_v4); - } - $query = "SELECT {$fields} " . - "FROM Packages LEFT JOIN PackageBases " . - "ON PackageBases.ID = Packages.PackageBaseID " . - "LEFT JOIN Users " . - "ON PackageBases.MaintainerUID = Users.ID " . - "WHERE ${where_condition} " . - "AND PackageBases.PackagerUID IS NOT NULL " . - "LIMIT $max_results"; - } - $result = $this->dbh->query($query); - - if ($result) { - $resultcount = 0; - $search_data = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $resultcount++; - $row['URLPath'] = sprintf(config_get('options', 'snapshot_uri'), urlencode($row['PackageBase'])); - if ($this->version < 4) { - $row['CategoryID'] = 1; - } - - /* - * Unfortunately, mysql_fetch_assoc() returns - * all fields as strings. We need to coerce - * numeric values into integers to provide - * proper data types in the JSON response. - */ - foreach (self::$numeric_fields as $field) { - if (isset($row[$field])) { - $row[$field] = intval($row[$field]); - } - } - - foreach (self::$decimal_fields as $field) { - if (isset($row[$field])) { - $row[$field] = floatval($row[$field]); - } - } - - if ($this->version >= 2 && ($type == 'info' || $type == 'multiinfo')) { - $extfields = $this->get_extended_fields($row['ID'], $row['PackageBaseID']); - if ($extfields) { - $row = array_merge($row, $extfields); - } - } - - if ($this->version < 3) { - if ($type == 'info') { - $search_data = $row; - break; - } else { - array_push($search_data, $row); - } - } elseif ($this->version >= 3) { - array_push($search_data, $row); - } - } - - if ($resultcount === $max_results) { - return $this->json_error('Too many package results.'); - } - - return $this->json_results($type, $resultcount, $search_data, NULL); - } else { - return $this->json_results($type, 0, array(), NULL); - } - } - - /* - * Parse the args to the multiinfo function. We may have a string or an - * array, so do the appropriate thing. Within the elements, both * package - * IDs and package names are valid; sort them into the relevant arrays and - * escape/quote the names. - * - * @param array $args Query parameters. - * - * @return mixed An array containing 'ids' and 'names'. - */ - private function parse_multiinfo_args($args) { - if (!is_array($args)) { - $args = array($args); - } - - $id_args = array(); - $name_args = array(); - foreach ($args as $arg) { - if (!$arg) { - continue; - } - if ($this->version < 5 && is_numeric($arg)) { - $id_args[] = intval($arg); - } else { - $name_args[] = $this->dbh->quote($arg); - } - } - - return array('ids' => $id_args, 'names' => $name_args); - } - - /* - * Performs a fulltext mysql search of the package database. - * - * @param array $http_data Query parameters. - * - * @return mixed Returns an array of package matches. - */ - private function search($http_data) { - $keyword_string = $http_data['arg']; - - if (isset($http_data['by'])) { - $search_by = $http_data['by']; - } else { - $search_by = 'name-desc'; - } - - if ($search_by === 'name' || $search_by === 'name-desc') { - if (strlen($keyword_string) < 2) { - return $this->json_error('Query arg too small.'); - } - - if ($this->version >= 6 && $search_by === 'name-desc') { - $where_condition = construct_keyword_search($this->dbh, - $keyword_string, true, false); - } else { - $keyword_string = $this->dbh->quote( - "%" . addcslashes($keyword_string, '%_') . "%"); - - if ($search_by === 'name') { - $where_condition = "(Packages.Name LIKE $keyword_string)"; - } else if ($search_by === 'name-desc') { - $where_condition = "(Packages.Name LIKE $keyword_string "; - $where_condition .= "OR Description LIKE $keyword_string)"; - } - - } - } else if ($search_by === 'maintainer') { - if (empty($keyword_string)) { - $where_condition = "Users.ID is NULL"; - } else { - $keyword_string = $this->dbh->quote($keyword_string); - $where_condition = "Users.Username = $keyword_string "; - } - } else if (in_array($search_by, self::$exposed_depfields)) { - if (empty($keyword_string)) { - return $this->json_error('Query arg is empty.'); - } else { - $keyword_string = $this->dbh->quote($keyword_string); - $search_by = $this->dbh->quote($search_by); - $subquery = "SELECT PackageDepends.DepName FROM PackageDepends "; - $subquery .= "LEFT JOIN DependencyTypes "; - $subquery .= "ON PackageDepends.DepTypeID = DependencyTypes.ID "; - $subquery .= "WHERE PackageDepends.PackageID = Packages.ID "; - $subquery .= "AND DependencyTypes.Name = $search_by"; - $where_condition = "$keyword_string IN ($subquery)"; - } - } - - return $this->process_query('search', $where_condition); - } - - /* - * Returns the info on a specific package. - * - * @param array $http_data Query parameters. - * - * @return mixed Returns an array of value data containing the package data - */ - private function info($http_data) { - $pqdata = $http_data['arg']; - if ($this->version < 5 && is_numeric($pqdata)) { - $where_condition = "Packages.ID = $pqdata"; - } else { - $where_condition = "Packages.Name = " . $this->dbh->quote($pqdata); - } - - return $this->process_query('info', $where_condition); - } - - /* - * Returns the info on multiple packages. - * - * @param array $http_data Query parameters. - * - * @return mixed Returns an array of results containing the package data - */ - private function multiinfo($http_data) { - $pqdata = $http_data['arg']; - $args = $this->parse_multiinfo_args($pqdata); - $ids = $args['ids']; - $names = $args['names']; - - if (!$ids && !$names) { - return $this->json_error('Invalid query arguments.'); - } - - $where_condition = ""; - if ($ids) { - $ids_value = implode(',', $args['ids']); - $where_condition .= "Packages.ID IN ($ids_value) "; - } - if ($ids && $names) { - $where_condition .= "OR "; - } - if ($names) { - /* - * Individual names were quoted in - * parse_multiinfo_args(). - */ - $names_value = implode(',', $args['names']); - $where_condition .= "Packages.Name IN ($names_value) "; - } - - return $this->process_query('multiinfo', $where_condition); - } - - /* - * Returns all the packages for a specific maintainer. - * - * @param array $http_data Query parameters. - * - * @return mixed Returns an array of value data containing the package data - */ - private function msearch($http_data) { - $http_data['by'] = 'maintainer'; - return $this->search($http_data); - } - - /* - * Get all package names that start with $search. - * - * @param array $http_data Query parameters. - * - * @return string The JSON formatted response data. - */ - private function suggest($http_data) { - $search = $http_data['arg']; - $query = "SELECT Packages.Name FROM Packages "; - $query.= "LEFT JOIN PackageBases "; - $query.= "ON PackageBases.ID = Packages.PackageBaseID "; - $query.= "WHERE Packages.Name LIKE "; - $query.= $this->dbh->quote(addcslashes($search, '%_') . '%'); - $query.= " AND PackageBases.PackagerUID IS NOT NULL "; - $query.= "ORDER BY Name ASC LIMIT 20"; - - $result = $this->dbh->query($query); - $result_array = array(); - - if ($result) { - $result_array = $result->fetchAll(PDO::FETCH_COLUMN, 0); - } - - return json_encode($result_array); - } - - /* - * Get all package base names that start with $search. - * - * @param array $http_data Query parameters. - * - * @return string The JSON formatted response data. - */ - private function suggest_pkgbase($http_data) { - $search = $http_data['arg']; - $query = "SELECT Name FROM PackageBases WHERE Name LIKE "; - $query.= $this->dbh->quote(addcslashes($search, '%_') . '%'); - $query.= " AND PackageBases.PackagerUID IS NOT NULL "; - $query.= "ORDER BY Name ASC LIMIT 20"; - - $result = $this->dbh->query($query); - $result_array = array(); - - if ($result) { - $result_array = $result->fetchAll(PDO::FETCH_COLUMN, 0); - } - - return json_encode($result_array); - } - - /** - * Get the HTML markup of the comment form. - * - * @param array $http_data Query parameters. - * - * @return string The JSON formatted response data. - */ - private function get_comment_form($http_data) { - if (!isset($http_data['base_id']) || !isset($http_data['pkgbase_name'])) { - $output = array( - 'success' => 0, - 'error' => __('Package base ID or package base name missing.') - ); - return json_encode($output); - } - - $comment_id = intval($http_data['arg']); - $base_id = intval($http_data['base_id']); - $pkgbase_name = $http_data['pkgbase_name']; - - list($user_id, $comment) = comment_by_id($comment_id); - - if (!has_credential(CRED_COMMENT_EDIT, array($user_id))) { - $output = array( - 'success' => 0, - 'error' => __('You are not allowed to edit this comment.') - ); - return json_encode($output); - } elseif (is_null($comment)) { - $output = array( - 'success' => 0, - 'error' => __('Comment does not exist.') - ); - return json_encode($output); - } - - ob_start(); - include('pkg_comment_form.php'); - $html = ob_get_clean(); - $output = array( - 'success' => 1, - 'form' => $html - ); - - return json_encode($output); - } -} diff --git a/web/lib/cachefuncs.inc.php b/web/lib/cachefuncs.inc.php deleted file mode 100644 index b2b96c24..00000000 --- a/web/lib/cachefuncs.inc.php +++ /dev/null @@ -1,99 +0,0 @@ -addServer($mcserver[0], intval($mcserver[1])); - } -} - -# Set a value in the cache (currently APC) if cache is available for use. If -# not available, this becomes effectively a no-op (return value is -# false). Accepts an optional TTL (defaults to 600 seconds). -function set_cache_value($key, $value, $ttl=600) { - $status = false; - if (defined('EXTENSION_LOADED_APC')) { - $status = apc_store(CACHE_PREFIX.$key, $value, $ttl); - } - if (defined('EXTENSION_LOADED_MEMCACHE')) { - global $memcache; - $status = $memcache->set(CACHE_PREFIX.$key, $value, $ttl); - } - return $status; -} - -# Get a value from the cache (currently APC) if cache is available for use. If -# not available, this returns false (optionally sets passed in variable $status -# to false, much like apc_fetch() behaves). This allows for testing the fetch -# result appropriately even in the event that a 'false' value was the value in -# the cache. -function get_cache_value($key, &$status=false) { - if(defined('EXTENSION_LOADED_APC')) { - $ret = apc_fetch(CACHE_PREFIX.$key, $status); - if ($status) { - return $ret; - } - } - if (defined('EXTENSION_LOADED_MEMCACHE')) { - global $memcache; - $ret = $memcache->get(CACHE_PREFIX.$key); - if (!$ret) { - $status = false; - } - else { - $status = true; - } - return $ret; - } - return $status; -} - -# Run a simple db query, retrieving and/or caching the value if APC is -# available for use. Accepts an optional TTL value (defaults to 600 seconds). -function db_cache_value($dbq, $key, $ttl=600) { - $dbh = DB::connect(); - $status = false; - $value = get_cache_value($key, $status); - if (!$status) { - $result = $dbh->query($dbq); - if (!$result) { - return false; - } - $row = $result->fetch(PDO::FETCH_NUM); - $value = $row[0]; - set_cache_value($key, $value, $ttl); - } - return $value; -} - -# Run a simple db query, retrieving and/or caching the result set if APC is -# available for use. Accepts an optional TTL value (defaults to 600 seconds). -function db_cache_result($dbq, $key, $fetch_style=PDO::FETCH_NUM, $ttl=600) { - $dbh = DB::connect(); - $status = false; - $value = get_cache_value($key, $status); - if (!$status) { - $result = $dbh->query($dbq); - if (!$result) { - return false; - } - $value = $result->fetchAll($fetch_style); - set_cache_value($key, $value, $ttl); - } - return $value; -} - -?> diff --git a/web/lib/confparser.inc.php b/web/lib/confparser.inc.php deleted file mode 100644 index fdd2b78e..00000000 --- a/web/lib/confparser.inc.php +++ /dev/null @@ -1,59 +0,0 @@ -useCached(); // use cached version if age<1 hour -$rss->title = "PHP news"; -$rss->description = "daily news from the PHP scripting world"; - -//optional -$rss->descriptionTruncSize = 500; -$rss->descriptionHtmlSyndicated = true; - -$rss->link = "http://www.dailyphp.net/news"; -$rss->syndicationURL = "http://www.dailyphp.net/".$_SERVER["PHP_SELF"]; - -$image = new FeedImage(); -$image->title = "dailyphp.net logo"; -$image->url = "http://www.dailyphp.net/images/logo.gif"; -$image->link = "http://www.dailyphp.net"; -$image->description = "Feed provided by dailyphp.net. Click to visit."; - -//optional -$image->descriptionTruncSize = 500; -$image->descriptionHtmlSyndicated = true; - -$rss->image = $image; - -// get your news items from somewhere, e.g. your database: -mysql_select_db($dbHost, $dbUser, $dbPass); -$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); -while ($data = mysql_fetch_object($res)) { - $item = new FeedItem(); - $item->title = $data->title; - $item->link = $data->url; - $item->description = $data->short; - - //optional - item->descriptionTruncSize = 500; - item->descriptionHtmlSyndicated = true; - - $item->date = $data->newsdate; - $item->source = "http://www.dailyphp.net"; - $item->author = "John Doe"; - - $rss->addItem($item); -} - -// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1 (deprecated), -// MBOX, OPML, ATOM, ATOM0.3, HTML, JS -echo $rss->saveFeed("RSS1.0", "news/feed.xml"); - - -*************************************************************************** -* A little setup * -**************************************************************************/ - -// your local timezone, set to "" to disable or for GMT -define("TIME_ZONE","+01:00"); - - - - -/** - * Version string. - **/ -define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2"); - - - -/** - * A FeedItem is a part of a FeedCreator feed. - * - * @author Kai Blankenhorn - * @since 1.3 - */ -class FeedItem extends HtmlDescribable { - /** - * Mandatory attributes of an item. - */ - var $title, $description, $link; - - /** - * Optional attributes of an item. - */ - var $author, $authorEmail, $image, $category, $comments, $guid, $guidIsPermaLink, $source, $creator; - - /** - * Publishing date of an item. May be in one of the following formats: - * - * RFC 822: - * "Mon, 20 Jan 03 18:05:41 +0400" - * "20 Jan 03 18:05:41 +0000" - * - * ISO 8601: - * "2003-01-20T18:05:41+04:00" - * - * Unix: - * 1043082341 - */ - var $date; - - /** - * Any additional elements to include as an assiciated array. All $key => $value pairs - * will be included unencoded in the feed item in the form - * <$key>$value - * Again: No encoding will be used! This means you can invalidate or enhance the feed - * if $value contains markup. This may be abused to embed tags not implemented by - * the FeedCreator class used. - */ - var $additionalElements = Array(); - - // on hold - // var $source; -} - - - -/** - * An FeedImage may be added to a FeedCreator feed. - * @author Kai Blankenhorn - * @since 1.3 - */ -class FeedImage extends HtmlDescribable { - /** - * Mandatory attributes of an image. - */ - var $title, $url, $link; - - /** - * Optional attributes of an image. - */ - var $width, $height, $description; -} - - - -/** - * An HtmlDescribable is an item within a feed that can have a description that may - * include HTML markup. - */ -class HtmlDescribable { - /** - * Indicates whether the description field should be rendered in HTML. - */ - var $descriptionHtmlSyndicated; - - /** - * Indicates whether and to how many characters a description should be truncated. - */ - var $descriptionTruncSize; - - /** - * Returns a formatted description field, depending on descriptionHtmlSyndicated and - * $descriptionTruncSize properties - * @return string the formatted description - */ - function getDescription() { - $descriptionField = new FeedHtmlField($this->description); - $descriptionField->syndicateHtml = $this->descriptionHtmlSyndicated; - $descriptionField->truncSize = $this->descriptionTruncSize; - return $descriptionField->output(); - } - -} - - -/** - * An FeedHtmlField describes and generates - * a feed, item or image html field (probably a description). Output is - * generated based on $truncSize, $syndicateHtml properties. - * @author Pascal Van Hecke - * @version 1.6 - */ -class FeedHtmlField { - /** - * Mandatory attributes of a FeedHtmlField. - */ - var $rawFieldContent; - - /** - * Optional attributes of a FeedHtmlField. - * - */ - var $truncSize, $syndicateHtml; - - /** - * Creates a new instance of FeedHtmlField. - * @param $string: if given, sets the rawFieldContent property - */ - function FeedHtmlField($parFieldContent) { - if ($parFieldContent) { - $this->rawFieldContent = $parFieldContent; - } - } - - - /** - * Creates the right output, depending on $truncSize, $syndicateHtml properties. - * @return string the formatted field - */ - function output() { - // when field available and syndicated in html we assume - // - valid html in $rawFieldContent and we enclose in CDATA tags - // - no truncation (truncating risks producing invalid html) - if (!$this->rawFieldContent) { - $result = ""; - } elseif ($this->syndicateHtml) { - $result = "rawFieldContent."]]>"; - } else { - if ($this->truncSize and is_int($this->truncSize)) { - $result = FeedCreator::iTrunc(htmlspecialchars($this->rawFieldContent),$this->truncSize); - } else { - $result = htmlspecialchars($this->rawFieldContent); - } - } - return $result; - } - -} - - - -/** - * UniversalFeedCreator lets you choose during runtime which - * format to build. - * For general usage of a feed class, see the FeedCreator class - * below or the example above. - * - * @since 1.3 - * @author Kai Blankenhorn - */ -class UniversalFeedCreator extends FeedCreator { - var $_feed; - - function _setFormat($format) { - switch (strtoupper($format)) { - - case "2.0": - // fall through - case "RSS2.0": - $this->_feed = new RSSCreator20(); - break; - - case "1.0": - // fall through - case "RSS1.0": - $this->_feed = new RSSCreator10(); - break; - - case "0.91": - // fall through - case "RSS0.91": - $this->_feed = new RSSCreator091(); - break; - - case "PIE0.1": - $this->_feed = new PIECreator01(); - break; - - case "MBOX": - $this->_feed = new MBOXCreator(); - break; - - case "OPML": - $this->_feed = new OPMLCreator(); - break; - - case "ATOM": - // fall through: always the latest ATOM version - - case "ATOM0.3": - $this->_feed = new AtomCreator03(); - break; - - case "HTML": - $this->_feed = new HTMLCreator(); - break; - - case "JS": - // fall through - case "JAVASCRIPT": - $this->_feed = new JSCreator(); - break; - - default: - $this->_feed = new RSSCreator091(); - break; - } - - $vars = get_object_vars($this); - foreach ($vars as $key => $value) { - // prevent overwriting of properties "contentType", "encoding"; do not copy "_feed" itself - if (!in_array($key, array("_feed", "contentType", "encoding"))) { - $this->_feed->{$key} = $this->{$key}; - } - } - } - - /** - * Creates a syndication feed based on the items previously added. - * - * @see FeedCreator::addItem() - * @param string format format the feed should comply to. Valid values are: - * "PIE0.1", "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3", "HTML", "JS" - * @return string the contents of the feed. - */ - function createFeed($format = "RSS0.91") { - $this->_setFormat($format); - return $this->_feed->createFeed(); - } - - - - /** - * Saves this feed as a file on the local disk. After the file is saved, an HTTP redirect - * header may be sent to redirect the use to the newly created file. - * @since 1.4 - * - * @param string format format the feed should comply to. Valid values are: - * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM", "ATOM0.3", "HTML", "JS" - * @param string filename optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). - * @param boolean displayContents optional send the content of the file or not. If true, the file will be sent in the body of the response. - */ - function saveFeed($format="RSS0.91", $filename="", $displayContents=true) { - $this->_setFormat($format); - $this->_feed->saveFeed($filename, $displayContents); - } - - - /** - * Turns on caching and checks if there is a recent version of this feed in the cache. - * If there is, an HTTP redirect header is sent. - * To effectively use caching, you should create the FeedCreator object and call this method - * before anything else, especially before you do the time consuming task to build the feed - * (web fetching, for example). - * - * @param string format format the feed should comply to. Valid values are: - * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3". - * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). - * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour) - */ - function useCached($format="RSS0.91", $filename="", $timeout=3600) { - $this->_setFormat($format); - $this->_feed->useCached($filename, $timeout); - } - -} - - -/** - * FeedCreator is the abstract base implementation for concrete - * implementations that implement a specific format of syndication. - * - * @abstract - * @author Kai Blankenhorn - * @since 1.4 - */ -class FeedCreator extends HtmlDescribable { - - /** - * Mandatory attributes of a feed. - */ - var $title, $description, $link; - - - /** - * Optional attributes of a feed. - */ - var $syndicationURL, $image, $language, $copyright, $pubDate, $lastBuildDate, $editor, $editorEmail, $webmaster, $category, $docs, $ttl, $rating, $skipHours, $skipDays; - - /** - * The url of the external xsl stylesheet used to format the naked rss feed. - * Ignored in the output when empty. - */ - var $xslStyleSheet = ""; - - - /** - * @access private - */ - var $items = Array(); - - - /** - * This feed's MIME content type. - * @since 1.4 - * @access private - */ - var $contentType = "application/xml"; - - - /** - * This feed's character encoding. - * @since 1.6.1 - **/ - var $encoding = "ISO-8859-1"; - - - /** - * Any additional elements to include as an assiciated array. All $key => $value pairs - * will be included unencoded in the feed in the form - * <$key>$value - * Again: No encoding will be used! This means you can invalidate or enhance the feed - * if $value contains markup. This may be abused to embed tags not implemented by - * the FeedCreator class used. - */ - var $additionalElements = Array(); - - - /** - * Adds an FeedItem to the feed. - * - * @param object FeedItem $item The FeedItem to add to the feed. - * @access public - */ - function addItem($item) { - $this->items[] = $item; - } - - - /** - * Truncates a string to a certain length at the most sensible point. - * First, if there's a '.' character near the end of the string, the string is truncated after this character. - * If there is no '.', the string is truncated after the last ' ' character. - * If the string is truncated, " ..." is appended. - * If the string is already shorter than $length, it is returned unchanged. - * - * @static - * @param string string A string to be truncated. - * @param int length the maximum length the string should be truncated to - * @return string the truncated string - */ - function iTrunc($string, $length) { - if (strlen($string)<=$length) { - return $string; - } - - $pos = strrpos($string,"."); - if ($pos>=$length-4) { - $string = substr($string,0,$length-4); - $pos = strrpos($string,"."); - } - if ($pos>=$length*0.4) { - return substr($string,0,$pos+1)." ..."; - } - - $pos = strrpos($string," "); - if ($pos>=$length-4) { - $string = substr($string,0,$length-4); - $pos = strrpos($string," "); - } - if ($pos>=$length*0.4) { - return substr($string,0,$pos)." ..."; - } - - return substr($string,0,$length-4)." ..."; - - } - - - /** - * Creates a comment indicating the generator of this feed. - * The format of this comment seems to be recognized by - * Syndic8.com. - */ - function _createGeneratorComment() { - return "\n"; - } - - - /** - * Creates a string containing all additional elements specified in - * $additionalElements. - * @param elements array an associative array containing key => value pairs - * @param indentString string a string that will be inserted before every generated line - * @return string the XML tags corresponding to $additionalElements - */ - function _createAdditionalElements($elements, $indentString="") { - $ae = ""; - if (is_array($elements)) { - foreach($elements AS $key => $value) { - $ae.= $indentString."<$key>$value\n"; - } - } - return $ae; - } - - function _createStylesheetReferences() { - $xml = ""; - if ($this->cssStyleSheet) $xml .= "cssStyleSheet."\" type=\"text/css\"?>\n"; - if ($this->xslStyleSheet) $xml .= "xslStyleSheet."\" type=\"text/xsl\"?>\n"; - return $xml; - } - - - /** - * Builds the feed's text. - * @abstract - * @return string the feed's complete text - */ - function createFeed() { - } - - /** - * Generate a filename for the feed cache file. The result will be $_SERVER["PHP_SELF"] with the extension changed to .xml. - * For example: - * - * echo $_SERVER["PHP_SELF"]."\n"; - * echo FeedCreator::_generateFilename(); - * - * would produce: - * - * /rss/latestnews.php - * latestnews.xml - * - * @return string the feed cache filename - * @since 1.4 - * @access private - */ - function _generateFilename() { - $fileInfo = pathinfo($_SERVER["PHP_SELF"]); - return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".xml"; - } - - - /** - * @since 1.4 - * @access private - */ - function _redirect($filename) { - // attention, heavily-commented-out-area - - // maybe use this in addition to file time checking - //Header("Expires: ".date("r",time()+$this->_timeout)); - - /* no caching at all, doesn't seem to work as good: - Header("Cache-Control: no-cache"); - Header("Pragma: no-cache"); - */ - - // HTTP redirect, some feed readers' simple HTTP implementations don't follow it - //Header("Location: ".$filename); - - Header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename)); - Header("Content-Disposition: inline; filename=".basename($filename)); - readfile($filename, "r"); - die(); - } - - /** - * Turns on caching and checks if there is a recent version of this feed in the cache. - * If there is, an HTTP redirect header is sent. - * To effectively use caching, you should create the FeedCreator object and call this method - * before anything else, especially before you do the time consuming task to build the feed - * (web fetching, for example). - * @since 1.4 - * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). - * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour) - */ - function useCached($filename="", $timeout=3600) { - $this->_timeout = $timeout; - if ($filename=="") { - $filename = $this->_generateFilename(); - } - if (file_exists($filename) AND (time()-filemtime($filename) < $timeout)) { - $this->_redirect($filename); - } - } - - - /** - * Saves this feed as a file on the local disk. After the file is saved, a redirect - * header may be sent to redirect the user to the newly created file. - * @since 1.4 - * - * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). - * @param redirect boolean optional send an HTTP redirect header or not. If true, the user will be automatically redirected to the created file. - */ - function saveFeed($filename="", $displayContents=true) { - if ($filename=="") { - $filename = $this->_generateFilename(); - } - $feedFile = fopen($filename, "w+"); - if ($feedFile) { - fputs($feedFile,$this->createFeed()); - fclose($feedFile); - if ($displayContents) { - $this->_redirect($filename); - } - } else { - echo "
    Error creating feed file, please check write permissions.
    "; - } - } - -} - - -/** - * FeedDate is an internal class that stores a date for a feed or feed item. - * Usually, you won't need to use this. - */ -class FeedDate { - var $unix; - - /** - * Creates a new instance of FeedDate representing a given date. - * Accepts RFC 822, ISO 8601 date formats as well as unix time stamps. - * @param mixed $dateString optional the date this FeedDate will represent. If not specified, the current date and time is used. - */ - function FeedDate($dateString="") { - if ($dateString=="") $dateString = date("r"); - - if (is_integer($dateString)) { - $this->unix = $dateString; - return; - } - if (preg_match("~(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\\s+)?(\\d{1,2})\\s+([a-zA-Z]{3})\\s+(\\d{4})\\s+(\\d{2}):(\\d{2}):(\\d{2})\\s+(.*)~",$dateString,$matches)) { - $months = Array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12); - $this->unix = mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]); - if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') { - $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60; - } else { - if (strlen($matches[7])==1) { - $oneHour = 3600; - $ord = ord($matches[7]); - if ($ord < ord("M")) { - $tzOffset = (ord("A") - $ord - 1) * $oneHour; - } elseif ($ord >= ord("M") AND $matches[7]!="Z") { - $tzOffset = ($ord - ord("M")) * $oneHour; - } elseif ($matches[7]=="Z") { - $tzOffset = 0; - } - } - switch ($matches[7]) { - case "UT": - case "GMT": $tzOffset = 0; - } - } - $this->unix += $tzOffset; - return; - } - if (preg_match("~(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.*)~",$dateString,$matches)) { - $this->unix = mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]); - if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') { - $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60; - } else { - if ($matches[7]=="Z") { - $tzOffset = 0; - } - } - $this->unix += $tzOffset; - return; - } - $this->unix = 0; - } - - /** - * Gets the date stored in this FeedDate as an RFC 822 date. - * - * @return a date in RFC 822 format - */ - function rfc822() { - //return gmdate("r",$this->unix); - $date = gmdate("D, d M Y H:i:s", $this->unix); - if (TIME_ZONE!="") $date .= " ".str_replace(":","",TIME_ZONE); - return $date; - } - - /** - * Gets the date stored in this FeedDate as an ISO 8601 date. - * - * @return a date in ISO 8601 format - */ - function iso8601() { - $date = gmdate("Y-m-d\TH:i:sO",$this->unix); - $date = substr($date,0,22) . ':' . substr($date,-2); - if (TIME_ZONE!="") $date = str_replace("+00:00",TIME_ZONE,$date); - return $date; - } - - /** - * Gets the date stored in this FeedDate as unix time stamp. - * - * @return a date as a unix time stamp - */ - function unix() { - return $this->unix; - } -} - - -/** - * RSSCreator10 is a FeedCreator that implements RDF Site Summary (RSS) 1.0. - * - * @see http://www.purl.org/rss/1.0/ - * @since 1.3 - * @author Kai Blankenhorn - */ -class RSSCreator10 extends FeedCreator { - - /** - * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0. - * The feed will contain all items previously added in the same order. - * @return string the feed's complete text - */ - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createGeneratorComment(); - if ($this->cssStyleSheet=="") { - $cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css"; - } - $feed.= $this->_createStylesheetReferences(); - $feed.= "\n"; - $feed.= " syndicationURL."\">\n"; - $feed.= " ".htmlspecialchars($this->title)."\n"; - $feed.= " ".htmlspecialchars($this->description)."\n"; - $feed.= " ".$this->link."\n"; - if ($this->image!=null) { - $feed.= " image->url."\" />\n"; - } - $now = new FeedDate(); - $feed.= " ".htmlspecialchars($now->iso8601())."\n"; - $feed.= " \n"; - $feed.= " \n"; - for ($i=0;$iitems);$i++) { - $feed.= " items[$i]->link)."\"/>\n"; - } - $feed.= " \n"; - $feed.= " \n"; - $feed.= " \n"; - if ($this->image!=null) { - $feed.= " image->url."\">\n"; - $feed.= " ".$this->image->title."\n"; - $feed.= " ".$this->image->link."\n"; - $feed.= " ".$this->image->url."\n"; - $feed.= " \n"; - } - $feed.= $this->_createAdditionalElements($this->additionalElements, " "); - - for ($i=0;$iitems);$i++) { - $feed.= " items[$i]->link)."\">\n"; - //$feed.= " Posting\n"; - $feed.= " text/html\n"; - if ($this->items[$i]->date!=null) { - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - } - if ($this->items[$i]->source!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->source)."\n"; - } - if ($this->items[$i]->author!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; - } - $feed.= " ".htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r"," ")))."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->description)."\n"; - $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); - $feed.= " \n"; - } - $feed.= "\n"; - return $feed; - } -} - - - -/** - * RSSCreator091 is a FeedCreator that implements RSS 0.91 Spec, revision 3. - * - * @see http://my.netscape.com/publish/formats/rss-spec-0.91.html - * @since 1.3 - * @author Kai Blankenhorn - */ -class RSSCreator091 extends FeedCreator { - - /** - * Stores this RSS feed's version number. - * @access private - */ - var $RSSVersion; - - function RSSCreator091() { - $this->_setRSSVersion("0.91"); - $this->contentType = "application/rss+xml"; - } - - /** - * Sets this RSS feed's version number. - * @access private - */ - function _setRSSVersion($version) { - $this->RSSVersion = $version; - } - - /** - * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0. - * The feed will contain all items previously added in the same order. - * @return string the feed's complete text - */ - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createGeneratorComment(); - $feed.= $this->_createStylesheetReferences(); - $feed.= "RSSVersion."\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n"; - $feed.= " \n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."\n"; - $this->descriptionTruncSize = 500; - $feed.= " ".$this->getDescription()."\n"; - $feed.= " ".$this->link."\n"; - $feed.= " syndicationURL."\" rel=\"self\" type=\"application/rss+xml\" />\n"; - $now = new FeedDate(); - $feed.= " ".htmlspecialchars($now->rfc822())."\n"; - $feed.= " ".FEEDCREATOR_VERSION."\n"; - - if ($this->image!=null) { - $feed.= " \n"; - $feed.= " ".$this->image->url."\n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->image->title),100)."\n"; - $feed.= " ".$this->image->link."\n"; - if ($this->image->width!="") { - $feed.= " ".$this->image->width."\n"; - } - if ($this->image->height!="") { - $feed.= " ".$this->image->height."\n"; - } - if ($this->image->description!="") { - $feed.= " ".$this->image->getDescription()."\n"; - } - $feed.= " \n"; - } - if ($this->language!="") { - $feed.= " ".$this->language."\n"; - } - if ($this->copyright!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->copyright),100)."\n"; - } - if ($this->editor!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->editor),100)."\n"; - } - if ($this->webmaster!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->webmaster),100)."\n"; - } - if ($this->pubDate!="") { - $pubDate = new FeedDate($this->pubDate); - $feed.= " ".htmlspecialchars($pubDate->rfc822())."\n"; - } - if ($this->category!="") { - $feed.= " ".htmlspecialchars($this->category)."\n"; - } - if ($this->docs!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->docs),500)."\n"; - } - if ($this->ttl!="") { - $feed.= " ".htmlspecialchars($this->ttl)."\n"; - } - if ($this->rating!="") { - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->rating),500)."\n"; - } - if ($this->skipHours!="") { - $feed.= " ".htmlspecialchars($this->skipHours)."\n"; - } - if ($this->skipDays!="") { - $feed.= " ".htmlspecialchars($this->skipDays)."\n"; - } - $feed.= $this->_createAdditionalElements($this->additionalElements, " "); - - for ($i=0;$iitems);$i++) { - $feed.= " \n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; - $feed.= " ".$this->items[$i]->getDescription()."\n"; - - if ($this->items[$i]->author!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; - } - /* - // on hold - if ($this->items[$i]->source!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->source)."\n"; - } - */ - if ($this->items[$i]->category!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->category)."\n"; - } - if ($this->items[$i]->comments!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->comments)."\n"; - } - if ($this->items[$i]->date!="") { - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= " ".htmlspecialchars($itemDate->rfc822())."\n"; - } - if ($this->items[$i]->guid!="") { - $feed.= " items[$i]->guidIsPermaLink == false) { - $feed.= " isPermaLink=\"false\""; - } - $feed.= ">".htmlspecialchars($this->items[$i]->guid)."\n"; - } - $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); - $feed.= " \n"; - } - $feed.= " \n"; - $feed.= "\n"; - return $feed; - } -} - - - -/** - * RSSCreator20 is a FeedCreator that implements RDF Site Summary (RSS) 2.0. - * - * @see http://backend.userland.com/rss - * @since 1.3 - * @author Kai Blankenhorn - */ -class RSSCreator20 extends RSSCreator091 { - - function RSSCreator20() { - parent::_setRSSVersion("2.0"); - } - -} - - -/** - * PIECreator01 is a FeedCreator that implements the emerging PIE specification, - * as in http://intertwingly.net/wiki/pie/Syntax. - * - * @deprecated - * @since 1.3 - * @author Scott Reynen and Kai Blankenhorn - */ -class PIECreator01 extends FeedCreator { - - function PIECreator01() { - $this->encoding = "utf-8"; - } - - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createStylesheetReferences(); - $feed.= "\n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."\n"; - $this->truncSize = 500; - $feed.= " ".$this->getDescription()."\n"; - $feed.= " ".$this->link."\n"; - for ($i=0;$iitems);$i++) { - $feed.= " \n"; - $feed.= " ".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->guid)."\n"; - if ($this->items[$i]->author!="") { - $feed.= " \n"; - $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; - if ($this->items[$i]->authorEmail!="") { - $feed.= " ".$this->items[$i]->authorEmail."\n"; - } - $feed.=" \n"; - } - $feed.= " \n"; - $feed.= "
    ".$this->items[$i]->getDescription()."
    \n"; - $feed.= "
    \n"; - $feed.= "
    \n"; - } - $feed.= "
    \n"; - return $feed; - } -} - - -/** - * AtomCreator03 is a FeedCreator that implements the atom specification, - * as in http://www.intertwingly.net/wiki/pie/FrontPage. - * Please note that just by using AtomCreator03 you won't automatically - * produce valid atom files. For example, you have to specify either an editor - * for the feed or an author for every single feed item. - * - * Some elements have not been implemented yet. These are (incomplete list): - * author URL, item author's email and URL, item contents, alternate links, - * other link content types than text/html. Some of them may be created with - * AtomCreator03::additionalElements. - * - * @see FeedCreator#additionalElements - * @since 1.6 - * @author Kai Blankenhorn , Scott Reynen - */ -class AtomCreator03 extends FeedCreator { - - function AtomCreator03() { - $this->contentType = "application/atom+xml"; - $this->encoding = "utf-8"; - } - - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createGeneratorComment(); - $feed.= $this->_createStylesheetReferences(); - $feed.= "language!="") { - $feed.= " xml:lang=\"".$this->language."\""; - } - $feed.= ">\n"; - $feed.= " ".htmlspecialchars($this->title)."\n"; - $feed.= " ".htmlspecialchars($this->description)."\n"; - $feed.= " link)."\"/>\n"; - $feed.= " ".htmlspecialchars($this->link)."\n"; - $now = new FeedDate(); - $feed.= " ".htmlspecialchars($now->iso8601())."\n"; - if ($this->editor!="") { - $feed.= " \n"; - $feed.= " ".$this->editor."\n"; - if ($this->editorEmail!="") { - $feed.= " ".$this->editorEmail."\n"; - } - $feed.= " \n"; - } - $feed.= " ".FEEDCREATOR_VERSION."\n"; - $feed.= $this->_createAdditionalElements($this->additionalElements, " "); - for ($i=0;$iitems);$i++) { - $feed.= " \n"; - $feed.= " ".htmlspecialchars(strip_tags($this->items[$i]->title))."\n"; - $feed.= " items[$i]->link)."\"/>\n"; - if ($this->items[$i]->date=="") { - $this->items[$i]->date = time(); - } - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($itemDate->iso8601())."\n"; - $feed.= " ".htmlspecialchars($this->items[$i]->link)."\n"; - $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); - if ($this->items[$i]->author!="") { - $feed.= " \n"; - $feed.= " ".htmlspecialchars($this->items[$i]->author)."\n"; - $feed.= " \n"; - } - if ($this->items[$i]->description!="") { - $feed.= " ".htmlspecialchars($this->items[$i]->description)."\n"; - } - $feed.= " \n"; - } - $feed.= "\n"; - return $feed; - } -} - - -/** - * MBOXCreator is a FeedCreator that implements the mbox format - * as described in http://www.qmail.org/man/man5/mbox.html - * - * @since 1.3 - * @author Kai Blankenhorn - */ -class MBOXCreator extends FeedCreator { - - function MBOXCreator() { - $this->contentType = "text/plain"; - $this->encoding = "ISO-8859-15"; - } - - function qp_enc($input = "", $line_max = 76) { - $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); - $lines = preg_split("/(?:\r\n|\r|\n)/", $input); - $eol = "\r\n"; - $escape = "="; - $output = ""; - while( list(, $line) = each($lines) ) { - //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary - $linlen = strlen($line); - $newline = ""; - for($i = 0; $i < $linlen; $i++) { - $c = substr($line, $i, 1); - $dec = ord($c); - if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only - $c = "=20"; - } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required - $h2 = floor($dec/16); $h1 = floor($dec%16); - $c = $escape.$hex["$h2"].$hex["$h1"]; - } - if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted - $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay - $newline = ""; - } - $newline .= $c; - } // end of for - $output .= $newline.$eol; - } - return trim($output); - } - - - /** - * Builds the MBOX contents. - * @return string the feed's complete text - */ - function createFeed() { - for ($i=0;$iitems);$i++) { - if ($this->items[$i]->author!="") { - $from = $this->items[$i]->author; - } else { - $from = $this->title; - } - $itemDate = new FeedDate($this->items[$i]->date); - $feed.= "From ".strtr(MBOXCreator::qp_enc($from)," ","_")." ".date("D M d H:i:s Y",$itemDate->unix())."\n"; - $feed.= "Content-Type: text/plain;\n"; - $feed.= " charset=\"".$this->encoding."\"\n"; - $feed.= "Content-Transfer-Encoding: quoted-printable\n"; - $feed.= "Content-Type: text/plain\n"; - $feed.= "From: \"".MBOXCreator::qp_enc($from)."\"\n"; - $feed.= "Date: ".$itemDate->rfc822()."\n"; - $feed.= "Subject: ".MBOXCreator::qp_enc(FeedCreator::iTrunc($this->items[$i]->title,100))."\n"; - $feed.= "\n"; - $body = chunk_split(MBOXCreator::qp_enc($this->items[$i]->description)); - $feed.= preg_replace("~\nFrom ([^\n]*)(\n?)~","\n>From $1$2\n",$body); - $feed.= "\n"; - $feed.= "\n"; - } - return $feed; - } - - /** - * Generate a filename for the feed cache file. Overridden from FeedCreator to prevent XML data types. - * @return string the feed cache filename - * @since 1.4 - * @access private - */ - function _generateFilename() { - $fileInfo = pathinfo($_SERVER["PHP_SELF"]); - return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".mbox"; - } -} - - -/** - * OPMLCreator is a FeedCreator that implements OPML 1.0. - * - * @see http://opml.scripting.com/spec - * @author Dirk Clemens, Kai Blankenhorn - * @since 1.5 - */ -class OPMLCreator extends FeedCreator { - - function OPMLCreator() { - $this->encoding = "utf-8"; - } - - function createFeed() { - $feed = "encoding."\"?>\n"; - $feed.= $this->_createGeneratorComment(); - $feed.= $this->_createStylesheetReferences(); - $feed.= "\n"; - $feed.= " \n"; - $feed.= " ".htmlspecialchars($this->title)."\n"; - if ($this->pubDate!="") { - $date = new FeedDate($this->pubDate); - $feed.= " ".$date->rfc822()."\n"; - } - if ($this->lastBuildDate!="") { - $date = new FeedDate($this->lastBuildDate); - $feed.= " ".$date->rfc822()."\n"; - } - if ($this->editor!="") { - $feed.= " ".$this->editor."\n"; - } - if ($this->editorEmail!="") { - $feed.= " ".$this->editorEmail."\n"; - } - $feed.= " \n"; - $feed.= " \n"; - for ($i=0;$iitems);$i++) { - $feed.= " items[$i]->title,"\n\r"," "))); - $feed.= " title=\"".$title."\""; - $feed.= " text=\"".$title."\""; - //$feed.= " description=\"".htmlspecialchars($this->items[$i]->description)."\""; - $feed.= " url=\"".htmlspecialchars($this->items[$i]->link)."\""; - $feed.= "/>\n"; - } - $feed.= " \n"; - $feed.= "\n"; - return $feed; - } -} - - - -/** - * HTMLCreator is a FeedCreator that writes an HTML feed file to a specific - * location, overriding the createFeed method of the parent FeedCreator. - * The HTML produced can be included over http by scripting languages, or serve - * as the source for an IFrame. - * All output by this class is embedded in
    tags to enable formatting - * using CSS. - * - * @author Pascal Van Hecke - * @since 1.7 - */ -class HTMLCreator extends FeedCreator { - - var $contentType = "text/html"; - - /** - * Contains HTML to be output at the start of the feed's html representation. - */ - var $header; - - /** - * Contains HTML to be output at the end of the feed's html representation. - */ - var $footer ; - - /** - * Contains HTML to be output between entries. A separator is only used in - * case of multiple entries. - */ - var $separator; - - /** - * Used to prefix the stylenames to make sure they are unique - * and do not clash with stylenames on the users' page. - */ - var $stylePrefix; - - /** - * Determines whether the links open in a new window or not. - */ - var $openInNewWindow = true; - - var $imageAlign ="right"; - - /** - * In case of very simple output you may want to get rid of the style tags, - * hence this variable. There's no equivalent on item level, but of course you can - * add strings to it while iterating over the items ($this->stylelessOutput .= ...) - * and when it is non-empty, ONLY the styleless output is printed, the rest is ignored - * in the function createFeed(). - */ - var $stylelessOutput =""; - - /** - * Writes the HTML. - * @return string the scripts's complete text - */ - function createFeed() { - // if there is styleless output, use the content of this variable and ignore the rest - if ($this->stylelessOutput!="") { - return $this->stylelessOutput; - } - - //if no stylePrefix is set, generate it yourself depending on the script name - if ($this->stylePrefix=="") { - $this->stylePrefix = str_replace(".", "_", $this->_generateFilename())."_"; - } - - //set an openInNewWindow_token_to be inserted or not - if ($this->openInNewWindow) { - $targetInsert = " target='_blank'"; - } - - // use this array to put the lines in and implode later with "document.write" javascript - $feedArray = array(); - if ($this->image!=null) { - $imageStr = "". - "".
-							FeedCreator::iTrunc(htmlspecialchars($this->image->title),100).
-							"image->width) { - $imageStr .=" width='".$this->image->width. "' "; - } - if ($this->image->height) { - $imageStr .=" height='".$this->image->height."' "; - } - $imageStr .="/>"; - $feedArray[] = $imageStr; - } - - if ($this->title) { - $feedArray[] = ""; - } - if ($this->getDescription()) { - $feedArray[] = "
    ". - str_replace("]]>", "", str_replace("getDescription())). - "
    "; - } - - if ($this->header) { - $feedArray[] = "
    ".$this->header."
    "; - } - - for ($i=0;$iitems);$i++) { - if ($this->separator and $i > 0) { - $feedArray[] = "
    ".$this->separator."
    "; - } - - if ($this->items[$i]->title) { - if ($this->items[$i]->link) { - $feedArray[] = - ""; - } else { - $feedArray[] = - "
    ". - FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100). - "
    "; - } - } - if ($this->items[$i]->getDescription()) { - $feedArray[] = - "
    ". - str_replace("]]>", "", str_replace("items[$i]->getDescription())). - "
    "; - } - } - if ($this->footer) { - $feedArray[] = "
    ".$this->footer."
    "; - } - - $feed= "".join($feedArray, "\r\n"); - return $feed; - } - - /** - * Overrrides parent to produce .html extensions - * - * @return string the feed cache filename - * @since 1.4 - * @access private - */ - function _generateFilename() { - $fileInfo = pathinfo($_SERVER["PHP_SELF"]); - return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".html"; - } -} - - -/** - * JSCreator is a class that writes a js file to a specific - * location, overriding the createFeed method of the parent HTMLCreator. - * - * @author Pascal Van Hecke - */ -class JSCreator extends HTMLCreator { - var $contentType = "text/javascript"; - - /** - * writes the javascript - * @return string the scripts's complete text - */ - function createFeed() - { - $feed = parent::createFeed(); - $feedArray = explode("\n",$feed); - - $jsFeed = ""; - foreach ($feedArray as $value) { - $jsFeed .= "document.write('".trim(addslashes($value))."');\n"; - } - return $jsFeed; - } - - /** - * Overrrides parent to produce .js extensions - * - * @return string the feed cache filename - * @since 1.4 - * @access private - */ - function _generateFilename() { - $fileInfo = pathinfo($_SERVER["PHP_SELF"]); - return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".js"; - } - -} - - - -/*** TEST SCRIPT ********************************************************* - -//include("feedcreator.class.php"); - -$rss = new UniversalFeedCreator(); -$rss->useCached(); -$rss->title = "PHP news"; -$rss->description = "daily news from the PHP scripting world"; - -//optional -//$rss->descriptionTruncSize = 500; -//$rss->descriptionHtmlSyndicated = true; -//$rss->xslStyleSheet = "http://feedster.com/rss20.xsl"; - -$rss->link = "http://www.dailyphp.net/news"; -$rss->feedURL = "http://www.dailyphp.net/".$PHP_SELF; - -$image = new FeedImage(); -$image->title = "dailyphp.net logo"; -$image->url = "http://www.dailyphp.net/images/logo.gif"; -$image->link = "http://www.dailyphp.net"; -$image->description = "Feed provided by dailyphp.net. Click to visit."; - -//optional -$image->descriptionTruncSize = 500; -$image->descriptionHtmlSyndicated = true; - -$rss->image = $image; - -// get your news items from somewhere, e.g. your database: -//mysql_select_db($dbHost, $dbUser, $dbPass); -//$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); -//while ($data = mysql_fetch_object($res)) { - $item = new FeedItem(); - $item->title = "This is an the test title of an item"; - $item->link = "http://localhost/item/"; - $item->description = "description in
    HTML"; - - //optional - //item->descriptionTruncSize = 500; - $item->descriptionHtmlSyndicated = true; - - $item->date = time(); - $item->source = "http://www.dailyphp.net"; - $item->author = "John Doe"; - - $rss->addItem($item); -//} - -// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1, MBOX, OPML, ATOM0.3, HTML, JS -echo $rss->saveFeed("RSS0.91", "feed.xml"); - - - -***************************************************************************/ - -?> diff --git a/web/lib/gettext.php b/web/lib/gettext.php deleted file mode 100644 index 098f0e5e..00000000 --- a/web/lib/gettext.php +++ /dev/null @@ -1,432 +0,0 @@ -. - Copyright (c) 2005 Nico Kaiser - - This file is part of PHP-gettext. - - PHP-gettext is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PHP-gettext is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with PHP-gettext; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -/** - * Provides a simple gettext replacement that works independently from - * the system's gettext abilities. - * It can read MO files and use them for translating strings. - * The files are passed to gettext_reader as a Stream (see streams.php) - * - * This version has the ability to cache all strings and translations to - * speed up the string lookup. - * While the cache is enabled by default, it can be switched off with the - * second parameter in the constructor (e.g. whenusing very large MO files - * that you don't want to keep in memory) - */ -class gettext_reader { - //public: - var $error = 0; // public variable that holds error code (0 if no error) - - //private: - var $BYTEORDER = 0; // 0: low endian, 1: big endian - var $STREAM = NULL; - var $short_circuit = false; - var $enable_cache = false; - var $originals = NULL; // offset of original table - var $translations = NULL; // offset of translation table - var $pluralheader = NULL; // cache header field for plural forms - var $total = 0; // total string count - var $table_originals = NULL; // table for original strings (offsets) - var $table_translations = NULL; // table for translated strings (offsets) - var $cache_translations = NULL; // original -> translation mapping - - - /* Methods */ - - - /** - * Reads a 32bit Integer from the Stream - * - * @access private - * @return Integer from the Stream - */ - function readint() { - if ($this->BYTEORDER == 0) { - // low endian - $input=unpack('V', $this->STREAM->read(4)); - return array_shift($input); - } else { - // big endian - $input=unpack('N', $this->STREAM->read(4)); - return array_shift($input); - } - } - - function read($bytes) { - return $this->STREAM->read($bytes); - } - - /** - * Reads an array of Integers from the Stream - * - * @param int count How many elements should be read - * @return Array of Integers - */ - function readintarray($count) { - if ($this->BYTEORDER == 0) { - // low endian - return unpack('V'.$count, $this->STREAM->read(4 * $count)); - } else { - // big endian - return unpack('N'.$count, $this->STREAM->read(4 * $count)); - } - } - - /** - * Constructor - * - * @param object Reader the StreamReader object - * @param boolean enable_cache Enable or disable caching of strings (default on) - */ - function __construct($Reader, $enable_cache = true) { - // If there isn't a StreamReader, turn on short circuit mode. - if (! $Reader || isset($Reader->error) ) { - $this->short_circuit = true; - return; - } - - // Caching can be turned off - $this->enable_cache = $enable_cache; - - $MAGIC1 = "\x95\x04\x12\xde"; - $MAGIC2 = "\xde\x12\x04\x95"; - - $this->STREAM = $Reader; - $magic = $this->read(4); - if ($magic == $MAGIC1) { - $this->BYTEORDER = 1; - } elseif ($magic == $MAGIC2) { - $this->BYTEORDER = 0; - } else { - $this->error = 1; // not MO file - return false; - } - - // FIXME: Do we care about revision? We should. - $revision = $this->readint(); - - $this->total = $this->readint(); - $this->originals = $this->readint(); - $this->translations = $this->readint(); - } - - /** - * Loads the translation tables from the MO file into the cache - * If caching is enabled, also loads all strings into a cache - * to speed up translation lookups - * - * @access private - */ - function load_tables() { - if (is_array($this->cache_translations) && - is_array($this->table_originals) && - is_array($this->table_translations)) - return; - - /* get original and translations tables */ - if (!is_array($this->table_originals)) { - $this->STREAM->seekto($this->originals); - $this->table_originals = $this->readintarray($this->total * 2); - } - if (!is_array($this->table_translations)) { - $this->STREAM->seekto($this->translations); - $this->table_translations = $this->readintarray($this->total * 2); - } - - if ($this->enable_cache) { - $this->cache_translations = array (); - /* read all strings in the cache */ - for ($i = 0; $i < $this->total; $i++) { - $this->STREAM->seekto($this->table_originals[$i * 2 + 2]); - $original = $this->STREAM->read($this->table_originals[$i * 2 + 1]); - $this->STREAM->seekto($this->table_translations[$i * 2 + 2]); - $translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]); - $this->cache_translations[$original] = $translation; - } - } - } - - /** - * Returns a string from the "originals" table - * - * @access private - * @param int num Offset number of original string - * @return string Requested string if found, otherwise '' - */ - function get_original_string($num) { - $length = $this->table_originals[$num * 2 + 1]; - $offset = $this->table_originals[$num * 2 + 2]; - if (! $length) - return ''; - $this->STREAM->seekto($offset); - $data = $this->STREAM->read($length); - return (string)$data; - } - - /** - * Returns a string from the "translations" table - * - * @access private - * @param int num Offset number of original string - * @return string Requested string if found, otherwise '' - */ - function get_translation_string($num) { - $length = $this->table_translations[$num * 2 + 1]; - $offset = $this->table_translations[$num * 2 + 2]; - if (! $length) - return ''; - $this->STREAM->seekto($offset); - $data = $this->STREAM->read($length); - return (string)$data; - } - - /** - * Binary search for string - * - * @access private - * @param string string - * @param int start (internally used in recursive function) - * @param int end (internally used in recursive function) - * @return int string number (offset in originals table) - */ - function find_string($string, $start = -1, $end = -1) { - if (($start == -1) or ($end == -1)) { - // find_string is called with only one parameter, set start end end - $start = 0; - $end = $this->total; - } - if (abs($start - $end) <= 1) { - // We're done, now we either found the string, or it doesn't exist - $txt = $this->get_original_string($start); - if ($string == $txt) - return $start; - else - return -1; - } else if ($start > $end) { - // start > end -> turn around and start over - return $this->find_string($string, $end, $start); - } else { - // Divide table in two parts - $half = (int)(($start + $end) / 2); - $cmp = strcmp($string, $this->get_original_string($half)); - if ($cmp == 0) - // string is exactly in the middle => return it - return $half; - else if ($cmp < 0) - // The string is in the upper half - return $this->find_string($string, $start, $half); - else - // The string is in the lower half - return $this->find_string($string, $half, $end); - } - } - - /** - * Translates a string - * - * @access public - * @param string string to be translated - * @return string translated string (or original, if not found) - */ - function translate($string) { - if ($this->short_circuit) - return $string; - $this->load_tables(); - - if ($this->enable_cache) { - // Caching enabled, get translated string from cache - if (array_key_exists($string, $this->cache_translations)) - return $this->cache_translations[$string]; - else - return $string; - } else { - // Caching not enabled, try to find string - $num = $this->find_string($string); - if ($num == -1) - return $string; - else - return $this->get_translation_string($num); - } - } - - /** - * Sanitize plural form expression for use in PHP eval call. - * - * @access private - * @return string sanitized plural form expression - */ - function sanitize_plural_expression($expr) { - // Get rid of disallowed characters. - $expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr); - - // Add parenthesis for tertiary '?' operator. - $expr .= ';'; - $res = ''; - $p = 0; - for ($i = 0; $i < strlen($expr); $i++) { - $ch = $expr[$i]; - switch ($ch) { - case '?': - $res .= ' ? ('; - $p++; - break; - case ':': - $res .= ') : ('; - break; - case ';': - $res .= str_repeat( ')', $p) . ';'; - $p = 0; - break; - default: - $res .= $ch; - } - } - return $res; - } - - /** - * Parse full PO header and extract only plural forms line. - * - * @access private - * @return string verbatim plural form header field - */ - function extract_plural_forms_header_from_po_header($header) { - if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs)) - $expr = $regs[2]; - else - $expr = "nplurals=2; plural=n == 1 ? 0 : 1;"; - return $expr; - } - - /** - * Get possible plural forms from MO header - * - * @access private - * @return string plural form header - */ - function get_plural_forms() { - // lets assume message number 0 is header - // this is true, right? - $this->load_tables(); - - // cache header field for plural forms - if (! is_string($this->pluralheader)) { - if ($this->enable_cache) { - $header = $this->cache_translations[""]; - } else { - $header = $this->get_translation_string(0); - } - $expr = $this->extract_plural_forms_header_from_po_header($header); - $this->pluralheader = $this->sanitize_plural_expression($expr); - } - return $this->pluralheader; - } - - /** - * Detects which plural form to take - * - * @access private - * @param n count - * @return int array index of the right plural form - */ - function select_string($n) { - $string = $this->get_plural_forms(); - $string = str_replace('nplurals',"\$total",$string); - $string = str_replace("n",$n,$string); - $string = str_replace('plural',"\$plural",$string); - - $total = 0; - $plural = 0; - - eval("$string"); - if ($plural >= $total) $plural = $total - 1; - return $plural; - } - - /** - * Plural version of gettext - * - * @access public - * @param string single - * @param string plural - * @param string number - * @return translated plural form - */ - function ngettext($single, $plural, $number) { - if ($this->short_circuit) { - if ($number != 1) - return $plural; - else - return $single; - } - - // find out the appropriate form - $select = $this->select_string($number); - - // this should contains all strings separated by NULLs - $key = $single . chr(0) . $plural; - - - if ($this->enable_cache) { - if (! array_key_exists($key, $this->cache_translations)) { - return ($number != 1) ? $plural : $single; - } else { - $result = $this->cache_translations[$key]; - $list = explode(chr(0), $result); - return $list[$select]; - } - } else { - $num = $this->find_string($key); - if ($num == -1) { - return ($number != 1) ? $plural : $single; - } else { - $result = $this->get_translation_string($num); - $list = explode(chr(0), $result); - return $list[$select]; - } - } - } - - function pgettext($context, $msgid) { - $key = $context . chr(4) . $msgid; - $ret = $this->translate($key); - if (strpos($ret, "\004") !== false) { - return $msgid; - } else { - return $ret; - } - } - - function npgettext($context, $singular, $plural, $number) { - $key = $context . chr(4) . $singular; - $ret = $this->ngettext($key, $plural, $number); - if (strpos($ret, "\004") !== false) { - return $singular; - } else { - return $ret; - } - - } -} - -?> diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php deleted file mode 100644 index a053962e..00000000 --- a/web/lib/pkgbasefuncs.inc.php +++ /dev/null @@ -1,1253 +0,0 @@ -query($q); - if (!$result) { - return null; - } - - return $result->fetchColumn(0); -} - -/** - * Get all package comment information for a specific package base - * - * @param int $base_id The package base ID to get comments for - * @param int $limit Maximum number of comments to return (0 means unlimited) - * @param bool $include_deleted True if deleted comments should be included - * @param bool $only_pinned True when only pinned comments are to be included - * - * @return array All package comment information for a specific package base - */ -function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false, $offset=0) { - $base_id = intval($base_id); - $limit = intval($limit); - if (!$base_id) { - return null; - } - - $dbh = DB::connect(); - $q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, "; - $q.= "PackageBaseID, CommentTS, DelTS, EditedTS, B.UserName AS EditUserName, "; - $q.= "DelUsersID, C.UserName AS DelUserName, RenderedComment, "; - $q.= "PinnedTS FROM PackageComments "; - $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; - $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; - $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID "; - $q.= "WHERE PackageBaseID = " . $base_id . " "; - - if (!$include_deleted) { - $q.= "AND DelTS IS NULL "; - } - if ($only_pinned) { - $q.= "AND NOT PinnedTS = 0 "; - } - $q.= "ORDER BY CommentTS DESC"; - if ($limit > 0) { - $q.=" LIMIT " . $limit; - } - if ($offset > 0) { - $q.=" OFFSET " . $offset; - } - $result = $dbh->query($q); - if (!$result) { - return null; - } - - return $result->fetchAll(); -} - -/* - * Invoke the comment rendering script. - * - * @param int $id ID of the comment to render - * - * @return void - */ -function render_comment($id) { - $cmd = config_get('options', 'render-comment-cmd'); - $cmd .= ' ' . intval($id); - - $descspec = array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - ); - - $p = proc_open($cmd, $descspec, $pipes); - - if (!is_resource($p)) { - return false; - } - - fclose($pipes[0]); - fclose($pipes[1]); - - return proc_close($p); -} - -/** - * Add a comment to a package page and send out appropriate notifications - * - * @param string $base_id The package base ID to add the comment on - * @param string $uid The user ID of the individual who left the comment - * @param string $comment The comment left on a package page - * - * @return void - */ -function pkgbase_add_comment($base_id, $uid, $comment) { - $dbh = DB::connect(); - - if (trim($comment) == '') { - return array(false, __('Comment cannot be empty.')); - } - - $q = "INSERT INTO PackageComments "; - $q.= "(PackageBaseID, UsersID, Comments, RenderedComment, CommentTS) "; - $q.= "VALUES (" . intval($base_id) . ", " . $uid . ", "; - $q.= $dbh->quote($comment) . ", '', " . strval(time()) . ")"; - $dbh->exec($q); - $comment_id = $dbh->lastInsertId(); - - render_comment($comment_id); - - notify(array('comment', $uid, $base_id, $comment_id)); - - return array(true, __('Comment has been added.')); -} - -/** - * Pin/unpin a package comment - * - * @param bool $unpin True if unpinning rather than pinning - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_pin_comment($unpin=false) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - - if (!$uid) { - return array(false, __("You must be logged in before you can edit package information.")); - } - - if (isset($_POST["comment_id"])) { - $comment_id = $_POST["comment_id"]; - } else { - return array(false, __("Missing comment ID.")); - } - - if (!$unpin) { - if (pkgbase_comments_count($_POST['package_base'], false, true) >= 5){ - return array(false, __("No more than 5 comments can be pinned.")); - } - } - - if (!can_pin_comment($comment_id)) { - if (!$unpin) { - return array(false, __("You are not allowed to pin this comment.")); - } else { - return array(false, __("You are not allowed to unpin this comment.")); - } - } - - $dbh = DB::connect(); - $q = "UPDATE PackageComments "; - if (!$unpin) { - $q.= "SET PinnedTS = " . strval(time()) . " "; - } else { - $q.= "SET PinnedTS = 0 "; - } - $q.= "WHERE ID = " . intval($comment_id); - $dbh->exec($q); - - if (!$unpin) { - return array(true, __("Comment has been pinned.")); - } else { - return array(true, __("Comment has been unpinned.")); - } -} - -/** - - * Get a list of all packages a logged-in user has voted for - * - * @param string $sid The session ID of the visitor - * - * @return array All packages the visitor has voted for - */ -function pkgbase_votes_from_sid($sid="") { - $pkgs = array(); - if (!$sid) {return $pkgs;} - $dbh = DB::connect(); - $q = "SELECT PackageBaseID "; - $q.= "FROM PackageVotes, Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Users.ID = PackageVotes.UsersID "; - $q.= "AND Sessions.SessionID = " . $dbh->quote($sid); - $result = $dbh->query($q); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_NUM)) { - $pkgs[$row[0]] = 1; - } - } - return $pkgs; -} - -/** - * Get the package base details - * - * @param string $id The package base ID to get description for - * - * @return array The package base's details OR error message - **/ -function pkgbase_get_details($base_id) { - $dbh = DB::connect(); - - $q = "SELECT PackageBases.ID, PackageBases.Name, "; - $q.= "PackageBases.NumVotes, PackageBases.Popularity, "; - $q.= "PackageBases.OutOfDateTS, PackageBases.SubmittedTS, "; - $q.= "PackageBases.ModifiedTS, PackageBases.SubmitterUID, "; - $q.= "PackageBases.MaintainerUID, PackageBases.PackagerUID, "; - $q.= "PackageBases.FlaggerUID, "; - $q.= "(SELECT COUNT(*) FROM PackageRequests "; - $q.= " WHERE PackageRequests.PackageBaseID = PackageBases.ID "; - $q.= " AND PackageRequests.Status = 0) AS RequestCount "; - $q.= "FROM PackageBases "; - $q.= "WHERE PackageBases.ID = " . intval($base_id); - $result = $dbh->query($q); - - $row = array(); - - if (!$result) { - $row['error'] = __("Error retrieving package details."); - } - else { - $row = $result->fetch(PDO::FETCH_ASSOC); - if (empty($row)) { - $row['error'] = __("Package details could not be found."); - } - } - - return $row; -} - -/** - * Display the package base details page - * - * @param string $id The package base ID to get details page for - * @param array $row Package base details retrieved by pkgbase_get_details() - * @param string $SID The session ID of the visitor - * - * @return void - */ -function pkgbase_display_details($base_id, $row, $SID="") { - if (isset($row['error'])) { - print "

    " . $row['error'] . "

    \n"; - } - else { - $pkgbase_name = pkgbase_name_from_id($base_id); - - include('pkgbase_details.php'); - - if ($SID) { - $comment_section = "package"; - include('pkg_comment_box.php'); - } - - $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); - - $limit_pinned = isset($_GET['pinned']) ? 0 : 5; - $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); - if (!empty($pinned)) { - $comment_section = "package"; - include('pkg_comments.php'); - } - unset($pinned); - - - $total_comment_count = pkgbase_comments_count($base_id, $include_deleted); - list($pagination_templs, $per_page, $offset) = calculate_pagination($total_comment_count); - - $comments = pkgbase_comments($base_id, $per_page, $include_deleted, false, $offset); - if (!empty($comments)) { - $comment_section = "package"; - include('pkg_comments.php'); - } - } -} - -/** - * Convert a list of package IDs into a list of corresponding package bases. - * - * @param array|int $ids Array of package IDs to convert - * - * @return array|int List of package base IDs - */ -function pkgbase_from_pkgid($ids) { - $dbh = DB::connect(); - - if (is_array($ids)) { - $q = "SELECT PackageBaseID FROM Packages "; - $q.= "WHERE ID IN (" . implode(",", $ids) . ")"; - $result = $dbh->query($q); - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - $q = "SELECT PackageBaseID FROM Packages "; - $q.= "WHERE ID = " . $ids; - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); - } -} - -/** - * Retrieve ID of a package base by name - * - * @param string $name The package base name to retrieve the ID for - * - * @return int The ID of the package base - */ -function pkgbase_from_name($name) { - $dbh = DB::connect(); - $q = "SELECT ID FROM PackageBases WHERE Name = " . $dbh->quote($name); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * Retrieve the name of a package base given its ID - * - * @param int $base_id The ID of the package base to query - * - * @return string The name of the package base - */ -function pkgbase_name_from_id($base_id) { - $dbh = DB::connect(); - $q = "SELECT Name FROM PackageBases WHERE ID = " . intval($base_id); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * Get the names of all packages belonging to a package base - * - * @param int $base_id The ID of the package base - * - * @return array The names of all packages belonging to the package base - */ -function pkgbase_get_pkgnames($base_id) { - $dbh = DB::connect(); - $q = "SELECT Name FROM Packages WHERE PackageBaseID = " . intval($base_id); - $result = $dbh->query($q); - return $result->fetchAll(PDO::FETCH_COLUMN, 0); -} - -/** - * Determine whether a package base is (or contains a) VCS package - * - * @param int $base_id The ID of the package base - * - * @return bool True if the package base is/contains a VCS package - */ -function pkgbase_is_vcs($base_id) { - $suffixes = array("-cvs", "-svn", "-git", "-hg", "-bzr", "-darcs"); - $haystack = pkgbase_get_pkgnames($base_id); - array_push($haystack, pkgbase_name_from_id($base_id)); - foreach ($haystack as $pkgname) { - foreach ($suffixes as $suffix) { - if (substr_compare($pkgname, $suffix, -strlen($suffix)) === 0) { - return true; - } - } - } - return false; -} - -/** - * Delete all packages belonging to a package base - * - * @param int $base_id The ID of the package base - * - * @return void - */ -function pkgbase_delete_packages($base_id) { - $dbh = DB::connect(); - $q = "DELETE FROM Packages WHERE PackageBaseID = " . intval($base_id); - $dbh->exec($q); -} - -/** - * Retrieve the maintainer of a package base given its ID - * - * @param int $base_id The ID of the package base to query - * - * @return int The user ID of the current package maintainer - */ -function pkgbase_maintainer_uid($base_id) { - $dbh = DB::connect(); - $q = "SELECT MaintainerUID FROM PackageBases WHERE ID = " . intval($base_id); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * Retrieve the maintainers of an array of package bases given by their ID - * - * @param int $base_ids The array of IDs of the package bases to query - * - * @return int The user ID of the current package maintainer - */ -function pkgbase_maintainer_uids($base_ids) { - $dbh = DB::connect(); - $q = "SELECT MaintainerUID FROM PackageBases WHERE ID IN (" . implode(",", $base_ids) . ")"; - $result = $dbh->query($q); - return $result->fetchAll(PDO::FETCH_COLUMN, 0); -} - -/** - * Flag package(s) as out-of-date - * - * @param array $base_ids Array of package base IDs to flag/unflag - * @param string $comment The comment to add - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_flag($base_ids, $comment) { - if (!has_credential(CRED_PKGBASE_FLAG)) { - return array(false, __("You must be logged in before you can flag packages.")); - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - return array(false, __("You did not select any packages to flag.")); - } - - if (strlen($comment) < 3) { - return array(false, __("The selected packages have not been flagged, please enter a comment.")); - } - - $uid = uid_from_sid($_COOKIE['AURSID']); - $dbh = DB::connect(); - - $q = "UPDATE PackageBases SET "; - $q.= "OutOfDateTS = " . strval(time()) . ", FlaggerUID = " . $uid . ", "; - $q.= "FlaggerComment = " . $dbh->quote($comment) . " "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - $q.= "AND OutOfDateTS IS NULL"; - $dbh->exec($q); - - foreach ($base_ids as $base_id) { - notify(array('flag', $uid, $base_id)); - } - - return array(true, __("The selected packages have been flagged out-of-date.")); -} - -/** - * Unflag package(s) as out-of-date - * - * @param array $base_ids Array of package base IDs to flag/unflag - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_unflag($base_ids) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - if (!$uid) { - return array(false, __("You must be logged in before you can unflag packages.")); - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - return array(false, __("You did not select any packages to unflag.")); - } - - $dbh = DB::connect(); - - $q = "UPDATE PackageBases SET "; - $q.= "OutOfDateTS = NULL "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - - $maintainers = array_merge(pkgbase_maintainer_uids($base_ids), pkgbase_get_comaintainer_uids($base_ids)); - if (!has_credential(CRED_PKGBASE_UNFLAG, $maintainers)) { - $q.= "AND (MaintainerUID = " . $uid . " OR FlaggerUID = " . $uid. ")"; - } - - $result = $dbh->exec($q); - - if ($result) { - return array(true, __("The selected packages have been unflagged.")); - } -} - -/** - * Get package flag OOD comment - * - * @param int $base_id - * - * @return array Tuple of pkgbase ID, reason for OOD, and user who flagged - */ -function pkgbase_get_flag_comment($base_id) { - $base_id = intval($base_id); - $dbh = DB::connect(); - - $q = "SELECT FlaggerComment,OutOfDateTS,Username FROM PackageBases "; - $q.= "LEFT JOIN Users ON FlaggerUID = Users.ID "; - $q.= "WHERE PackageBases.ID = " . $base_id . " "; - $q.= "AND PackageBases.OutOfDateTS IS NOT NULL"; - $result = $dbh->query($q); - - $row = array(); - - if (!$result) { - $row['error'] = __("Error retrieving package details."); - } - else { - $row = $result->fetch(PDO::FETCH_ASSOC); - if (empty($row)) { - $row['error'] = __("Package details could not be found."); - } - } - - return $row; -} - -/** - * Delete package bases - * - * @param array $base_ids Array of package base IDs to delete - * @param int $merge_base_id Package base to merge the deleted ones into - * @param int $via Package request to close upon deletion - * @param bool $grant Allow anyone to delete the package base - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_delete ($base_ids, $merge_base_id, $via, $grant=false) { - if (!$grant && !has_credential(CRED_PKGBASE_DELETE)) { - return array(false, __("You do not have permission to delete packages.")); - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - return array(false, __("You did not select any packages to delete.")); - } - - $dbh = DB::connect(); - - if ($merge_base_id) { - $merge_base_name = pkgbase_name_from_id($merge_base_id); - } - - $uid = uid_from_sid($_COOKIE['AURSID']); - foreach ($base_ids as $base_id) { - if ($merge_base_id) { - notify(array('delete', $uid, $base_id, $merge_base_id)); - } else { - notify(array('delete', $uid, $base_id)); - } - } - - /* - * Close package request if the deletion was initiated through the - * request interface. NOTE: This needs to happen *before* the actual - * deletion. Otherwise, the former maintainer will not be included in - * the Cc list of the request notification email. - */ - if ($via) { - pkgreq_close(intval($via), 'accepted', ''); - } - - /* Scan through pending deletion requests and close them. */ - $username = username_from_sid($_COOKIE['AURSID']); - foreach ($base_ids as $base_id) { - $pkgreq_ids = array_merge(pkgreq_by_pkgbase($base_id)); - foreach ($pkgreq_ids as $pkgreq_id) { - pkgreq_close(intval($pkgreq_id), 'accepted', - 'The user ' . $username . - ' deleted the package.', true); - } - } - - if ($merge_base_id) { - /* Merge comments */ - $q = "UPDATE PackageComments "; - $q.= "SET PackageBaseID = " . intval($merge_base_id) . " "; - $q.= "WHERE PackageBaseID IN (" . implode(",", $base_ids) . ")"; - $dbh->exec($q); - - /* Merge notifications */ - $q = "SELECT DISTINCT UserID FROM PackageNotifications cn "; - $q.= "WHERE PackageBaseID IN (" . implode(",", $base_ids) . ") "; - $q.= "AND NOT EXISTS (SELECT * FROM PackageNotifications cn2 "; - $q.= "WHERE cn2.PackageBaseID = " . intval($merge_base_id) . " "; - $q.= "AND cn2.UserID = cn.UserID)"; - $result = $dbh->query($q); - - while ($notify_uid = $result->fetch(PDO::FETCH_COLUMN, 0)) { - $q = "INSERT INTO PackageNotifications (UserID, PackageBaseID) "; - $q.= "VALUES (" . intval($notify_uid) . ", " . intval($merge_base_id) . ")"; - $dbh->exec($q); - } - - /* Merge votes */ - foreach ($base_ids as $base_id) { - $q = "UPDATE PackageVotes "; - $q.= "SET PackageBaseID = " . intval($merge_base_id) . " "; - $q.= "WHERE PackageBaseID = " . $base_id . " "; - $q.= "AND UsersID NOT IN ("; - $q.= "SELECT * FROM (SELECT UsersID "; - $q.= "FROM PackageVotes "; - $q.= "WHERE PackageBaseID = " . intval($merge_base_id); - $q.= ") temp)"; - $dbh->exec($q); - } - - $q = "UPDATE PackageBases "; - $q.= "SET NumVotes = (SELECT COUNT(*) FROM PackageVotes "; - $q.= "WHERE PackageBaseID = " . intval($merge_base_id) . ") "; - $q.= "WHERE ID = " . intval($merge_base_id); - $dbh->exec($q); - } - - $q = "DELETE FROM Packages WHERE PackageBaseID IN (" . implode(",", $base_ids) . ")"; - $dbh->exec($q); - - $q = "DELETE FROM PackageBases WHERE ID IN (" . implode(",", $base_ids) . ")"; - $dbh->exec($q); - - return array(true, __("The selected packages have been deleted.")); -} - -/** - * Adopt or disown packages - * - * @param array $base_ids Array of package base IDs to adopt/disown - * @param bool $action Adopts if true, disowns if false. Adopts by default - * @param int $via Package request to close upon adoption - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_adopt ($base_ids, $action=true, $via) { - $dbh = DB::connect(); - - $uid = uid_from_sid($_COOKIE["AURSID"]); - if (!$uid) { - if ($action) { - return array(false, __("You must be logged in before you can adopt packages.")); - } else { - return array(false, __("You must be logged in before you can disown packages.")); - } - } - - /* Verify package ownership. */ - $base_ids = sanitize_ids($base_ids); - - $q = "SELECT ID FROM PackageBases "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - - if ($action && !has_credential(CRED_PKGBASE_ADOPT)) { - /* Regular users may only adopt orphan packages. */ - $q.= "AND MaintainerUID IS NULL"; - } - if (!$action && !has_credential(CRED_PKGBASE_DISOWN)) { - /* Regular users may only disown their own packages. */ - $q.= "AND MaintainerUID = " . $uid; - } - - $result = $dbh->query($q); - $base_ids = $result->fetchAll(PDO::FETCH_COLUMN, 0); - - /* Error out if the list of remaining packages is empty. */ - if (empty($base_ids)) { - if ($action) { - return array(false, __("You did not select any packages to adopt.")); - } else { - return array(false, __("You did not select any packages to disown.")); - } - } - - /* - * Close package request if the disownment was initiated through the - * request interface. NOTE: This needs to happen *before* the actual - * disown operation. Otherwise, the former maintainer will not be - * included in the Cc list of the request notification email. - */ - if ($via) { - pkgreq_close(intval($via), 'accepted', ''); - } - - /* Scan through pending orphan requests and close them. */ - if (!$action) { - $username = username_from_sid($_COOKIE['AURSID']); - foreach ($base_ids as $base_id) { - $pkgreq_ids = pkgreq_by_pkgbase($base_id, 'orphan'); - foreach ($pkgreq_ids as $pkgreq_id) { - pkgreq_close(intval($pkgreq_id), 'accepted', - 'The user ' . $username . - ' disowned the package.', true); - } - } - } - - /* Adopt or disown the package. */ - if ($action) { - $q = "UPDATE PackageBases "; - $q.= "SET MaintainerUID = $uid "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - $dbh->exec($q); - - /* Add the new maintainer to the notification list. */ - pkgbase_notify($base_ids); - } else { - /* Update the co-maintainer list when disowning a package. */ - if (has_credential(CRED_PKGBASE_DISOWN)) { - foreach ($base_ids as $base_id) { - pkgbase_set_comaintainers($base_id, array()); - } - - $q = "UPDATE PackageBases "; - $q.= "SET MaintainerUID = NULL "; - $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - $dbh->exec($q); - } else { - foreach ($base_ids as $base_id) { - $comaintainers = pkgbase_get_comaintainers($base_id); - - if (count($comaintainers) > 0) { - $comaintainer_uid = uid_from_username($comaintainers[0]); - $comaintainers = array_diff($comaintainers, array($comaintainers[0])); - pkgbase_set_comaintainers($base_id, $comaintainers); - } else { - $comaintainer_uid = "NULL"; - } - - $q = "UPDATE PackageBases "; - $q.= "SET MaintainerUID = " . $comaintainer_uid . " "; - $q.= "WHERE ID = " . $base_id; - $dbh->exec($q); - } - } - } - - foreach ($base_ids as $base_id) { - notify(array($action ? 'adopt' : 'disown', $uid, $base_id)); - } - - if ($action) { - return array(true, __("The selected packages have been adopted.")); - } else { - return array(true, __("The selected packages have been disowned.")); - } -} - -/** - * Vote and un-vote for packages - * - * @param array $base_ids Array of package base IDs to vote/un-vote - * @param bool $action Votes if true, un-votes if false. Votes by default - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_vote ($base_ids, $action=true) { - if (!has_credential(CRED_PKGBASE_VOTE)) { - if ($action) { - return array(false, __("You must be logged in before you can vote for packages.")); - } else { - return array(false, __("You must be logged in before you can un-vote for packages.")); - } - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - if ($action) { - return array(false, __("You did not select any packages to vote for.")); - } else { - return array(false, __("Your votes have been removed from the selected packages.")); - } - } - - $dbh = DB::connect(); - $my_votes = pkgbase_votes_from_sid($_COOKIE["AURSID"]); - $uid = uid_from_sid($_COOKIE["AURSID"]); - - $first = 1; - $vote_ids = ""; - $vote_clauses = ""; - foreach ($base_ids as $pid) { - if ($action) { - $check = !isset($my_votes[$pid]); - } else { - $check = isset($my_votes[$pid]); - } - - if ($check) { - if ($first) { - $first = 0; - $vote_ids = $pid; - if ($action) { - $vote_clauses = "($uid, $pid, " . strval(time()) . ")"; - } - } else { - $vote_ids .= ", $pid"; - if ($action) { - $vote_clauses .= ", ($uid, $pid, " . strval(time()) . ")"; - } - } - } - } - - if (!empty($vote_ids)) { - /* Only add votes for packages the user hasn't already voted for. */ - $op = $action ? "+" : "-"; - $q = "UPDATE PackageBases SET NumVotes = NumVotes $op 1 "; - $q.= "WHERE ID IN ($vote_ids)"; - - $dbh->exec($q); - - if ($action) { - $q = "INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS) VALUES "; - $q.= $vote_clauses; - } else { - $q = "DELETE FROM PackageVotes WHERE UsersID = $uid "; - $q.= "AND PackageBaseID IN ($vote_ids)"; - } - - $dbh->exec($q); - } - - if ($action) { - return array(true, __("Your votes have been cast for the selected packages.")); - } else { - return array(true, __("Your votes have been removed from the selected packages.")); - } -} - -/** - * Get all usernames and IDs that voted for a specific package base - * - * @param string $pkgbase_name The package base to retrieve votes for - * - * @return array User IDs and usernames that voted for a specific package base - */ -function pkgbase_votes_from_name($pkgbase_name) { - $dbh = DB::connect(); - - $q = "SELECT UsersID, Username, Name, VoteTS FROM PackageVotes "; - $q.= "LEFT JOIN Users ON UsersID = Users.ID "; - $q.= "LEFT JOIN PackageBases "; - $q.= "ON PackageVotes.PackageBaseID = PackageBases.ID "; - $q.= "WHERE PackageBases.Name = ". $dbh->quote($pkgbase_name) . " "; - $q.= "ORDER BY Username"; - $result = $dbh->query($q); - - if (!$result) { - return; - } - - $votes = array(); - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $votes[] = $row; - } - - return $votes; -} - -/** - * Determine if a user has already voted for a specific package base - * - * @param string $uid The user ID to check for an existing vote - * @param string $base_id The package base ID to check for an existing vote - * - * @return bool True if the user has already voted, otherwise false - */ -function pkgbase_user_voted($uid, $base_id) { - $dbh = DB::connect(); - $q = "SELECT COUNT(*) FROM PackageVotes WHERE "; - $q.= "UsersID = ". $dbh->quote($uid) . " AND "; - $q.= "PackageBaseID = " . $dbh->quote($base_id); - $result = $dbh->query($q); - if (!$result) { - return null; - } - - return ($result->fetch(PDO::FETCH_COLUMN, 0) > 0); -} - -/** - * Determine if a user wants notifications for a specific package base - * - * @param string $uid User ID to check in the database - * @param string $base_id Package base ID to check notifications for - * - * @return bool True if the user wants notifications, otherwise false - */ -function pkgbase_user_notify($uid, $base_id) { - $dbh = DB::connect(); - - $q = "SELECT * FROM PackageNotifications WHERE UserID = " . $dbh->quote($uid); - $q.= " AND PackageBaseID = " . $dbh->quote($base_id); - $result = $dbh->query($q); - - if (!$result) { - return false; - } - - return ($result->fetch(PDO::FETCH_NUM) > 0); -} - -/** - * Toggle notification of packages - * - * @param array $base_ids Array of package base IDs to toggle - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_notify ($base_ids, $action=true) { - if (!has_credential(CRED_PKGBASE_NOTIFY)) { - return; - } - - $base_ids = sanitize_ids($base_ids); - if (empty($base_ids)) { - return array(false, __("Couldn't add to notification list.")); - } - - $dbh = DB::connect(); - $uid = uid_from_sid($_COOKIE["AURSID"]); - - $output = ""; - - $first = true; - - /* - * There currently shouldn't be multiple requests here, but the format - * in which it's sent requires this. - */ - foreach ($base_ids as $bid) { - $q = "SELECT Name FROM PackageBases WHERE ID = $bid"; - $result = $dbh->query($q); - if ($result) { - $row = $result->fetch(PDO::FETCH_NUM); - $basename = $row[0]; - } - else { - $basename = ''; - } - - if ($first) - $first = false; - else - $output .= ", "; - - - if ($action) { - $q = "SELECT COUNT(*) FROM PackageNotifications WHERE "; - $q .= "UserID = $uid AND PackageBaseID = $bid"; - - /* Notification already added. Don't add again. */ - $result = $dbh->query($q); - if ($result->fetchColumn() == 0) { - $q = "INSERT INTO PackageNotifications (PackageBaseID, UserID) VALUES ($bid, $uid)"; - $dbh->exec($q); - } - - $output .= $basename; - } - else { - $q = "DELETE FROM PackageNotifications WHERE PackageBaseID = $bid "; - $q .= "AND UserID = $uid"; - $dbh->exec($q); - - $output .= $basename; - } - } - - if ($action) { - $output = __("You have been added to the comment notification list for %s.", $output); - } - else { - $output = __("You have been removed from the comment notification list for %s.", $output); - } - - return array(true, $output); -} - -/** - * Delete a package comment - * - * @param boolean $undelete True if undeleting rather than deleting - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_delete_comment($undelete=false) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - if (!$uid) { - return array(false, __("You must be logged in before you can edit package information.")); - } - - if (isset($_POST["comment_id"])) { - $comment_id = $_POST["comment_id"]; - } else { - return array(false, __("Missing comment ID.")); - } - - $dbh = DB::connect(); - if ($undelete) { - if (!has_credential(CRED_COMMENT_UNDELETE)) { - return array(false, __("You are not allowed to undelete this comment.")); - } - - $q = "UPDATE PackageComments "; - $q.= "SET DelUsersID = NULL, "; - $q.= "DelTS = NULL "; - $q.= "WHERE ID = ".intval($comment_id); - $dbh->exec($q); - return array(true, __("Comment has been undeleted.")); - } else { - if (!can_delete_comment($comment_id)) { - return array(false, __("You are not allowed to delete this comment.")); - } - - $q = "UPDATE PackageComments "; - $q.= "SET DelUsersID = ".$uid.", "; - $q.= "DelTS = " . strval(time()) . " "; - $q.= "WHERE ID = ".intval($comment_id); - $dbh->exec($q); - return array(true, __("Comment has been deleted.")); - } -} - -/** - * Edit a package comment - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_edit_comment($comment) { - $uid = uid_from_sid($_COOKIE["AURSID"]); - if (!$uid) { - return array(false, __("You must be logged in before you can edit package information.")); - } - - if (isset($_POST["comment_id"])) { - $comment_id = $_POST["comment_id"]; - } else { - return array(false, __("Missing comment ID.")); - } - - if (trim($comment) == '') { - return array(false, __('Comment cannot be empty.')); - } - - $dbh = DB::connect(); - if (can_edit_comment($comment_id)) { - $q = "UPDATE PackageComments "; - $q.= "SET EditedUsersID = ".$uid.", "; - $q.= "Comments = ".$dbh->quote($comment).", "; - $q.= "EditedTS = " . strval(time()) . " "; - $q.= "WHERE ID = ".intval($comment_id); - $dbh->exec($q); - - render_comment($comment_id); - - return array(true, __("Comment has been edited.")); - } else { - return array(false, __("You are not allowed to edit this comment.")); - } -} - -/** - * Get a list of package base keywords - * - * @param int $base_id The package base ID to retrieve the keywords for - * - * @return array An array of keywords - */ -function pkgbase_get_keywords($base_id) { - $dbh = DB::connect(); - $q = "SELECT Keyword FROM PackageKeywords "; - $q .= "WHERE PackageBaseID = " . intval($base_id) . " "; - $q .= "ORDER BY Keyword ASC"; - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - return array(); - } -} - -/** - * Update the list of keywords of a package base - * - * @param int $base_id The package base ID to update the keywords of - * @param array $users Array of keywords - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_set_keywords($base_id, $keywords) { - $base_id = intval($base_id); - - $maintainers = array_merge(array(pkgbase_maintainer_uid($base_id)), pkgbase_get_comaintainer_uids(array($base_id))); - if (!has_credential(CRED_PKGBASE_SET_KEYWORDS, $maintainers)) { - return array(false, __("You are not allowed to edit the keywords of this package base.")); - } - - /* Remove empty and duplicate user names. */ - $keywords = array_unique(array_filter(array_map('trim', $keywords))); - - $dbh = DB::connect(); - - $q = sprintf("DELETE FROM PackageKeywords WHERE PackageBaseID = %d", $base_id); - $dbh->exec($q); - - $i = 0; - foreach ($keywords as $keyword) { - $q = sprintf("INSERT INTO PackageKeywords (PackageBaseID, Keyword) VALUES (%d, %s)", $base_id, $dbh->quote($keyword)); - $dbh->exec($q); - - $i++; - if ($i >= 20) { - break; - } - } - - return array(true, __("The package base keywords have been updated.")); -} - -/** - * Get a list of package base co-maintainers - * - * @param int $base_id The package base ID to retrieve the co-maintainers for - * - * @return array An array of co-maintainer user names - */ -function pkgbase_get_comaintainers($base_id) { - $dbh = DB::connect(); - $q = "SELECT UserName FROM PackageComaintainers "; - $q .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; - $q .= "WHERE PackageComaintainers.PackageBaseID = " . intval($base_id) . " "; - $q .= "ORDER BY Priority ASC"; - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - return array(); - } -} - -/** - * Get a list of package base co-maintainer IDs - * - * @param int $base_id The package base ID to retrieve the co-maintainers for - * - * @return array An array of co-maintainer user UDs - */ -function pkgbase_get_comaintainer_uids($base_ids) { - $dbh = DB::connect(); - $q = "SELECT UsersID FROM PackageComaintainers "; - $q .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; - $q .= "WHERE PackageComaintainers.PackageBaseID IN (" . implode(",", $base_ids) . ") "; - $q .= "ORDER BY Priority ASC"; - $result = $dbh->query($q); - - if ($result) { - return $result->fetchAll(PDO::FETCH_COLUMN, 0); - } else { - return array(); - } -} - -/** - * Update the list of co-maintainers of a package base - * - * @param int $base_id The package base ID to update the co-maintainers of - * @param array $users Array of co-maintainer user names - * @param boolean $override Override credential check if true - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgbase_set_comaintainers($base_id, $users, $override=false) { - $maintainer_uid = pkgbase_maintainer_uid($base_id); - if (!$override && !has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array($maintainer_uid))) { - return array(false, __("You are not allowed to manage co-maintainers of this package base.")); - } - - /* Remove empty and duplicate user names. */ - $users = array_unique(array_filter(array_map('trim', $users))); - - $dbh = DB::connect(); - - $uids_new = array(); - foreach($users as $user) { - $q = "SELECT ID FROM Users "; - $q .= "WHERE UserName = " . $dbh->quote($user); - $result = $dbh->query($q); - $uid = $result->fetchColumn(0); - - if (!$uid) { - return array(false, __("Invalid user name: %s", $user)); - } elseif ($uid == $maintainer_uid) { - // silently ignore when maintainer == co-maintainer - continue; - } else { - $uids_new[] = $uid; - } - } - - $q = sprintf("SELECT UsersID FROM PackageComaintainers WHERE PackageBaseID = %d", $base_id); - $result = $dbh->query($q); - $uids_old = $result->fetchAll(PDO::FETCH_COLUMN, 0); - - $uids_add = array_diff($uids_new, $uids_old); - $uids_rem = array_diff($uids_old, $uids_new); - - $i = 1; - foreach ($uids_new as $uid) { - if (in_array($uid, $uids_add)) { - $q = sprintf("INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (%d, %d, %d)", $base_id, $uid, $i); - notify(array('comaintainer-add', $uid, $base_id)); - } else { - $q = sprintf("UPDATE PackageComaintainers SET Priority = %d WHERE PackageBaseID = %d AND UsersID = %d", $i, $base_id, $uid); - } - - $dbh->exec($q); - $i++; - } - - foreach ($uids_rem as $uid) { - $q = sprintf("DELETE FROM PackageComaintainers WHERE PackageBaseID = %d AND UsersID = %d", $base_id, $uid); - $dbh->exec($q); - notify(array('comaintainer-remove', $uid, $base_id)); - } - - return array(true, __("The package base co-maintainers have been updated.")); -} - -function pkgbase_remove_comaintainer($base_id, $uid) { - $uname = username_from_id($uid); - $names = pkgbase_get_comaintainers($base_id); - $names = array_diff($names, array($uname)); - return pkgbase_set_comaintainers($base_id, $names, true); -} diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php deleted file mode 100644 index 140c7ec1..00000000 --- a/web/lib/pkgfuncs.inc.php +++ /dev/null @@ -1,957 +0,0 @@ -query($q); - - if (!$result) { - return false; - } - - $uid = $result->fetch(PDO::FETCH_COLUMN, 0); - - return has_credential(CRED_COMMENT_DELETE, array($uid)); -} - -/** - * Determine if the user can delete a specific package comment using an array - * - * Only the comment submitter, Trusted Users, and Developers can delete - * comments. This function is used for the frontend side of comment deletion. - * - * @param array $comment All database information relating a specific comment - * - * @return bool True if the user can delete the comment, otherwise false - */ -function can_delete_comment_array($comment) { - return has_credential(CRED_COMMENT_DELETE, array($comment['UsersID'])); -} - -/** - * Determine if the user can edit a specific package comment - * - * Only the comment submitter, Trusted Users, and Developers can edit - * comments. This function is used for the backend side of comment editing. - * - * @param string $comment_id The comment ID in the database - * - * @return bool True if the user can edit the comment, otherwise false - */ -function can_edit_comment($comment_id=0) { - $dbh = DB::connect(); - - $q = "SELECT UsersID FROM PackageComments "; - $q.= "WHERE ID = " . intval($comment_id); - $result = $dbh->query($q); - - if (!$result) { - return false; - } - - $uid = $result->fetch(PDO::FETCH_COLUMN, 0); - - return has_credential(CRED_COMMENT_EDIT, array($uid)); -} - -/** - * Determine if the user can edit a specific package comment using an array - * - * Only the comment submitter, Trusted Users, and Developers can edit - * comments. This function is used for the frontend side of comment editing. - * - * @param array $comment All database information relating a specific comment - * - * @return bool True if the user can edit the comment, otherwise false - */ -function can_edit_comment_array($comment) { - return has_credential(CRED_COMMENT_EDIT, array($comment['UsersID'])); -} - -/** - * Determine if the user can pin a specific package comment - * - * Only the Package Maintainer, Package Co-maintainers, Trusted Users, and - * Developers can pin comments. This function is used for the backend side of - * comment pinning. - * - * @param string $comment_id The comment ID in the database - * - * @return bool True if the user can pin the comment, otherwise false - */ -function can_pin_comment($comment_id=0) { - $dbh = DB::connect(); - - $q = "SELECT MaintainerUID FROM PackageBases AS pb "; - $q.= "LEFT JOIN PackageComments AS pc ON pb.ID = pc.PackageBaseID "; - $q.= "WHERE pc.ID = " . intval($comment_id) . " "; - $q.= "UNION "; - $q.= "SELECT pcm.UsersID FROM PackageComaintainers AS pcm "; - $q.= "LEFT JOIN PackageComments AS pc "; - $q.= "ON pcm.PackageBaseID = pc.PackageBaseID "; - $q.= "WHERE pc.ID = " . intval($comment_id); - $result = $dbh->query($q); - - if (!$result) { - return false; - } - - $uids = $result->fetchAll(PDO::FETCH_COLUMN, 0); - - return has_credential(CRED_COMMENT_PIN, $uids); -} - -/** - * Determine if the user can edit a specific package comment using an array - * - * Only the Package Maintainer, Package Co-maintainers, Trusted Users, and - * Developers can pin comments. This function is used for the frontend side of - * comment pinning. - * - * @param array $comment All database information relating a specific comment - * - * @return bool True if the user can edit the comment, otherwise false - */ -function can_pin_comment_array($comment) { - return can_pin_comment($comment['ID']); -} - -/** - * Check to see if the package name already exists in the database - * - * @param string $name The package name to check - * - * @return string|void Package name if it already exists - */ -function pkg_from_name($name="") { - if (!$name) {return NULL;} - $dbh = DB::connect(); - $q = "SELECT ID FROM Packages "; - $q.= "WHERE Name = " . $dbh->quote($name); - $result = $dbh->query($q); - if (!$result) { - return; - } - $row = $result->fetch(PDO::FETCH_NUM); - if ($row) { - return $row[0]; - } -} - -/** - * Get licenses for a specific package - * - * @param int $pkgid The package to get licenses for - * - * @return array All licenses for the package - */ -function pkg_licenses($pkgid) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT l.Name FROM Licenses l "; - $q.= "INNER JOIN PackageLicenses pl ON pl.LicenseID = l.ID "; - $q.= "WHERE pl.PackageID = ". $pkgid; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - $rows = db_cache_result($q, 'licenses:' . $pkgid, PDO::FETCH_NUM, $ttl); - return array_map(function ($x) { return $x[0]; }, $rows); -} - -/** - * Get package groups for a specific package - * - * @param int $pkgid The package to get groups for - * - * @return array All package groups for the package - */ -function pkg_groups($pkgid) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT g.Name FROM `Groups` g "; - $q.= "INNER JOIN PackageGroups pg ON pg.GroupID = g.ID "; - $q.= "WHERE pg.PackageID = ". $pkgid; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - $rows = db_cache_result($q, 'groups:' . $pkgid, PDO::FETCH_NUM, $ttl); - return array_map(function ($x) { return $x[0]; }, $rows); -} - -/** - * Get providers for a specific package - * - * @param string $name The name of the "package" to get providers for - * - * @return array The IDs and names of all providers of the package - */ -function pkg_providers($name) { - $dbh = DB::connect(); - $q = "SELECT p.ID, p.Name FROM Packages p "; - $q.= "WHERE p.Name = " . $dbh->quote($name) . " "; - $q.= "UNION "; - $q.= "SELECT p.ID, p.Name FROM Packages p "; - $q.= "LEFT JOIN PackageRelations pr ON pr.PackageID = p.ID "; - $q.= "LEFT JOIN RelationTypes rt ON rt.ID = pr.RelTypeID "; - $q.= "WHERE (rt.Name = 'provides' "; - $q.= "AND pr.RelName = " . $dbh->quote($name) . ")"; - $q.= "UNION "; - $q.= "SELECT 0, Name FROM OfficialProviders "; - $q.= "WHERE Provides = " . $dbh->quote($name); - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - return db_cache_result($q, 'providers:' . $name, PDO::FETCH_NUM, $ttl); -} - -/** - * Get package dependencies for a specific package - * - * @param int $pkgid The package to get dependencies for - * @param int $limit An upper bound for the number of packages to retrieve - * - * @return array All package dependencies for the package - */ -function pkg_dependencies($pkgid, $limit) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT pd.DepName, dt.Name, pd.DepDesc, "; - $q.= "pd.DepCondition, pd.DepArch, p.ID "; - $q.= "FROM PackageDepends pd "; - $q.= "LEFT JOIN Packages p ON pd.DepName = p.Name "; - $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; - $q.= "WHERE pd.PackageID = ". $pkgid . " "; - $q.= "ORDER BY pd.DepName LIMIT " . intval($limit); - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - return db_cache_result($q, 'dependencies:' . $pkgid, PDO::FETCH_NUM, $ttl); -} - -/** - * Get package relations for a specific package - * - * @param int $pkgid The package to get relations for - * - * @return array All package relations for the package - */ -function pkg_relations($pkgid) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT pr.RelName, rt.Name, pr.RelCondition, pr.RelArch, p.ID FROM PackageRelations pr "; - $q.= "LEFT JOIN Packages p ON pr.RelName = p.Name "; - $q.= "LEFT JOIN RelationTypes rt ON rt.ID = pr.RelTypeID "; - $q.= "WHERE pr.PackageID = ". $pkgid . " "; - $q.= "ORDER BY pr.RelName"; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - return db_cache_result($q, 'relations:' . $pkgid, PDO::FETCH_NUM, $ttl); -} - -/** - * Get the HTML code to display a package dependency link annotation - * (dependency type, architecture, ...) - * - * @param string $type The name of the dependency type - * @param string $arch The package dependency architecture - * @param string $desc An optdepends description - * - * @return string The HTML code of the label to display - */ -function pkg_deplink_annotation($type, $arch, $desc=false) { - if ($type == 'depends' && !$arch) { - return ''; - } - - $link = ' ('; - - if ($type == 'makedepends') { - $link .= 'make'; - } elseif ($type == 'checkdepends') { - $link .= 'check'; - } elseif ($type == 'optdepends') { - $link .= 'optional'; - } - - if ($type != 'depends' && $arch) { - $link .= ', '; - } - - if ($arch) { - $link .= htmlspecialchars($arch); - } - - $link .= ')'; - if ($type == 'optdepends' && $desc) { - $link .= ' – ' . htmlspecialchars($desc) . ' '; - } - $link .= ''; - - return $link; -} - -/** - * Get the HTML code to display a package provider link - * - * @param string $name The name of the provider - * @param bool $official True if the package is in the official repositories - * - * @return string The HTML code of the link to display - */ -function pkg_provider_link($name, $official) { - $link = ''; - $link .= htmlspecialchars($name) . ''; - - return $link; -} - -/** - * Get the HTML code to display a package dependency link - * - * @param string $name The name of the dependency - * @param string $type The name of the dependency type - * @param string $desc The (optional) description of the dependency - * @param string $cond The package dependency condition string - * @param string $arch The package dependency architecture - * @param int $pkg_id The package of the package to display the dependency for - * - * @return string The HTML code of the label to display - */ -function pkg_depend_link($name, $type, $desc, $cond, $arch, $pkg_id) { - /* - * TODO: We currently perform one SQL query per nonexistent package - * dependency. It would be much better if we could annotate dependency - * data with providers so that we already know whether a dependency is - * a "provision name" or a package from the official repositories at - * this point. - */ - $providers = pkg_providers($name); - - if (count($providers) == 0) { - $link = ''; - $link .= htmlspecialchars($name); - $link .= ''; - $link .= htmlspecialchars($cond) . ' '; - $link .= pkg_deplink_annotation($type, $arch, $desc); - return $link; - } - - $link = htmlspecialchars($name); - foreach ($providers as $provider) { - if ($provider[1] == $name) { - $is_official = ($provider[0] == 0); - $name = $provider[1]; - $link = pkg_provider_link($name, $is_official); - break; - } - } - $link .= htmlspecialchars($cond) . ' '; - - foreach ($providers as $key => $provider) { - if ($provider[1] == $name) { - unset($providers[$key]); - } - } - - if (count($providers) > 0) { - $link .= '('; - foreach ($providers as $provider) { - $is_official = ($provider[0] == 0); - $name = $provider[1]; - $link .= pkg_provider_link($name, $is_official) . ', '; - } - $link = substr($link, 0, -2); - $link .= ')'; - } - - $link .= pkg_deplink_annotation($type, $arch, $desc); - - return $link; -} - -/** - * Get the HTML code to display a package requirement link - * - * @param string $name The name of the requirement - * @param string $depends The (literal) name of the dependency of $name - * @param string $type The name of the dependency type - * @param string $arch The package dependency architecture - * @param string $pkgname The name of dependant package - * - * @return string The HTML code of the link to display - */ -function pkg_requiredby_link($name, $depends, $type, $arch, $pkgname) { - $link = ''; - $link .= htmlspecialchars($name) . ''; - - if ($depends != $pkgname) { - $link .= ' ('; - $link .= __('requires %s', htmlspecialchars($depends)); - $link .= ')'; - } - - return $link . pkg_deplink_annotation($type, $arch); -} - -/** - * Get the HTML code to display a package relation - * - * @param string $name The name of the relation - * @param string $cond The package relation condition string - * @param string $arch The package relation architecture - * - * @return string The HTML code of the label to display - */ -function pkg_rel_html($name, $cond, $arch) { - $html = htmlspecialchars($name) . htmlspecialchars($cond); - - if ($arch) { - $html .= ' (' . htmlspecialchars($arch) . ')'; - } - - return $html; -} - -/** - * Get the HTML code to display a source link - * - * @param string $url The URL of the source - * @param string $arch The source architecture - * @param string $package The name of the package - * - * @return string The HTML code of the label to display - */ -function pkg_source_link($url, $arch, $package) { - $url = explode('::', $url); - $parsed_url = parse_url($url[0]); - - if (isset($parsed_url['scheme']) || isset($url[1])) { - $link = '' . htmlspecialchars($url[0]) . ''; - } else { - $file_url = sprintf(config_get('options', 'source_file_uri'), htmlspecialchars($url[0]), $package); - $link = '' . htmlspecialchars($url[0]) . ''; - } - - if ($arch) { - $link .= ' (' . htmlspecialchars($arch) . ')'; - } - - return $link; -} - -/** - * Determine packages that depend on a package - * - * @param string $name The package name for the dependency search - * @param array $provides A list of virtual provisions of the package - * @param int $limit An upper bound for the number of packages to retrieve - * - * @return array All packages that depend on the specified package name - */ -function pkg_required($name="", $provides, $limit) { - $deps = array(); - if ($name != "") { - $dbh = DB::connect(); - - $name_list = $dbh->quote($name); - foreach ($provides as $p) { - $name_list .= ',' . $dbh->quote($p[0]); - } - - $q = "SELECT p.Name, pd.DepName, dt.Name, pd.DepArch "; - $q.= "FROM PackageDepends pd "; - $q.= "LEFT JOIN Packages p ON p.ID = pd.PackageID "; - $q.= "LEFT JOIN DependencyTypes dt ON dt.ID = pd.DepTypeID "; - $q.= "WHERE pd.DepName IN (" . $name_list . ") "; - $q.= "ORDER BY p.Name LIMIT " . intval($limit); - /* Not invalidated by package updates. */ - return db_cache_result($q, 'required:' . $name, PDO::FETCH_NUM); - } - return $deps; -} - -/** - * Get all package sources for a specific package - * - * @param string $pkgid The package ID to get the sources for - * - * @return array All sources associated with a specific package - */ -function pkg_sources($pkgid) { - $pkgid = intval($pkgid); - if (!$pkgid) { - return array(); - } - $q = "SELECT Source, SourceArch FROM PackageSources "; - $q.= "WHERE PackageID = " . $pkgid; - $q.= " ORDER BY Source"; - $ttl = config_get_int('options', 'cache_pkginfo_ttl'); - return db_cache_result($q, 'required:' . $pkgid, PDO::FETCH_NUM, $ttl); -} - -/** - * Get the package details - * - * @param string $id The package ID to get description for - * - * @return array The package's details OR error message - **/ -function pkg_get_details($id=0) { - $dbh = DB::connect(); - - $q = "SELECT Packages.*, PackageBases.ID AS BaseID, "; - $q.= "PackageBases.Name AS BaseName, PackageBases.NumVotes, "; - $q.= "PackageBases.Popularity, PackageBases.OutOfDateTS, "; - $q.= "PackageBases.SubmittedTS, PackageBases.ModifiedTS, "; - $q.= "PackageBases.SubmitterUID, PackageBases.MaintainerUID, "; - $q.= "PackageBases.PackagerUID, PackageBases.FlaggerUID, "; - $q.= "(SELECT COUNT(*) FROM PackageRequests "; - $q.= " WHERE PackageRequests.PackageBaseID = Packages.PackageBaseID "; - $q.= " AND PackageRequests.Status = 0) AS RequestCount "; - $q.= "FROM Packages, PackageBases "; - $q.= "WHERE PackageBases.ID = Packages.PackageBaseID "; - $q.= "AND Packages.ID = " . intval($id); - $result = $dbh->query($q); - - $row = array(); - - if (!$result) { - $row['error'] = __("Error retrieving package details."); - } - else { - $row = $result->fetch(PDO::FETCH_ASSOC); - if (empty($row)) { - $row['error'] = __("Package details could not be found."); - } - } - - return $row; -} - -/** - * Display the package details page - * - * @param string $id The package ID to get details page for - * @param array $row Package details retrieved by pkg_get_details() - * @param string $SID The session ID of the visitor - * - * @return void - */ -function pkg_display_details($id=0, $row, $SID="") { - $dbh = DB::connect(); - - if (isset($row['error'])) { - print "

    " . $row['error'] . "

    \n"; - } - else { - $base_id = pkgbase_from_pkgid($id); - $pkgbase_name = pkgbase_name_from_id($base_id); - - include('pkg_details.php'); - - if ($SID) { - include('pkg_comment_box.php'); - } - - $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); - - $limit_pinned = isset($_GET['pinned']) ? 0 : 5; - $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); - if (!empty($pinned)) { - $comment_section = "package"; - include('pkg_comments.php'); - } - unset($pinned); - - - $total_comment_count = pkgbase_comments_count($base_id, $include_deleted); - list($pagination_templs, $per_page, $offset) = calculate_pagination($total_comment_count); - - $comments = pkgbase_comments($base_id, $per_page, $include_deleted, false, $offset); - if (!empty($comments)) { - $comment_section = "package"; - include('pkg_comments.php'); - } - } -} - -/** - * Output the body of the search results page - * - * @param array $params Search parameters - * @param bool $show_headers True if statistics should be included - * @param string $SID The session ID of the visitor - * - * @return int The total number of packages matching the query - */ -function pkg_search_page($params, $show_headers=true, $SID="") { - $dbh = DB::connect(); - - /* - * Get commonly used variables. - * TODO: Reduce the number of database queries! - */ - if ($SID) - $myuid = uid_from_sid($SID); - - /* Sanitize paging variables. */ - if (isset($params['O'])) { - $params['O'] = bound(intval($params['O']), 0, 2500); - } else { - $params['O'] = 0; - } - - if (isset($params["PP"])) { - $params["PP"] = bound(intval($params["PP"]), 50, 250); - } else { - $params["PP"] = 50; - } - - /* - * FIXME: Pull out DB-related code. All of it! This one's worth a - * choco-chip cookie, one of those nice big soft ones. - */ - - /* Build the package search query. */ - $q_select = "SELECT "; - if ($SID) { - $q_select .= "PackageNotifications.UserID AS Notify, - PackageVotes.UsersID AS Voted, "; - } - $q_select .= "Users.Username AS Maintainer, - Packages.Name, Packages.Version, Packages.Description, - PackageBases.NumVotes, PackageBases.Popularity, Packages.ID, - Packages.PackageBaseID, PackageBases.OutOfDateTS "; - - $q_from = "FROM Packages - LEFT JOIN PackageBases ON (PackageBases.ID = Packages.PackageBaseID) - LEFT JOIN Users ON (PackageBases.MaintainerUID = Users.ID) "; - if ($SID) { - /* This is not needed for the total row count query. */ - $q_from_extra = "LEFT JOIN PackageVotes - ON (PackageBases.ID = PackageVotes.PackageBaseID AND PackageVotes.UsersID = $myuid) - LEFT JOIN PackageNotifications - ON (PackageBases.ID = PackageNotifications.PackageBaseID AND PackageNotifications.UserID = $myuid) "; - } else { - $q_from_extra = ""; - } - - $q_where = 'WHERE PackageBases.PackagerUID IS NOT NULL '; - - if (isset($params['K'])) { - if (isset($params["SeB"]) && $params["SeB"] == "m") { - /* Search by maintainer. */ - $q_where .= "AND Users.Username = " . $dbh->quote($params['K']) . " "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "c") { - /* Search by co-maintainer. */ - $q_where .= "AND EXISTS (SELECT * FROM PackageComaintainers "; - $q_where .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; - $q_where .= "WHERE PackageComaintainers.PackageBaseID = PackageBases.ID "; - $q_where .= "AND Users.Username = " . $dbh->quote($params['K']) . ")"; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "M") { - /* Search by maintainer and co-maintainer. */ - $q_where .= "AND (Users.Username = " . $dbh->quote($params['K']) . " "; - $q_where .= "OR EXISTS (SELECT * FROM PackageComaintainers "; - $q_where .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID "; - $q_where .= "WHERE PackageComaintainers.PackageBaseID = PackageBases.ID "; - $q_where .= "AND Users.Username = " . $dbh->quote($params['K']) . "))"; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "s") { - /* Search by submitter. */ - $q_where .= "AND SubmitterUID = " . intval(uid_from_username($params['K'])) . " "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "n") { - /* Search by name. */ - $K = "%" . addcslashes($params['K'], '%_') . "%"; - $q_where .= "AND (Packages.Name LIKE " . $dbh->quote($K) . ") "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "b") { - /* Search by package base name. */ - $K = "%" . addcslashes($params['K'], '%_') . "%"; - $q_where .= "AND (PackageBases.Name LIKE " . $dbh->quote($K) . ") "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "k") { - /* Search by name. */ - $q_where .= construct_keyword_search($dbh, $params['K'], false, true); - } - elseif (isset($params["SeB"]) && $params["SeB"] == "N") { - /* Search by name (exact match). */ - $q_where .= "AND (Packages.Name = " . $dbh->quote($params['K']) . ") "; - } - elseif (isset($params["SeB"]) && $params["SeB"] == "B") { - /* Search by package base name (exact match). */ - $q_where .= "AND (PackageBases.Name = " . $dbh->quote($params['K']) . ") "; - } - else { - /* Keyword search (default). */ - $q_where .= construct_keyword_search($dbh, $params['K'], true, true); - } - } - - if (isset($params["do_Orphans"])) { - $q_where .= "AND MaintainerUID IS NULL "; - } - - if (isset($params['outdated'])) { - if ($params['outdated'] == 'on') { - $q_where .= "AND OutOfDateTS IS NOT NULL "; - } - elseif ($params['outdated'] == 'off') { - $q_where .= "AND OutOfDateTS IS NULL "; - } - } - - $order = (isset($params["SO"]) && $params["SO"] == 'd') ? 'DESC' : 'ASC'; - - $q_sort = "ORDER BY "; - $sort_by = isset($params["SB"]) ? $params["SB"] : ''; - switch ($sort_by) { - case 'v': - $q_sort .= "NumVotes " . $order . ", "; - break; - case 'p': - $q_sort .= "Popularity " . $order . ", "; - break; - case 'w': - if ($SID) { - $q_sort .= "Voted " . $order . ", "; - } - break; - case 'o': - if ($SID) { - $q_sort .= "Notify " . $order . ", "; - } - break; - case 'm': - $q_sort .= "Maintainer " . $order . ", "; - break; - case 'l': - $q_sort .= "ModifiedTS " . $order . ", "; - break; - case 'a': - /* For compatibility with old search links. */ - $q_sort .= "-ModifiedTS " . $order . ", "; - break; - default: - break; - } - $q_sort .= " Packages.Name " . $order . " "; - - $q_limit = "LIMIT ".$params["PP"]." OFFSET ".$params["O"]; - - $q = $q_select . $q_from . $q_from_extra . $q_where . $q_sort . $q_limit; - $q_total = "SELECT COUNT(*) " . $q_from . $q_where; - - $result = $dbh->query($q); - $result_t = $dbh->query($q_total); - if ($result_t) { - $row = $result_t->fetch(PDO::FETCH_NUM); - $total = min($row[0], 2500); - } else { - $total = 0; - } - - if ($result && $total > 0) { - if (isset($params["SO"]) && $params["SO"] == "d"){ - $SO_next = "a"; - } - else { - $SO_next = "d"; - } - } - - /* Calculate the results to use. */ - $first = $params['O'] + 1; - - /* Calculation of pagination links. */ - $per_page = ($params['PP'] > 0) ? $params['PP'] : 50; - $current = ceil($first / $per_page); - $pages = ceil($total / $per_page); - $templ_pages = array(); - - if ($current > 1) { - $templ_pages['« ' . __('First')] = 0; - $templ_pages['‹ ' . __('Previous')] = ($current - 2) * $per_page; - } - - if ($current - 5 > 1) - $templ_pages["..."] = false; - - for ($i = max($current - 5, 1); $i <= min($pages, $current + 5); $i++) { - $templ_pages[$i] = ($i - 1) * $per_page; - } - - if ($current + 5 < $pages) - $templ_pages["... "] = false; - - if ($current < $pages) { - $templ_pages[__('Next') . ' ›'] = $current * $per_page; - $templ_pages[__('Last') . ' »'] = ($pages - 1) * $per_page; - } - - $searchresults = array(); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $searchresults[] = $row; - } - } - - include('pkg_search_results.php'); - - return $total; -} - -/** - * Construct the WHERE part of the sophisticated keyword search - * - * @param handle $dbh Database handle - * @param string $keywords The search term - * @param bool $namedesc Search name and description fields - * @param bool $keyword Search packages with a matching PackageBases.Keyword - * - * @return string WHERE part of the SQL clause - */ -function construct_keyword_search($dbh, $keywords, $namedesc, $keyword=false) { - $count = 0; - $where_part = ""; - $q_keywords = ""; - $op = ""; - - foreach (str_getcsv($keywords, ' ') as $term) { - if ($term == "") { - continue; - } - if ($count > 0 && strtolower($term) == "and") { - $op = "AND "; - continue; - } - if ($count > 0 && strtolower($term) == "or") { - $op = "OR "; - continue; - } - if ($count > 0 && strtolower($term) == "not") { - $op .= "NOT "; - continue; - } - - $term = "%" . addcslashes($term, '%_') . "%"; - $q_keywords .= $op . " ("; - $q_keywords .= "Packages.Name LIKE " . $dbh->quote($term) . " "; - if ($namedesc) { - $q_keywords .= "OR Description LIKE " . $dbh->quote($term) . " "; - } - - if ($keyword) { - $q_keywords .= "OR EXISTS (SELECT * FROM PackageKeywords WHERE "; - $q_keywords .= "PackageKeywords.PackageBaseID = Packages.PackageBaseID AND "; - $q_keywords .= "PackageKeywords.Keyword LIKE " . $dbh->quote($term) . ")) "; - } else { - $q_keywords .= ") "; - } - - $count++; - if ($count >= 20) { - break; - } - $op = "AND "; - } - - if (!empty($q_keywords)) { - $where_part = "AND (" . $q_keywords . ") "; - } - - return $where_part; -} - -/** - * Determine if a POST string has been sent by a visitor - * - * @param string $action String to check has been sent via POST - * - * @return bool True if the POST string was used, otherwise false - */ -function current_action($action) { - return (isset($_POST['action']) && $_POST['action'] == $action) || - isset($_POST[$action]); -} - -/** - * Determine if sent IDs are valid integers - * - * @param array $ids IDs to validate - * - * @return array All sent IDs that are valid integers - */ -function sanitize_ids($ids) { - $new_ids = array(); - foreach ($ids as $id) { - $id = intval($id); - if ($id > 0) { - $new_ids[] = $id; - } - } - return $new_ids; -} - -/** - * Determine package information for latest package - * - * @param int $numpkgs Number of packages to get information on - * - * @return array $packages Package info for the specified number of recent packages - */ -function latest_pkgs($numpkgs, $orderBy='SubmittedTS') { - $dbh = DB::connect(); - - $q = "SELECT Packages.*, MaintainerUID, SubmittedTS, ModifiedTS "; - $q.= "FROM Packages LEFT JOIN PackageBases ON "; - $q.= "PackageBases.ID = Packages.PackageBaseID "; - $q.= "ORDER BY " . $orderBy . " DESC "; - $q.= "LIMIT " . intval($numpkgs); - $result = $dbh->query($q); - - $packages = array(); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $packages[] = $row; - } - } - - return $packages; -} - -/** - * Determine package information for latest modified packages - * - * @param int $numpkgs Number of packages to get information on - * - * @return array $packages Package info for the specified number of recently modified packages - */ -function latest_modified_pkgs($numpkgs) { - return latest_pkgs($numpkgs, 'ModifiedTS'); -} diff --git a/web/lib/pkgreqfuncs.inc.php b/web/lib/pkgreqfuncs.inc.php deleted file mode 100644 index 7fce307c..00000000 --- a/web/lib/pkgreqfuncs.inc.php +++ /dev/null @@ -1,260 +0,0 @@ -query($q)->fetchColumn(); -} - -/** - * Get a list of all package requests - * - * @param int $offset The index of the first request to return - * @param int $limit The maximum number of requests to return - * @param int $uid Only return packages affecting the given user - * @param int $from Do not return packages older than the given date - * - * @return array List of package requests with details - */ -function pkgreq_list($offset, $limit, $uid=false, $from=false) { - $dbh = DB::connect(); - - $q = "SELECT PackageRequests.ID, "; - $q.= "PackageRequests.PackageBaseID AS BaseID, "; - $q.= "PackageRequests.PackageBaseName AS Name, "; - $q.= "PackageRequests.MergeBaseName AS MergeInto, "; - $q.= "RequestTypes.Name AS Type, PackageRequests.Comments, "; - $q.= "Users.Username AS User, PackageRequests.RequestTS, "; - $q.= "PackageRequests.Status, PackageRequests.Status = 0 AS Open "; - $q.= "FROM PackageRequests INNER JOIN RequestTypes ON "; - $q.= "RequestTypes.ID = PackageRequests.ReqTypeID "; - $q.= "INNER JOIN Users ON Users.ID = PackageRequests.UsersID "; - - if ($uid || $from) { - $q.= "WHERE "; - if ($uid) { - $q.= "(PackageRequests.UsersID = " . intval($uid). " "; - $q.= "OR Users.ID = " . intval($uid) . ") AND "; - } - if ($from) { - $q.= "RequestTS >= " . intval($from). " "; - } - } - - $q.= "ORDER BY Open DESC, RequestTS DESC "; - $q.= "LIMIT " . $limit . " OFFSET " . $offset; - - return $dbh->query($q)->fetchAll(); -} - -/** - * Get a list of all open package requests belonging to a certain package base - * - * @param int $baseid The package base ID to retrieve requests for - * @param int $type The type of requests to obtain - * - * @return array List of package request IDs - */ -function pkgreq_by_pkgbase($baseid, $type=false) { - $dbh = DB::connect(); - - $q = "SELECT PackageRequests.ID "; - $q.= "FROM PackageRequests INNER JOIN RequestTypes ON "; - $q.= "RequestTypes.ID = PackageRequests.ReqTypeID "; - $q.= "WHERE PackageRequests.Status = 0 "; - $q.= "AND PackageRequests.PackageBaseID = " . intval($baseid); - - if ($type) { - $q .= " AND RequestTypes.Name = " . $dbh->quote($type); - } - - return $dbh->query($q)->fetchAll(PDO::FETCH_COLUMN, 0); -} - -/** - * Obtain the package base that belongs to a package request. - * - * @param int $id Package request ID to retrieve the package base for - * - * @return int The name of the corresponding package base - */ -function pkgreq_get_pkgbase_name($id) { - $dbh = DB::connect(); - - $q = "SELECT PackageBaseName FROM PackageRequests "; - $q.= "WHERE ID = " . intval($id); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * Obtain the email address of the creator of a package request - * - * @param int $id Package request ID to retrieve the creator for - * - * @return int The email address of the creator - */ -function pkgreq_get_creator_email($id) { - $dbh = DB::connect(); - - $q = "SELECT Email FROM Users INNER JOIN PackageRequests "; - $q.= "ON Users.ID = PackageRequests.UsersID "; - $q.= "WHERE PackageRequests.ID = " . intval($id); - $result = $dbh->query($q); - return $result->fetch(PDO::FETCH_COLUMN, 0); -} - -/** - * File a deletion/orphan request against a package base - * - * @param string $ids The package base IDs to file the request against - * @param string $type The type of the request - * @param string $merge_into The target of a merge operation - * @param string $comments The comments to be added to the request - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgreq_file($ids, $type, $merge_into, $comments) { - if (!has_credential(CRED_PKGREQ_FILE)) { - return array(false, __("You must be logged in to file package requests.")); - } - - /* Ignore merge target for non-merge requests. */ - if ($type !== 'merge') { - $merge_into = ''; - } - - if (!empty($merge_into) && !preg_match("/^[a-z0-9][a-z0-9\.+_-]*$/D", $merge_into)) { - return array(false, __("Invalid name: only lowercase letters are allowed.")); - } - - if (!empty($merge_into) && !pkgbase_from_name($merge_into)) { - return array(false, __("Cannot find package to merge votes and comments into.")); - } - - if (empty($comments)) { - return array(false, __("The comment field must not be empty.")); - } - - $dbh = DB::connect(); - $uid = uid_from_sid($_COOKIE["AURSID"]); - - /* TODO: Allow for filing multiple requests at once. */ - $base_id = intval($ids[0]); - $pkgbase_name = pkgbase_name_from_id($base_id); - - if ($merge_into == $pkgbase_name) { - return array(false, __("Cannot merge a package base with itself.")); - } - - $q = "SELECT ID FROM RequestTypes WHERE Name = " . $dbh->quote($type); - $result = $dbh->query($q); - if ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $type_id = $row['ID']; - } else { - return array(false, __("Invalid request type.")); - } - - $q = "INSERT INTO PackageRequests "; - $q.= "(ReqTypeID, PackageBaseID, PackageBaseName, MergeBaseName, "; - $q.= "UsersID, Comments, ClosureComment, RequestTS) VALUES (" . $type_id . ", "; - $q.= $base_id . ", " . $dbh->quote($pkgbase_name) . ", "; - $q.= $dbh->quote($merge_into) . ", " . $uid . ", "; - $q.= $dbh->quote($comments) . ", '', " . strval(time()) . ")"; - $dbh->exec($q); - $request_id = $dbh->lastInsertId(); - - /* Send e-mail notifications. */ - $params = array('request-open', $uid, $request_id, $type, $base_id); - if ($type === 'merge') { - $params[] = $merge_into; - } - notify($params); - - $auto_orphan_age = config_get('options', 'auto_orphan_age'); - $auto_delete_age = config_get('options', 'auto_delete_age'); - $details = pkgbase_get_details($base_id); - if ($type == 'orphan' && $details['OutOfDateTS'] > 0 && - time() - $details['OutOfDateTS'] >= $auto_orphan_age && - $auto_orphan_age > 0) { - /* - * Close package request. NOTE: This needs to happen *before* - * the actual disown operation. Otherwise, the former - * maintainer will not be included in the Cc list of the - * request notification email. - */ - $out_of_date_time = date("Y-m-d", intval($details["OutOfDateTS"])); - pkgreq_close($request_id, "accepted", - "The package base has been flagged out-of-date " . - "since " . $out_of_date_time . ".", true); - $q = "UPDATE PackageBases SET MaintainerUID = NULL "; - $q.= "WHERE ID = " . $base_id; - $dbh->exec($q); - } else if ($type == 'deletion' && $details['MaintainerUID'] == $uid && - $details['SubmittedTS'] > 0 && $auto_delete_age > 0 && - time() - $details['SubmittedTS'] <= $auto_delete_age) { - /* - * Close package request. NOTE: This needs to happen *before* - * the actual deletion operation. Otherwise, the former - * maintainer will not be included in the Cc list of the - * request notification email. - */ - pkgreq_close($request_id, "accepted", - "Deletion of a fresh package requested by its " . - "current maintainer.", true); - pkgbase_delete(array($base_id), NULL, NULL, true); - } - - return array(true, __("Added request successfully.")); -} - -/** - * Close a deletion/orphan request - * - * @param int $id The package request to close - * @param string $reason Whether the request was accepted or rejected - * @param string $comments Comments to be added to the notification email - * @param boolean $auto_close (optional) Whether the request is auto-closed - * - * @return array Tuple of success/failure indicator and error message - */ -function pkgreq_close($id, $reason, $comments, $auto_close=false) { - switch ($reason) { - case 'accepted': - $status = 2; - break; - case 'rejected': - $status = 3; - break; - default: - return array(false, __("Invalid reason.")); - } - - $dbh = DB::connect(); - $id = intval($id); - $uid = $auto_close ? 0 : uid_from_sid($_COOKIE["AURSID"]); - - if (!$auto_close && !has_credential(CRED_PKGREQ_CLOSE)) { - return array(false, __("Only TUs and developers can close requests.")); - } - - $q = "UPDATE PackageRequests SET Status = " . intval($status) . ", "; - $q.= "ClosedTS = " . strval(time()) . ", "; - $q.= "ClosedUID = " . ($uid == 0 ? "NULL" : intval($uid)) . ", "; - $q.= "ClosureComment = " . $dbh->quote($comments) . " "; - $q.= "WHERE ID = " . intval($id); - $dbh->exec($q); - - /* Send e-mail notifications. */ - notify(array('request-close', $uid, $id, $reason)); - - return array(true, __("Request closed successfully.")); -} diff --git a/web/lib/routing.inc.php b/web/lib/routing.inc.php deleted file mode 100644 index 73c667d2..00000000 --- a/web/lib/routing.inc.php +++ /dev/null @@ -1,85 +0,0 @@ - 'home.php', - '/index.php' => 'home.php', - '/packages' => 'packages.php', - '/pkgbase' => 'pkgbase.php', - '/requests' => 'pkgreq.php', - '/register' => 'register.php', - '/account' => 'account.php', - '/accounts' => 'account.php', - '/login' => 'login.php', - '/logout' => 'logout.php', - '/passreset' => 'passreset.php', - '/rpc' => 'rpc.php', - '/rss/modified' => 'modified-rss.php', - '/rss' => 'rss.php', - '/tos' => 'tos.php', - '/tu' => 'tu.php', - '/addvote' => 'addvote.php', -); - -$PKG_PATH = '/packages'; -$PKGBASE_PATH = '/pkgbase'; -$PKGREQ_PATH = '/requests'; -$USER_PATH = '/account'; - -function get_route($path) { - global $ROUTES; - - $path = rtrim($path, '/'); - if (isset($ROUTES[$path])) { - return $ROUTES[$path]; - } else { - return NULL; - } -} - -function get_uri($path, $absolute=false) { - if ($absolute) { - return rtrim(aur_location(), '/') . $path; - } else { - return $path; - } -} - -function get_pkg_route() { - global $PKG_PATH; - return $PKG_PATH; -} - -function get_pkgbase_route() { - global $PKGBASE_PATH; - return $PKGBASE_PATH; -} - -function get_pkgreq_route() { - global $PKGREQ_PATH; - return $PKGREQ_PATH; -} - -function get_pkg_uri($pkgname, $absolute=false) { - global $PKG_PATH; - $path = $PKG_PATH . '/' . urlencode($pkgname) . '/'; - return get_uri($path, $absolute); -} - -function get_pkgbase_uri($pkgbase_name, $absolute=false) { - global $PKGBASE_PATH; - $path = $PKGBASE_PATH . '/' . urlencode($pkgbase_name) . '/'; - return get_uri($path, $absolute); -} - -function get_user_route() { - global $USER_PATH; - return $USER_PATH; -} - -function get_user_uri($username, $absolute=false) { - global $USER_PATH; - $path = $USER_PATH . '/' . urlencode($username) . '/'; - return get_uri($path, $absolute); -} diff --git a/web/lib/stats.inc.php b/web/lib/stats.inc.php deleted file mode 100644 index f5692f96..00000000 --- a/web/lib/stats.inc.php +++ /dev/null @@ -1,108 +0,0 @@ -query($q); - - $newest_packages = new ArrayObject(); - if ($result) { - while ($row = $result->fetch(PDO::FETCH_ASSOC)) { - $newest_packages->append($row); - } - set_cache_value($key, $newest_packages); - } - } - include('stats/updates_table.php'); -} - -/** - * Display a user's statistics table - * - * @param string $userid The user ID of the person to get package statistics for - * - * @return void - */ -function user_table($userid) { - $base_q = "SELECT COUNT(*) FROM PackageBases "; - $base_q.= "WHERE MaintainerUID = " . $userid . " "; - $base_q.= "AND PackagerUID IS NOT NULL"; - - $user_pkg_count = db_cache_value($base_q, 'user_pkg_count:' . $userid); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE OutOfDateTS IS NOT NULL "; - $q.= "AND MaintainerUID = " . $userid . " "; - $q.= "AND PackagerUID IS NOT NULL"; - - $flagged_outdated = db_cache_value($q, 'user_flagged_outdated:' . $userid); - - include('stats/user_table.php'); -} - -/** - * Display the general package statistics table - * - * @return void - */ -function general_stats_table() { - # AUR statistics - $q = "SELECT COUNT(*) FROM PackageBases WHERE PackagerUID IS NOT NULL"; - $pkg_count = db_cache_value($q, 'pkg_count'); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE MaintainerUID IS NULL "; - $q.= "AND PackagerUID IS NOT NULL"; - $orphan_count = db_cache_value($q, 'orphan_count'); - - $q = "SELECT count(*) FROM Users"; - $user_count = db_cache_value($q, 'user_count'); - - $q = "SELECT count(*) FROM Users,AccountTypes WHERE Users.AccountTypeID = AccountTypes.ID AND (AccountTypes.AccountType = 'Trusted User' OR AccountTypes.AccountType = 'Trusted User & Developer')"; - $tu_count = db_cache_value($q, 'tu_count'); - - $targstamp = intval(strtotime("-7 days")); - $yearstamp = intval(strtotime("-1 year")); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE SubmittedTS >= $targstamp "; - $q.= "AND PackagerUID IS NOT NULL"; - $add_count = db_cache_value($q, 'add_count'); - - /* - * A package whose last modification time differs less than an hour - * from the initial submission time is considered new. - */ - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE ModifiedTS >= $targstamp "; - $q.= "AND ModifiedTS - SubmittedTS >= 3600 "; - $q.= "AND PackagerUID IS NOT NULL"; - $update_count = db_cache_value($q, 'update_count'); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE ModifiedTS >= $yearstamp "; - $q.= "AND ModifiedTS - SubmittedTS >= 3600 "; - $q.= "AND PackagerUID IS NOT NULL"; - $update_year_count = db_cache_value($q, 'update_year_count'); - - $q = "SELECT COUNT(*) FROM PackageBases "; - $q.= "WHERE ModifiedTS - SubmittedTS < 3600 "; - $q.= "AND PackagerUID IS NOT NULL"; - $never_update_count = db_cache_value($q, 'never_update_count'); - - include('stats/general_stats_table.php'); -} diff --git a/web/lib/streams.php b/web/lib/streams.php deleted file mode 100644 index 00cf6cc5..00000000 --- a/web/lib/streams.php +++ /dev/null @@ -1,167 +0,0 @@ -. - - This file is part of PHP-gettext. - - PHP-gettext is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PHP-gettext is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with PHP-gettext; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - - - // Simple class to wrap file streams, string streams, etc. - // seek is essential, and it should be byte stream -class StreamReader { - // should return a string [FIXME: perhaps return array of bytes?] - function read($bytes) { - return false; - } - - // should return new position - function seekto($position) { - return false; - } - - // returns current position - function currentpos() { - return false; - } - - // returns length of entire stream (limit for seekto()s) - function length() { - return false; - } -}; - -class StringReader { - var $_pos; - var $_str; - - function __construct($str='') { - $this->_str = $str; - $this->_pos = 0; - } - - function read($bytes) { - $data = substr($this->_str, $this->_pos, $bytes); - $this->_pos += $bytes; - if (strlen($this->_str)<$this->_pos) - $this->_pos = strlen($this->_str); - - return $data; - } - - function seekto($pos) { - $this->_pos = $pos; - if (strlen($this->_str)<$this->_pos) - $this->_pos = strlen($this->_str); - return $this->_pos; - } - - function currentpos() { - return $this->_pos; - } - - function length() { - return strlen($this->_str); - } - -}; - - -class FileReader { - var $_pos; - var $_fd; - var $_length; - - function __construct($filename) { - if (file_exists($filename)) { - - $this->_length=filesize($filename); - $this->_pos = 0; - $this->_fd = fopen($filename,'rb'); - if (!$this->_fd) { - $this->error = 3; // Cannot read file, probably permissions - return false; - } - } else { - $this->error = 2; // File doesn't exist - return false; - } - } - - function read($bytes) { - if ($bytes) { - fseek($this->_fd, $this->_pos); - - // PHP 5.1.1 does not read more than 8192 bytes in one fread() - // the discussions at PHP Bugs suggest it's the intended behaviour - $data = ''; - while ($bytes > 0) { - $chunk = fread($this->_fd, $bytes); - $data .= $chunk; - $bytes -= strlen($chunk); - } - $this->_pos = ftell($this->_fd); - - return $data; - } else return ''; - } - - function seekto($pos) { - fseek($this->_fd, $pos); - $this->_pos = ftell($this->_fd); - return $this->_pos; - } - - function currentpos() { - return $this->_pos; - } - - function length() { - return $this->_length; - } - - function close() { - fclose($this->_fd); - } - -}; - -// Preloads entire file in memory first, then creates a StringReader -// over it (it assumes knowledge of StringReader internals) -class CachedFileReader extends StringReader { - function __construct($filename) { - if (file_exists($filename)) { - - $length=filesize($filename); - $fd = fopen($filename,'rb'); - - if (!$fd) { - $this->error = 3; // Cannot read file, probably permissions - return false; - } - $this->_str = fread($fd, $length); - fclose($fd); - - } else { - $this->error = 2; // File doesn't exist - return false; - } - } -}; - - -?> diff --git a/web/lib/timezone.inc.php b/web/lib/timezone.inc.php deleted file mode 100644 index 949f846d..00000000 --- a/web/lib/timezone.inc.php +++ /dev/null @@ -1,63 +0,0 @@ - Displayed Description - */ -function generate_timezone_list() { - $php_timezones = DateTimeZone::listIdentifiers(DateTimeZone::ALL); - - $offsets = array(); - foreach ($php_timezones as $timezone) { - $tz = new DateTimeZone($timezone); - $offset = $tz->getOffset(new DateTime()); - $offsets[$timezone] = "(UTC" . ($offset < 0 ? "-" : "+") . gmdate("H:i", abs($offset)) . - ") " . $timezone; - } - - asort($offsets); - return $offsets; -} - -/** - * Set the timezone for the user. - * - * @return null - */ -function set_tz() { - $timezones = generate_timezone_list(); - $update_cookie = false; - - if (isset($_COOKIE["AURTZ"])) { - $timezone = $_COOKIE["AURTZ"]; - } elseif (isset($_COOKIE["AURSID"])) { - $dbh = DB::connect(); - $q = "SELECT Timezone FROM Users, Sessions "; - $q .= "WHERE Users.ID = Sessions.UsersID "; - $q .= "AND Sessions.SessionID = "; - $q .= $dbh->quote($_COOKIE["AURSID"]); - $result = $dbh->query($q); - - if ($result) { - $timezone = $result->fetchColumn(0); - if (!$timezone) { - unset($timezone); - } - } - - $update_cookie = true; - } - - if (!isset($timezone) || !array_key_exists($timezone, $timezones)) { - $timezone = config_get("options", "default_timezone"); - } - date_default_timezone_set($timezone); - - if ($update_cookie) { - $timeout = intval(config_get("options", "persistent_cookie_timeout")); - $cookie_time = time() + $timeout; - setcookie("AURTZ", $timezone, $cookie_time, "/"); - } -} diff --git a/web/lib/translator.inc.php b/web/lib/translator.inc.php deleted file mode 100644 index cbed1274..00000000 --- a/web/lib/translator.inc.php +++ /dev/null @@ -1,139 +0,0 @@ -", ""); - -include_once("confparser.inc.php"); -include_once('DB.class.php'); -include_once('gettext.php'); -include_once('streams.php'); - -global $streamer, $l10n; - -# Languages we have translations for -$SUPPORTED_LANGS = array( - "ar" => "العربية", - "ast" => "Asturianu", - "ca" => "Català", - "cs" => "Český", - "da" => "Dansk", - "de" => "Deutsch", - "en" => "English", - "el" => "Ελληνικά", - "es" => "Español", - "es_419" => "Español (Latinoamérica)", - "fi" => "Suomi", - "fr" => "Français", - "he" => "עברית", - "hr" => "Hrvatski", - "hu" => "Magyar", - "it" => "Italiano", - "ja" => "日本語", - "nb" => "Norsk", - "nl" => "Nederlands", - "pl" => "Polski", - "pt_BR" => "Português (Brasil)", - "pt_PT" => "Português (Portugal)", - "ro" => "Română", - "ru" => "Русский", - "sk" => "Slovenčina", - "sr" => "Srpski", - "tr" => "Türkçe", - "uk" => "Українська", - "zh_CN" => "简体中文", - "zh_TW" => "正體中文" -); - -function __() { - global $LANG; - global $l10n; - - # Create the translation. - $args = func_get_args(); - - # First argument is always string to be translated - $tag = array_shift($args); - - # Translate using gettext_reader initialized before. - $translated = $l10n->translate($tag); - $translated = htmlspecialchars($translated, ENT_QUOTES); - - # Subsequent arguments are strings to be formatted - if (count($args) > 0) { - $translated = vsprintf($translated, $args); - } - - return $translated; -} - -function _n($msgid1, $msgid2, $n) { - global $l10n; - - $translated = sprintf($l10n->ngettext($msgid1, $msgid2, $n), $n); - return htmlspecialchars($translated, ENT_QUOTES); -} - -# set up the visitor's language -# -function set_lang() { - global $LANG; - global $SUPPORTED_LANGS; - global $streamer, $l10n; - - $update_cookie = 0; - if (isset($_POST['setlang'])) { - # visitor is requesting a language change - # - $LANG = $_POST['setlang']; - $update_cookie = 1; - - } elseif (isset($_COOKIE['AURLANG'])) { - # If a cookie is set, use that - # - $LANG = $_COOKIE['AURLANG']; - - } elseif (isset($_COOKIE["AURSID"])) { - # No language but a session; use default lang preference - # - $dbh = DB::connect(); - $q = "SELECT LangPreference FROM Users, Sessions "; - $q.= "WHERE Users.ID = Sessions.UsersID "; - $q.= "AND Sessions.SessionID = "; - $q.= $dbh->quote($_COOKIE["AURSID"]); - $result = $dbh->query($q); - - if ($result) { - $LANG = $result->fetchColumn(0); - if (!$LANG) { - unset($LANG); - } - } - $update_cookie = 1; - } - - # Set $LANG to default if nothing is valid. - if (!isset($LANG) || !array_key_exists($LANG, $SUPPORTED_LANGS)) { - $LANG = config_get('options', 'default_lang'); - } - - if ($update_cookie) { - $timeout = intval(config_get('options', 'persistent_cookie_timeout')); - $cookie_time = time() + $timeout; - setcookie("AURLANG", $LANG, $cookie_time, "/"); - } - - $localedir = config_get('options', 'localedir'); - $streamer = new FileReader($localedir . '/' . $LANG . - '/LC_MESSAGES/aurweb.mo'); - $l10n = new gettext_reader($streamer, true); - - return; -} diff --git a/web/lib/version.inc.php b/web/lib/version.inc.php deleted file mode 100644 index 81d960bc..00000000 --- a/web/lib/version.inc.php +++ /dev/null @@ -1,2 +0,0 @@ - - ' . htmlspecialchars($username) . '') ?> -

    -

    - ', '') ?> -

    - -
    -
    - - - -
    -
    -

    - - -

    - -

    - -

    - -

    - " /> -

    -
    -
    diff --git a/web/template/account_details.php b/web/template/account_details.php deleted file mode 100644 index 84f8b9c5..00000000 --- a/web/template/account_details.php +++ /dev/null @@ -1,93 +0,0 @@ - - - - -
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - -
    - " . __("hidden") . ""; - else: - ?> - "> - -
    " rel="nofollow">
    - -
    format('Y-m-d') ?>
    - -
    Links:
      -
    • - -
    • - - -
    • - -
    -
    diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php deleted file mode 100644 index 4ce6b875..00000000 --- a/web/template/account_edit_form.php +++ /dev/null @@ -1,222 +0,0 @@ - -

    - ', '') ?> - ', '') ?> - ', '') ?> -

    - -
    - - - -
    - - - - - -
    -
    -

    - - () -

    -

    - -

    - -

    - - -

    - -

    - - - - - - -

    - - - -

    - - /> -

    - - -

    - - () -

    -

    - -

    - -

    - - /> -

    -

    - -

    - -

    - - -

    -

    - - - - " . __("Hide Email Address") . "") ?> - -

    - -

    - - -

    - -

    - - -

    - -

    - - -

    - -

    - - -

    - -

    - - -

    -

    - - -

    -
    - - -
    - -

    - - -

    - -

    - - -

    -
    - - -
    - -

    - - -

    -
    - -
    - : -

    - - /> -

    -

    - - /> -

    -

    - - /> -

    -
    - -
    - - -

    - - -

    - - -

    - - () - -

    - -
    - -
    -

    - - - " />   - - " />   - - " /> -

    -
    -
    diff --git a/web/template/account_search_results.php b/web/template/account_search_results.php deleted file mode 100644 index 0f7eb7a4..00000000 --- a/web/template/account_search_results.php +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - $row): ?> - - - - - - - - - - - -
    "> - - - - "> - -   - -
    - - - - - - -
    -
    -
    - - - $ind): - ?> - - - " /> -
    -
    -
    -
    -
    - - - $ind): - ?> - - - -->" /> -
    -
    -
    - -

    - -

    - - diff --git a/web/template/cgit/footer.html b/web/template/cgit/footer.html deleted file mode 100644 index 14c358f1..00000000 --- a/web/template/cgit/footer.html +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/web/template/cgit/header.html b/web/template/cgit/header.html deleted file mode 100644 index 2d418702..00000000 --- a/web/template/cgit/header.html +++ /dev/null @@ -1,15 +0,0 @@ - diff --git a/web/template/comaintainers_form.php b/web/template/comaintainers_form.php deleted file mode 100644 index f61d494c..00000000 --- a/web/template/comaintainers_form.php +++ /dev/null @@ -1,19 +0,0 @@ -
    -

    :

    -

    - ', htmlspecialchars($pkgbase_name), ''); ?> -

    -
    -
    - -

    - - -

    -

    - " /> -

    -
    -
    -
    diff --git a/web/template/flag_comment.php b/web/template/flag_comment.php deleted file mode 100644 index dc285a97..00000000 --- a/web/template/flag_comment.php +++ /dev/null @@ -1,26 +0,0 @@ -
    -

    -

    - - ', html_format_username($message['Username']), '', - '', htmlspecialchars($pkgbase_name), '', - '', date('Y-m-d', $message['OutOfDateTS']), ''); ?> - - ', htmlspecialchars($pkgbase_name), ''); ?> - -

    - -

    -

    -

    -
    -

    - -

    -

    - " /> -
    -

    -
    diff --git a/web/template/footer.php b/web/template/footer.php deleted file mode 100644 index 7f97aae0..00000000 --- a/web/template/footer.php +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - diff --git a/web/template/header.php b/web/template/header.php deleted file mode 100644 index 9631be91..00000000 --- a/web/template/header.php +++ /dev/null @@ -1,82 +0,0 @@ -'; ?> - - - - AUR (<?= htmlspecialchars($LANG); ?>)<?php if ($title != "") { print " - " . htmlspecialchars($title); } ?> - - - - ' /> - ' /> - - - - - - - - -
    -
    -
    "> -
    -
    - - -
    -
    -
    -
    -
    -
      - -
    • -
    • - -
    • - - -
    • - -
    • -
    • -
    • - -
    • AUR
    • -
    • -
    • - -
    • - -
    • - - -
    -
    - diff --git a/web/template/pkg_comment_box.php b/web/template/pkg_comment_box.php deleted file mode 100644 index 22f90d4a..00000000 --- a/web/template/pkg_comment_box.php +++ /dev/null @@ -1,4 +0,0 @@ -
    -

    - -
    diff --git a/web/template/pkg_comment_form.php b/web/template/pkg_comment_form.php deleted file mode 100644 index e8a516e3..00000000 --- a/web/template/pkg_comment_form.php +++ /dev/null @@ -1,28 +0,0 @@ -
    -
    -
    - " /> - - - - - -
    -

    - - ', "") ?> -

    -

    - -

    -

    - " /> - - - - - - -

    -
    -
    diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php deleted file mode 100644 index ffa9e137..00000000 --- a/web/template/pkg_comments.php +++ /dev/null @@ -1,239 +0,0 @@ - - - - -
    - -
    - -
    -

    - - - - - - - - - - - - -

    - - 1): ?> -

    - $pagestart): ?> - - - - - - - - - - - - -

    - -
    - - $row): ?> - ' . $date_fmtd . ''; - if ($comment_section == "package") { - if ($row['UserName']) { - $user_fmtd = html_format_username($row['UserName']); - $heading = __('%s commented on %s', $user_fmtd, $date_link); - } else { - $heading = __('Anonymous comment on %s', $date_link); - } - } elseif ($comment_section == "account") { - $pkg_uri = '' . htmlspecialchars($row['PackageBaseName']) . ''; - $heading = __('Commented on package %s on %s', $pkg_uri, $date_link); - } - - $is_deleted = $row['DelTS']; - $is_edited = $row['EditedTS']; - $is_pinned = $row['PinnedTS']; - - if ($uid && $is_deleted) { - $date_fmtd = date('Y-m-d H:i', $row['DelTS']); - $heading .= ' ('; - if ($row['DelUserName']) { - $user_fmtd = html_format_username($row['DelUserName']); - $heading .= __('deleted on %s by %s', $date_fmtd, $user_fmtd); - } else { - $heading .= __('deleted on %s', $date_fmtd); - } - $heading .= ')'; - } elseif ($uid && $is_edited) { - $date_fmtd = date('Y-m-d H:i', $row['EditedTS']); - $heading .= ' ('; - if ($row['EditUserName']) { - $user_fmtd = html_format_username($row['EditUserName']); - $heading .= __('edited on %s by %s', $date_fmtd, $user_fmtd); - } else { - $heading .= __('edited on %s', $date_fmtd); - } - $heading .= ')'; - } - - $comment_classes = "comment-header"; - if ($is_deleted) { - $comment_classes .= " comment-deleted"; - } - ?> -

    - - -
    -
    - - - - " /> - -
    -
    - - - -
    -
    - - - - " /> - -
    -
    - - - - <?= __('Edit comment') ?> - - - = 5)): ?> -
    -
    - - - " /> - - " /> - -
    -
    - - - -
    -
    - - - - " /> - -
    -
    - -

    -
    -
    - - - -

    - -

    - -
    -
    - -
    - - diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php deleted file mode 100644 index 25d85b78..00000000 --- a/web/template/pkg_details.php +++ /dev/null @@ -1,317 +0,0 @@ - -
    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0): -?> - - - - - - 0): ?> - - - - - - 0): ?> - - - - - - 0): ?> - - - - - - 0): ?> - - - - - - 0): ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - (, ) - -
    () - -
    - -
    -
    - - - - - "/> - -
    -
    -' . htmlspecialchars($kw) . "\n"; - } -endif; -?> -
    - - - - , - - - - - -
    - - - - , - - - - - -
    - - - - , - - - - - -
    - - - - , - - - - - -
    - - - - , - - - - - -
    = .2 ? 2 : 6) ?>
    - -
    -
    -

    - 0): ?> -
      - $darr): ?> -
    • - -
    - -
    -
    -

    - 0): ?> -
      - $darr): ?> -
    • - -
    - -
    -
    -

    -
    - 0): ?> -
    -
      - $src): ?> -
    • - -
    -
    - -
    -
    - - diff --git a/web/template/pkg_search_form.php b/web/template/pkg_search_form.php deleted file mode 100644 index 3d0cde6c..00000000 --- a/web/template/pkg_search_form.php +++ /dev/null @@ -1,120 +0,0 @@ - __('Name, Description'), - 'n' => __('Name Only'), - 'b' => __('Package Base'), - 'N' => __('Exact Name'), - 'B' => __('Exact Package Base'), - 'k' => __('Keywords'), - 'm' => __('Maintainer'), - 'c' => __('Co-maintainer'), - 'M' => __('Maintainer, Co-maintainer'), - 's' => __('Submitter') -); - -$outdated_flags = array( - '' => __('All'), - 'on' => __('Flagged'), - 'off' => __('Not Flagged') -); - -$sortby = array( - 'n' => __('Name'), - 'v' => __('Votes'), - 'p' => __('Popularity'), - 'w' => __('Voted'), - 'o' => __('Notify'), - 'm' => __('Maintainer'), - 'l' => __('Last modified') -); - -$orderby = array( - 'a' => __('Ascending'), - 'd' => __('Descending') -); - -$per_page = array(50, 100, 250); -?> - - diff --git a/web/template/pkg_search_results.php b/web/template/pkg_search_results.php deleted file mode 100644 index 61335560..00000000 --- a/web/template/pkg_search_results.php +++ /dev/null @@ -1,153 +0,0 @@ -'; - if ($sb) { - echo '' . $title . ''; - } else { - echo $title; - } - if ($hint) { - echo '?'; - } - echo ''; - }; -} else { - $fmtth = function($title, $sb=false, $so=false, $hint=false) { - echo '' . $title . ''; - }; -} - -if (!$result): ?> -

    - -

    - - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    - - -
    - - - - - - - - - - - - - - - - - - - - - $row): ?> - - - - - - class="flagged"> - - - - - - - - - - - - -
     
    ]" value="1" />"> - - - - - - - - - - - - - - - - - -
    - - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    - - -

    - - - - - - - - " /> -

    - - -
    - diff --git a/web/template/pkgbase_actions.php b/web/template/pkgbase_actions.php deleted file mode 100644 index 3d208328..00000000 --- a/web/template/pkgbase_actions.php +++ /dev/null @@ -1,49 +0,0 @@ - diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php deleted file mode 100644 index bde29c1c..00000000 --- a/web/template/pkgbase_details.php +++ /dev/null @@ -1,146 +0,0 @@ - -
    -

    - - - - - - - - - 0): -?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - (, ) - -
    () - -
    - -
    -
    - - - - - "/> - -
    -
    -' . htmlspecialchars($kw) . "\n"; - } -endif; -?> -
    = .2 ? 2 : 6) ?>
    - -
    -
    -

    - 0): ?> -
      - $pkg): -?> -
    • - -
    - -
    -
    -
    - - diff --git a/web/template/pkgreq_close_form.php b/web/template/pkgreq_close_form.php deleted file mode 100644 index 6228f6ab..00000000 --- a/web/template/pkgreq_close_form.php +++ /dev/null @@ -1,31 +0,0 @@ -
    -

    :

    -

    - ', htmlspecialchars($pkgbase_name), ''); ?> -

    -

    - : - -

    -
    -
    - - -

    - - -

    -

    - - -

    -

    - " /> -

    -
    -
    -
    diff --git a/web/template/pkgreq_form.php b/web/template/pkgreq_form.php deleted file mode 100644 index 9d74093e..00000000 --- a/web/template/pkgreq_form.php +++ /dev/null @@ -1,81 +0,0 @@ -
    -

    :

    -

    - ', htmlspecialchars($pkgbase_name), ''); ?> -

    -
      - -
    • - -
    -
    -
    - - - -

    - - -

    - - -

    - - -

    -

    - - -

    -

    - -

    -

    - -

    -

    - -

    -

    - " /> -

    -
    -
    -
    diff --git a/web/template/pkgreq_results.php b/web/template/pkgreq_results.php deleted file mode 100644 index 1a565c3e..00000000 --- a/web/template/pkgreq_results.php +++ /dev/null @@ -1,129 +0,0 @@ - -

    - - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    - - - - - - - - - - - - - - - - $row): ?> - $idle_time); - if (!$due) { - $time_left = $idle_time - (time() - intval($row['RequestTS'])); - if ($time_left > 48 * 3600) { - $time_left_fmt = _n("~%d day left", "~%d days left", round($time_left / (24 * 3600))); - } elseif ($time_left > 3600) { - $time_left_fmt = _n("~%d hour left", "~%d hours left", round($time_left / 3600)); - } else { - $time_left_fmt = __("<1 hour left"); - } - } - ?> - - - - - - - - - - - - - - class="flagged"> - - - - - - - - - - - - - - - - - -
    "> - - - () - - - - - - - - - - - - - () - -
    - - -
    - - -
    -

    - - -

    - 1): ?> -

    - $pagestart): ?> - - - - - - - - -

    - -
    - - diff --git a/web/template/search_accounts_form.php b/web/template/search_accounts_form.php deleted file mode 100644 index f7824a94..00000000 --- a/web/template/search_accounts_form.php +++ /dev/null @@ -1,52 +0,0 @@ -
    -
    -
    - -
    -
    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - " />   - " /> -

    -
    -
    diff --git a/web/template/stats/general_stats_table.php b/web/template/stats/general_stats_table.php deleted file mode 100644 index 9dcc3aaf..00000000 --- a/web/template/stats/general_stats_table.php +++ /dev/null @@ -1,36 +0,0 @@ -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    diff --git a/web/template/stats/updates_table.php b/web/template/stats/updates_table.php deleted file mode 100644 index 23a86288..00000000 --- a/web/template/stats/updates_table.php +++ /dev/null @@ -1,19 +0,0 @@ -

    ()

    - -RSS Feed -RSS Feed - - - - getIterator() as $row): ?> - - - - - - -
    - " title=""> - - -
    diff --git a/web/template/stats/user_table.php b/web/template/stats/user_table.php deleted file mode 100644 index e7b00834..00000000 --- a/web/template/stats/user_table.php +++ /dev/null @@ -1,21 +0,0 @@ - - -

    - - - - - - - - - - -
    - - -
    - -
    diff --git a/web/template/template.phps b/web/template/template.phps deleted file mode 100644 index f1a0bb0d..00000000 --- a/web/template/template.phps +++ /dev/null @@ -1,19 +0,0 @@ -\n"; - - -html_footer(AURWEB_VERSION); diff --git a/web/template/tu_details.php b/web/template/tu_details.php deleted file mode 100644 index d739060d..00000000 --- a/web/template/tu_details.php +++ /dev/null @@ -1,123 +0,0 @@ - 0) { - $participation = $total / $active_tus; -} else { - $participation = 0; -} - -if ($yes > $active_tus / 2) { - $vote_accepted = true; -} elseif ($participation > $quorum && $yes > $no) { - $vote_accepted = true; -} else { - $vote_accepted = false; -} -?> -
    -

    - - -

    - -

    - - -

    - : - - - - - N/A - - -
    - -
    - : - - -
    - : - - - - - - - - -

    - -

    - \n", htmlspecialchars($row['Agenda'])) ?> -

    - - - - - - - - - - - - - - - - - - - - - 0): ?> - - - - - -
    - - - - - - %
    -
    - - -
    -

    -
      - -
    • - -
    -
    - - -
    - - -
    -
    - " /> - " /> - " /> - - -
    -
    - - -
    diff --git a/web/template/tu_last_votes_list.php b/web/template/tu_last_votes_list.php deleted file mode 100644 index 6e852581..00000000 --- a/web/template/tu_last_votes_list.php +++ /dev/null @@ -1,36 +0,0 @@ -
    -

    - - - - - - - - - - - - $row): - if ($indx % 2): - $c = "even"; - else: - $c = "odd"; - endif; - $username = username_from_id($row["UserID"]); - ?> - - - - - - -
    - - - -
    -
    diff --git a/web/template/tu_list.php b/web/template/tu_list.php deleted file mode 100644 index 204c89ea..00000000 --- a/web/template/tu_list.php +++ /dev/null @@ -1,82 +0,0 @@ -
    -

    - - -
      -
    • -
    - - - -

    - - - - - - - - - - - - - - - - - - $row): ?> - - - - - - - - - - - - - - -
    - - - - - - - - - - - -
    - -
    -

    - - 0 && $off != 0): - $back = (($off - $limit) <= 0) ? 0 : $off - $limit; ?> - ?off=&by='>‹ - - - - - -

    - -