Page MenuHomePhabricator

Add REST endpoint PATCH /worklist/{wiki}/{title} (add article)
Closed, ResolvedPublic3 Estimated Story Points

Description

Background: Endpoint to add and/or remove articles in an event's worklist. The worklist is
identified by its page title; the articles to add and remove are grouped by wiki and applied as a
single delta.

Type of story
  • Backend
Acceptance criteria
  • The endpoint is available only when the Worklist feature flag is enabled (T423606). When disabled, it returns a controlled error response, aligned with the sibling DELETE endpoint (T423656) โ€” i.e. 404, so a disabled wiki does not reveal the resource.
  • Only logged in users (not temp account) can use the API
  • The endpoint must be documented at: Extension:CampaignEvents/Api (see below)
Messages and copy included
  • For happy path: NOT NEEDED (the 204 response has no user-facing message)
  • For unhappy path:
      • Reused (NOT a new key): campaignevents-rest-event-not-found
        • Returned in the API 404 response body when the worklist feature is disabled on the wiki, so a disabled wiki does not reveal the endpoint. Reuses the standard message; do not create a worklist-specific event-not-found message.
    • When using the API to edit a non-worklist page:
      • "campaignevents-worklist-page-not-worklist": "The target page already exists and is not a worklist page.",
Are there dependencies (on someone else or learning something new)?
  • Requires investigation of how the extension validates that a page exists on a (possibly remote) wiki. The reviewer hopes this can be done synchronously. Check existing cross-wiki validation patterns in the codebase before implementing.
Depends on
  • T423332 (DB layer for the worklist store โ€” addArticle() and isArticleInWorklist())
  • T423606 (Worklist feature flag gating must be implemented)
  • Behaviour layer updates โ€” an AddWorklistArticleCommand (or equivalent) that performs the permission check and the synchronous article validation, returning a result that distinguishes "added" from "already present". (No dedicated task for this yet โ€” flagged by the reviewer; align with the existing RemoveWorklistArticleCommand shape.)
Testing required?
  • Yes
  • Minimum testing to pass QA:
    • With feature flag ON: unit tests cover 204 add, 204 remove, 204 no-op (article already present / absent), 400 unrecognised wiki, 400 malformed title, 403 for logged-out or temporary-account users, and 404 (feature disabled).
    • With feature flag OFF: the endpoint is not accessible (404).
  • Tested end-to-end in: T423634 (Worklist tab โ€” add article form)
Split patches suggestion
  • Branch 1: PATCH handler + route registration + permission check + validation + unit tests.
API documentation
== Add or remove worklist pages ==

Route: `/campaignevents/v0/worklist/{title}/pages`
Content type: `application/json`
Method: PATCH
Returns: 204 No Content

Applies a delta to a worklist's page list: pages to add and/or remove, grouped by wiki. The worklist
is identified by its page title. Only logged-in (named) users may edit. The operation is idempotent:
adding a page that is already present, or removing one that is absent, is a no-op.

=== Parameters ===

`title`
required | path
The worklist page title (e.g. "Event1/Worklist"). The client MUST percent-encode it
(`encodeURIComponent`), including slashes as `%2F` for subpage titles.

`add`
optional | body
Object mapping wiki ID to a list of prefixed page titles to add, e.g. `{ "enwiki": [ "Article One" ] }`.

`remove`
optional | body
Object mapping wiki ID to a list of prefixed page titles to remove, e.g. `{ "enwiki": [ "Article Two" ] }`.

`token`
required | body
CSRF token.

=== Responses ===

204
Success. The delta was applied (or there was nothing to change).

400
The request is invalid: e.g. a malformed title or an unrecognised wiki in the body.

403
The performer is not a logged-in (named) user, i.e. logged out or using a temporary account
(`campaignevents-worklist-edit-permission-denied`).

404
The worklist feature is disabled on this wiki (`campaignevents-rest-event-not-found`).

Details

Event Timeline

A few quick things:

Add REST endpoint POST /worklist

Given how this endpoint works (adds a single, given article; does not change the worklist as a whole), I would rather have a PUT endpoint where the article is specified in the path, e.g. /campaignevents/v0/event_registration/{id}/worklist/{wiki}/{title}. POST/PUT for the entire /worklist resource could be reserved for an endpoint that replaces the entire worklist.

