From 21d6e09cb2ec6f2d080df8f972569a42eda31eb5 Mon Sep 17 00:00:00 2001 From: ibrahem Qasim Date: Tue, 6 Oct 2026 07:09:32 +0300 Subject: [PATCH 1/7] Add graph data endpoint and filters Adds a dedicated graph_data endpoint with a custom handler, formatter, and response mapping. The handler now supports user/lang filters and groups monthly page counts by date for chart output. This also includes endpoint parameter metadata updates, improved server-side error reporting, and small cleanup in the missing_exists query helpers. --- src/app/APIController.php | 4 +- src/app/Database/Database.php | 1 + src/app/Endpoints/EndpointContext.php | 2 + src/app/Endpoints/EndpointRegistry.php | 11 +----- .../Endpoints/Handlers/GraphDataHandler.php | 37 +++++++++++++++++++ src/app/Formatting/GraphDataFormatter.php | 17 +++++++++ src/app/Formatting/ResponseBuilder.php | 4 ++ src/app/Logger.php | 2 - src/app/endpoint_params.json | 17 ++++++++- src/app/subs/missing_exists.php | 8 +--- 10 files changed, 84 insertions(+), 19 deletions(-) create mode 100644 src/app/Endpoints/Handlers/GraphDataHandler.php create mode 100644 src/app/Formatting/GraphDataFormatter.php diff --git a/src/app/APIController.php b/src/app/APIController.php index c4bf9e7..33f4cde 100644 --- a/src/app/APIController.php +++ b/src/app/APIController.php @@ -88,7 +88,9 @@ public function handleRequest(): void } catch (Throwable $e) { error_log('[API] ' . $e->getMessage()); http_response_code(500); - $this->emit($this->builder->errorOnly('internal error')); + $result = $this->builder->errorOnly('internal error'); + $result["e"] = $e->getMessage(); + $this->emit($result); } } diff --git a/src/app/Database/Database.php b/src/app/Database/Database.php index 9adefd7..0a0e803 100644 --- a/src/app/Database/Database.php +++ b/src/app/Database/Database.php @@ -119,6 +119,7 @@ public function fetchQuery(string $sqlQuery, ?array $params = null): array return $stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { Logger::error('SQL Error in fetchQuery: ' . $e->getMessage() . ' | Query: ' . $sqlQuery); + Logger::debug('SQL Error in fetchQuery: Query: ' . $sqlQuery); throw new DatabaseException('Query failed', 0, $e); } } diff --git a/src/app/Endpoints/EndpointContext.php b/src/app/Endpoints/EndpointContext.php index fd010e9..7fae402 100644 --- a/src/app/Endpoints/EndpointContext.php +++ b/src/app/Endpoints/EndpointContext.php @@ -23,8 +23,10 @@ public function __construct( public readonly Request $request, ) { $this->params = $data['params'] ?? []; + $this->columns = $data['columns'] ?? []; $this->select = SelectBuilder::build($this->params, $this->columns, $request); + $this->distinct = $request->enabled('distinct') ? 'DISTINCT ' : ''; $this->group = $request->get('group'); $this->order = $request->get('order'); diff --git a/src/app/Endpoints/EndpointRegistry.php b/src/app/Endpoints/EndpointRegistry.php index fd7434c..9524e0b 100644 --- a/src/app/Endpoints/EndpointRegistry.php +++ b/src/app/Endpoints/EndpointRegistry.php @@ -5,6 +5,7 @@ namespace App\Endpoints; use App\Endpoints\Handlers\{ + GraphDataHandler, CallableHandler, DefaultTableHandler, StaticSqlHandler, @@ -135,15 +136,7 @@ public function __construct() 'langs' => new StaticSqlHandler('SELECT code, autonym, name, redirects FROM langs'), - 'graph_data' => new StaticSqlHandler( - "SELECT LEFT(pupdate, 7) AS m, COUNT(*) AS c - FROM pages - WHERE target != '' - GROUP BY LEFT(pupdate, 7) - ORDER BY LEFT(pupdate, 7) ASC - ", - applyOrder: false, - ), + 'graph_data' => new GraphDataHandler(), 'user_access' => new FilteredSqlHandler('SELECT id, user_name, created_at FROM access_keys'), diff --git a/src/app/Endpoints/Handlers/GraphDataHandler.php b/src/app/Endpoints/Handlers/GraphDataHandler.php new file mode 100644 index 0000000..4f9414a --- /dev/null +++ b/src/app/Endpoints/Handlers/GraphDataHandler.php @@ -0,0 +1,37 @@ +applyFilters($sql); + + $sql .= " GROUP BY LEFT(p.pupdate, 7)"; + + return new QuerySpec($sql, $params, defaultOrder: 'date ASC'); + } + + public function handle1(EndpointContext $ctx): QuerySpec + { + $sql = "SELECT DISTINCT YEAR(p.pupdate) AS year, count(*) as count + FROM pages p + LEFT JOIN categories ca ON p.cat = ca.category + "; + [$sql, $params] = $ctx->applyFilters($sql); + + $sql .= " GROUP BY 1"; + + return new QuerySpec($sql, $params, defaultOrder: '1 ASC'); + } +} diff --git a/src/app/Formatting/GraphDataFormatter.php b/src/app/Formatting/GraphDataFormatter.php new file mode 100644 index 0000000..15eb41e --- /dev/null +++ b/src/app/Formatting/GraphDataFormatter.php @@ -0,0 +1,17 @@ + array_column($rows, 'date'), + 'counts' => array_column($rows, 'count'), + ]; + return $result; + } +} diff --git a/src/app/Formatting/ResponseBuilder.php b/src/app/Formatting/ResponseBuilder.php index 891713c..e283b16 100644 --- a/src/app/Formatting/ResponseBuilder.php +++ b/src/app/Formatting/ResponseBuilder.php @@ -5,6 +5,9 @@ namespace App\Formatting; use App\Endpoints\EndpointContext; +use App\Formatting\GraphDataFormatter; +use App\Formatting\LeaderboardFormatter; +use App\Formatting\LangsFormatter; use App\Http\Environment; final class ResponseBuilder @@ -12,6 +15,7 @@ final class ResponseBuilder public function format(string $get, array $results): array { return match ($get) { + 'graph_data' => GraphDataFormatter::format($results), 'leaderboard_table_formated' => LeaderboardFormatter::format($results), 'langs' => LangsFormatter::format($results), default => $results, diff --git a/src/app/Logger.php b/src/app/Logger.php index cdaa144..7205455 100644 --- a/src/app/Logger.php +++ b/src/app/Logger.php @@ -13,7 +13,6 @@ private static function isDebug(): bool return self::$debug ??= ((getenv('APP_ENV') ?: ($_ENV['APP_ENV'] ?? '')) === 'development'); } - /** يُكتب في سجل الخادم فقط، وفي وضع development فقط */ public static function debug(mixed $s): void { if (self::isDebug()) { @@ -21,7 +20,6 @@ public static function debug(mixed $s): void } } - /** يُكتب دائماً في سجل الخادم، ولا يصل للمستخدم أبداً */ public static function error(string $message): void { error_log($message); diff --git a/src/app/endpoint_params.json b/src/app/endpoint_params.json index e202a65..faddf34 100644 --- a/src/app/endpoint_params.json +++ b/src/app/endpoint_params.json @@ -1098,7 +1098,22 @@ }, "graph_data": { "columns": [], - "params": [] + "params": [ + { + "name": "user", + "column": "p.user", + "type": "text", + "placeholder": "Username", + "no_empty_value": false + }, + { + "name": "lang", + "column": "p.lang", + "type": "text", + "placeholder": "Language code", + "no_empty_value": false + } + ] }, "users_by_last_pupdate": { "columns": [], diff --git a/src/app/subs/missing_exists.php b/src/app/subs/missing_exists.php index 1adb9ce..10f6c63 100644 --- a/src/app/subs/missing_exists.php +++ b/src/app/subs/missing_exists.php @@ -53,7 +53,6 @@ function exists_statics_by_category($endpoint_params) $params = [$category]; return [$qua, $params, ""]; - } function missing_by_lang_and_category($endpoint_params) @@ -101,14 +100,13 @@ function missing_by_lang_and_category($endpoint_params) c.category = ? AND aq.target IS NULL - /* to work with valid langs */ AND EXISTS ( SELECT 1 FROM langs la WHERE la.code = ? ) SQL; + /* to work with valid langs */ $params = [$lang_code, $category, $lang_code]; return [$qua, $params, $error]; - } @@ -156,14 +154,13 @@ function exists_by_lang_and_category($endpoint_params) c.category = ? AND aq.target IS NOT NULL - /* to work with valid langs */ AND EXISTS ( SELECT 1 FROM langs la WHERE la.code = ? ) SQL; + /* to work with valid langs */ $params = [$lang_code, $category, $lang_code]; return [$qua, $params, ""]; - } function statics_by_category($endpoint_params) @@ -196,5 +193,4 @@ function statics_by_category($endpoint_params) $params = [$category]; return [$qua, $params, ""]; - } From 93756462c4d3b2895b1812ff35d03885c8913e89 Mon Sep 17 00:00:00 2001 From: ibrahem Qasim Date: Tue, 6 Oct 2026 07:10:32 +0300 Subject: [PATCH 2/7] Update endpoint_params.json --- src/app/endpoint_params.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/endpoint_params.json b/src/app/endpoint_params.json index faddf34..0eee06e 100644 --- a/src/app/endpoint_params.json +++ b/src/app/endpoint_params.json @@ -1099,6 +1099,13 @@ "graph_data": { "columns": [], "params": [ + { + "name": "year", + "column": "YEAR(p.pupdate)", + "type": "number", + "placeholder": "year of date", + "no_empty_value": true + }, { "name": "user", "column": "p.user", From b45c30683b8a8ebb96abc58cdd1838921ff1dbbd Mon Sep 17 00:00:00 2001 From: ibrahem Qasim Date: Wed, 7 Oct 2026 02:18:19 +0300 Subject: [PATCH 3/7] Update ResponseBuilder.php --- src/app/Formatting/ResponseBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/Formatting/ResponseBuilder.php b/src/app/Formatting/ResponseBuilder.php index e283b16..ecaac7a 100644 --- a/src/app/Formatting/ResponseBuilder.php +++ b/src/app/Formatting/ResponseBuilder.php @@ -15,7 +15,7 @@ final class ResponseBuilder public function format(string $get, array $results): array { return match ($get) { - 'graph_data' => GraphDataFormatter::format($results), + // 'graph_data' => GraphDataFormatter::format($results), 'leaderboard_table_formated' => LeaderboardFormatter::format($results), 'langs' => LangsFormatter::format($results), default => $results, From e91cd24b1ec12758c6ba8fc135ef688cb70bd924 Mon Sep 17 00:00:00 2001 From: ibrahem Qasim Date: Wed, 7 Oct 2026 02:35:41 +0300 Subject: [PATCH 4/7] Centralize campaign/category filtering Introduce EndpointContext::applyCampaignCategory (with PATTERN and InputSanitizer) to centralize campaign/category filtering and sanitization. Update GraphDataHandler and PagesHandler to exclude campaign/cat/category from applyFilters and call the new method. Remove the duplicated GraphDataHandler::handle1 and streamline query construction. --- src/app/Endpoints/EndpointContext.php | 29 +++++++++++++++++++ .../Endpoints/Handlers/GraphDataHandler.php | 19 ++++-------- src/app/Endpoints/Handlers/PagesHandler.php | 23 ++------------- src/app/endpoint_params.json | 19 ++++++++++++ 4 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/app/Endpoints/EndpointContext.php b/src/app/Endpoints/EndpointContext.php index 7fae402..bdb91d9 100644 --- a/src/app/Endpoints/EndpointContext.php +++ b/src/app/Endpoints/EndpointContext.php @@ -1,15 +1,19 @@ data, $this->group); } + + /** @return array{0: string, 1: array} [sql, params] */ + public function applyCampaignCategory( + string $sql, + array $params + ): array { + + // Apply campaign/category filters + $campaign = InputSanitizer::match($this->request->get('campaign') ?? '', self::PATTERN); + $category = InputSanitizer::match( + $this->request->get('category') ?? $this->request->get('cat') ?? '', + self::PATTERN + ); + + $glue = FilterBuilder::glue($sql); + + if ($category !== null) { + $sql .= "$glue p.cat = ?"; + $params[] = $category; + } elseif ($campaign !== null) { + $sql .= "$glue ca.campaign = ?"; + $params[] = $campaign; + } + return [$sql, $params]; + } } diff --git a/src/app/Endpoints/Handlers/GraphDataHandler.php b/src/app/Endpoints/Handlers/GraphDataHandler.php index 4f9414a..3f09682 100644 --- a/src/app/Endpoints/Handlers/GraphDataHandler.php +++ b/src/app/Endpoints/Handlers/GraphDataHandler.php @@ -12,26 +12,17 @@ public function handle(EndpointContext $ctx): QuerySpec { $sql = "SELECT DISTINCT LEFT(p.pupdate, 7) AS date, COUNT(*) AS count FROM pages p + LEFT JOIN categories ca ON p.cat = ca.category WHERE p.target != '' "; - [$sql, $params] = $ctx->applyFilters($sql); + [$sql, $params] = $ctx->applyFilters($sql, ['campaign', 'cat', 'category']); + + // Apply campaign/category filters + [$sql, $params] = $ctx->applyCampaignCategory($sql, $params); $sql .= " GROUP BY LEFT(p.pupdate, 7)"; return new QuerySpec($sql, $params, defaultOrder: 'date ASC'); } - - public function handle1(EndpointContext $ctx): QuerySpec - { - $sql = "SELECT DISTINCT YEAR(p.pupdate) AS year, count(*) as count - FROM pages p - LEFT JOIN categories ca ON p.cat = ca.category - "; - [$sql, $params] = $ctx->applyFilters($sql); - - $sql .= " GROUP BY 1"; - - return new QuerySpec($sql, $params, defaultOrder: '1 ASC'); - } } diff --git a/src/app/Endpoints/Handlers/PagesHandler.php b/src/app/Endpoints/Handlers/PagesHandler.php index 647f1ea..89516fd 100644 --- a/src/app/Endpoints/Handlers/PagesHandler.php +++ b/src/app/Endpoints/Handlers/PagesHandler.php @@ -3,8 +3,6 @@ declare(strict_types=1); namespace App\Endpoints\Handlers; -use App\Query\FilterBuilder; -use App\Query\InputSanitizer; use App\Endpoints\{EndpointContext, EndpointHandler, QuerySpec}; @@ -13,8 +11,6 @@ final class PagesHandler implements EndpointHandler private const DEFAULT_SELECT = 'title, word, translate_type, cat, lang, user, target, date, pupdate, add_date, deleted, mdwiki_revid, campaign'; - private const PATTERN = '/^[A-Za-z0-9- ]+$/'; - /** @param 'pages'|'pages_users' $table يُمرَّر ثابتاً من Registry */ public function __construct(private string $table) {} @@ -26,24 +22,11 @@ public function handle(EndpointContext $ctx): QuerySpec FROM `{$this->table}` p LEFT JOIN categories ca ON p.cat = ca.category"; - // campaign / cat / category تُعالج يدوياً أدناه + // campaign / cat / category are handled manually below [$sql, $params] = $ctx->applyFilters($sql, ['campaign', 'cat', 'category']); - $campaign = InputSanitizer::match($ctx->request->get('campaign') ?? '', self::PATTERN); - $category = InputSanitizer::match( - $ctx->request->get('category') ?? $ctx->request->get('cat') ?? '', - self::PATTERN - ); - - $glue = FilterBuilder::glue($sql); - - if ($category !== null) { - $sql .= "$glue p.cat = ?"; - $params[] = $category; - } elseif ($campaign !== null) { - $sql .= "$glue ca.campaign = ?"; - $params[] = $campaign; - } + // Apply campaign/category filters + [$sql, $params] = $ctx->applyCampaignCategory($sql, $params); return new QuerySpec($sql, $params); } diff --git a/src/app/endpoint_params.json b/src/app/endpoint_params.json index 0eee06e..7f32c91 100644 --- a/src/app/endpoint_params.json +++ b/src/app/endpoint_params.json @@ -1099,6 +1099,13 @@ "graph_data": { "columns": [], "params": [ + { + "name": "month", + "column": "MONTH(p.pupdate)", + "type": "number", + "placeholder": "month of date", + "no_empty_value": true + }, { "name": "year", "column": "YEAR(p.pupdate)", @@ -1119,6 +1126,18 @@ "type": "text", "placeholder": "Language code", "no_empty_value": false + }, + { + "name": "category", + "column": "p.cat", + "type": "text", + "placeholder": "Category" + }, + { + "name": "campaign", + "column": "p.campaign", + "type": "text", + "placeholder": "Campaign" } ] }, From a43181be103e7dc2e6a2d77ef9fb9a9979bf6a68 Mon Sep 17 00:00:00 2001 From: ibrahem Qasim Date: Wed, 7 Oct 2026 03:42:19 +0300 Subject: [PATCH 5/7] Add language-year endpoint and filter fixes This change adds the get_lang_years endpoint, replacing the old user_lang_status alias with a proper language-years query and updating the API metadata and docs. It also makes filter handling more consistent by treating empty and 'All' values as inactive, fixes category/campaign validation, and adds the user_group filter support for graph_data with the required join. --- README.md | 2 +- src/app/Endpoints/EndpointContext.php | 4 +-- src/app/Endpoints/EndpointRegistry.php | 10 ++++-- .../Endpoints/Handlers/GraphDataHandler.php | 2 ++ src/app/Endpoints/Handlers/PagesHandler.php | 3 +- src/app/Query/FilterBuilder.php | 35 +++++++++++++++---- src/app/endpoint_params.json | 19 ++++++++-- src/app/request.php | 18 ++++++---- src/openapi.json | 25 +++++++++++++ 9 files changed, 96 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 20707d0..a6036bb 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ All endpoints accept **HTTP GET** requests. The API uses a single entry point (` | `/api.php?get=top_users` | GET | Top users by targets, words, views | | `/api.php?get=translate_type` | GET | Translation types (lead/full) | | `/api.php?get=user_access` | GET | Access keys with usernames | -| `/api.php?get=user_lang_status` | GET | User status by language (redirects to user_status) | +| `/api.php?get=get_lang_years` | GET | User status by language (redirects to user_status) | | `/api.php?get=user_status` | GET | User status by language with year/select options | | `/api.php?get=user_views2` | GET | Page views filtered by a specific user (alias) | | `/api.php?get=user_views` | GET | Page views filtered by a specific user | diff --git a/src/app/Endpoints/EndpointContext.php b/src/app/Endpoints/EndpointContext.php index bdb91d9..a505294 100644 --- a/src/app/Endpoints/EndpointContext.php +++ b/src/app/Endpoints/EndpointContext.php @@ -62,10 +62,10 @@ public function applyCampaignCategory( $glue = FilterBuilder::glue($sql); - if ($category !== null) { + if (FilterBuilder::isValid($category)) { $sql .= "$glue p.cat = ?"; $params[] = $category; - } elseif ($campaign !== null) { + } elseif (FilterBuilder::isValid($campaign)) { $sql .= "$glue ca.campaign = ?"; $params[] = $campaign; } diff --git a/src/app/Endpoints/EndpointRegistry.php b/src/app/Endpoints/EndpointRegistry.php index 9524e0b..f57e485 100644 --- a/src/app/Endpoints/EndpointRegistry.php +++ b/src/app/Endpoints/EndpointRegistry.php @@ -73,7 +73,7 @@ final class EndpointRegistry 'in_process', 'pages_with_views', - 'user_lang_status', + 'get_lang_years', 'user_status', 'pages_by_user_or_lang', 'users_by_last_pupdate', @@ -205,7 +205,13 @@ public function __construct() ), 'user_status' => new UserStatusHandler(), - 'user_lang_status' => new UserStatusHandler(), + + 'get_lang_years' => new FilteredSqlHandler( + 'SELECT DISTINCT YEAR(p.pupdate) as year + FROM pages p + LEFT JOIN categories ca ON p.cat = ca.category', + ), + 'pages' => new PagesHandler('pages'), 'pages_users' => new PagesHandler('pages_users'), ]; diff --git a/src/app/Endpoints/Handlers/GraphDataHandler.php b/src/app/Endpoints/Handlers/GraphDataHandler.php index 3f09682..3b0bd21 100644 --- a/src/app/Endpoints/Handlers/GraphDataHandler.php +++ b/src/app/Endpoints/Handlers/GraphDataHandler.php @@ -10,9 +10,11 @@ final class GraphDataHandler implements EndpointHandler { public function handle(EndpointContext $ctx): QuerySpec { + // api.php?get=graph_data&year=All&month=&category=&campaign=All&user_group=all $sql = "SELECT DISTINCT LEFT(p.pupdate, 7) AS date, COUNT(*) AS count FROM pages p LEFT JOIN categories ca ON p.cat = ca.category + LEFT JOIN users u ON p.user = u.username WHERE p.target != '' "; diff --git a/src/app/Endpoints/Handlers/PagesHandler.php b/src/app/Endpoints/Handlers/PagesHandler.php index 89516fd..f9a06ef 100644 --- a/src/app/Endpoints/Handlers/PagesHandler.php +++ b/src/app/Endpoints/Handlers/PagesHandler.php @@ -20,7 +20,8 @@ public function handle(EndpointContext $ctx): QuerySpec $sql = "SELECT {$ctx->distinct}{$select} FROM `{$this->table}` p - LEFT JOIN categories ca ON p.cat = ca.category"; + LEFT JOIN categories ca ON p.cat = ca.category + "; // campaign / cat / category are handled manually below [$sql, $params] = $ctx->applyFilters($sql, ['campaign', 'cat', 'category']); diff --git a/src/app/Query/FilterBuilder.php b/src/app/Query/FilterBuilder.php index 2796597..d999944 100644 --- a/src/app/Query/FilterBuilder.php +++ b/src/app/Query/FilterBuilder.php @@ -1,14 +1,26 @@ > $endpointParams - * @param list $ignore أسماء بارامترات تُعالج يدوياً + * @param list $ignore parameters to handled manually * @return array{0: string, 1: array} [sql, params] */ - public static function apply(string $sql, array $endpointParams, Request $request, array $ignore = []): array - { + public static function apply( + string $sql, + array $endpointParams, + Request $request, + array $ignore = [] + ): array { $params = []; foreach (self::filters($endpointParams, $ignore) as $name => $def) { @@ -34,7 +50,7 @@ public static function apply(string $sql, array $endpointParams, Request $reques $value = $request->get($column) ?? ''; } - if ($column === 'limit' || $column === 'select' || strtolower($value) === 'all') { + if ($column === 'limit' || $column === 'select' || !self::isValid($value)) { continue; } if (isset($def['no_empty_value']) && empty($value)) { @@ -71,7 +87,12 @@ private static function filters(array $endpointParams, array $ignore): array /** @return array{0: string, 1: array} */ private static function condition( - string $sql, string $name, string $column, string $value, array $def, Request $request + string $sql, + string $name, + string $column, + string $value, + array $def, + Request $request ): array { $glue = self::glue($sql); diff --git a/src/app/endpoint_params.json b/src/app/endpoint_params.json index 7f32c91..309e916 100644 --- a/src/app/endpoint_params.json +++ b/src/app/endpoint_params.json @@ -1099,6 +1099,12 @@ "graph_data": { "columns": [], "params": [ + { + "name": "user_group", + "column": "u.user_group", + "type": "text", + "placeholder": "User Group Name" + }, { "name": "month", "column": "MONTH(p.pupdate)", @@ -1252,7 +1258,16 @@ } ] }, - "user_lang_status": { - "redirect": "user_status" + "get_lang_years": { + "columns": [], + "params": [ + { + "name": "lang", + "column": "p.lang", + "type": "text", + "placeholder": "Language code", + "no_empty_value": false + } + ] } } diff --git a/src/app/request.php b/src/app/request.php index 8a6ca53..5eee8de 100644 --- a/src/app/request.php +++ b/src/app/request.php @@ -329,19 +329,23 @@ function enabled(string $key): bool $query = add_group($query, $endpoint_data, $get_group_value); break; - case 'user_lang_status': // now at UserStatusHandler.php - case 'user_status': + case 'get_lang_years': + $qua = "SELECT DISTINCT YEAR(p.pupdate) as year + FROM pages p + LEFT JOIN categories ca ON p.cat = ca.category + "; + [$query, $params] = add_li_params($qua, [], $endpoint_params); + break; - $SELECT = ($SELECT == "*" || $SELECT == "year") ? "YEAR(p.pupdate) as year" : $SELECT; + case 'user_status': // now at UserStatusHandler.php + $SELECT = ($SELECT == "*" || $SELECT == "year") ? "YEAR(p.pupdate) as year" : $SELECT; $qua = "SELECT DISTINCT $SELECT FROM pages p - LEFT JOIN categories ca - ON p.cat = ca.category - "; + LEFT JOIN categories ca ON p.cat = ca.category + "; [$query, $params] = add_li_params($qua, [], $endpoint_params); - break; case 'users_by_last_pupdate': diff --git a/src/openapi.json b/src/openapi.json index aa26421..8057457 100644 --- a/src/openapi.json +++ b/src/openapi.json @@ -1697,6 +1697,31 @@ } } } + }, + "/api.php?get=get_lang_years": { + "get": { + "summary": "", + "description": "list of years of language", + "tags": [ + "languages" + ], + "parameters": [ + { + "in": "query", + "name": "lang", + "description": "Language code", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/Success" + } + } + } } } } From 08385a378fcb024d1c7cfe546e1440f8911e3bb1 Mon Sep 17 00:00:00 2001 From: ibrahem Qasim Date: Wed, 7 Oct 2026 05:50:18 +0300 Subject: [PATCH 6/7] Replace legacy status endpoint Removes the old status endpoint and its docs/config entries, and replaces it with the newer user data status flow. The endpoint registry now exposes user_status and user_data_status, backed by a dedicated handler and formatter so the API reflects the current status reporting model. --- README.md | 1 - _works_files/tree.md | 3 +- docs/new-structure-oc.md | 157 ++++++++++-------- src/app/Endpoints/EndpointContext.php | 4 + src/app/Endpoints/EndpointRegistry.php | 9 +- src/app/Endpoints/Handlers/StatusHandler.php | 47 ------ .../Handlers/UserDataStatusHandler.php | 29 ++++ src/app/Formatting/ResponseBuilder.php | 4 +- .../Formatting/UserDataStatusFormatter.php | 29 ++++ src/app/README.md | 2 +- src/app/README_old.md | 1 - src/app/bootstrap.php | 1 - src/app/endpoint_params.json | 30 ---- src/app/request.php | 5 - src/app/status.php | 59 ------- src/openapi.json | 31 ---- 16 files changed, 162 insertions(+), 250 deletions(-) delete mode 100644 src/app/Endpoints/Handlers/StatusHandler.php create mode 100644 src/app/Endpoints/Handlers/UserDataStatusHandler.php create mode 100644 src/app/Formatting/UserDataStatusFormatter.php delete mode 100644 src/app/status.php diff --git a/README.md b/README.md index a6036bb..acd749b 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,6 @@ All endpoints accept **HTTP GET** requests. The API uses a single entry point (` | `/api.php?get=revids` | GET | MDWiki revision IDs for titles | | `/api.php?get=settings` | GET | System configuration settings | | `/api.php?get=statics_by_category` | GET | Count of existing articles grouped by language for a category | -| `/api.php?get=status` | GET | Page publication counts by month (optional filters) | | `/api.php?get=titles` | GET | Page titles with assessments, refs, views, QIDs, words | | `/api.php?get=top_lang_of_users` | GET | Top language per user (by page count) | | `/api.php?get=top_langs` | GET | Top languages by targets, words, views | diff --git a/_works_files/tree.md b/_works_files/tree.md index 687bff2..7177f95 100644 --- a/_works_files/tree.md +++ b/_works_files/tree.md @@ -53,7 +53,6 @@ src/ │ ├── request.php │ ├── select_helps.php │ ├── sql.php -│ └── status.php ├── api.php ├── bootstrap.php ├── index.php @@ -61,4 +60,4 @@ src/ ├── README.md └── request.php -``` \ No newline at end of file +``` diff --git a/docs/new-structure-oc.md b/docs/new-structure-oc.md index 7f79585..5d9e1e3 100644 --- a/docs/new-structure-oc.md +++ b/docs/new-structure-oc.md @@ -176,17 +176,20 @@ td_api/ **Purpose**: Contains the core business logic, independent of any external frameworks or infrastructure. **Key Components**: -- **Entities**: Objects with identity (Page, User, Translation) -- **Value Objects**: Immutable objects without identity (Language, Qid) -- **Repository Interfaces**: Contracts defining data access requirements -- **Domain Services**: Complex business operations that don't fit in entities + +- **Entities**: Objects with identity (Page, User, Translation) +- **Value Objects**: Immutable objects without identity (Language, Qid) +- **Repository Interfaces**: Contracts defining data access requirements +- **Domain Services**: Complex business operations that don't fit in entities **Benefits**: -- Business logic is isolated and testable without database -- Changes to infrastructure don't affect business rules -- Clear boundaries make the codebase easier to understand + +- Business logic is isolated and testable without database +- Changes to infrastructure don't affect business rules +- Clear boundaries make the codebase easier to understand **Migration Example**: + ```php // Current approach (app/request.php) switch ($get) { @@ -209,39 +212,44 @@ class GetPagesAction { **Purpose**: Orchestrates use cases by coordinating domain objects. No business rules here, only coordination. **Key Components**: -- **Actions/Commands**: Handle write operations -- **Queries**: Handle read operations (CQRS pattern) -- **DTOs**: Data structures for crossing layer boundaries -- **Validators**: Input validation and sanitization + +- **Actions/Commands**: Handle write operations +- **Queries**: Handle read operations (CQRS pattern) +- **DTOs**: Data structures for crossing layer boundaries +- **Validators**: Input validation and sanitization **Benefits**: -- Clear entry points for each use case -- Request validation separated from business logic -- Easier to add new features without modifying existing code + +- Clear entry points for each use case +- Request validation separated from business logic +- Easier to add new features without modifying existing code ### 3. Infrastructure Layer (`src/Infrastructure/`) **Purpose**: Contains all technical details and external concerns. **Key Components**: -- **Database**: Concrete repository implementations, connection management -- **Cache**: APCu and other caching implementations -- **Http**: Controllers, middleware, request/response handling -- **External**: Third-party API integrations + +- **Database**: Concrete repository implementations, connection management +- **Cache**: APCu and other caching implementations +- **Http**: Controllers, middleware, request/response handling +- **External**: Third-party API integrations **Benefits**: -- Technical details are isolated -- Easy to swap implementations (e.g., APCu → Redis) -- Database schema changes only affect repository implementations + +- Technical details are isolated +- Easy to swap implementations (e.g., APCu → Redis) +- Database schema changes only affect repository implementations ### 4. Shared Kernel (`src/Shared/`) **Purpose**: Common utilities used across all layers. **Migration Path**: -- Move `app/helps.php` functions to `src/Shared/Sanitizers.php` -- Refactor into static utility classes with clear responsibilities -- Maintain backward compatibility with gradual migration + +- Move `app/helps.php` functions to `src/Shared/Sanitizers.php` +- Refactor into static utility classes with clear responsibilities +- Maintain backward compatibility with gradual migration --- @@ -252,6 +260,7 @@ class GetPagesAction { **Current Risk**: All files in the web root are accessible via HTTP, including `app/sql.php` which contains database credentials. **Solution**: + ``` # Apache/Nginx configuration DocumentRoot /var/www/td_api/public @@ -260,19 +269,22 @@ DocumentRoot /var/www/td_api/public ``` **Benefits**: -- Source code files are not directly accessible -- Configuration files protected from HTTP access -- Prevents accidental exposure of sensitive data + +- Source code files are not directly accessible +- Configuration files protected from HTTP access +- Prevents accidental exposure of sensitive data ### 2. Configuration Management **Current Approach**: + ```php // Hardcoded in sql.php $ts_mycnf = parse_ini_file($this->home_dir . "/confs/db.ini"); ``` **Proposed Approach**: + ```php // config/database.php return [ @@ -292,13 +304,15 @@ return [ ``` **Benefits**: -- Environment-specific configuration via `.env` files -- No hardcoded credentials in source code -- Easy to manage different environments (dev, staging, production) + +- Environment-specific configuration via `.env` files +- No hardcoded credentials in source code +- Easy to manage different environments (dev, staging, production) ### 3. Autoloading and Namespaces **Current**: Manual includes in `app/bootstrap.php` + ```php include_once __DIR__ . '/helps.php'; include_once __DIR__ . '/sql.php'; @@ -306,6 +320,7 @@ include_once __DIR__ . '/sql.php'; ``` **Proposed**: PSR-4 autoloading via Composer + ```json { "autoload": { @@ -317,15 +332,17 @@ include_once __DIR__ . '/sql.php'; ``` **Benefits**: -- No manual include/require statements -- Class loading on-demand -- Namespace-based organization + +- No manual include/require statements +- Class loading on-demand +- Namespace-based organization ### 4. Testing Infrastructure **Current**: Frontend test files (`test/`, `test2/`) mixed with source **Proposed**: Comprehensive test suite + ``` tests/ ├── Unit/ # Fast, isolated tests for domain logic @@ -334,16 +351,18 @@ tests/ ``` **Benefits**: -- Regression prevention -- Confidence when refactoring -- Documentation via tests -- PHPUnit integration for CI/CD + +- Regression prevention +- Confidence when refactoring +- Documentation via tests +- PHPUnit integration for CI/CD ### 5. API Documentation **Current**: `openapi.html` at root, `openapi.json` separate **Proposed**: Organized documentation + ``` docs/ ├── api/ # API usage guides @@ -407,21 +426,20 @@ resources/schemas/ # OpenAPI JSON specs ## File Mapping: Current → Proposed -| Current Location | Proposed Location | Rationale | -|-----------------|-------------------|-----------| -| `app/request.php` | `src/Infrastructure/Http/Controllers/ApiController.php` | HTTP handling belongs in infrastructure | -| `app/sql.php` | `src/Infrastructure/Database/` | Database access is infrastructure concern | -| `app/helps.php` | `src/Shared/Sanitizers.php`, `src/Application/Validators/` | Split into shared utilities and validators | -| `app/QueryBuilder.php` | `src/Infrastructure/Database/QueryBuilders/` | Specific builders for each entity | -| `app/langs/*` | `src/Domain/ValueObjects/Language.php`, `resources/lang/` | Language as value object + translations | -| `app/subs/*` | `src/Infrastructure/Database/QueryBuilders/` | Query building logic | -| `app/leaderboard.php` | `src/Application/Actions/GetLeaderboardAction.php` | Use case in application layer | -| `app/status.php` | `src/Application/Queries/GetTranslationStatusQuery.php` | CQRS query | -| `endpoint_params.json` | `config/endpoints/params.php` | PHP config for better caching | -| `index.php`, `api.php` | `public/index.php` | Single entry point with routing | -| `openapi.html` | `public/swagger-ui/index.html` | Organized documentation | -| `test/`, `test2/` | `tests/Functional/`, `public/assets/` | Separate test suite from frontend assets | -| `x/` | `bin/`, `var/temp/` | Scripts in bin/, temp files in var/ | +| Current Location | Proposed Location | Rationale | +| ---------------------- | ---------------------------------------------------------- | ------------------------------------------ | +| `app/request.php` | `src/Infrastructure/Http/Controllers/ApiController.php` | HTTP handling belongs in infrastructure | +| `app/sql.php` | `src/Infrastructure/Database/` | Database access is infrastructure concern | +| `app/helps.php` | `src/Shared/Sanitizers.php`, `src/Application/Validators/` | Split into shared utilities and validators | +| `app/QueryBuilder.php` | `src/Infrastructure/Database/QueryBuilders/` | Specific builders for each entity | +| `app/langs/*` | `src/Domain/ValueObjects/Language.php`, `resources/lang/` | Language as value object + translations | +| `app/subs/*` | `src/Infrastructure/Database/QueryBuilders/` | Query building logic | +| `app/leaderboard.php` | `src/Application/Actions/GetLeaderboardAction.php` | Use case in application layer | +| `endpoint_params.json` | `config/endpoints/params.php` | PHP config for better caching | +| `index.php`, `api.php` | `public/index.php` | Single entry point with routing | +| `openapi.html` | `public/swagger-ui/index.html` | Organized documentation | +| `test/`, `test2/` | `tests/Functional/`, `public/assets/` | Separate test suite from frontend assets | +| `x/` | `bin/`, `var/temp/` | Scripts in bin/, temp files in var/ | --- @@ -491,29 +509,34 @@ server { ## Benefits Summary ### Maintainability -- **Clear separation of concerns**: Each layer has a single responsibility -- **Easy to navigate**: Developers know exactly where to find code -- **Reduced cognitive load**: Smaller, focused classes instead of large files + +- **Clear separation of concerns**: Each layer has a single responsibility +- **Easy to navigate**: Developers know exactly where to find code +- **Reduced cognitive load**: Smaller, focused classes instead of large files ### Testability -- **Domain layer**: Unit testable without database -- **Infrastructure layer**: Mockable interfaces for testing -- **Integration tests**: Test database queries in isolation + +- **Domain layer**: Unit testable without database +- **Infrastructure layer**: Mockable interfaces for testing +- **Integration tests**: Test database queries in isolation ### Scalability -- **Horizontal scaling**: Stateless design allows multiple servers -- **Caching strategy**: Centralized cache layer easy to optimize -- **Database optimization**: Repository pattern allows query optimization without affecting business logic + +- **Horizontal scaling**: Stateless design allows multiple servers +- **Caching strategy**: Centralized cache layer easy to optimize +- **Database optimization**: Repository pattern allows query optimization without affecting business logic ### Security -- **Defense in depth**: Web root isolation prevents source code exposure -- **Input validation**: Centralized validation layer -- **Environment isolation**: Configuration separated from code + +- **Defense in depth**: Web root isolation prevents source code exposure +- **Input validation**: Centralized validation layer +- **Environment isolation**: Configuration separated from code ### Developer Experience -- **IDE support**: PSR-4 autoloading enables better autocomplete -- **Type safety**: Gradual introduction of type hints -- **Documentation**: Clear architecture boundaries serve as documentation + +- **IDE support**: PSR-4 autoloading enables better autocomplete +- **Type safety**: Gradual introduction of type hints +- **Documentation**: Clear architecture boundaries serve as documentation --- diff --git a/src/app/Endpoints/EndpointContext.php b/src/app/Endpoints/EndpointContext.php index a505294..3e28073 100644 --- a/src/app/Endpoints/EndpointContext.php +++ b/src/app/Endpoints/EndpointContext.php @@ -71,4 +71,8 @@ public function applyCampaignCategory( } return [$sql, $params]; } + public function isValid(string $value): bool + { + return FilterBuilder::isValid($value); + } } diff --git a/src/app/Endpoints/EndpointRegistry.php b/src/app/Endpoints/EndpointRegistry.php index f57e485..44c6bf6 100644 --- a/src/app/Endpoints/EndpointRegistry.php +++ b/src/app/Endpoints/EndpointRegistry.php @@ -20,7 +20,7 @@ PagesByUserOrLangHandler, UserStatusHandler, PagesHandler, - StatusHandler, + UserDataStatusHandler, }; use function API\Missing\{ @@ -121,7 +121,10 @@ public function __construct() left join refs_counts rc on rc.r_title = ase.title left join words w on w.w_title = ase.title" ), - 'status' => new StatusHandler(), + + 'user_status' => new UserStatusHandler(), + 'user_data_status' => new UserDataStatusHandler(), + 'top_langs' => new CallableHandler(fn($c): array => top_langs($c->params)), 'top_users' => new CallableHandler(fn($c): array => top_users($c->params)), 'top_lang_of_users' => new CallableHandler(fn($c): array => top_lang_of_users($c->params)), @@ -204,8 +207,6 @@ public function __construct() 'SELECT lang, autonym FROM pages_users p LEFT JOIN langs la ON lang = la.code GROUP BY lang' ), - 'user_status' => new UserStatusHandler(), - 'get_lang_years' => new FilteredSqlHandler( 'SELECT DISTINCT YEAR(p.pupdate) as year FROM pages p diff --git a/src/app/Endpoints/Handlers/StatusHandler.php b/src/app/Endpoints/Handlers/StatusHandler.php deleted file mode 100644 index c14536d..0000000 --- a/src/app/Endpoints/Handlers/StatusHandler.php +++ /dev/null @@ -1,47 +0,0 @@ -request; - - $sql = "SELECT LEFT(p.pupdate, 7) AS date, COUNT(*) AS count - FROM pages p - LEFT JOIN users u ON p.user = u.username - WHERE p.target != ''"; - $params = []; - - if (($year = InputSanitizer::match($r->get('year'), '/^\d+$/')) !== null) { - $sql .= ' AND YEAR(p.pupdate) = ?'; - $params[] = $year; - } - - if (($group = InputSanitizer::match($r->get('user_group'), self::WORDS)) !== null) { - $sql .= ' AND u.user_group = ?'; - $params[] = $group; - } - - $campaign = InputSanitizer::match($r->get('campaign'), self::WORDS); - $category = InputSanitizer::match($r->get('category') ?? $r->get('cat'), self::WORDS); - - if ($category !== null) { - $sql .= ' AND p.cat = ?'; - $params[] = $category; - } elseif ($campaign !== null) { - $sql .= ' AND p.cat IN (SELECT category FROM categories WHERE campaign = ?)'; - $params[] = $campaign; - } - - return new QuerySpec($sql . ' GROUP BY 1', $params, defaultOrder: '1 ASC'); - } -} diff --git a/src/app/Endpoints/Handlers/UserDataStatusHandler.php b/src/app/Endpoints/Handlers/UserDataStatusHandler.php new file mode 100644 index 0000000..0eec5bf --- /dev/null +++ b/src/app/Endpoints/Handlers/UserDataStatusHandler.php @@ -0,0 +1,29 @@ +request->get('user'); + + if ($ctx->isValid($user)) { + $sql .= "WHERE p.user = ?"; + $params[] = $user; + } + + return new QuerySpec($sql, $params); + } +} diff --git a/src/app/Formatting/ResponseBuilder.php b/src/app/Formatting/ResponseBuilder.php index ecaac7a..aa00183 100644 --- a/src/app/Formatting/ResponseBuilder.php +++ b/src/app/Formatting/ResponseBuilder.php @@ -7,6 +7,7 @@ use App\Endpoints\EndpointContext; use App\Formatting\GraphDataFormatter; use App\Formatting\LeaderboardFormatter; +use App\Formatting\UserDataStatusFormatter; use App\Formatting\LangsFormatter; use App\Http\Environment; @@ -15,7 +16,8 @@ final class ResponseBuilder public function format(string $get, array $results): array { return match ($get) { - // 'graph_data' => GraphDataFormatter::format($results), + // 'graph_data' => GraphDataFormatter::format($results), + 'user_data_status' => UserDataStatusFormatter::format($results), 'leaderboard_table_formated' => LeaderboardFormatter::format($results), 'langs' => LangsFormatter::format($results), default => $results, diff --git a/src/app/Formatting/UserDataStatusFormatter.php b/src/app/Formatting/UserDataStatusFormatter.php new file mode 100644 index 0000000..be68344 --- /dev/null +++ b/src/app/Formatting/UserDataStatusFormatter.php @@ -0,0 +1,29 @@ + [], + "langs" => [], + "camps" => [], + ]; + + foreach ($rows as $row) { + $year = $row['year'] ?? ''; + $lang = $row['lang'] ?? ''; + $campaign = $row['campaign'] ?? ''; + + foreach (['years' => $year, 'langs' => $lang, 'camps' => $campaign] as $bucket => $key) { + $result[$bucket][$key] ??= 0; + $result[$bucket][$key] += 1; + } + } + return $result; + } +} diff --git a/src/app/README.md b/src/app/README.md index 19036df..507dbd2 100644 --- a/src/app/README.md +++ b/src/app/README.md @@ -24,7 +24,7 @@ src/app/ │ │ ├── Pages/ (PagesHandler, PagesWithViewsHandler, PagesByUserOrLangHandler, PagesLangsHandler) │ │ ├── Views/ (ViewsHandler, UserViewsHandler, LangViewsHandler) │ │ ├── Users/ (UsersHandler, UsersByLastPupdateHandler, CoordinatorsHandler, CountPagesHandler) -│ │ ├── Stats/ (LeaderboardHandler, GraphDataHandler, StatusHandler, Top*Handler) +│ │ ├── Stats/ (LeaderboardHandler, GraphDataHandler, UserDataStatusHandler, Top*Handler) │ │ ├── Missing/ (MissingHandler, ExistsHandler, StaticsHandler) │ │ └── Misc/ (LangsHandler, QidsHandler, InProcessHandler, PublishReportsHandler ...) │ └── Queries/ ← Heavy SQL queries (migrated from subs/) diff --git a/src/app/README_old.md b/src/app/README_old.md index cd4c592..2547598 100644 --- a/src/app/README_old.md +++ b/src/app/README_old.md @@ -52,7 +52,6 @@ src/app/ | `sql.php` | `API\SQL` | `Database` class (PDO), `fetch_query_new()` with APCu integration | | `helps.php` | `API\Helps` | `add_li_params()`, `add_order()`, `add_limit()`, `add_offset()`, `sanitize_input()` | | `select_helps.php` | `API\SelectHelps` | `get_select()` builds SELECT clause from `$_GET['select']` | -| `status.php` | `API\Status` | `make_status_query()` for the `/status` endpoint | | `leaderboard.php` | `API\Leaderboard` | `leaderboard_table_format()`, `langs_format()` | | `qids.php` | `API\Qids` | `qids_qua()` for Wikidata QID endpoints | | `subs/missing_exists.php` | `API\Missing` | Complex queries for missing/exists article analysis | diff --git a/src/app/bootstrap.php b/src/app/bootstrap.php index 9bac1ff..7f41127 100644 --- a/src/app/bootstrap.php +++ b/src/app/bootstrap.php @@ -10,7 +10,6 @@ include_once __DIR__ . '/select_helps.php'; include_once __DIR__ . '/qids.php'; include_once __DIR__ . '/leaderboard.php'; -include_once __DIR__ . '/status.php'; include_once __DIR__ . '/subs/titles_infos.php'; include_once __DIR__ . '/subs/missing_exists.php'; diff --git a/src/app/endpoint_params.json b/src/app/endpoint_params.json index 309e916..a46b049 100644 --- a/src/app/endpoint_params.json +++ b/src/app/endpoint_params.json @@ -733,36 +733,6 @@ } ] }, - "status": { - "columns": [], - "params": [ - { - "name": "year", - "column": "year", - "type": "number", - "placeholder": "Year" - }, - { - "name": "user_group", - "column": "user_group", - "type": "text", - "placeholder": "User Group Name" - }, - { - "name": "campaign", - "column": "campaign", - "type": "text", - "placeholder": "Campaign" - }, - { - "name": "cat", - "column": "cat", - "type": "text", - "placeholder": "Category", - "value_can_be_null": true - } - ] - }, "leaderboard_table": { "columns": [ "u.user_group" diff --git a/src/app/request.php b/src/app/request.php index 5eee8de..80d5e9c 100644 --- a/src/app/request.php +++ b/src/app/request.php @@ -12,7 +12,6 @@ use function API\Qids\qids_qua; use function API\Leaderboard\leaderboard_table_format; use function API\Leaderboard\langs_format; -use function API\Status\make_status_query; use function API\TitlesInfos\titles_query; use function API\TitlesInfos\mdwiki_revids; use function API\Missing\exists_statics_by_category; @@ -99,10 +98,6 @@ function enabled(string $key): bool [$query, $params, $error] = titles_query($endpoint_params); break; - case 'status': - [$query, $params, $error] = make_status_query($endpoint_params); - break; - case 'top_lang_of_users': [$query, $params, $error] = top_lang_of_users($endpoint_params); break; diff --git a/src/app/status.php b/src/app/status.php deleted file mode 100644 index e7298f9..0000000 --- a/src/app/status.php +++ /dev/null @@ -1,59 +0,0 @@ - Date: Wed, 7 Oct 2026 06:58:10 +0300 Subject: [PATCH 7/7] . --- .../Formatting/UserDataStatusFormatter.php | 1 + src/app/endpoint_params.json | 1244 +---------------- src/app/request.php | 3 + 3 files changed, 5 insertions(+), 1243 deletions(-) diff --git a/src/app/Formatting/UserDataStatusFormatter.php b/src/app/Formatting/UserDataStatusFormatter.php index be68344..30dc1f6 100644 --- a/src/app/Formatting/UserDataStatusFormatter.php +++ b/src/app/Formatting/UserDataStatusFormatter.php @@ -24,6 +24,7 @@ public static function format(array $rows): array $result[$bucket][$key] += 1; } } + // { "years": { "2021": 6, ... }, "langs": { "ar": 14, ... }, "camps": { "Main": 12, ... } } return $result; } } diff --git a/src/app/endpoint_params.json b/src/app/endpoint_params.json index a46b049..4fdef2c 100644 --- a/src/app/endpoint_params.json +++ b/src/app/endpoint_params.json @@ -1,1243 +1 @@ -{ - "publish_reports": { - "columns": [ - "date", - "title", - "user", - "lang", - "sourcetitle", - "result", - "data" - ], - "params": [ - { - "name": "year", - "column": "YEAR(date)", - "type": "number", - "placeholder": "year of date" - }, - { - "name": "month", - "column": "MONTH(date)", - "type": "number", - "placeholder": "month of date" - }, - { - "name": "title", - "column": "title", - "type": "text", - "placeholder": "Page Title" - }, - { - "name": "user", - "column": "user", - "type": "text", - "placeholder": "user" - }, - { - "name": "lang", - "column": "lang", - "type": "text", - "placeholder": "Language code" - }, - { - "name": "sourcetitle", - "column": "sourcetitle", - "type": "text", - "placeholder": "sourcetitle" - }, - { - "name": "result", - "column": "result", - "type": "text", - "placeholder": "result" - }, - { - "name": "select", - "column": "select", - "type": "text", - "placeholder": "Select fields", - "no_select": true - }, - { - "name": "distinct", - "column": "distinct", - "type": "switch", - "no_select": true - } - ] - }, - "language_settings": { - "columns": [ - "lang_code", - "move_dots", - "expend", - "add_en_lang" - ], - "params": [ - { - "name": "lang_code", - "column": "lang_code", - "type": "text", - "placeholder": "Language code" - } - ] - }, - "publish_reports_stats": { - "columns": [], - "params": [ - { - "name": "lang", - "column": "lang", - "type": "text", - "placeholder": "Language code" - }, - { - "name": "user", - "column": "user", - "type": "text", - "placeholder": "Username" - } - ] - }, - "missing": { - "columns": [], - "params": [ - { - "name": "lang", - "column": "t.code", - "type": "text", - "placeholder": "Language code" - }, - { - "name": "category", - "column": "a.category", - "type": "text", - "placeholder": "Category" - }, - { - "name": "order", - "column": "order", - "type": "text", - "placeholder": "Order by", - "no_select": true - } - ] - }, - "exists_statics_by_category": { - "columns": [], - "params": [ - { - "name": "category", - "column": "a.category", - "type": "text", - "placeholder": "Category", - "default": "RTT", - "required": true - } - ] - }, - "missing_by_lang_and_category": { - "columns": [], - "params": [ - { - "name": "lang", - "column": "t.code", - "type": "text", - "placeholder": "Language code", - "required": true - }, - { - "name": "category", - "column": "a.category", - "type": "text", - "placeholder": "Category", - "default": "RTT" - } - ] - }, - "exists_by_lang_and_category": { - "columns": [], - "params": [ - { - "name": "lang", - "column": "t.code", - "type": "text", - "placeholder": "Language code", - "required": true - }, - { - "name": "category", - "column": "a.category", - "type": "text", - "placeholder": "Category", - "default": "RTT" - } - ] - }, - "titles": { - "columns": [], - "params": [ - { - "name": "title", - "column": "ase.title", - "type": "text", - "placeholder": "Page Title" - }, - { - "name": "importance", - "column": "ase.importance", - "type": "text", - "placeholder": "Importance" - }, - { - "name": "titles", - "column": "ase.title", - "type": "array" - } - ] - }, - "revids": { - "columns": [ - "title", - "revid" - ], - "params": [ - { - "name": "title", - "column": "title", - "type": "text", - "placeholder": "Page Title" - }, - { - "name": "titles", - "column": "title", - "type": "array" - } - ] - }, - "assessments": { - "columns": [ - "title", - "importance" - ], - "params": [ - { - "name": "title", - "column": "title", - "type": "text", - "placeholder": "Page Title" - }, - { - "name": "importance", - "column": "importance", - "type": "text", - "placeholder": "Importance" - }, - { - "name": "distinct", - "column": "distinct", - "type": "switch", - "no_select": true - } - ] - }, - "refs_counts": { - "columns": [ - "r_id", - "r_title", - "r_lead_refs", - "r_all_refs" - ], - "params": [ - { - "name": "title", - "column": "r_title", - "type": "text", - "placeholder": "Page Title" - }, - { - "name": "lead", - "column": "r_lead_refs", - "type": "number", - "placeholder": "Lead Refs Count" - }, - { - "name": "all", - "column": "r_all_refs", - "type": "number", - "placeholder": "All Refs Count" - } - ] - }, - "enwiki_pageviews": { - "columns": [ - "title", - "en_views" - ], - "params": [ - { - "name": "title", - "column": "title", - "type": "text", - "placeholder": "Page Title" - }, - { - "name": "en_views", - "column": "en_views", - "type": "number", - "placeholder": "Views Count" - } - ] - }, - "categories": { - "columns": [ - "category", - "category2", - "display", - "campaign", - "depth", - "is_default" - ], - "params": [ - { - "name": "Depth", - "column": "depth", - "type": "number", - "placeholder": "Depth Level" - }, - { - "name": "campaign", - "column": "campaign", - "type": "text", - "placeholder": "Campaign" - }, - { - "name": "select", - "column": "select", - "type": "text", - "placeholder": "Select fields", - "no_select": true - } - ] - }, - "coordinators": { - "columns": [ - "username", - "is_active" - ], - "params": [ - { - "name": "Username", - "column": "username", - "type": "text", - "placeholder": "Coordinator Username" - } - ] - }, - "pages": { - "columns": [ - "title", - "word", - "translate_type", - "cat", - "lang", - "user", - "target", - "date", - "pupdate", - "add_date", - "deleted", - "mdwiki_revid" - ], - "params": [ - { - "name": "title", - "column": "p.title", - "type": "text", - "placeholder": "Page Title" - }, - { - "name": "lang", - "column": "p.lang", - "type": "text", - "placeholder": "Language code" - }, - { - "name": "user", - "column": "p.user", - "type": "text", - "placeholder": "Username" - }, - { - "name": "target", - "column": "p.target", - "type": "text", - "placeholder": "Target" - }, - { - "name": "cat", - "column": "p.cat", - "type": "text", - "placeholder": "Category" - }, - { - "name": "campaign", - "column": "campaign", - "type": "text", - "placeholder": "Campaign" - }, - { - "name": "group", - "column": "group", - "type": "text", - "placeholder": "Group by field", - "no_select": true, - "options": [] - }, - { - "name": "order", - "column": "order", - "type": "text", - "placeholder": "Order by", - "no_select": true - }, - { - "name": "pupdate", - "column": "p.pupdate", - "type": "text", - "placeholder": "Date of publication" - }, - { - "name": "add_date", - "column": "p.add_date", - "type": "text", - "placeholder": "Date of addition to DB" - }, - { - "name": "limit", - "column": "p.limit", - "type": "number", - "placeholder": "Limit results", - "value": "50", - "no_select": true - }, - { - "name": "offset", - "column": "p.offset", - "type": "number", - "placeholder": "Offset results", - "value": "0", - "no_select": true - }, - { - "name": "year", - "column": "YEAR(p.pupdate)", - "type": "number", - "placeholder": "Year of publication" - }, - { - "name": "date_year", - "column": "YEAR(p.date)", - "type": "number", - "placeholder": "year of date" - }, - { - "name": "select", - "column": "select", - "type": "text", - "placeholder": "Select fields", - "no_select": true, - "options": [ - "count(*)" - ] - }, - { - "name": "translate_type", - "column": "p.translate_type", - "type": "select", - "options": [ - "all", - "lead" - ] - }, - { - "name": "distinct", - "column": "p.distinct", - "type": "switch", - "no_select": true - }, - { - "name": "Deleted", - "column": "p.deleted", - "type": "switch", - "placeholder": "0 or 1" - } - ], - "order_values": { - "pupdate_or_add_date": "GREATEST(UNIX_TIMESTAMP(pupdate), UNIX_TIMESTAMP(add_date))" - } - }, - "pages_with_views": { - "redirect": "pages" - }, - "pages_users": { - "columns": [ - "title", - "word", - "translate_type", - "cat", - "lang", - "user", - "target", - "date", - "pupdate", - "add_date", - "deleted", - "mdwiki_revid" - ], - "params": [ - { - "name": "lang", - "column": "lang", - "type": "text", - "placeholder": "Language code" - }, - { - "name": "user", - "column": "user", - "type": "text", - "placeholder": "Username" - }, - { - "name": "target", - "column": "target", - "type": "text", - "placeholder": "Target" - }, - { - "name": "title", - "column": "title", - "type": "text", - "placeholder": "Page Title" - }, - { - "name": "order", - "column": "order", - "type": "text", - "placeholder": "Order by", - "no_select": true - }, - { - "name": "pupdate", - "column": "pupdate", - "type": "text", - "placeholder": "Date of publication" - }, - { - "name": "add_date", - "column": "add_date", - "type": "text", - "placeholder": "Date of addition to DB" - }, - { - "name": "group", - "column": "group", - "type": "text", - "placeholder": "Group by field", - "no_select": true, - "options": [] - }, - { - "name": "limit", - "column": "limit", - "type": "number", - "placeholder": "Limit results", - "value": "50", - "no_select": true - }, - { - "name": "offset", - "column": "p.offset", - "type": "number", - "placeholder": "Offset results", - "value": "0", - "no_select": true - }, - { - "name": "select", - "column": "select", - "type": "text", - "placeholder": "Select fields", - "no_select": true - }, - { - "name": "distinct", - "column": "distinct", - "type": "switch", - "no_select": true - } - ] - }, - "in_process": { - "columns": [ - "title", - "user", - "lang", - "cat", - "translate_type", - "word", - "add_date" - ], - "params": [ - { - "name": "lang", - "column": "lang", - "type": "text", - "placeholder": "Language code" - }, - { - "name": "cat", - "column": "cat", - "type": "text", - "placeholder": "Category" - }, - { - "name": "user", - "column": "user", - "type": "text", - "placeholder": "Username" - }, - { - "name": "select", - "column": "select", - "type": "text", - "placeholder": "Select fields", - "no_select": true - }, - { - "name": "distinct", - "column": "distinct", - "type": "switch", - "no_select": true - }, - { - "name": "group", - "column": "group", - "type": "text", - "placeholder": "Group by field", - "no_select": true - }, - { - "name": "order", - "column": "order", - "type": "text", - "placeholder": "Order by", - "no_select": true - }, - { - "name": "year", - "column": "YEAR(add_date)", - "type": "number", - "placeholder": "year of date" - } - ] - }, - "pages_by_user_or_lang": { - "columns": [], - "params": [ - { - "name": "lang", - "column": "p.lang", - "type": "text", - "placeholder": "Language code" - }, - { - "name": "user", - "column": "p.user", - "type": "text", - "placeholder": "Username" - }, - { - "name": "year", - "column": "YEAR(p.date)", - "type": "number", - "placeholder": "year of date" - }, - { - "name": "order", - "column": "order", - "type": "text", - "placeholder": "Order by", - "no_select": true - } - ] - }, - "user_access": { - "columns": [], - "params": [ - { - "name": "user_name", - "column": "user_name", - "type": "text", - "placeholder": "Username" - } - ] - }, - "qids": { - "columns": [ - "title", - "qid" - ], - "params": [ - { - "name": "dis", - "column": "dis", - "type": "select", - "options": [ - "", - "empty", - "all", - "duplicate" - ] - } - ] - }, - "qids_others": { - "columns": [ - "title", - "qid" - ], - "params": [ - { - "name": "dis", - "column": "dis", - "type": "select", - "options": [ - "", - "empty", - "all", - "duplicate" - ] - } - ] - }, - "count_pages": { - "columns": [], - "params": [ - { - "name": "target", - "column": "target", - "type": "text", - "placeholder": "Target" - } - ] - }, - "leaderboard_table": { - "columns": [ - "u.user_group" - ], - "params": [ - { - "name": "year", - "column": "YEAR(p.pupdate)", - "type": "number", - "placeholder": "Year of publication" - }, - { - "name": "cat", - "column": "cat", - "type": "text", - "placeholder": "Category", - "value_can_be_null": true - }, - { - "name": "user_group", - "column": "u.user_group", - "type": "text", - "placeholder": "User Group Name" - }, - { - "name": "order", - "column": "order", - "type": "text", - "placeholder": "Order by", - "no_select": true - } - ] - }, - "leaderboard_table_formated": { - "columns": [ - "u.user_group" - ], - "params": [ - { - "name": "year", - "column": "YEAR(p.pupdate)", - "type": "number", - "placeholder": "Year of publication" - }, - { - "name": "cat", - "column": "cat", - "type": "text", - "placeholder": "Category", - "value_can_be_null": true - }, - { - "name": "user_group", - "column": "u.user_group", - "type": "text", - "placeholder": "User Group Name" - }, - { - "name": "order", - "column": "order", - "type": "text", - "placeholder": "Order by", - "no_select": true - } - ] - }, - "lang_views": { - "columns": [], - "params": [ - { - "name": "user", - "column": "p.user", - "type": "text", - "placeholder": "Username" - }, - { - "name": "lang", - "column": "p.lang", - "type": "text", - "placeholder": "Language code" - }, - { - "name": "year", - "column": "YEAR(pupdate)", - "type": "number", - "placeholder": "Year" - } - ] - }, - "lang_views2": { - "columns": [], - "params": [ - { - "name": "user", - "column": "p.user", - "type": "text", - "placeholder": "Username" - }, - { - "name": "lang", - "column": "p.lang", - "type": "text", - "placeholder": "Language code" - }, - { - "name": "year", - "column": "YEAR(pupdate)", - "type": "number", - "placeholder": "Year" - } - ] - }, - "user_views": { - "columns": [], - "params": [ - { - "name": "user", - "column": "p.user", - "type": "text", - "placeholder": "Username" - }, - { - "name": "lang", - "column": "p.lang", - "type": "text", - "placeholder": "Language code" - }, - { - "name": "year", - "column": "YEAR(pupdate)", - "type": "number", - "placeholder": "Year" - } - ] - }, - "user_views2": { - "columns": [], - "params": [ - { - "name": "user", - "column": "p.user", - "type": "text", - "placeholder": "Username" - }, - { - "name": "lang", - "column": "p.lang", - "type": "text", - "placeholder": "Language code" - }, - { - "name": "year", - "column": "YEAR(pupdate)", - "type": "number", - "placeholder": "Year" - } - ] - }, - "users": { - "columns": [ - "user_id", - "username", - "email", - "wiki", - "user_group", - "reg_date" - ], - "params": [ - { - "name": "userlike", - "column": "userlike", - "type": "text", - "placeholder": "Username starts with", - "required": true - }, - { - "name": "wiki", - "column": "wiki", - "type": "text", - "placeholder": "Wiki Name" - }, - { - "name": "user_group", - "column": "user_group", - "type": "text", - "placeholder": "User Group Name", - "no_select": true - } - ] - }, - "views": { - "columns": [], - "params": [ - { - "name": "lang", - "column": "p.lang", - "type": "text", - "placeholder": "Language code" - }, - { - "name": "year", - "column": "YEAR(p.pupdate)", - "type": "number", - "placeholder": "Year of publication" - } - ] - }, - "views_new": { - "columns": [ - "target", - "lang", - "year", - "views" - ], - "params": [ - { - "name": "lang", - "column": "v.lang", - "type": "text", - "placeholder": "Language code" - }, - { - "name": "year", - "column": "YEAR(p.pupdate)", - "type": "number", - "placeholder": "Year of publication" - }, - { - "name": "views", - "column": "v.views", - "type": "number", - "placeholder": "Views" - } - ] - }, - "words": { - "columns": [ - "w_id", - "w_title", - "w_lead_words", - "w_all_words" - ], - "params": [ - { - "name": "title", - "column": "w_title", - "type": "text", - "placeholder": "Page Title" - }, - { - "name": "lead_words", - "column": "w_lead_words", - "type": "number", - "placeholder": "Lead words Count" - }, - { - "name": "all_words", - "column": "w_all_words", - "type": "number", - "placeholder": "Total words Count" - } - ] - }, - "translate_type": { - "columns": [ - "tt_id", - "tt_title", - "tt_lead", - "tt_full" - ], - "params": [ - { - "name": "Lead", - "column": "tt_lead", - "type": "number", - "placeholder": "Lead Translation (0 or 1)" - }, - { - "name": "Full", - "column": "tt_full", - "type": "number", - "placeholder": "Full Translation (0 or 1)" - } - ] - }, - "langs": { - "columns": [ - "code", - "autonym", - "name", - "redirects" - ], - "params": [] - }, - "projects": { - "columns": [ - "g_id", - "g_title" - ], - "params": [] - }, - "pages_users_to_main": { - "columns": [ - "new_target", - "new_user", - "new_qid" - ], - "params": [] - }, - "users_no_inprocess": { - "columns": [ - "user", - "is_active" - ], - "params": [] - }, - "full_translators": { - "columns": [ - "user", - "is_active" - ], - "params": [] - }, - "settings": { - "columns": [ - "title", - "displayed", - "Type", - "value", - "ignored" - ], - "params": [] - }, - "graph_data": { - "columns": [], - "params": [ - { - "name": "user_group", - "column": "u.user_group", - "type": "text", - "placeholder": "User Group Name" - }, - { - "name": "month", - "column": "MONTH(p.pupdate)", - "type": "number", - "placeholder": "month of date", - "no_empty_value": true - }, - { - "name": "year", - "column": "YEAR(p.pupdate)", - "type": "number", - "placeholder": "year of date", - "no_empty_value": true - }, - { - "name": "user", - "column": "p.user", - "type": "text", - "placeholder": "Username", - "no_empty_value": false - }, - { - "name": "lang", - "column": "p.lang", - "type": "text", - "placeholder": "Language code", - "no_empty_value": false - }, - { - "name": "category", - "column": "p.cat", - "type": "text", - "placeholder": "Category" - }, - { - "name": "campaign", - "column": "p.campaign", - "type": "text", - "placeholder": "Campaign" - } - ] - }, - "users_by_last_pupdate": { - "columns": [], - "params": [] - }, - "top_users": { - "columns": [], - "params": [ - { - "name": "year", - "column": "YEAR(p.pupdate)", - "type": "number", - "placeholder": "year of date", - "no_empty_value": true - }, - { - "name": "month", - "column": "MONTH(p.pupdate)", - "type": "number", - "placeholder": "month of date", - "no_empty_value": true - }, - { - "name": "user_group", - "column": "u.user_group", - "type": "text", - "placeholder": "User Group Name", - "no_empty_value": true - }, - { - "name": "cat", - "column": "p.cat", - "type": "text", - "placeholder": "Category", - "no_empty_value": true - } - ] - }, - "top_langs": { - "columns": [], - "params": [ - { - "name": "year", - "column": "YEAR(p.pupdate)", - "type": "number", - "placeholder": "year of date", - "no_empty_value": true - }, - { - "name": "month", - "column": "MONTH(p.pupdate)", - "type": "number", - "placeholder": "month of date", - "no_empty_value": true - }, - { - "name": "user_group", - "column": "u.user_group", - "type": "text", - "placeholder": "User Group Name", - "no_empty_value": true - }, - { - "name": "cat", - "column": "p.cat", - "type": "text", - "placeholder": "Category", - "no_empty_value": true - } - ] - }, - "top_lang_of_users": { - "columns": [], - "params": [ - { - "name": "users", - "column": "p.user", - "type": "array" - } - ] - }, - "user_status": { - "columns": [], - "params": [ - { - "name": "user", - "column": "p.user", - "type": "text", - "placeholder": "Username", - "no_empty_value": false - }, - { - "name": "lang", - "column": "p.lang", - "type": "text", - "placeholder": "Language code", - "no_empty_value": false - }, - { - "name": "select", - "column": "select", - "type": "text", - "placeholder": "Select fields", - "options": [ - "lang", - "campaign", - "cat", - "year" - ] - } - ] - }, - "get_lang_years": { - "columns": [], - "params": [ - { - "name": "lang", - "column": "p.lang", - "type": "text", - "placeholder": "Language code", - "no_empty_value": false - } - ] - } -} +{ "publish_reports": { "columns": [ "date", "title", "user", "lang", "sourcetitle", "result", "data" ], "params": [ { "name": "year", "column": "YEAR(date)", "type": "number", "placeholder": "year of date" }, { "name": "month", "column": "MONTH(date)", "type": "number", "placeholder": "month of date" }, { "name": "title", "column": "title", "type": "text", "placeholder": "Page Title" }, { "name": "user", "column": "user", "type": "text", "placeholder": "user" }, { "name": "lang", "column": "lang", "type": "text", "placeholder": "Language code" }, { "name": "sourcetitle", "column": "sourcetitle", "type": "text", "placeholder": "sourcetitle" }, { "name": "result", "column": "result", "type": "text", "placeholder": "result" }, { "name": "select", "column": "select", "type": "text", "placeholder": "Select fields", "no_select": true }, { "name": "distinct", "column": "distinct", "type": "switch", "no_select": true } ] }, "language_settings": { "columns": [ "lang_code", "move_dots", "expend", "add_en_lang" ], "params": [ { "name": "lang_code", "column": "lang_code", "type": "text", "placeholder": "Language code" } ] }, "publish_reports_stats": { "columns": [], "params": [ { "name": "lang", "column": "lang", "type": "text", "placeholder": "Language code" }, { "name": "user", "column": "user", "type": "text", "placeholder": "Username" } ] }, "missing": { "columns": [], "params": [ { "name": "lang", "column": "t.code", "type": "text", "placeholder": "Language code" }, { "name": "category", "column": "a.category", "type": "text", "placeholder": "Category" }, { "name": "order", "column": "order", "type": "text", "placeholder": "Order by", "no_select": true } ] }, "exists_statics_by_category": { "columns": [], "params": [ { "name": "category", "column": "a.category", "type": "text", "placeholder": "Category", "default": "RTT", "required": true } ] }, "missing_by_lang_and_category": { "columns": [], "params": [ { "name": "lang", "column": "t.code", "type": "text", "placeholder": "Language code", "required": true }, { "name": "category", "column": "a.category", "type": "text", "placeholder": "Category", "default": "RTT" } ] }, "exists_by_lang_and_category": { "columns": [], "params": [ { "name": "lang", "column": "t.code", "type": "text", "placeholder": "Language code", "required": true }, { "name": "category", "column": "a.category", "type": "text", "placeholder": "Category", "default": "RTT" } ] }, "titles": { "columns": [], "params": [ { "name": "title", "column": "ase.title", "type": "text", "placeholder": "Page Title" }, { "name": "importance", "column": "ase.importance", "type": "text", "placeholder": "Importance" }, { "name": "titles", "column": "ase.title", "type": "array" } ] }, "revids": { "columns": [ "title", "revid" ], "params": [ { "name": "title", "column": "title", "type": "text", "placeholder": "Page Title" }, { "name": "titles", "column": "title", "type": "array" } ] }, "assessments": { "columns": [ "title", "importance" ], "params": [ { "name": "title", "column": "title", "type": "text", "placeholder": "Page Title" }, { "name": "importance", "column": "importance", "type": "text", "placeholder": "Importance" }, { "name": "distinct", "column": "distinct", "type": "switch", "no_select": true } ] }, "refs_counts": { "columns": [ "r_id", "r_title", "r_lead_refs", "r_all_refs" ], "params": [ { "name": "title", "column": "r_title", "type": "text", "placeholder": "Page Title" }, { "name": "lead", "column": "r_lead_refs", "type": "number", "placeholder": "Lead Refs Count" }, { "name": "all", "column": "r_all_refs", "type": "number", "placeholder": "All Refs Count" } ] }, "enwiki_pageviews": { "columns": [ "title", "en_views" ], "params": [ { "name": "title", "column": "title", "type": "text", "placeholder": "Page Title" }, { "name": "en_views", "column": "en_views", "type": "number", "placeholder": "Views Count" } ] }, "categories": { "columns": [ "category", "category2", "display", "campaign", "depth", "is_default" ], "params": [ { "name": "Depth", "column": "depth", "type": "number", "placeholder": "Depth Level" }, { "name": "campaign", "column": "campaign", "type": "text", "placeholder": "Campaign" }, { "name": "select", "column": "select", "type": "text", "placeholder": "Select fields", "no_select": true } ] }, "coordinators": { "columns": [ "username", "is_active" ], "params": [ { "name": "Username", "column": "username", "type": "text", "placeholder": "Coordinator Username" } ] }, "pages": { "columns": [ "title", "word", "translate_type", "cat", "lang", "user", "target", "date", "pupdate", "add_date", "deleted", "mdwiki_revid" ], "params": [ { "name": "title", "column": "p.title", "type": "text", "placeholder": "Page Title" }, { "name": "lang", "column": "p.lang", "type": "text", "placeholder": "Language code" }, { "name": "user", "column": "p.user", "type": "text", "placeholder": "Username" }, { "name": "target", "column": "p.target", "type": "text", "placeholder": "Target" }, { "name": "cat", "column": "p.cat", "type": "text", "placeholder": "Category" }, { "name": "campaign", "column": "campaign", "type": "text", "placeholder": "Campaign" }, { "name": "group", "column": "group", "type": "text", "placeholder": "Group by field", "no_select": true, "options": [] }, { "name": "order", "column": "order", "type": "text", "placeholder": "Order by", "no_select": true }, { "name": "pupdate", "column": "p.pupdate", "type": "text", "placeholder": "Date of publication" }, { "name": "add_date", "column": "p.add_date", "type": "text", "placeholder": "Date of addition to DB" }, { "name": "limit", "column": "p.limit", "type": "number", "placeholder": "Limit results", "value": "50", "no_select": true }, { "name": "offset", "column": "p.offset", "type": "number", "placeholder": "Offset results", "value": "0", "no_select": true }, { "name": "year", "column": "YEAR(p.pupdate)", "type": "number", "placeholder": "Year of publication" }, { "name": "date_year", "column": "YEAR(p.date)", "type": "number", "placeholder": "year of date" }, { "name": "select", "column": "select", "type": "text", "placeholder": "Select fields", "no_select": true, "options": [ "count(*)" ] }, { "name": "translate_type", "column": "p.translate_type", "type": "select", "options": [ "all", "lead" ] }, { "name": "distinct", "column": "p.distinct", "type": "switch", "no_select": true }, { "name": "Deleted", "column": "p.deleted", "type": "switch", "placeholder": "0 or 1" } ], "order_values": { "pupdate_or_add_date": "GREATEST(UNIX_TIMESTAMP(pupdate), UNIX_TIMESTAMP(add_date))" } }, "pages_with_views": { "redirect": "pages" }, "pages_users": { "columns": [ "title", "word", "translate_type", "cat", "lang", "user", "target", "date", "pupdate", "add_date", "deleted", "mdwiki_revid" ], "params": [ { "name": "lang", "column": "lang", "type": "text", "placeholder": "Language code" }, { "name": "user", "column": "user", "type": "text", "placeholder": "Username" }, { "name": "target", "column": "target", "type": "text", "placeholder": "Target" }, { "name": "title", "column": "title", "type": "text", "placeholder": "Page Title" }, { "name": "order", "column": "order", "type": "text", "placeholder": "Order by", "no_select": true }, { "name": "pupdate", "column": "pupdate", "type": "text", "placeholder": "Date of publication" }, { "name": "add_date", "column": "add_date", "type": "text", "placeholder": "Date of addition to DB" }, { "name": "group", "column": "group", "type": "text", "placeholder": "Group by field", "no_select": true, "options": [] }, { "name": "limit", "column": "limit", "type": "number", "placeholder": "Limit results", "value": "50", "no_select": true }, { "name": "offset", "column": "p.offset", "type": "number", "placeholder": "Offset results", "value": "0", "no_select": true }, { "name": "select", "column": "select", "type": "text", "placeholder": "Select fields", "no_select": true }, { "name": "distinct", "column": "distinct", "type": "switch", "no_select": true } ] }, "in_process": { "columns": [ "title", "user", "lang", "cat", "translate_type", "word", "add_date" ], "params": [ { "name": "lang", "column": "lang", "type": "text", "placeholder": "Language code" }, { "name": "cat", "column": "cat", "type": "text", "placeholder": "Category" }, { "name": "user", "column": "user", "type": "text", "placeholder": "Username" }, { "name": "select", "column": "select", "type": "text", "placeholder": "Select fields", "no_select": true }, { "name": "distinct", "column": "distinct", "type": "switch", "no_select": true }, { "name": "group", "column": "group", "type": "text", "placeholder": "Group by field", "no_select": true }, { "name": "order", "column": "order", "type": "text", "placeholder": "Order by", "no_select": true }, { "name": "year", "column": "YEAR(add_date)", "type": "number", "placeholder": "year of date" } ] }, "pages_by_user_or_lang": { "columns": [], "params": [ { "name": "lang", "column": "p.lang", "type": "text", "placeholder": "Language code" }, { "name": "user", "column": "p.user", "type": "text", "placeholder": "Username" }, { "name": "year", "column": "YEAR(p.date)", "type": "number", "placeholder": "year of date" }, { "name": "order", "column": "order", "type": "text", "placeholder": "Order by", "no_select": true } ] }, "user_access": { "columns": [], "params": [ { "name": "user_name", "column": "user_name", "type": "text", "placeholder": "Username" } ] }, "qids": { "columns": [ "title", "qid" ], "params": [ { "name": "dis", "column": "dis", "type": "select", "options": [ "", "empty", "all", "duplicate" ] } ] }, "qids_others": { "columns": [ "title", "qid" ], "params": [ { "name": "dis", "column": "dis", "type": "select", "options": [ "", "empty", "all", "duplicate" ] } ] }, "count_pages": { "columns": [], "params": [ { "name": "target", "column": "target", "type": "text", "placeholder": "Target" } ] }, "leaderboard_table": { "columns": [ "u.user_group" ], "params": [ { "name": "year", "column": "YEAR(p.pupdate)", "type": "number", "placeholder": "Year of publication" }, { "name": "cat", "column": "cat", "type": "text", "placeholder": "Category", "value_can_be_null": true }, { "name": "user_group", "column": "u.user_group", "type": "text", "placeholder": "User Group Name" }, { "name": "order", "column": "order", "type": "text", "placeholder": "Order by", "no_select": true } ] }, "leaderboard_table_formated": { "columns": [ "u.user_group" ], "params": [ { "name": "year", "column": "YEAR(p.pupdate)", "type": "number", "placeholder": "Year of publication" }, { "name": "cat", "column": "cat", "type": "text", "placeholder": "Category", "value_can_be_null": true }, { "name": "user_group", "column": "u.user_group", "type": "text", "placeholder": "User Group Name" }, { "name": "order", "column": "order", "type": "text", "placeholder": "Order by", "no_select": true } ] }, "lang_views": { "columns": [], "params": [ { "name": "user", "column": "p.user", "type": "text", "placeholder": "Username" }, { "name": "lang", "column": "p.lang", "type": "text", "placeholder": "Language code" }, { "name": "year", "column": "YEAR(pupdate)", "type": "number", "placeholder": "Year" } ] }, "lang_views2": { "columns": [], "params": [ { "name": "user", "column": "p.user", "type": "text", "placeholder": "Username" }, { "name": "lang", "column": "p.lang", "type": "text", "placeholder": "Language code" }, { "name": "year", "column": "YEAR(pupdate)", "type": "number", "placeholder": "Year" } ] }, "user_views": { "columns": [], "params": [ { "name": "user", "column": "p.user", "type": "text", "placeholder": "Username" }, { "name": "lang", "column": "p.lang", "type": "text", "placeholder": "Language code" }, { "name": "year", "column": "YEAR(pupdate)", "type": "number", "placeholder": "Year" } ] }, "user_views2": { "columns": [], "params": [ { "name": "user", "column": "p.user", "type": "text", "placeholder": "Username" }, { "name": "lang", "column": "p.lang", "type": "text", "placeholder": "Language code" }, { "name": "year", "column": "YEAR(pupdate)", "type": "number", "placeholder": "Year" } ] }, "users": { "columns": [ "user_id", "username", "email", "wiki", "user_group", "reg_date" ], "params": [ { "name": "userlike", "column": "userlike", "type": "text", "placeholder": "Username starts with", "required": true }, { "name": "wiki", "column": "wiki", "type": "text", "placeholder": "Wiki Name" }, { "name": "user_group", "column": "user_group", "type": "text", "placeholder": "User Group Name", "no_select": true } ] }, "views": { "columns": [], "params": [ { "name": "lang", "column": "p.lang", "type": "text", "placeholder": "Language code" }, { "name": "year", "column": "YEAR(p.pupdate)", "type": "number", "placeholder": "Year of publication" } ] }, "views_new": { "columns": [ "target", "lang", "year", "views" ], "params": [ { "name": "lang", "column": "v.lang", "type": "text", "placeholder": "Language code" }, { "name": "year", "column": "YEAR(p.pupdate)", "type": "number", "placeholder": "Year of publication" }, { "name": "views", "column": "v.views", "type": "number", "placeholder": "Views" } ] }, "words": { "columns": [ "w_id", "w_title", "w_lead_words", "w_all_words" ], "params": [ { "name": "title", "column": "w_title", "type": "text", "placeholder": "Page Title" }, { "name": "lead_words", "column": "w_lead_words", "type": "number", "placeholder": "Lead words Count" }, { "name": "all_words", "column": "w_all_words", "type": "number", "placeholder": "Total words Count" } ] }, "translate_type": { "columns": [ "tt_id", "tt_title", "tt_lead", "tt_full" ], "params": [ { "name": "Lead", "column": "tt_lead", "type": "number", "placeholder": "Lead Translation (0 or 1)" }, { "name": "Full", "column": "tt_full", "type": "number", "placeholder": "Full Translation (0 or 1)" } ] }, "langs": { "columns": [ "code", "autonym", "name", "redirects" ], "params": [] }, "projects": { "columns": [ "g_id", "g_title" ], "params": [] }, "pages_users_to_main": { "columns": [ "new_target", "new_user", "new_qid" ], "params": [] }, "users_no_inprocess": { "columns": [ "user", "is_active" ], "params": [] }, "full_translators": { "columns": [ "user", "is_active" ], "params": [] }, "settings": { "columns": [ "title", "displayed", "Type", "value", "ignored" ], "params": [] }, "graph_data": { "columns": [], "params": [ { "name": "user_group", "column": "u.user_group", "type": "text", "placeholder": "User Group Name" }, { "name": "month", "column": "MONTH(p.pupdate)", "type": "number", "placeholder": "month of date", "no_empty_value": true }, { "name": "year", "column": "YEAR(p.pupdate)", "type": "number", "placeholder": "year of date", "no_empty_value": true }, { "name": "user", "column": "p.user", "type": "text", "placeholder": "Username", "no_empty_value": false }, { "name": "lang", "column": "p.lang", "type": "text", "placeholder": "Language code", "no_empty_value": false }, { "name": "category", "column": "p.cat", "type": "text", "placeholder": "Category" }, { "name": "campaign", "column": "p.campaign", "type": "text", "placeholder": "Campaign" } ] }, "users_by_last_pupdate": { "columns": [], "params": [] }, "top_users": { "columns": [], "params": [ { "name": "year", "column": "YEAR(p.pupdate)", "type": "number", "placeholder": "year of date", "no_empty_value": true }, { "name": "month", "column": "MONTH(p.pupdate)", "type": "number", "placeholder": "month of date", "no_empty_value": true }, { "name": "user_group", "column": "u.user_group", "type": "text", "placeholder": "User Group Name", "no_empty_value": true }, { "name": "cat", "column": "p.cat", "type": "text", "placeholder": "Category", "no_empty_value": true } ] }, "top_langs": { "columns": [], "params": [ { "name": "year", "column": "YEAR(p.pupdate)", "type": "number", "placeholder": "year of date", "no_empty_value": true }, { "name": "month", "column": "MONTH(p.pupdate)", "type": "number", "placeholder": "month of date", "no_empty_value": true }, { "name": "user_group", "column": "u.user_group", "type": "text", "placeholder": "User Group Name", "no_empty_value": true }, { "name": "cat", "column": "p.cat", "type": "text", "placeholder": "Category", "no_empty_value": true } ] }, "top_lang_of_users": { "columns": [], "params": [ { "name": "users", "column": "p.user", "type": "array" } ] }, "user_status": { "columns": [], "params": [ { "name": "user", "column": "p.user", "type": "text", "placeholder": "Username", "no_empty_value": false }, { "name": "lang", "column": "p.lang", "type": "text", "placeholder": "Language code", "no_empty_value": false }, { "name": "select", "column": "select", "type": "text", "placeholder": "Select fields", "options": [ "lang", "campaign", "cat", "year" ] } ] }, "get_lang_years": { "columns": [], "params": [ { "name": "lang", "column": "p.lang", "type": "text", "placeholder": "Language code", "no_empty_value": false } ] } } diff --git a/src/app/request.php b/src/app/request.php index 80d5e9c..dd8864a 100644 --- a/src/app/request.php +++ b/src/app/request.php @@ -1,6 +1,9 @@