Conversation
| return [$id]; | ||
| } | ||
|
|
||
| if ($self->req->method eq 'POST') { |
There was a problem hiding this comment.
ids on POST is now only accepted from a JSON body.
The legacy layer took it from the query string too — Bugzilla::WebService::Server::REST::_retrieve_json_params deliberately merged query-string params for non-GET requests ("Allow parameters in the query string if request was non-GET"), and CGI parsed urlencoded bodies. So both of these used to work and now fail:
POST /rest/bug_user_last_visit?ids=123→param_required(empty body decodes to{})POST /rest/bug_user_last_visitwithContent-Type: application/x-www-form-urlencodedand bodyids=123&ids=456→decode_jsonthrows →rest_malformed_json
Suggest falling back to $self->every_param('ids') when the body is absent or isn't JSON.
There was a problem hiding this comment.
Fixed in "Bug 2065171 - Merge query-string and JSON body params for ids/include_fields"
| try { $params = decode_json($self->req->body || '{}'); } | ||
| catch { $error = 'rest_malformed_json'; }; | ||
| return (undef, $error) if $error; | ||
| my $ids = $params->{ids} // []; |
There was a problem hiding this comment.
Input type validation was dropped along with validate(@_, 'ids').
ref $ids ? $ids : [$ids] passes any reference straight through, so {"ids":{"a":1}} returns a hashref and the @$ids check in update dies with "Not an ARRAY reference" → HTTP 500 / unknown-fatal. Legacy returned a clean invalid_params user error.
Suggest ref $ids eq 'ARRAY' with a user error otherwise.
There was a problem hiding this comment.
Fixed following your suggestion: ref $ids eq 'ARRAY' ? $ids : [$ids]; and added user_error "ids must be an array" if $ids ne 'ARRAY'.
Committed in "Bug 2065171 - Reject non-array ids with invalid_params"
| 'User' => 'Bugzilla::WebService::User', | ||
| 'Product' => 'Bugzilla::WebService::Product', | ||
| 'Group' => 'Bugzilla::WebService::Group', | ||
| 'BugUserLastVisit' => 'Bugzilla::WebService::BugUserLastVisit', |
There was a problem hiding this comment.
Dropping this entry removes the methods from JSON-RPC and XML-RPC as well, not just from the legacy REST layer — anything calling jsonrpc.cgi with method=BugUserLastVisit.get/update will start getting an unknown-method error.
This matches the pattern of the earlier migrations in the series, so probably intentional, but it's an undocumented breaking change that seems worth calling out in the PR description / API docs.
There was a problem hiding this comment.
Correct, and yes intentional: same tradeoff as the Classification/Bugzilla(system-info) migrations before this one => dropping the WS_DISPATCH entry removes BugUserLastVisit.get/update from JSON-RPC and XML-RPC as well as from the legacy REST dispatcher, since all three share that table. Native Mojo routes only serve REST.
I hadn't called this out explicitly in the description => added a note to it now
Happy to raise that on 2057358 too, as it'd apply to every resource in the series, not just this one.
And yes, I totally agree, API documentation needs an update too, and even a big one ;)
|
Reading API doc, I realized that => Fixed in "Bug 2065171 - Fix ids/include_fields precedence: query string wins over body" |
`_request_params->{ids} // []` made a missing ids param filter to nothing instead of returning every visited bug, since an empty arrayref is truthy. Legacy left $ids undef when the param is absent, skipping filter entirely. Return undef in that case matches legacy behavior. An empty array still filters to nothing.
| if (my $id = $self->param('id')) { | ||
| return [$id]; | ||
| } | ||
|
|
||
| my $ids = $self->_request_params->{ids}; | ||
| return undef unless defined $ids; | ||
| return (undef, 'invalid_params', {type_error => 'ids must be an array'}) | ||
| if ref $ids && ref $ids ne 'ARRAY'; | ||
| return ref $ids eq 'ARRAY' ? $ids : [$ids]; |
There was a problem hiding this comment.
two precedence differences from the legacy layer here
-
path id short-circuits
ids, but legacy merged the request body over path params (_retrieve_json_paramsapplies%$extra_paramslast), soPOST /rest/bug_user_last_visit/123with body{"ids":[456]}used to update 456 and now updates 123. query-string precedence is unchanged, just the body -
if (my $id = $self->param('id'))is a truthiness test, so/bug_user_last_visit/0falls through to the no-ids branch andgetreturns the whole last-visited list instead of an empty one.$self->paramalso falls back to request params, so?id=5is now treated as a filter where legacy only looked atids
checking defined $self->stash('id') instead would fix both halves of 2
There was a problem hiding this comment.
Fixed:
- ids precedence now matches legacy:
-> for POST, a body/query-stringidsoverrides the path id (falls back to the path id only when the request has noidsat all)
-> for GET, no change (the path id still wins) - Switched from
$self->param('id')todefined $self->stash('id'), which fixes both id=0 (was falsy, fell through to "no ids") and the stray?id=5query param being misread as a path id.
| return ref $ids eq 'ARRAY' ? $ids : [$ids]; | ||
| } | ||
|
|
||
| sub _request_params { |
There was a problem hiding this comment.
this param-merging layer is hand-rolled and has no automated coverage
the other native migrations in this series each have a qa test (rest_classification.t, rest_components.t, rest_reminders.t) and 65642f5 updated rest_bugzilla.t, so qa/t/rest_bug_user_last_visit.t would fit the convention
worth covering the cases already in the PR test plan plus the query-string-vs-json-body precedence, since three frontend call sites depend on this endpoint (bug_modal.js, MyDashboard/query.js, show-header.html.tmpl) and they post a json body with no Content-Type, which is exactly the path decode_json here handles
There was a problem hiding this comment.
Added qa/t/rest_bug_user_last_visit.t, matching the rest_classification.t, rest_components.t, and rest_reminders.t convention.
It covers the PR test plan cases plus the query-string-vs-json-body/path precedence (including the no-Content-Type case the three frontend callers rely on).
=> Fixed in "Bug 2065171 - Add qa/t/rest_bug_user_last_visit.t"
_request_params duplicated the query-string/JSON-body merge logic. Now call a single shared Bugzilla::WebService::Util::merge_request_params helper, so it's a one-place change to drop later if query-string-on-POST support is ever removed.
|
Pushed a follow-up commit: |
_ids_from_request short-circuited to the path id whenever present, never consulting the merged
query-string/body params. Legacy's _retrieve_json_params merges non-GET request-body/query
params in *after* the path-derived params, so those win for POST. For GET, the path id still wins
(legacy's override step only ran for non-GET requests), so that precedence is unchanged.
Also switch from $self->param('id') (a truthiness check that also falls back to a same-named
query param) to $self->stash('id') (defined check, route-placeholder only). This fixes two more bugs:
- /bug_user_last_visit/0 was falling through to the no-ids branch since "0" is falsy
- a stray ?id=5 query parameter (distinct from ids) was being treated as if it were a path id
Covers: anonymous access requiring login, OPTIONS, POST via path id, POST via a JSON ids body, POST with a JSON body posted with no Content-Type header, GET via path id vs query-string ids precedence, GET via query-string ids, and GET with no ids returning every visited bug
Summary
Ports
Bugzilla::WebService::BugUserLastVisit'sget/updatemethods into a nativeBugzilla::API::V1::BugUserLastVisitMojo controller, mirroring the pattern already used for Classification/Component/Teams/Reminders/Configuration/Bugzilla (system info).This is a child bug of 2057358, see there for details.
Changes
Bugzilla/API/V1/BugUserLastVisit.pm:GET/POST /rest/bug_user_last_visitand/rest/bug_user_last_visit/<id>(login required), same JSON response shape as the legacy endpointsBugzilla/WebService/BugUserLastVisit.pmandBugzilla/WebService/Server/REST/Resources/BugUserLastVisit.pmBugUserLastVisitentry fromWS_DISPATCHinBugzilla/WebService/Constants.pmand drop the correspondinguseline inBugzilla/WebService/Server/REST.pmBreaking change: removing the
WS_DISPATCHentry also removesBugUserLastVisit.get/updatefrom JSON-RPC and XML-RPC, not just the legacy REST dispatcher, since all three share that table. Native Mojo routes only serve REST. This matches the same tradeoff already made in the Classification and Bugzilla (system-info) migrations earlier in this series.Test plan
GET /rest/bug_user_last_visit(anonymous =>login_required, authenticated => list of last-visited bugs)GET /rest/bug_user_last_visit/<id>GET /rest/bug_user_last_visit?ids=<id>&ids=<id>POST /rest/bug_user_last_visit/<id>POST /rest/bug_user_last_visitwith{"ids":[...]}bodyOPTIONSon both routes returnsAllow: GET, POSTlast_visit_tswith trailingZ) matches the legacy endpointReferences