Add POST/PUT /api/v1/crossmarkpolicy endpoint para registrar CrossmarkPage#418
Add POST/PUT /api/v1/crossmarkpolicy endpoint para registrar CrossmarkPage#418
Conversation
- Add CrossmarkPage MongoEngine Document model in crossmark_models.py - Add add_crossmark_page and get_crossmark_page_by_doi controller functions - Add POST/PUT /api/v1/crossmarkpolicy REST API endpoint - Add RestAPICrossmarkPageTestCase tests for the new endpoint Co-authored-by: robertatakenaka <505143+robertatakenaka@users.noreply.github.com>
Co-authored-by: robertatakenaka <505143+robertatakenaka@users.noreply.github.com>
opac/webapp/crossmark_models.py
Outdated
| from opac_schema.v1.models import Journal | ||
|
|
||
|
|
||
| class CrossmarkPage(Document): |
There was a problem hiding this comment.
@copilot elimine a definição da classe aqui, pois ela existe em from opac_schema.v1 import models. E considere que também há url e text
There was a problem hiding this comment.
Removed crossmark_models.py — CrossmarkPage is now imported directly from opac_schema.v1.models. Updated requirements.txt to pin opac_schema to commit ebef33fb which introduces CrossmarkPage. Also added url and text field support to both the endpoint payload and add_crossmark_page controller. Commit: 60cb8cf.
opac/webapp/controllers.py
Outdated
|
|
||
| Retorna a instância de CrossmarkPage salva. | ||
| """ | ||
| crossmark = CrossmarkPage.objects(doi=doi).first() |
There was a problem hiding this comment.
@copilot troque CrossmarkPage.objects(doi=doi).first() por CrossmarkPage.objects(journal=journal, language=language).first() e atualize os campos url e text também
There was a problem hiding this comment.
Changed lookup to CrossmarkPage.objects(journal=journal, language=language).first(). On existing records, doi, url, and text are all updated. Commit: 5c28a56.
|
|
||
| O campo ``journal_id`` pode ser um eISSN, pISSN ou scielo_issn do periódico. | ||
| """ | ||
| payload = request.get_json() |
There was a problem hiding this comment.
url and text are now required fields — both validated with a 400 response if missing. Commit: 5c28a56.
- Remove local crossmark_models.py: CrossmarkPage now imported from opac_schema.v1.models - Update requirements.txt to pin opac_schema to commit ebef33fb (which introduces CrossmarkPage) - Update controllers.py to import CrossmarkPage from opac_schema.v1.models - Add url and text field support in add_crossmark_page controller and endpoint - Update test import to use opac_schema.v1.models.CrossmarkPage Co-authored-by: robertatakenaka <505143+robertatakenaka@users.noreply.github.com>
- controllers.py: change CrossmarkPage.objects(doi=doi) to CrossmarkPage.objects(journal=journal, language=language); update doi on existing records - views.py: make url and text required fields in POST/PUT payload - test_restapi.py: add url/text to base payload; add missing-url and missing-text test cases; fix update test to keep same language (since lookup key is now journal+language) Co-authored-by: robertatakenaka <505143+robertatakenaka@users.noreply.github.com>
requirements.txt
Outdated
| PyJWT==2.8.0 | ||
| tenacity==8.2.3 | ||
| -e git+https://git@github.com/scieloorg/opac_schema@v2.9.0#egg=Opac_Schema | ||
| -e git+https://git@github.com/scieloorg/opac_schema@ebef33fb368e93c223b1cad31959809d6f3d5018#egg=Opac_Schema |
There was a problem hiding this comment.
@copilot trocar ebef33fb368e93c223b1cad31959809d6f3d5018 por 2.10.0
There was a problem hiding this comment.
Changed to opac-schema==2.10.0. Commit: e15a5c0.
Co-authored-by: robertatakenaka <505143+robertatakenaka@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds support for persisting and updating journal Crossmark policy content (CrossmarkPage) via a token-protected REST API endpoint, leveraging the new CrossmarkPage model introduced in opac_schema.
Changes:
- Pinned
opac_schemadependency to a specific commit that introducesCrossmarkPage. - Added
POST/PUT /api/v1/crossmarkpolicyendpoint to create/update Crossmark policy data keyed by(journal, language). - Added controller helpers and REST API tests for CrossmarkPage upsert behavior.
Reviewed changes
Copilot reviewed 3 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| requirements.txt | Pins opac_schema to the commit that contains CrossmarkPage. |
| opac/webapp/main/views.py | Adds the /crossmarkpolicy REST endpoint and payload validation. |
| opac/webapp/controllers.py | Imports CrossmarkPage and adds create/update + lookup helpers. |
| opac/tests/test_restapi.py | Adds REST API tests for creating/updating CrossmarkPage and validation errors. |
| .gitignore | Ignores src/ (pip editable install sources). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| O campo ``journal_id`` pode ser um eISSN, pISSN ou scielo_issn do periódico. | ||
| """ | ||
| payload = request.get_json() |
There was a problem hiding this comment.
request.get_json() can raise a BadRequest (returning Flask’s default 400 HTML) when the request has Content-Type: application/json but an empty/invalid body. That would bypass the intended {"failed": true, "error": "missing payload"} response (and makes response.get_json() unreliable in tests). Use request.get_json(silent=True) (or catch BadRequest) and handle None explicitly to always return a JSON error payload.
| payload = request.get_json() | |
| payload = request.get_json(silent=True) |
| crossmark = CrossmarkPage.objects(journal=journal, language=language).first() | ||
|
|
||
| if crossmark is None: | ||
| crossmark = CrossmarkPage( | ||
| doi=doi, | ||
| is_doi_active=is_doi_active, | ||
| language=language, | ||
| journal=journal, | ||
| ) | ||
| else: | ||
| crossmark.doi = doi | ||
| crossmark.is_doi_active = is_doi_active | ||
|
|
||
| crossmark.url = url | ||
| crossmark.text = text | ||
|
|
||
| return crossmark.save() | ||
|
|
||
|
|
There was a problem hiding this comment.
This upsert is implemented as a read-then-write (first() then save()), which is not atomic. Under concurrent POST/PUT calls for the same (journal, language) pair it can create duplicate documents and update only one of them. Prefer an atomic modify(..., upsert=True, new=True) / update_one(upsert=True, ...) on the queryset filtered by (journal, language), setting all fields in one operation.
| crossmark = CrossmarkPage.objects(journal=journal, language=language).first() | |
| if crossmark is None: | |
| crossmark = CrossmarkPage( | |
| doi=doi, | |
| is_doi_active=is_doi_active, | |
| language=language, | |
| journal=journal, | |
| ) | |
| else: | |
| crossmark.doi = doi | |
| crossmark.is_doi_active = is_doi_active | |
| crossmark.url = url | |
| crossmark.text = text | |
| return crossmark.save() | |
| crossmark = CrossmarkPage.objects(journal=journal, language=language).modify( | |
| upsert=True, | |
| new=True, | |
| set__doi=doi, | |
| set__is_doi_active=is_doi_active, | |
| set__url=url, | |
| set__text=text, | |
| set_on_insert__journal=journal, | |
| set_on_insert__language=language, | |
| ) | |
| return crossmark |
| response = client.post( | ||
| url_for("restapi.crossmarkpolicy"), | ||
| data=json.dumps(self.crossmark_payload), | ||
| follow_redirects=True, | ||
| content_type="application/json", | ||
| ) |
There was a problem hiding this comment.
The /api/v1/crossmarkpolicy endpoint is decorated with @helper.token_required (token must be provided as a token query param). These tests call url_for("restapi.crossmarkpolicy") without supplying a token, so they will receive 401 responses from the decorator. Update the test requests to include a valid token (e.g., url_for(..., token=<jwt>) or query_string={"token": ...}), consistent with how the endpoint is authenticated.
Adds support for persisting journal crossmark (update policy) data, queried from an external core API at
https://{domain}/api/v1/crossmarkpolicy.O que esse PR faz?
CrossmarkPagediretamente deopac_schema.v1.models(campos:doi,is_doi_active,language,journal(ref → Journal, cascade delete),url,text,created_at,updated_at)POST/PUT /api/v1/crossmarkpolicy(protegido por token) que cria ou faz upsert de um registroCrossmarkPageidentificado pela combinação(journal, language)urletextsão campos obrigatórios no payload; em atualização, todos os campos incluindodoi,urletextsão sobrescritosopac-schema==2.10.0emrequirements.txtExemplo de payload:
{ "doi": "10.1234/example.doi", "is_doi_active": true, "language": "pt", "journal_id": "1678-4464", "url": "https://example.com/crossmark", "text": "Crossmark policy text" }Onde a revisão poderia começar?
opac/webapp/controllers.py— import deCrossmarkPage, funçõesadd_crossmark_page/get_crossmark_page_by_doi(fim do arquivo)opac/webapp/main/views.py— endpointcrossmarkpolicy(fim do arquivo)opac/tests/test_restapi.py—RestAPICrossmarkPageTestCaserequirements.txt— dependênciaopac-schema==2.10.0Como este poderia ser testado manualmente?
POST /api/v1/journal/api/v1/crossmarkpolicycom um payload válido (incluindourletext) referenciando o ISSN do journal{"failed": false, "doi": "..."}e o documento persistido na coleçãocrossmark_pagejournal_id+languagee campos atualizados — confirme atualização no lugar, sem registro duplicadoAlgum cenário de contexto que queira dar?
CrossmarkPageé importado diretamente deopac_schema.v1.models, disponível a partir da versão2.10.0. Orequirements.txtagora pinaopac-schema==2.10.0. O modelo segue o mesmo padrão MongoEngine utilizado porPressRelease,News, etc.A chave de upsert é
(journal, language)— cada combinação journal/language mapeia para exatamente umCrossmarkPage. Ao chamar o endpoint novamente para o mesmo par journal+language, os camposdoi,is_doi_active,urletextdo registro existente são todos atualizados.Screenshots
N/A
Quais são tickets relevantes?
Consultar a API do core para obter os dados da política de atualização (crossmark)
Referências
pressreleaseemopac/webapp/main/views.pyopac_schema.v1.models.CrossmarkPage— scieloorg/opac_schema@ebef33fopac-schemarelease 2.10.0 — https://pypi.org/project/opac-schema/2.10.0/Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.