Bug 17314 - REST API: Add API route to create, list and delete a purchase suggestion
Summary: REST API: Add API route to create, list and delete a purchase suggestion
Status: Failed QA
Alias: None
Product: Koha
Classification: Unclassified
Component: REST api (show other bugs)
Version: master
Hardware: All All
: P5 - low enhancement (vote)
Assignee: Arthur Suzuki
QA Contact:
URL: https://wiki.koha-community.org/wiki/...
Keywords:
Depends on:
Blocks: 16652
  Show dependency treegraph
 
Reported: 2016-09-18 14:59 UTC by Jiri Kozlovsky
Modified: 2019-09-10 21:16 UTC (History)
7 users (show)

See Also:
Change sponsored?: ---
Patch complexity: Medium patch
Who signed the patch off:
Text to go in the release notes:
Version(s) released in:


Attachments
Implemented suggestions REST API (26.09 KB, patch)
2016-12-10 20:22 UTC, Jiri Kozlovsky
Details | Diff | Splinter Review
Implemented suggestions REST API (26.09 KB, patch)
2016-12-11 22:13 UTC, Jiri Kozlovsky
Details | Diff | Splinter Review
Implemented suggestions REST API (26.10 KB, patch)
2016-12-11 22:16 UTC, Jiri Kozlovsky
Details | Diff | Splinter Review
QA followup (2.04 KB, patch)
2017-01-14 22:26 UTC, Jiri Kozlovsky
Details | Diff | Splinter Review
Bug 17314 - QA followup 2nd (5.00 KB, patch)
2017-02-12 17:48 UTC, Jiri Kozlovsky
Details | Diff | Splinter Review
Implemented suggestions REST API (24.71 KB, patch)
2019-05-28 23:58 UTC, Arthur Suzuki
Details | Diff | Splinter Review
Bug 17314 : Migration from Swagger2 to OpenApi (14.92 KB, patch)
2019-05-28 23:59 UTC, Arthur Suzuki
Details | Diff | Splinter Review
Bug 17314 : QA Followup (4.23 KB, patch)
2019-05-29 08:59 UTC, Arthur Suzuki
Details | Diff | Splinter Review
Bug 17314 : Added _to_model and _to_api methods (4.51 KB, patch)
2019-07-16 10:26 UTC, Arthur Suzuki
Details | Diff | Splinter Review
Bug 17314 : Added _to_model and _to_api methods and changed attirbutes naming (8.99 KB, patch)
2019-07-16 10:37 UTC, Arthur Suzuki
Details | Diff | Splinter Review

Note You need to log in before you can comment on or make changes to this bug.
Description Jiri Kozlovsky 2016-09-18 14:59:45 UTC
It would be nice to have an API for creating a purchase suggestion.

It would be used for instance in VuFind.

Proposed implementation:

To create:
POST /suggestions/{borrowernumber}

Incoming data:
{
  title (required)
  author
  copyrightdate
  isbn
  publishercode
  collectiontitle
  place
  itemtype
  patronreason
  note
  negcap
}

Outcoming data:
200 OK / 403 Forbidden / 409 Conflict (when already exists the proposal)
{
  error
  status
}

To list:
GET /suggestions/{borrowernumber}

Outcoming data:
list of suggestions

To delete:
DELETE /suggestions/{borrowernumber}/{suggestion_id}

Outcoming data:
204 No Content (successful deletion) / 403 Forbidden / 404 Not Found
Comment 1 Katrin Fischer 2016-09-18 15:13:23 UTC
Hi, just read through this and have some notes/questions:

- collectiontitle: I think it's not clear in the interface what this is to be used for, maybe a question we should talk about first and then maybe choose a better name?

- copyrightdate: MARC21 uses copyrightdate in the database, UNIMARC publicationyear. Both fields appear in biblioitems/biblio and in suggestions. Something to tidy up/take into account here?

- negcap - This is to keep the robots off. My impression is that this would always be empty?

It's possible to make anonymous suggestions - will this be taken into account?

