From a48e6ed0ab24b58f07a59cb6a19b0f55a5eee321 Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Thu, 25 Sep 2025 15:00:06 -0300 Subject: [PATCH 01/17] adiciona func updat_collection --- opac/webapp/main/views.py | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/opac/webapp/main/views.py b/opac/webapp/main/views.py index 022827a60..6873cfd18 100644 --- a/opac/webapp/main/views.py +++ b/opac/webapp/main/views.py @@ -1,8 +1,8 @@ # coding: utf-8 -import re import json import logging import mimetypes +import re from collections import OrderedDict from datetime import datetime, timedelta from io import BytesIO @@ -11,20 +11,9 @@ import requests from bs4 import BeautifulSoup from feedwerk.atom import AtomFeed -from flask import ( - Response, - abort, - current_app, - g, - jsonify, - make_response, - redirect, - render_template, - request, - send_from_directory, - session, - url_for, -) +from flask import (Response, abort, current_app, g, jsonify, make_response, + redirect, render_template, request, send_from_directory, + session, url_for) from flask_babelex import gettext as _ from legendarium.formatter import descriptive_short_format from lxml import etree @@ -32,15 +21,14 @@ from packtools import HTMLGenerator from webapp import babel, cache, controllers, forms from webapp.choices import STUDY_AREAS -from webapp.controllers import create_press_release_record from webapp.config.lang_names import display_original_lang_name +from webapp.controllers import create_press_release_record +from webapp.main.errors import internal_server_error, page_not_found from webapp.utils import utils -from webapp.utils.caching import cache_key_with_lang, cache_key_with_lang_with_qs -from webapp.main.errors import page_not_found, internal_server_error +from webapp.utils.caching import (cache_key_with_lang, + cache_key_with_lang_with_qs) -from . import helper - -from . import main, restapi +from . import helper, main, restapi, decorators logger = logging.getLogger(__name__) @@ -2187,7 +2175,6 @@ def pressrelease(*args): """ payload = request.get_json() - params = request.args.to_dict() if not payload.get("journal_id"): return jsonify({"failed": True, "id": 1}), 200 @@ -2222,3 +2209,11 @@ def journal_last_issues(*args): def remover_tags_html(texto): soup = BeautifulSoup(texto, 'html.parser') return soup.get_text() + + +@restapi.route("/update_collection", methods=["POST", "PUT"]) +@decorators.require_jwt +def update_collection(*args): + payload = request.get_json() + controllers.complete_collection(payload.get("results")) + return jsonify({"success": True}) From 8e58d74a4d1ff6144eb1b6f95a9fbe9458d90039 Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Thu, 25 Sep 2025 15:03:29 -0300 Subject: [PATCH 02/17] =?UTF-8?q?Adiciona=20estrutura=20para=20decodifica?= =?UTF-8?q?=C3=A7=C3=A3o=20e=20autoriza=C3=A7=C3=A3o=20do=20endpoint=20upd?= =?UTF-8?q?ate=5Fcollection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jwt_public_local.pem | 9 +++++++++ opac/webapp/config/default.py | 9 +++++++++ opac/webapp/main/decorators.py | 19 +++++++++++++++++++ opac/webapp/main/helper.py | 18 ++++++++++++++++++ requirements.txt | 1 + 5 files changed, 56 insertions(+) create mode 100644 jwt_public_local.pem create mode 100644 opac/webapp/main/decorators.py diff --git a/jwt_public_local.pem b/jwt_public_local.pem new file mode 100644 index 000000000..e9043afa7 --- /dev/null +++ b/jwt_public_local.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQB2+n5vaPzgUNvvnyDQ8NJi +XCpUx1gktxJ9MUP5RTR+v9z5h4K0I+ktSHtydgOr43d/TlWztOT5sVubC3AsLxV9 +Be5D1zRZ5PqJ881fDnydhpedyjrXdfhvKdMRSPGptD7lYeQZh5M46yH1GZHNMX5Z +cVrRynUAOWr7js0HLgRuWPgTvUJm4YGztTBJGw27O4h5v9UvDpe42LFEeVLxtmWT +LPJncGSQdcE1uBBGcQ3SYrkOhcJ/fwDAlAMvHu5CrYnk5cQ2Ge1jTqOfbtcWTFly +E5EbZFqUHzwu4yHYmN8LDp0/siF/2dGnMANRVkEHASsqlbRgBtZUBdDOrPJA6ElB +AgMBAAE= +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/opac/webapp/config/default.py b/opac/webapp/config/default.py index ed183774f..7610a46d9 100644 --- a/opac/webapp/config/default.py +++ b/opac/webapp/config/default.py @@ -690,3 +690,12 @@ ANALYTICS_AGENT_DARKVISITORS_ENABLED = os.environ.get('OPAC_ANALYTICS_AGENT_DARKVISITORS_ENABLED', 'False').lower() in ('true', '1', 't', 'yes', 'y') ANALYTICS_AGENT_DARKVISITORS_PROJECT_KEY = os.environ.get("OPAC_ANALYTICS_AGENT_DARKVISITORS_PROJECT_KEY") +# JWT PARA ENDPOINT CORE TO COLLECTION +JWT_PUBLIC_KEY_PATH = os.environ.get("JWT_PUBLIC_KEY_PATH", default="/app/jwt_public_local.pem") +with open(JWT_PUBLIC_KEY_PATH, "rb") as f: + JWT_PUBLIC_KEY_PEM = f.read() + +JWT_ALG = "RS256" +JWT_ISS = os.environ.get("JWT_ISS", "https://api.seu-django.com") +JWT_AUD = os.environ.get("JWT_AUD", "seu-flask-servico") + diff --git a/opac/webapp/main/decorators.py b/opac/webapp/main/decorators.py new file mode 100644 index 000000000..c56989734 --- /dev/null +++ b/opac/webapp/main/decorators.py @@ -0,0 +1,19 @@ +from functools import wraps +from flask import jsonify, g +from jwt import PyJWTError +from .helper import get_bearer_token, verify_jwt + + +def require_jwt(f): + @wraps(f) + def wrapper(*args, **kwargs): + token = get_bearer_token() + if not token: + return jsonify({"detail": "Missing Bearer token"}), 401 + try: + g.jwt = verify_jwt(token) + except PyJWTError as e: + print("Erro na validação JWT:", str(e)) + return jsonify({"detail": f"Invalid token: {str(e)}"}), 401 + return f(*args, **kwargs) + return wrapper \ No newline at end of file diff --git a/opac/webapp/main/helper.py b/opac/webapp/main/helper.py index 4d97886cb..5a330cd0a 100644 --- a/opac/webapp/main/helper.py +++ b/opac/webapp/main/helper.py @@ -68,3 +68,21 @@ def auth(): ), 401, ) + + +def get_bearer_token(): + auth = request.headers.get("Authorization", "") + if auth.startswith("Bearer "): + return auth[len("Bearer "):] + return None + +def verify_jwt(token): + return jwt.decode( + token, + current_app.config["JWT_PUBLIC_KEY_PEM"], + algorithms=[current_app.config["JWT_ALG"]], + audience=current_app.config["JWT_AUD"], + issuer=current_app.config["JWT_ISS"], + # options={"require": ["exp", "iat", "nbf", "iss", "aud"]}, + leeway=30, + ) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 39fe5cdd4..85de160db 100644 --- a/requirements.txt +++ b/requirements.txt @@ -97,3 +97,4 @@ 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/packtools@4.11.20#egg=packtools -e git+https://github.com/scieloorg/scieloh5m5.git@1.9.5#egg=scieloh5m5 +cryptography==46.0.1 \ No newline at end of file From 937ae432bc4932ec9aeded998edcdbcc43597d8b Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Thu, 25 Sep 2025 15:04:54 -0300 Subject: [PATCH 03/17] =?UTF-8?q?Adiciona=20fun=C3=A7=C3=B5es=20para=20atr?= =?UTF-8?q?ibuir=20valores=20nos=20attr=20de=20collection=20e=20sponsor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- opac/webapp/controllers.py | 164 ++++++++++++++++++++++--- opac/webapp/utils/handler_with_logo.py | 43 +++++++ 2 files changed, 191 insertions(+), 16 deletions(-) create mode 100644 opac/webapp/utils/handler_with_logo.py diff --git a/opac/webapp/controllers.py b/opac/webapp/controllers.py index c812400c8..62bf9da50 100644 --- a/opac/webapp/controllers.py +++ b/opac/webapp/controllers.py @@ -6,11 +6,9 @@ ou outras camadas superiores, evitando assim que as camadas superiores acessem diretamente a camada inferior de modelos. """ -import logging import io +import logging import re -import requests -from bs4 import BeautifulSoup from collections import OrderedDict from datetime import datetime from uuid import uuid4 @@ -24,26 +22,18 @@ from flask_mongoengine import Pagination from legendarium.formatter import descriptive_very_short_format from mongoengine import Q -from mongoengine.errors import InvalidQueryError -from opac_schema.v1.models import ( - Article, - Collection, - Issue, - Journal, - News, - Pages, - PressRelease, - Sponsor, - LastIssue, -) +from opac_schema.v1.models import (Article, Collection, Issue, Journal, + LastIssue, News, Pages, PressRelease, + Sponsor) from scieloh5m5 import h5m5 from slugify import slugify from webapp import dbsql from .choices import INDEX_NAME, JOURNAL_STATUS, STUDY_AREAS +from .factory import ArticleFactory, IssueFactory, JournalFactory from .models import User -from .factory import JournalFactory, IssueFactory, ArticleFactory from .utils import utils +from .utils.handler_with_logo import handler_with_logo HIGHLIGHTED_TYPES = ( "article-commentary", @@ -174,6 +164,148 @@ def get_collection_tweets(): return [] +def extract_collection_names(json_data): + data ={} + for name in json_data.get("collection_names"): + if name.get("language"): + lang = name.get("language").get("code2") + data[lang] = name.get("text") + return data + + +def set_atributtes_logos(collection, logos, name_logos=["home_logo", "logo_menu", "header_logo"], langs=["pt", "en", "es"]): + """ + Atribuí os logos do modelo collection. (home_logo, logo_menu, header_logo) + Ex: + "logos": { + "homepage": { + "pt": "http://localhost/media/original_images/wjcm_glogo_F5dW55p.gif", + "en": "http://localhost/media/original_images/zcr_glogo_eCDkZlK.gif" + }, + "header": { + "pt": "http://localhost/media/original_images/yt_glogo_8AxTwaK.gif" + } + } + """ + if not logos: + return None + list_logo = [] + list_logo.append(logos.get("homepage", "")) + list_logo.append(logos.get("header", "")) + list_logo.append(logos.get("menu", "")) + for logo in list_logo: + if not logo: + continue + for name_logo, lang in zip(name_logos, langs): + if hasattr(collection, f"{name_logo}_{lang}"): + logo = handler_with_logo(logo_url=logo.get(lang), folder=f"img/{name_logo}") + if logo.get("rel_path"): + collection_logo = f"http://{current_app.config['SERVER_NAME']}{logo.get('rel_path')}" + setattr(collection, f"{name_logo}_{lang}", collection_logo) + + +def complete_collection(json_data): + collection = get_current_collection() + if not collection or not json_data: + return None + print(json_data) + + code = json_data.get("code") + main_name = json_data.get('main_name') + + if code and collection.acronym != code: + collection.acronym = code + if main_name and collection.name != main_name: + collection.name = main_name + + sponsors = handler_collection_sponsos(json_data.get("supporting_organizations")) + collection_names = extract_collection_names(json_data=json_data) + set_atributtes_logos(collection=collection, logos=json_data.get("logos")) + collection.name_pt = collection_names.get('pt') + collection.name_es = collection_names.get('es') + collection.name_en = collection_names.get('en') + collection.sponsors = sponsors + + collection.save() + + +def upsert_sponsor_by_acronym(data, order): + """ + Cria ou atualiza objetos sponsors e retorna o objeto Sponsor + Order é de acordo com a ordem recebida no payload do endpoint update_collection. + Ex data: + Um dicionario com os dados do sponsor + { + "acronym": "SP", + "name": "Sponsor", + "url": "https://www.sponsor.com" + "logo_url": "https://core.scielo.org/media/original_images/logo.png" + } + """ + import time + + name = data.get('name', '').strip() + url = data.get('url') or None + logo_url = data.get("logo_url") or None + + logo = handler_with_logo(logo_url=logo_url, folder="img/sponsors") + + # Por causa do order unique, evitar error ao mudar a ordem + temp_order = -int(time.time()*1000) # incrementa um valor aleatório em order. + rel_path = logo.get("rel_path") + obj = Sponsor.objects(name=name).modify( + upsert=True, + new=True, + set__url=url, + set__order=temp_order, + set__logo_url=f"http://{current_app.config['SERVER_NAME']}{rel_path}" if rel_path else None, + ) + existing = Sponsor.objects(order=order, _id__ne=obj.id).first() + if existing: + existing.modify(set__order=temp_order - 1) + obj.modify(set__order=order) + return obj + + +def handler_collection_sponsos(data): + """ + Recebe uma lista de dados sobre os sponsors e retorna uma lista de objetos sponsors + Ex data: + Uma lista de dicionarios com os dados dos sponsors + [ + { + "organization": { + "acronym": "SP", + "name": "Sponsor", + "url": "https://www.sponsor.com" + "logo_url": "https://core.scielo.org/media/original_images/logo.png" + "location": { + "country_name": "Brasil", + "country_acronym": "BR", + "country_acron3": "BRA", + "state_name": "SP", + "state_acronym": "SP", + "city_name": "São Paulo" + + } + }, + } + ] + """ + + sponsors = [] + if not data: + return sponsors + if not isinstance(data, list): + raise ValueError("data must be a list of sponsor dicts") + + for i, item in enumerate(data): + sponsor = upsert_sponsor_by_acronym(item.get("organization"), order=i) + if sponsor is not None: + sponsors.append(sponsor) + return sponsors + + # -------- PRESSRELEASES -------- diff --git a/opac/webapp/utils/handler_with_logo.py b/opac/webapp/utils/handler_with_logo.py new file mode 100644 index 000000000..e84f0891c --- /dev/null +++ b/opac/webapp/utils/handler_with_logo.py @@ -0,0 +1,43 @@ +import logging +import os +from urllib.parse import urlparse + +import requests +from flask import current_app + + +def handler_with_logo(logo_url, folder): + """ + Ex logo_url: https://core.scielo.org/media/original_images/av_glogo.gif + + """ + if not logo_url or logo_url == "null": + return {} + + # Extrai o nome do arquivo com extensão a partir da URL. + base_name = os.path.basename(urlparse(logo_url).path) + rel_path = os.path.join(folder, base_name) + # abs_path /app/opac/webapp/static/img/sponsors/screenshot_from_2024-10-14_11-20-16.png + abs_path = os.path.join(current_app.static_folder, rel_path) + os.makedirs(os.path.dirname(abs_path), exist_ok=True) + print(os.path.join(current_app.static_url_path, rel_path)) + try: + resp = requests.get(logo_url, stream=True, timeout=60) + resp.raise_for_status() + + with open(abs_path, "wb") as f: + for chuck in resp.iter_content(chunk_size=8192): + f.write(chuck) + logging.info(f"File {base_name} downloaded successfully") + except requests.exceptions.RequestException as e: + logging.error(f"Error downloading file {base_name}: {e}") + except OSError as e: + logging.error(f"Error saving file {base_name}: {e}") + + return { + 'abs_path': abs_path, + 'rel_path': os.path.join( + current_app.static_url_path, + rel_path + ) + } \ No newline at end of file From e00eb701f092bfe91517b2861c72e92fde434195 Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Thu, 25 Sep 2025 15:12:52 -0300 Subject: [PATCH 04/17] remove inutils imports --- opac/webapp/main/views.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/opac/webapp/main/views.py b/opac/webapp/main/views.py index 6873cfd18..63c849154 100644 --- a/opac/webapp/main/views.py +++ b/opac/webapp/main/views.py @@ -2,7 +2,6 @@ import json import logging import mimetypes -import re from collections import OrderedDict from datetime import datetime, timedelta from io import BytesIO @@ -17,18 +16,17 @@ from flask_babelex import gettext as _ from legendarium.formatter import descriptive_short_format from lxml import etree -from opac_schema.v1.models import Article, Collection, Issue, Journal +from opac_schema.v1.models import Article, Collection, Journal from packtools import HTMLGenerator from webapp import babel, cache, controllers, forms from webapp.choices import STUDY_AREAS from webapp.config.lang_names import display_original_lang_name from webapp.controllers import create_press_release_record -from webapp.main.errors import internal_server_error, page_not_found from webapp.utils import utils from webapp.utils.caching import (cache_key_with_lang, cache_key_with_lang_with_qs) -from . import helper, main, restapi, decorators +from . import decorators, helper, main, restapi logger = logging.getLogger(__name__) From 74a57c6ca4b084c5b8e5f4eb0c2c015ad2c47b6c Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Thu, 25 Sep 2025 15:07:33 -0300 Subject: [PATCH 05/17] gitignore update --- .gitignore | 1 + data/db/.gitkeep | 0 2 files changed, 1 insertion(+) delete mode 100644 data/db/.gitkeep diff --git a/.gitignore b/.gitignore index d230d7d50..dbbffb437 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,4 @@ opac/webapp/media/images/*.* # nodejs/gulp/etc node_modules/ +data \ No newline at end of file diff --git a/data/db/.gitkeep b/data/db/.gitkeep deleted file mode 100644 index e69de29bb..000000000 From 90d2e49c121d701c597a3d6e865fe06f0220f4d4 Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Thu, 25 Sep 2025 15:29:18 -0300 Subject: [PATCH 06/17] Remove print --- opac/webapp/controllers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/opac/webapp/controllers.py b/opac/webapp/controllers.py index 62bf9da50..9586ea9b5 100644 --- a/opac/webapp/controllers.py +++ b/opac/webapp/controllers.py @@ -208,7 +208,6 @@ def complete_collection(json_data): collection = get_current_collection() if not collection or not json_data: return None - print(json_data) code = json_data.get("code") main_name = json_data.get('main_name') From 305993dc06af84eba525166ddd96f430a9191d5e Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Thu, 25 Sep 2025 15:29:36 -0300 Subject: [PATCH 07/17] Altera ISS e AUD de JWT --- opac/webapp/config/default.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opac/webapp/config/default.py b/opac/webapp/config/default.py index 7610a46d9..9d135cb4b 100644 --- a/opac/webapp/config/default.py +++ b/opac/webapp/config/default.py @@ -696,6 +696,6 @@ JWT_PUBLIC_KEY_PEM = f.read() JWT_ALG = "RS256" -JWT_ISS = os.environ.get("JWT_ISS", "https://api.seu-django.com") -JWT_AUD = os.environ.get("JWT_AUD", "seu-flask-servico") +JWT_ISS = os.environ.get("JWT_ISS", default="Scielo Core") +JWT_AUD = os.environ.get("JWT_AUD", default="opac_5") From 625dc7f0833b8e1fc7d34bf2fe850c6ea35bf067 Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Fri, 26 Sep 2025 14:47:06 -0300 Subject: [PATCH 08/17] remove token publico --- jwt_public_local.pem | 9 --------- opac/webapp/config/default.py | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) delete mode 100644 jwt_public_local.pem diff --git a/jwt_public_local.pem b/jwt_public_local.pem deleted file mode 100644 index e9043afa7..000000000 --- a/jwt_public_local.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBITANBgkqhkiG9w0BAQEFAAOCAQ4AMIIBCQKCAQB2+n5vaPzgUNvvnyDQ8NJi -XCpUx1gktxJ9MUP5RTR+v9z5h4K0I+ktSHtydgOr43d/TlWztOT5sVubC3AsLxV9 -Be5D1zRZ5PqJ881fDnydhpedyjrXdfhvKdMRSPGptD7lYeQZh5M46yH1GZHNMX5Z -cVrRynUAOWr7js0HLgRuWPgTvUJm4YGztTBJGw27O4h5v9UvDpe42LFEeVLxtmWT -LPJncGSQdcE1uBBGcQ3SYrkOhcJ/fwDAlAMvHu5CrYnk5cQ2Ge1jTqOfbtcWTFly -E5EbZFqUHzwu4yHYmN8LDp0/siF/2dGnMANRVkEHASsqlbRgBtZUBdDOrPJA6ElB -AgMBAAE= ------END PUBLIC KEY----- \ No newline at end of file diff --git a/opac/webapp/config/default.py b/opac/webapp/config/default.py index 9d135cb4b..d8ac365be 100644 --- a/opac/webapp/config/default.py +++ b/opac/webapp/config/default.py @@ -691,7 +691,7 @@ ANALYTICS_AGENT_DARKVISITORS_PROJECT_KEY = os.environ.get("OPAC_ANALYTICS_AGENT_DARKVISITORS_PROJECT_KEY") # JWT PARA ENDPOINT CORE TO COLLECTION -JWT_PUBLIC_KEY_PATH = os.environ.get("JWT_PUBLIC_KEY_PATH", default="/app/jwt_public_local.pem") +JWT_PUBLIC_KEY_PATH = os.environ.get("JWT_PUBLIC_KEY_PATH", default="/app/jwt_public.pem") with open(JWT_PUBLIC_KEY_PATH, "rb") as f: JWT_PUBLIC_KEY_PEM = f.read() From 04880456e94782142236027b342fd3984ee6750f Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Mon, 6 Oct 2025 16:12:44 -0300 Subject: [PATCH 09/17] =?UTF-8?q?melhora=20atribui=C3=A7=C3=A3o=20da=20var?= =?UTF-8?q?iavel=20list=5Flogo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- opac/webapp/controllers.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/opac/webapp/controllers.py b/opac/webapp/controllers.py index 9586ea9b5..9d327f2f8 100644 --- a/opac/webapp/controllers.py +++ b/opac/webapp/controllers.py @@ -189,10 +189,7 @@ def set_atributtes_logos(collection, logos, name_logos=["home_logo", "logo_menu" """ if not logos: return None - list_logo = [] - list_logo.append(logos.get("homepage", "")) - list_logo.append(logos.get("header", "")) - list_logo.append(logos.get("menu", "")) + list_logo = [logos.get(key, "") for key in ["homepage", "header", "menu"]] for logo in list_logo: if not logo: continue From bae1b7722fc215acb64a5a40a9a83ecb5be81079 Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Mon, 6 Oct 2025 16:13:07 -0300 Subject: [PATCH 10/17] muda set_atributtes_logos para set_attributtes_logos --- opac/webapp/controllers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opac/webapp/controllers.py b/opac/webapp/controllers.py index 9d327f2f8..e24aeac08 100644 --- a/opac/webapp/controllers.py +++ b/opac/webapp/controllers.py @@ -173,7 +173,7 @@ def extract_collection_names(json_data): return data -def set_atributtes_logos(collection, logos, name_logos=["home_logo", "logo_menu", "header_logo"], langs=["pt", "en", "es"]): +def set_attributtes_logos(collection, logos, name_logos=["home_logo", "logo_menu", "header_logo"], langs=["pt", "en", "es"]): """ Atribuí os logos do modelo collection. (home_logo, logo_menu, header_logo) Ex: @@ -216,7 +216,7 @@ def complete_collection(json_data): sponsors = handler_collection_sponsos(json_data.get("supporting_organizations")) collection_names = extract_collection_names(json_data=json_data) - set_atributtes_logos(collection=collection, logos=json_data.get("logos")) + set_attributtes_logos(collection=collection, logos=json_data.get("logos")) collection.name_pt = collection_names.get('pt') collection.name_es = collection_names.get('es') collection.name_en = collection_names.get('en') From 7409146731236ab621c2739a41e5b23e8d87eae0 Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Mon, 6 Oct 2025 16:13:22 -0300 Subject: [PATCH 11/17] muda nome chuck para chunk --- opac/webapp/utils/handler_with_logo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opac/webapp/utils/handler_with_logo.py b/opac/webapp/utils/handler_with_logo.py index e84f0891c..669a52d02 100644 --- a/opac/webapp/utils/handler_with_logo.py +++ b/opac/webapp/utils/handler_with_logo.py @@ -26,8 +26,8 @@ def handler_with_logo(logo_url, folder): resp.raise_for_status() with open(abs_path, "wb") as f: - for chuck in resp.iter_content(chunk_size=8192): - f.write(chuck) + for chunk in resp.iter_content(chunk_size=8192): + f.write(chunk) logging.info(f"File {base_name} downloaded successfully") except requests.exceptions.RequestException as e: logging.error(f"Error downloading file {base_name}: {e}") From 89cef51676f00fd9713383a54fc1e164c5abc398 Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Mon, 6 Oct 2025 16:13:29 -0300 Subject: [PATCH 12/17] Add logging error --- opac/webapp/main/decorators.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/opac/webapp/main/decorators.py b/opac/webapp/main/decorators.py index c56989734..4d5b7c76d 100644 --- a/opac/webapp/main/decorators.py +++ b/opac/webapp/main/decorators.py @@ -1,7 +1,10 @@ +import logging from functools import wraps -from flask import jsonify, g + +from flask import g, jsonify from jwt import PyJWTError -from .helper import get_bearer_token, verify_jwt + +from .helper import get_bearer_token, verify_jwt def require_jwt(f): @@ -13,7 +16,7 @@ def wrapper(*args, **kwargs): try: g.jwt = verify_jwt(token) except PyJWTError as e: - print("Erro na validação JWT:", str(e)) + logging.error("Erro na validação JWT:", str(e)) return jsonify({"detail": f"Invalid token: {str(e)}"}), 401 return f(*args, **kwargs) return wrapper \ No newline at end of file From 3238cc049119f8e964a663b477c2ea03731f3d70 Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Mon, 6 Oct 2025 16:43:21 -0300 Subject: [PATCH 13/17] altera nomes de variaveis em set_attributtes_logos --- opac/webapp/controllers.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/opac/webapp/controllers.py b/opac/webapp/controllers.py index e24aeac08..609b208b4 100644 --- a/opac/webapp/controllers.py +++ b/opac/webapp/controllers.py @@ -190,17 +190,16 @@ def set_attributtes_logos(collection, logos, name_logos=["home_logo", "logo_menu if not logos: return None list_logo = [logos.get(key, "") for key in ["homepage", "header", "menu"]] - for logo in list_logo: - if not logo: + for logo_data in list_logo: + if not logo_data: continue for name_logo, lang in zip(name_logos, langs): if hasattr(collection, f"{name_logo}_{lang}"): - logo = handler_with_logo(logo_url=logo.get(lang), folder=f"img/{name_logo}") - if logo.get("rel_path"): - collection_logo = f"http://{current_app.config['SERVER_NAME']}{logo.get('rel_path')}" + logo_info = handler_with_logo(logo_url=logo_data.get(lang), folder=f"img/{name_logo}") + if rel_path := logo_info.get("rel_path"): + collection_logo = f"http://{current_app.config['SERVER_NAME']}{rel_path}" setattr(collection, f"{name_logo}_{lang}", collection_logo) - def complete_collection(json_data): collection = get_current_collection() if not collection or not json_data: From 45b5db861ac754fa2ad0004e58a0d26380245913 Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Mon, 6 Oct 2025 16:43:54 -0300 Subject: [PATCH 14/17] =?UTF-8?q?Adiciona=20fun=C3=A7=C3=A3o=20para=20pega?= =?UTF-8?q?r=20get=5Fjwt=5Fpublic=5Fkey?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- opac/webapp/main/helper.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/opac/webapp/main/helper.py b/opac/webapp/main/helper.py index 5a330cd0a..ca011eba1 100644 --- a/opac/webapp/main/helper.py +++ b/opac/webapp/main/helper.py @@ -1,3 +1,4 @@ +import logging import datetime from functools import wraps @@ -76,10 +77,24 @@ def get_bearer_token(): return auth[len("Bearer "):] return None +def get_jwt_public_key(): + public_key = current_app.config["JWT_PUBLIC_KEY_PATH"] + try: + with open(public_key, "rb") as f: + return f.read() + except (FileNotFoundError, PermissionError, OSError) as e: + logging.error(f"Error reading public key: {e}") + + def verify_jwt(token): + public_key = get_jwt_public_key() + + if not public_key: + return None + return jwt.decode( token, - current_app.config["JWT_PUBLIC_KEY_PEM"], + public_key, algorithms=[current_app.config["JWT_ALG"]], audience=current_app.config["JWT_AUD"], issuer=current_app.config["JWT_ISS"], From 89248b9a7500308030a3ddc04bb03a188b9c20d5 Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Mon, 6 Oct 2025 16:45:58 -0300 Subject: [PATCH 15/17] muda nome func handler_collection_sponsos para handler_collection_sponsors --- opac/webapp/controllers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opac/webapp/controllers.py b/opac/webapp/controllers.py index 609b208b4..2b20f7950 100644 --- a/opac/webapp/controllers.py +++ b/opac/webapp/controllers.py @@ -213,7 +213,7 @@ def complete_collection(json_data): if main_name and collection.name != main_name: collection.name = main_name - sponsors = handler_collection_sponsos(json_data.get("supporting_organizations")) + sponsors = handler_collection_sponsors(json_data.get("supporting_organizations")) collection_names = extract_collection_names(json_data=json_data) set_attributtes_logos(collection=collection, logos=json_data.get("logos")) collection.name_pt = collection_names.get('pt') @@ -262,7 +262,7 @@ def upsert_sponsor_by_acronym(data, order): return obj -def handler_collection_sponsos(data): +def handler_collection_sponsors(data): """ Recebe uma lista de dados sobre os sponsors e retorna uma lista de objetos sponsors Ex data: From 81e47d15efa17cedfbd5dce2c6cbf8c19963ad3d Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Tue, 18 Nov 2025 10:26:32 -0300 Subject: [PATCH 16/17] =?UTF-8?q?Adiciona=20condi=C3=A7=C3=A3o=20para=20ve?= =?UTF-8?q?rificar=20se=20ha=20sponsors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- opac/webapp/templates/includes/footer.html | 51 +++++++++++----------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/opac/webapp/templates/includes/footer.html b/opac/webapp/templates/includes/footer.html index 2291abac3..be3e241fa 100644 --- a/opac/webapp/templates/includes/footer.html +++ b/opac/webapp/templates/includes/footer.html @@ -81,35 +81,36 @@
-
- CAPESCAPES - CNPqCNPq - FAPESPFAPESP - BVSBVS - BIREMEBIREME - FAP-UNIFESPFAP-UNIFESP -
-
-
-
- {% if g.collection and g.collection.sponsors %} - {% for sponsor in g.collection.sponsors|sort(attribute='order') %} - {% if sponsor.url and sponsor.logo_url %} - - {% if sponsor.logo_url %} + {% if g.collection.sponsors %} +
+ {% if g.collection and g.collection.sponsors %} + {% for sponsor in g.collection.sponsors|sort(attribute='order') %} + {% if sponsor.url and sponsor.logo_url %} + + {% if sponsor.logo_url %} + {{ sponsor.name }} + {% else %} + {{ sponsor.name }} + {% endif %} + + {% elif sponsor.logo_url %} {{ sponsor.name }} - {% else %} + {% else %} {{ sponsor.name }} - {% endif %} - - {% elif sponsor.logo_url %} - {{ sponsor.name }} - {% else %} - {{ sponsor.name }} + {% endif %} + {% endfor %} {% endif %} - {% endfor %} +
+ {% else %} +
+ CAPESCAPES + CNPqCNPq + FAPESPFAPESP + BVSBVS + BIREMEBIREME + FAP-UNIFESPFAP-UNIFESP +
{% endif %} -
From 5d60f6607c6c5f1838c0797bac2d5e60d235d473 Mon Sep 17 00:00:00 2001 From: Samuel Veiga Rangel Date: Tue, 18 Nov 2025 10:26:46 -0300 Subject: [PATCH 17/17] Adiciona chave publica --- jwt_public.pem | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 jwt_public.pem diff --git a/jwt_public.pem b/jwt_public.pem new file mode 100644 index 000000000..22bcf41c3 --- /dev/null +++ b/jwt_public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAg2CAMS9xU5wlcIgD+lHv +HjmeehX1FjB0T3oJl2e5XEnI7OvqrtQTnp8Y9PQd8tjUICgeFr17mzvHDHgwBhRd +A0h0oZp0EJTr7DdsBGleV5yjLpFl8rTW8DHwWrrj0Lz91Ym527qpiosyuoBKhFRV +bN9P5ZepUyYKVzEuxPAIb2R2NBde6Ggf5p7y3RtYDRZsK0tzy2KlQree2u8Dau6a +8uS7F66h9lxg8gz6iNe2zz1OFQL1efgR4pxMYryVH58Qo3VPcgCTbf1YUoXmvnaR +iXK/otcp3RemJtsz8u5gAi81Rk71co6YRGcUF9C+IyGjx+N4qzX4iC+CY/TsuBPm +xwIDAQAB +-----END PUBLIC KEY-----