[WIP] Feat/push likes to wiki pages#299
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a new Artisan command to export per-page "Likes" to the French wiki, a WikiSemanticApiClient to update wiki semantic properties via REST, a migration and model fillable for the REST endpoint, and schedules the command to run daily. Changes
Sequence DiagramsequenceDiagram
participant Scheduler as Laravel Scheduler
participant Command as ExportPageDetailsToWiki
participant DB as Database
participant Client as WikiSemanticApiClient
participant WikiAPI as Wiki REST API
Scheduler->>Command: Run scheduled job
Command->>DB: Query pages with likes (grouped by title/wiki, HAVING MAX(i.updated_at) >= threshold)
DB-->>Command: Return grouped page results
loop For each locale (filter to "fr")
Command->>Client: instantiate with wiki_api_url, wiki_restapi_url
loop For each page result
Command->>Client: postPageLikesAmount(title, likes)
alt Client needs auth
Client->>WikiAPI: GET login token
WikiAPI-->>Client: token
Client->>WikiAPI: POST login (bot creds + token)
WikiAPI-->>Client: login response
end
Client->>WikiAPI: PUT semantic property (normalized title, likes)
WikiAPI-->>Client: result
Client-->>Command: return success/failure
alt Success
Command->>Command: Log success
else Failure
Command->>Command: Log per-page error
end
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
d1f9f57 to
3c69c06
Compare
There was a problem hiding this comment.
Pull request overview
This PR adds functionality to export page like counts from the application to wiki pages using the MediaWiki Semantic API. The feature includes a new command to push like counts to wiki pages and the necessary authentication infrastructure.
Key changes:
- Adds a new
WikiSemanticApiClientclass to interact with the MediaWiki Semantic API for updating page properties - Implements a console command
pages:export-details-to-wikito export like counts from the database to the wiki - Adds database migration to store wiki REST API URLs in the
locales_configtable
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| wiki-bot-passwords.md | Documents required bot permissions for posting like counts to wiki pages |
| database/migrations/2025_12_01_220632_add_rest_api_url.php | Adds wiki_restapi_url column to locales_config table and populates it based on existing API URLs |
| app/Src/WikiSemanticApiClient.php | Implements client for authenticating with and posting semantic properties to MediaWiki |
| app/LocalesConfig.php | Adds wiki_restapi_url to fillable attributes |
| app/Console/Commands/ExportPageDetailsToWiki.php | Implements command to query like counts and export them to wiki (incomplete) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } | ||
| } |
There was a problem hiding this comment.
Direct usage of env() in application code is discouraged in Laravel. Environment variables should be accessed through config files. Create a config file (e.g., config/wiki.php) and retrieve values using config('wiki.bot_username') instead.
| } | |
| } | |
| 'lgname' => config('wiki.bot_username'), | |
| 'lgpassword' => config('wiki.bot_password'), |
a966231 to
389b53f
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
app/Src/WikiSemanticApiClient.php (1)
83-84: Direct env() usage is discouraged in Laravel application code.This is a duplicate of a previous review comment. Environment variables should be accessed through config files for consistency, caching benefits, and testability.
Create a config file (e.g.,
config/wiki.php):return [ 'bot_username' => env('WIKI_BOT_USERNAME'), 'bot_password' => env('WIKI_BOT_PASSWORD'), ];Then apply this diff:
- 'lgname' => env('WIKI_BOT_USERNAME'), - 'lgpassword' => env('WIKI_BOT_PASSWORD'), + 'lgname' => config('wiki.bot_username'), + 'lgpassword' => config('wiki.bot_password'),
🧹 Nitpick comments (2)
database/migrations/2025_12_01_220632_add_rest_api_url.php (1)
15-17: Consider making nullability explicit.The column is implicitly nullable when added to an existing table, but it's clearer to be explicit about this constraint.
Apply this diff to make the intent explicit:
- $table->string('wiki_restapi_url', 191)->after('wiki_api_url'); + $table->string('wiki_restapi_url', 191)->nullable()->after('wiki_api_url');app/Src/WikiSemanticApiClient.php (1)
62-62: Clarify the null coalescing operator usage.The expression
'success' === $responseContent['result'] ?? falseis confusing due to operator precedence. While it works correctly (because of theisset()check above), the intent would be clearer with explicit parentheses or a different structure.Apply this diff to improve clarity:
- return 'success' === $responseContent['result'] ?? false; + return ($responseContent['result'] ?? '') === 'success';
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
app/Console/Commands/ExportPageDetailsToWiki.php(1 hunks)app/Console/Kernel.php(1 hunks)app/LocalesConfig.php(1 hunks)app/Src/WikiSemanticApiClient.php(1 hunks)database/migrations/2025_12_01_220632_add_rest_api_url.php(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
app/Console/Commands/ExportPageDetailsToWiki.php (2)
app/LocalesConfig.php (1)
LocalesConfig(11-74)app/Src/WikiSemanticApiClient.php (2)
WikiSemanticApiClient(19-98)postPageLikesAmount(36-63)
🔇 Additional comments (5)
app/Console/Kernel.php (1)
31-31: LGTM! Command scheduling is appropriate.The scheduled command runs at a suitable time between other tasks and correctly passes the
--since-x-days=3parameter as specified in the PR description.app/LocalesConfig.php (1)
19-19: LGTM! Fillable attribute addition is correct.The addition of
wiki_restapi_urlto the fillable array aligns with the migration and enables proper mass assignment for this field.app/Console/Commands/ExportPageDetailsToWiki.php (2)
19-37: LGTM! Solid error isolation and locale handling.The per-locale error handling ensures that a failure in one locale doesn't prevent processing others. The FR-only filter aligns with the current scope mentioned in the PR description.
40-95: LGTM! Export logic is well-structured with comprehensive error handling.The method correctly:
- Queries pages with likes updated since the threshold
- Handles errors per page without failing the entire export
- Provides detailed logging for success and failure cases
The variable naming issues mentioned in past review comments appear to be resolved.
database/migrations/2025_12_01_220632_add_rest_api_url.php (1)
19-25: The URL transformation is safe and follows the standard MediaWiki API pattern. Thewiki_api_urlcolumn is defined asNOT NULLin the initial migration and is consistently used across the codebase (WikiClient and WikiSemanticApiClient) with the expected format ending inapi.php. TheREPLACElogic to transformapi.phptorest.phpdirectly corresponds to MediaWiki's standard pattern for the legacy API vs. REST API endpoints.
389b53f to
59c92a9
Compare
59c92a9 to
bf077df
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
app/Console/Commands/ExportPageDetailsToWiki.php (2)
26-29: Consider making the locale filter configurable.The hardcoded FR-only filter works for the current requirements, but making it configurable (e.g., via command option
--locale=fror environment variable) would improve flexibility for future expansion to other wikis.Example implementation:
- protected $signature = 'pages:export-details-to-wiki {--since-x-days=15}'; + protected $signature = 'pages:export-details-to-wiki {--since-x-days=15} {--locale=fr}'; // In handle() method: - // On ne traite que le wiki FR pour l'instant - if ('fr' !== $localeConfig->code) { + if ($this->option('locale') !== $localeConfig->code) { continue; }
60-94: Consider adding rate limiting and progress indication.For robustness and better user experience, especially during manual backfill runs (e.g.,
--since-x-days 3650), consider:
- Rate limiting: Add a small delay between wiki API calls to avoid hitting rate limits
- Progress indication: Use
$this->output->progressStart()andprogressAdvance()to show progressExample additions:
+ $this->output->progressStart(count($rawResults)); + foreach ($rawResults as $eligiblePage) { try { $success = $client->postPageLikesAmount($eligiblePage->title, $eligiblePage->likes_amount); if (!$success) { $this->error( sprintf( 'Failed to export Likes (%d) for page "%s" (%s)', $eligiblePage->likes_amount, $eligiblePage->title, $eligiblePage->wiki ) ); } else { $this->info( sprintf( 'Successfully exported Likes (%d) for page "%s" (%s)', $eligiblePage->likes_amount, $eligiblePage->title, $eligiblePage->wiki ) ); } + + // Rate limiting: small delay between API calls + usleep(100000); // 100ms delay } catch (\Throwable $e) { $this->error( sprintf( 'Error exporting Likes (%d) for page "%s" (%s): %s', $eligiblePage->likes_amount, $eligiblePage->title, $eligiblePage->wiki, $e->getMessage() ) ); } + $this->output->progressAdvance(); } + + $this->output->progressFinish();
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
app/Console/Commands/ExportPageDetailsToWiki.php(1 hunks)app/Console/Kernel.php(1 hunks)app/LocalesConfig.php(1 hunks)app/Src/WikiSemanticApiClient.php(1 hunks)database/migrations/2025_12_01_220632_add_rest_api_url.php(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- database/migrations/2025_12_01_220632_add_rest_api_url.php
- app/Src/WikiSemanticApiClient.php
- app/Console/Kernel.php
🔇 Additional comments (2)
app/LocalesConfig.php (1)
19-19: LGTM!The addition of
wiki_restapi_urlto the fillable attributes is correct and consistent with the other wiki-related configuration fields.app/Console/Commands/ExportPageDetailsToWiki.php (1)
47-54: SQL query logic is correct as designed.The HAVING clause properly filters pages with recent activity (interactions updated within the threshold). The query correctly exports total likes for pages with recent activity—not just recent likes. This is the intended behavior: the
--since-x-daysparameter determines which pages to export (those with recent interaction updates), whilelikes_amountreflects the cumulative total of all likes (follow = 1interactions) for that page.The query is well-optimized with indexes on
interactions(page_id, wiki)supporting the JOIN condition, and schema constraints ensure data integrity.
|
|
||
| class ExportPageDetailsToWiki extends Command | ||
| { | ||
| protected $signature = 'pages:export-details-to-wiki {--since-x-days=15}'; |
There was a problem hiding this comment.
Add type validation for the since-x-days option.
The option value is used in line 21 with sprintf('%d days', ...) which expects an integer, but Laravel command options return strings by default. If a non-numeric value is provided, this could cause unexpected behavior.
Apply this diff to add type safety:
public function handle(): void
{
- $dateThreshold = Carbon::now()->sub(sprintf('%d days', $this->option('since-x-days')))->setTime(0, 0, 0);
+ $sinceDays = (int) $this->option('since-x-days');
+ if ($sinceDays < 1) {
+ $this->error('Option --since-x-days must be a positive integer.');
+ return;
+ }
+ $dateThreshold = Carbon::now()->sub(sprintf('%d days', $sinceDays))->setTime(0, 0, 0);Also applies to: 21-21
🤖 Prompt for AI Agents
In app/Console/Commands/ExportPageDetailsToWiki.php around line 15 (and usage at
line 21), the `since-x-days` option is taken as a string but used with
sprintf('%d days', ...); validate and coerce it to an integer before use: fetch
the option, ensure it is numeric (or cast to int after validation), throw a
clear InvalidArgumentException or call $this->error()/return if validation
fails, and then pass the validated integer into sprintf so non-numeric input is
rejected and type-safety is ensured.
|
|
||
| private function handleExportPageLikes(LocalesConfig $localeConfig, Carbon $dateThreshold): void | ||
| { | ||
| $client = new WikiSemanticApiClient($localeConfig->toArray()); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify WikiSemanticApiClient exists and check its implementation
echo "=== Finding WikiSemanticApiClient class ==="
fd -e php -i wikisemanticapiclient
echo -e "\n=== Searching for WikiSemanticApiClient references ==="
rg -n "class WikiSemanticApiClient" --type=php
echo -e "\n=== Checking postPageLikesAmount method ==="
rg -n "postPageLikesAmount" --type=php -A 3
echo -e "\n=== Checking environment variable usage in config/wiki.php or similar ==="
fd -e php wiki && rg -n "WIKI_BOT_USERNAME|WIKI_BOT_PASSWORD" --type=phpRepository: neayi/insights
Length of output: 2132
🏁 Script executed:
#!/bin/bash
# Inspect WikiSemanticApiClient constructor and initialization
echo "=== Reading WikiSemanticApiClient class (first 100 lines) ==="
head -100 app/Src/WikiSemanticApiClient.php
echo -e "\n=== Checking for env() calls and validation ==="
rg -n "env\(" app/Src/WikiSemanticApiClient.php -B 2 -A 2Repository: neayi/insights
Length of output: 4016
🏁 Script executed:
#!/bin/bash
# Check ExportPageDetailsToWiki.php context around line 42
echo "=== ExportPageDetailsToWiki.php lines 35-50 ==="
sed -n '35,50p' app/Console/Commands/ExportPageDetailsToWiki.php
echo -e "\n=== Check $localeConfig declaration and import ==="
head -50 app/Console/Commands/ExportPageDetailsToWiki.php | grep -n "localeConfig\|use\|class"
echo -e "\n=== Check if environment variables are validated in config ==="
fd -e php config && rg -n "WIKI_BOT_USERNAME|WIKI_BOT_PASSWORD" config/Repository: neayi/insights
Length of output: 1952
🏁 Script executed:
#!/bin/bash
# Check LocalesConfig class structure
echo "=== Reading LocalesConfig.php ==="
head -150 app/LocalesConfig.php
echo -e "\n=== Searching for toArray method ==="
rg -n "toArray" app/LocalesConfig.php -A 10Repository: neayi/insights
Length of output: 2277
🏁 Script executed:
#!/bin/bash
# Check for environment variable validation
echo "=== Checking config files for validation ==="
fd -e php config/ 2>/dev/null | head -10
echo -e "\n=== Checking for .env.example or validation of required env vars ==="
fd -e example
fd -e env | grep -E "env|example"
echo -e "\n=== Checking ServiceProvider or bootstrap for env validation ==="
rg -n "WIKI_BOT" --type=php -B 3 -A 3Repository: neayi/insights
Length of output: 848
Add validation for required environment variables WIKI_BOT_USERNAME and WIKI_BOT_PASSWORD.
The WikiSemanticApiClient is correctly instantiated with the locale config array, and the method signature matches its usage. However, the authenticate() method (lines 88-89) accesses environment variables WIKI_BOT_USERNAME and WIKI_BOT_PASSWORD via env() without validation. If either variable is missing, the login will fail without a clear error message. Add validation in the constructor or at startup to ensure both variables are set before attempting authentication.
Also applies to: 62-62
🤖 Prompt for AI Agents
In app/Console/Commands/ExportPageDetailsToWiki.php around lines 42 and 62, the
code instantiates WikiSemanticApiClient then calls authenticate() which reads
WIKI_BOT_USERNAME and WIKI_BOT_PASSWORD via env() without checking they exist;
add explicit validation for both environment variables before attempting
authentication (either in this command just after creating the client or inside
the client constructor): if either env var is missing or empty, log a clear
error and abort/throw an exception with a descriptive message indicating which
variable is missing; ensure the check uses env(..., null) or equivalent and
treats empty strings as missing so authentication is never attempted with
invalid credentials.
Resolves #278
Nouvelle propriété du wiki
Number of likes
Variables d'environnement à configurer
Permissions données au robot créé sur le wiki pour poster le nombre de likes
Programmation de la commande
Jouer la commande une première fois pour rattrapage sur 10 ans :
php artisan pages:export-details-to-wiki --since-x-days 3650La commande est configurée pour être jouée tous les jours à 22h45, et traiter les pages qui ont eu des interactrions modifiées sur les 3 derniers jours.
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.