For DELETE:
DELETE /suggestions/{borrowernumber}/{suggestion_id}
Why include the borrowernumber? Would the suggestion_id not be sufficient?
Comment 2 Jiri Kozlovsky 2016-09-18 15:32:01 UTC
(In reply to Katrin Fischer from comment #1)
> Hi, just read through this and have some notes/questions:
> 
> - collectiontitle: I think it's not clear in the interface what this is to
> be used for, maybe a question we should talk about first and then maybe
> choose a better name?

I don't actually know exactly what does it have to mean, but you can see it as "Collection title" on the OPAC site for creating a suggestion:
http://koha-opac/cgi-bin/koha/opac-suggestions.pl?op=add

> - copyrightdate: MARC21 uses copyrightdate in the database, UNIMARC
> publicationyear. Both fields appear in biblioitems/biblio and in
> suggestions. Something to tidy up/take into account here?

In OPAC the copyrightdate has maximum 4 characters, so it is the MARC21. The question is, whether we should allow specifying also the publicationyear?

> - negcap - This is to keep the robots off. My impression is that this would
> always be empty?

That's right, we leave it empty, thus we won't include it to the incoming data for POST - the controller will take care of that.

> It's possible to make anonymous suggestions - will this be taken into
> account?

Oh, that's the first time I hear about this functionality. Could you provide me with an example how to submit an anonymous suggestion?

> For DELETE:
> DELETE /suggestions/{borrowernumber}/{suggestion_id}
> Why include the borrowernumber? Would the suggestion_id not be sufficient?

It's because of the privileges check. Imagine some curious user in VuFind, who changes his suggestion_id in the form and tries to delete suggestion of someone else - this should prevent it and return 403 Forbidden.
Comment 3 Katrin Fischer 2016-09-18 15:49:28 UTC
> > - collectiontitle: I think it's not clear in the interface what this is to
> > be used for, maybe a question we should talk about first and then maybe
> > choose a better name?
> 
> I don't actually know exactly what does it have to mean, but you can see it
> as "Collection title" on the OPAC site for creating a suggestion:
> http://koha-opac/cgi-bin/koha/opac-suggestions.pl?op=add

Yes, I know - it just seems to cause some confusion. I was wondering if it should be better named 'series' or similar. As we are trying to use good terminology in the API from the beginning it would be nice to take a look if that would make more sense.

> > - copyrightdate: MARC21 uses copyrightdate in the database, UNIMARC
> > publicationyear. Both fields appear in biblioitems/biblio and in
> > suggestions. Something to tidy up/take into account here?
> 
> In OPAC the copyrightdate has maximum 4 characters, so it is the MARC21. The
> question is, whether we should allow specifying also the publicationyear?

What I tried to explain (badly) is that there is something a little odd in Koha. The same information goes into different fields depending on MARC flavour - so it would be good to take a look at the code to verify if both suggestions.copyrightdate and suggestions.publicationsyear are used maybe. Also kind of a terminology question - but it might not play a big role here.

> > It's possible to make anonymous suggestions - will this be taken into
> > account?
> 
> Oh, that's the first time I hear about this functionality. Could you provide
> me with an example how to submit an anonymous suggestion?

Take a look at the system preferences related to suggestions:
suggestion - on/off switch for suggestions in the OPAC
AllowPurchaseSuggestionBranchChoice - on/off for ability to select the branch
OPACViewOthersSuggestions - on/off for seeing ALL suggestions in the system (without creators name)
AnonSuggestions - ability to make suggestions without logging in

> 
> > For DELETE:
> > DELETE /suggestions/{borrowernumber}/{suggestion_id}
> > Why include the borrowernumber? Would the suggestion_id not be sufficient?
> 
> It's because of the privileges check. Imagine some curious user in VuFind,
> who changes his suggestion_id in the form and tries to delete suggestion of
> someone else - this should prevent it and return 403 Forbidden.

I think if changing the URL is enough - we are doing something wrong :) Will the permission check be so that guessing a borrowernumber will also not allow to delete another user's suggestions?
Comment 4 Jiri Kozlovsky 2016-12-04 23:40:22 UTC
(In reply to Katrin Fischer from comment #3)

I'm sorry for such a delay in my response - there was a lot of job to do.

From today's point of view and existence of the How-To write REST API https://wiki.koha-community.org/wiki/Rest_Api_HowTo we shouldn't take care of the data it flows in or out at the API, but create Koha Object if it doesn't exists yet and use it to pass the data.

So, if you suggest to rename collectiontitle to series, just create a new bug for it to compose it into the DB directly - the API will also use it implicitly.

The issue between copyrightdate & publicationyear should be handled from within the Koha Object -> I'll submit a new dependent bug for this.
Comment 5 Jiri Kozlovsky 2016-12-10 20:22:55 UTC
Created attachment 58098 [details] [review]
Implemented suggestions REST API
Comment 6 Jiri Kozlovsky 2016-12-10 22:28:16 UTC
(In reply to Jiri Kozlovsky from comment #5)
> Created attachment 58098 [details] [review] [review]
> Implemented suggestions REST API

Basic test plan 1.part:
1. Login using account without any permissions and copy Cookie's CGISESSID=TOKEN and copy it's borrowernumber
2. Using your favorite HttpRequester send POST to /api/v1/suggestions with the cookie in Headers:
{
  "title": "Suggested title",
  "author": "hawking",
  "suggestedby": "BORROWER_NUMBER"
}
3. Obtain the suggestionid from the response and send GET to /api/v1/suggestions/YOUR_SUGG_ID
4. Check that returned data matches data sent at point 2.
5. Send PUT request to /api/v1/suggestions/YOUR_SUGG_ID:
{
  "title": "Updated suggested title"
}
6. Repeat steps 3 + 4.
7. Login using another account again without any permissions and copy Cookie's CGISESSID=TOKEN
8. Using your favorite HttpRequester send POST to /api/v1/suggestions with the cookie in Headers:
{
  "title": "Suggested title",
  "author": "hawking",
  "suggestedby": "YOUR_BORROWER_NUMBER",
  "STATUS": "ACCEPTED"
}
9. Check that error was returned.
10. Create valid suggestion (repeat 8. step, but remove the STATUS) and remember the suggestionid.
11. Send PUT request to /api/v1/suggestions/YOUR_SUGG_ID:
{
  "STATUS": "ACCEPTED"
}
12. Check that error was returned.
13. Send GET request to suggestionid from the first user. (Check that you don't have enough permissions)
14. Send GET request to suggestionid of current user. (should succeed)
15. Send DELETE request to suggestion of current user. (should return 200 OK only .. without any body)
16. Repeat 14. point - should fail.
17. Send GET request to /api/v1/suggestions/?suggestedby=BORROWER_NUMBER
18. Check that there were returned all active suggestions for the user.
19. Send DELETE request to suggestion of the first user (not enough permissions - should fail)

Basic test plan 2.part:
1. Login using user with permissions of "acquisition" and copy your CGISESSID from the Cookie.
2. Using your favorite HttpRequester send POST to /api/v1/suggestions with the cookie in Headers:
{
  "title": "Suggested title from librarian",
  "author": "hawking",
  "STATUS": "ACCEPTED",
  "suggestedby": "BORROWER_NUMBER"
}
3. Check that new suggestion was created successfully and note the suggestionid.
4. Disable "AnonSuggestions" syspref and repeat 1. & 2. step without "suggestedby". (should fail because anonymous suggestions are disabled)
5. Enable "AnonSuggestions" syspref and repeat 1. & 2. step without "suggestedby". (success)
6. Send PUT request to /api/v1/suggestions/YOUR_SUGG_ID:
{
  "STATUS": "REJECTED"
}
7. Check that the suggestion was updated successfully.

This should provide you basic understanding of how does "add", "update", "list" and "delete" work.

Now you can test the following:
1. While adding / updating suggestion with patronreason or branchcode or STATUS or itemtype specified, check that the API refuses invalid values, while accepts valid ones.
2. While adding / updating suggestion with suggestedby or managedby specified, as a user with acquisition permissions, check that the API refuses ids which are invalid, while accepts valid ones (invalid are nonexisting borrowernumbers).
3. Setup "MaxOpenSuggestions" syspref to custom value and check that it applies to all borrowers excluding anonymous suggestions.
4. Setup "OPACSuggestionMandatoryFields" syspref to custom values and check that those required fields are required only while creating suggestions, not when updating, because you may want to update only a title for example.
5. Setup "AllowPurchaseSuggestionBranchChoice" syspref to enabled and check that regular users (without acquisition rights) can create and update suggestions with branchcode specified. Also check that it is forbidden for them to do so when the syspref is disabled.
6. Check that regular users can create and update suggestions only with the following fields specified:
('suggestedby', 'title', 'author', 'copyrightdate', 'isbn', 'publishercode', 'collectiontitle', 'place', 'itemtype', 'patronreason', 'note') ... branchcode is added when syspref AllowPurchaseSuggestionBranchChoice is enabled.

... That's it ! You got it all covered!

Btw, thanks for signing this off in advance !
Comment 7 Jiri Kozlovsky 2016-12-11 22:13:15 UTC
Created attachment 58100 [details] [review]
Implemented suggestions REST API

Added HTTP Codes for remaining errors
Comment 8 Jiri Kozlovsky 2016-12-11 22:16:11 UTC
Created attachment 58101 [details] [review]
Implemented suggestions REST API

Added HTTP Codes for remaining errors (previous attachment didn't change anything [I forgot to add changes to the commit])

Test plan unchanged.
Comment 9 Josef Moravec 2017-01-11 08:50:34 UTC
Started testing...

For first koha-qa complains:
 FAIL	Koha/REST/V1/Suggestions.pm
   FAIL	  valid
		Smartmatch is experimental
Comment 10 Josef Moravec 2017-01-11 08:53:08 UTC
prove t/db_dependent/api/v1/swagger/definitions.t says:

#   Failed test 'Columns is nullable in DB, not in swagger file for suggestion: publicationyear, suggesteddate'
Comment 11 Jiri Kozlovsky 2017-01-14 22:26:12 UTC
Created attachment 58993 [details] [review]
QA followup

test plan unchanged
Comment 12 Josef Moravec 2017-01-17 19:45:18 UTC
On step 5 of test plan part 1 i got:

{
  "error": "Anonymous suggestions are disabled"
}

step 11: i don't think this is the error it should return:
{
  "errors": [
    {
      "path": "/body/title",
      "message": "Missing property."
    }
  ]
}

And I found one problem: when I'am adding suggestion through API, I can't see them in the user interface, unless I add the branchcode - it should be somehow set as mandatory I think
Comment 13 Josef Moravec 2017-01-17 19:47:13 UTC
Also, unit test are needed I think
Comment 14 Jiri Kozlovsky 2017-02-12 16:53:39 UTC
> And I found one problem: when I'am adding suggestion through API, I can't
> see them in the user interface, unless I add the branchcode - it should be
> somehow set as mandatory I think

Well, you have to change your filters (click on "Acquisition information" -> Library -> Any)

If you would like to set branch_code as mandatory, you should set up "OPACSuggestionMandatoryFields" accordingly.

Note that there is always possible to enter a suggestion without it's branchcode unless it is forced by the settings. You can do it in the OPAC & the Intranet also by setting Library -> Any.
Comment 15 Jiri Kozlovsky 2017-02-12 17:12:48 UTC
(In reply to Jiri Kozlovsky from comment #14)
> > And I found one problem: when I'am adding suggestion through API, I can't
> > see them in the user interface, unless I add the branchcode - it should be
> > somehow set as mandatory I think
> 
> Well, you have to change your filters (click on "Acquisition information" ->
> Library -> Any)
> 
> If you would like to set branch_code as mandatory, you should set up
> "OPACSuggestionMandatoryFields" accordingly.
> 
> Note that there is always possible to enter a suggestion without it's
> branchcode unless it is forced by the settings. You can do it in the OPAC &
> the Intranet also by setting Library -> Any.

But yeah, I've just noticed, that regular users doesn't have the possibility to specify the branchcode, it'll automatically belong to the library they're registered in. Only those with access to intranet can create suggestions belonging to Any library.
Comment 16 Jiri Kozlovsky 2017-02-12 17:19:21 UTC
(In reply to Jiri Kozlovsky from comment #15)
> (In reply to Jiri Kozlovsky from comment #14)
> > > And I found one problem: when I'am adding suggestion through API, I can't
> > > see them in the user interface, unless I add the branchcode - it should be
> > > somehow set as mandatory I think
> > 
> > Well, you have to change your filters (click on "Acquisition information" ->
> > Library -> Any)
> > 
> > If you would like to set branch_code as mandatory, you should set up
> > "OPACSuggestionMandatoryFields" accordingly.
> > 
> > Note that there is always possible to enter a suggestion without it's
> > branchcode unless it is forced by the settings. You can do it in the OPAC &
> > the Intranet also by setting Library -> Any.
> 
> But yeah, I've just noticed, that regular users doesn't have the possibility
> to specify the branchcode, it'll automatically belong to the library they're
> registered in. Only those with access to intranet can create suggestions
> belonging to Any library.

Well, it's a bit more complicated .. There can be set "AllowPurchaseSuggestionBranchChoice" preference, which allows user to pick a library. But there's no choice for "Any", so the behavior I'm going to implement is to choose user's default library if the preference is Off. If it is On, then it'll let user pick a library, except Any, choosing his own library if not specified.
Comment 17 Jiri Kozlovsky 2017-02-12 17:48:27 UTC
Created attachment 60133 [details] [review]
Bug 17314 - QA followup 2nd

Fixed:
Smartmatch
Updating suggestion when AnonSuggestions disabled
Not requiring title when updating
Branch choosing with respect to AllowPurchaseSuggestionBranchChoice

Test plan unchanged
Comment 18 Josef Moravec 2017-04-27 11:40:16 UTC
I think that when the API makes new suggestion, it should inject "STATUS":"ASKED" as default, if STATUS is not passed by client...

Also, when i make branch mandatory and turn on allowPurchaseSuggestionBranchChoice preference, I get the "Properties not allowed: branch" error message when providing branch code.
Comment 19 Jon Knight 2017-08-07 17:01:07 UTC
Just been playing with this (as I've been asked to look at getting our LORLS reading list system purchase predictor to generate purchasing suggestions directly into Koha rather than just emailing the suggestions to library staff).  Its good stuff.

I'd concur about the "STATUS": "ASKED" by default, and I also needed to put a "branchcode" of "TEST" in (on kohadevbox).  Without these, the suggestions made via the API didn't show up in the "Home › Acquisitions › Suggestions management" interface, even if I searched for status of "Any" and even though they were in the tables.

Good to see that it can be used to insert quantity and price too.

Is development of this patch still ongoing?  Also PUT appears to actually be a PATCH operation as it doesn't require the whole object data to be specified - should the HTTP method be changed to reflect that?
Comment 20 Jon Knight 2017-11-01 11:14:05 UTC
I noticed that this doesn't apply cleanly to the latest master HEAD on my kohadevbox.  I could help rebase if that would be useful to nudge this bug along?  Unless of course Jiri is working on an updated version?
Comment 21 Jiri Kozlovsky 2017-11-04 20:27:34 UTC
(In reply to Jon Knight from comment #20)
> I noticed that this doesn't apply cleanly to the latest master HEAD on my
> kohadevbox.  I could help rebase if that would be useful to nudge this bug
> along?  Unless of course Jiri is working on an updated version?

Well, I've been working on rebasing on top of master HEAD for a little time already and I'm near completion. 

Right now I'm actually solving a really strange bug when GET on an item (/suggestions/{id}) works perfectly fine, but GET on a list of items (/suggestions) fails on "Method not implemented" although I've basically copy & pasted the /patrons implementation.

As soon as I'll solve this strange behaviour, I'll post my work here ;) But thank you for your effort.(In reply to Jon Knight from comment #19)

> Is development of this patch still ongoing?  Also PUT appears to actually be
> a PATCH operation as it doesn't require the whole object data to be
> specified - should the HTTP method be changed to reflect that?

I'm going to fix this too in my next patch.
Comment 22 Arthur Suzuki 2019-05-28 23:58:04 UTC
Created attachment 90171 [details] [review]
Implemented suggestions REST API
Comment 23 Arthur Suzuki 2019-05-28 23:59:50 UTC
Created attachment 90172 [details] [review]
Bug 17314 : Migration from Swagger2 to OpenApi
Comment 24 Jonathan Druart 2019-05-29 00:25:55 UTC
I do not know if there is a precedence, but here, adding a new suggestion from the REST API and from the interface will not called the same method/subroutine

IMO we should not do that.
Before implementing this, we should move/update C4 code and controllers to use Koha::Suggestion.
Comment 25 Arthur Suzuki 2019-05-29 08:59:32 UTC
Created attachment 90176 [details] [review]
Bug 17314 : QA Followup

Test plan unchanged
Comment 26 Arthur Suzuki 2019-05-29 09:18:04 UTC
(In reply to Jonathan Druart from comment #24)
> I do not know if there is a precedence, but here, adding a new suggestion
> from the REST API and from the interface will not called the same
> method/subroutine
> 
> IMO we should not do that.
> Before implementing this, we should move/update C4 code and controllers to
> use Koha::Suggestion.

Hi Jonathan,
Thanks for the remark, I've just rewrote part of this patch but it's quite old and I might definitely have missed something.
I'll check your comment right now and provide a followup :)
Thanks for your fast QA answer!
Comment 27 Arthur Suzuki 2019-05-29 23:44:20 UTC
Hhmmm...
I'd say the following :
The API is not a huge mass of users.
Also, C4 code is also going to move toward Koha::Suggestion one day or another.
It's not like we'd be developing new features in C4 I'd say it's rather a move forward.

I've been looking into the dependencies to C4 but I'm still feeling a bit newbie for that task.
Is there a bug already? Couldn't find one (and it's getting late here I'll go to bed instead of creating a new one).

Plus, I'd really like to get this patch integrated to have portal software start using it (not the best reason I admit :D)
Comment 28 Tomás Cohen Arazi 2019-06-10 15:45:59 UTC
I have a few remarks:
- The method you are adding to Koha::Patron (->suggestions) needs tests, and it should be actually relying on a relationship, and thus using _new_from_dbic so it is prefetchable. This has been discussed recently so you couldn't know beforehand.
- There's now a clear distinction between endpoints that target unprivileged users (OPAC) and administrative ones (e.g. staff interface). If this bug only targets the 'privileged' one, maybe make it explicit and make sure the permissions are correct.
- The attribute names seem to come straight from the DB structure. This should be fixed. Look at the RFCs page [1] and please follow naming conventions discussed and voted there. For example, borrowernumber is not used on the API, use patron_id instead.
- POD is missing on the controller
- Take a look at Koha::REST::V1::Cities and how it uses ->objects_search. It will automagically add pagination to the list method, which is desierd on busy sites (i.e. make the list manageable).
- objects_search requires you to pass the _to_api and _to_model methods you will need to write to comply with the currently voted RFCs regarding terminology.
- If you want the end user (session) to create purchase suggestions, then you need an endpoint in /public. And if you need to list them on the patron's page, maybe worth generating /public/patron/{patron_id}/purchase_suggestions (this is very arguable, just a thought).

[1] https://wiki.koha-community.org/wiki/REST_api_RFCs
Comment 29 Arthur Suzuki 2019-07-15 11:49:40 UTC
Added RFC :
https://wiki.koha-community.org/wiki/Suggestions_endpoint_RFC

Work still in progress to make the patch conform with RFC.
Comment 30 Arthur Suzuki 2019-07-16 10:26:05 UTC
Created attachment 91545 [details] [review]
Bug 17314 : Added _to_model and _to_api methods
Comment 31 Michal Denar 2019-07-16 10:29:31 UTC
Hi Arthur,
nice to see progress in this bug. I'm ready to test :-)
Comment 32 Arthur Suzuki 2019-07-16 10:37:33 UTC
Created attachment 91546 [details] [review]
Bug 17314 : Added _to_model and _to_api methods and changed attirbutes naming
Comment 33 Arthur Suzuki 2019-07-16 10:40:34 UTC
Hi Michal,
great to see your interest! feel free to test and let me know :)
Comment 34 Tomás Cohen Arazi 2019-09-10 21:13:46 UTC
Hi all, since this got written we made some design decisions that affect this patches. They are easy to address, though :-D

- Request validation is done using the spec, by Mojolicious::Plugin::OpenAPI
- We decided not to mix 'public' endpoints (that don't require privileged access) from the ones restricted to privileged access users.
- The above decision implies that endpoints that have 'allow_owner' or 'allow_guarantor' permissions, need to be separated, and moved to /public. In this case, I'd say:

GET /public/patrons/:patron_id/suggestions <- list of suggestions
POST /public/patrons/:patron_id/suggestions { object with required attributes } <- add

This change should simplify the logic inside the controller (i.e. a separate controller method for the public one)

I haven't checked if we allow cancelling a request and in which cases it is/should be allowed. In that case a DELETE verb could be allowed in the /public namespace.

- Using C4::Context::user_env is forbidden here. It relies on Cookie auth, which is not obvious to assume is the case (we have several auth mechanisms for the API). So you have two options: (a) make the parameter mandatory (why not? and just return 400 bad request) or (b) use the stashed Koha::Patron object (i.e. the one guessed from the authentication mechanism, accessible through $c->stash('koha.user') (yes, it is the Koha::Patron object for the patron that was granted the access). Keep in mind this use case: do we allow anonymous purchase suggestions? Only authenticated users get the Koha::Patron stashed of course :-D

- This should be better handled by the separation of concerns (public vs privileged), and relaying on the spec for validation:
+            unless (any { /^$param$/ } @allowed_fields) {
+                # Ouch ! User trying to edit field he has no rights to edit!