If the article is already in the worklist for this event, the endpoint returns 400 or 422 (TBD) with the localised error message campaignevents-worklist-article-already-exists.

Generally, but especially if we make this a PUT, the response should be a 20x as the resource is already in the desired state. If needed, a boolean can be added to the response body to indicate whether any modification actually took place (we use this "modified": true|false pattern in other endpoints).

On success the endpoint returns 201 with { "id": <integer> } and a Location header pointing to the worklist resource.

It's not the worklist itself that got created but the article resource. I'm not sure if the URI of the GET /worklist endpoint would be a semantically correct use of the Location header here.

Message key: campaignevents-worklist-event-not-found

This should use the standard campaignevents-rest-event-not-found from EventIDParamTrait.

Depends on

Also on behaviour layer updates (including permission checks and article validation, which BTW I'm hoping we can make synchronously, but I'm not sure), for which I'm not seeing a task yet.

Minimum testing to pass QA: unit tests covering happy path (201), 400 invalid article, 400 non-existent page, 403 forbidden, 404 event not found, 409 duplicate.

No 409 duplicate state above.

Also

Error messages and copy included

These are not using the correct message prefix (which includes -rest-).

Change #1298449 had a related patch set uploaded (by Cmelo; author: Cmelo):

[mediawiki/extensions/CampaignEvents@master] Add REST endpoint PUT /worklist

https://gerrit.wikimedia.org/r/1298449

cmelo renamed this task from Add REST endpoint POST /worklist to Add REST endpoint PUT /worklist.Jun 8 2026, 7:15 AM
cmelo claimed this task.
cmelo renamed this task from Add REST endpoint PUT /worklist to Add REST endpoint PUT /worklist/{wiki}/{title} (add article).Jun 8 2026, 7:22 AM
cmelo updated the task description. (Show Details)
cmelo set the point value for this task to 3.Jun 22 2026, 7:10 PM
cmelo renamed this task from Add REST endpoint PUT /worklist/{wiki}/{title} (add article) to Add REST endpoint PATCH /worklist/{wiki}/{title} (add article).Jul 9 2026, 11:48 AM
cmelo updated the task description. (Show Details)

Change #1298449 merged by jenkins-bot:

[mediawiki/extensions/CampaignEvents@master] Add REST endpoint PATCH /worklist

https://gerrit.wikimedia.org/r/1298449

  • The endpoint is available only when the Worklist feature flag is enabled (T423606). When disabled, it returns a controlled error response, aligned with the sibling DELETE endpoint (T423656) โ€” i.e. 404, so a disabled wiki does not reveal the resource.

โš ๏ธ The endpoint is always available, but when worklists are disabled, it fails with the error message listed below. We also no longer have a corresponding DELETE endpoint, but that is fine. Overall, this is good enough.

  • Only logged in users (not temp account) can use the API

โœ… When editing an existing worklist, I get "Only logged-in (named) users may edit worklist pages." as expected. Instead, when trying to create a new worklist I get "apierror-cantchangecontentmodel", as the content model check fails first (only logged-in users have the createwithcontentmodel right).

โœ… I have done this now.

Messages and copy included
  • For happy path: NOT NEEDED (the 204 response has no user-facing message)

โœ… Verified it's a 204.

  • For unhappy path:
    • Reused (NOT a new key): campaignevents-rest-event-not-found
      • Returned in the API 404 response body when the worklist feature is disabled on the wiki, so a disabled wiki does not reveal the endpoint. Reuses the standard message; do not create a worklist-specific event-not-found message.

โœ… Verified (and excuded this from the docs as it's really just temporary).

  • When using the API to edit a non-worklist page:
    • "campaignevents-worklist-page-not-worklist": "The target page already exists and is not a worklist page.",

โœ… Verified.


However, the endpoint does not perform validation of the supplied arrays. So for example, passing "add":["Main Page"] results in Error: exception of type TypeError: array_merge(): Argument #2 must be of type array, string given in WorklistArticleHelper.php line 130. I have filed T432709 to fix this.

Closing this task as indirect testing will be done via the frontend.