invenio-banners 3.1.1__tar.gz → 3.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of invenio-banners might be problematic. Click here for more details.

Files changed (123) hide show
  1. invenio-banners-3.2.0/.github/workflows/tests.yml +28 -0
  2. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/CHANGES.rst +4 -4
  3. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/PKG-INFO +5 -5
  4. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/__init__.py +2 -1
  5. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/records/models.py +25 -26
  6. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/resources/errors.py +4 -4
  7. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/services/results.py +9 -1
  8. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/services/schemas.py +2 -2
  9. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/services/service.py +10 -5
  10. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners.egg-info/PKG-INFO +5 -5
  11. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/tests/resources/test_resources.py +55 -26
  12. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/tests/services/test_services.py +12 -6
  13. invenio-banners-3.1.1/.github/workflows/tests.yml +0 -69
  14. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/.dockerignore +0 -0
  15. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/.editorconfig +0 -0
  16. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/.git-blame-ignore-revs +0 -0
  17. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/.github/workflows/i18n-pull.yml +0 -0
  18. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/.github/workflows/i18n-push.yml +0 -0
  19. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/.github/workflows/pypi-publish.yml +0 -0
  20. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/.tx/config +0 -0
  21. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/AUTHORS.rst +0 -0
  22. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/CONTRIBUTING.rst +0 -0
  23. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/INSTALL.rst +0 -0
  24. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/LICENSE +0 -0
  25. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/MANIFEST.in +0 -0
  26. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/README.rst +0 -0
  27. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/babel.ini +0 -0
  28. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/docs/Makefile +0 -0
  29. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/docs/api.rst +0 -0
  30. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/docs/authors.rst +0 -0
  31. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/docs/changes.rst +0 -0
  32. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/docs/conf.py +0 -0
  33. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/docs/configuration.rst +0 -0
  34. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/docs/contributing.rst +0 -0
  35. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/docs/index.rst +0 -0
  36. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/docs/installation.rst +0 -0
  37. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/docs/license.rst +0 -0
  38. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/docs/make.bat +0 -0
  39. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/docs/requirements.txt +0 -0
  40. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/docs/usage.rst +0 -0
  41. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/administration/__init__.py +0 -0
  42. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/administration/banners.py +0 -0
  43. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/alembic/5e02314da32e_create_invenio_banners_db_table.py +0 -0
  44. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/alembic/e40d93d99040_create_invenio_banners_branch.py +0 -0
  45. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/config.py +0 -0
  46. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/ext.py +0 -0
  47. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/proxies.py +0 -0
  48. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/records/__init__.py +0 -0
  49. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/resources/__init__.py +0 -0
  50. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/resources/config.py +0 -0
  51. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/resources/resource.py +0 -0
  52. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/services/__init__.py +0 -0
  53. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/services/config.py +0 -0
  54. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/services/errors.py +0 -0
  55. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/services/permissions.py +0 -0
  56. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/templates/semantic-ui/invenio_banners/banner.html +0 -0
  57. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/af/LC_MESSAGES/messages.po +0 -0
  58. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/ar/LC_MESSAGES/messages.po +0 -0
  59. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/bg/LC_MESSAGES/messages.po +0 -0
  60. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/ca/LC_MESSAGES/messages.po +0 -0
  61. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/cs/LC_MESSAGES/messages.po +0 -0
  62. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/da/LC_MESSAGES/messages.po +0 -0
  63. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/de/LC_MESSAGES/messages.po +0 -0
  64. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/de_AT/LC_MESSAGES/messages.po +0 -0
  65. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/de_DE/LC_MESSAGES/messages.po +0 -0
  66. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/el/LC_MESSAGES/messages.po +0 -0
  67. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/en_AT/LC_MESSAGES/messages.po +0 -0
  68. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/en_HU/LC_MESSAGES/messages.po +0 -0
  69. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/es/LC_MESSAGES/messages.po +0 -0
  70. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/es_CU/LC_MESSAGES/messages.po +0 -0
  71. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/es_MX/LC_MESSAGES/messages.po +0 -0
  72. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/et/LC_MESSAGES/messages.po +0 -0
  73. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/et_EE/LC_MESSAGES/messages.po +0 -0
  74. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/fa/LC_MESSAGES/messages.po +0 -0
  75. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/fa_IR/LC_MESSAGES/messages.po +0 -0
  76. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/fr/LC_MESSAGES/messages.po +0 -0
  77. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/fr_CI/LC_MESSAGES/messages.po +0 -0
  78. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/fr_FR/LC_MESSAGES/messages.po +0 -0
  79. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/gl/LC_MESSAGES/messages.po +0 -0
  80. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/hi_IN/LC_MESSAGES/messages.po +0 -0
  81. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/hr/LC_MESSAGES/messages.po +0 -0
  82. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/hu/LC_MESSAGES/messages.po +0 -0
  83. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/hu_HU/LC_MESSAGES/messages.po +0 -0
  84. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/it/LC_MESSAGES/messages.po +0 -0
  85. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/ja/LC_MESSAGES/messages.po +0 -0
  86. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/ka/LC_MESSAGES/messages.po +0 -0
  87. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/lt/LC_MESSAGES/messages.po +0 -0
  88. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/messages.pot +0 -0
  89. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/ne/LC_MESSAGES/messages.po +0 -0
  90. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/no/LC_MESSAGES/messages.po +0 -0
  91. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/pl/LC_MESSAGES/messages.po +0 -0
  92. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/pt/LC_MESSAGES/messages.po +0 -0
  93. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/ro/LC_MESSAGES/messages.po +0 -0
  94. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/ru/LC_MESSAGES/messages.po +0 -0
  95. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/rw/LC_MESSAGES/messages.po +0 -0
  96. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/sk/LC_MESSAGES/messages.po +0 -0
  97. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/sv/LC_MESSAGES/messages.po +0 -0
  98. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/sv_SE/LC_MESSAGES/messages.po +0 -0
  99. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/tr/LC_MESSAGES/messages.po +0 -0
  100. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/uk/LC_MESSAGES/messages.po +0 -0
  101. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/uk_UA/LC_MESSAGES/messages.po +0 -0
  102. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/zh_CN/LC_MESSAGES/messages.po +0 -0
  103. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/translations/zh_TW/LC_MESSAGES/messages.po +0 -0
  104. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/utils.py +0 -0
  105. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners/views.py +0 -0
  106. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners.egg-info/SOURCES.txt +0 -0
  107. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners.egg-info/dependency_links.txt +0 -0
  108. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners.egg-info/entry_points.txt +0 -0
  109. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners.egg-info/not-zip-safe +0 -0
  110. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners.egg-info/requires.txt +0 -0
  111. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/invenio_banners.egg-info/top_level.txt +0 -0
  112. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/pyproject.toml +0 -0
  113. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/requirements-devel.txt +0 -0
  114. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/run-tests.sh +0 -0
  115. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/setup.cfg +0 -0
  116. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/setup.py +0 -0
  117. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/tests/conftest.py +0 -0
  118. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/tests/records/test_disable.py +0 -0
  119. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/tests/records/test_models.py +0 -0
  120. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/tests/resources/conftest.py +0 -0
  121. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/tests/services/conftest.py +0 -0
  122. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/tests/test_invenio_banners.py +0 -0
  123. {invenio-banners-3.1.1 → invenio-banners-3.2.0}/tests/test_macro.py +0 -0
@@ -0,0 +1,28 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # This file is part of Invenio.
4
+ # Copyright (C) 2020-2024 CERN.
5
+ #
6
+ # Invenio-Banners is free software; you can redistribute it and/or modify it
7
+ # under the terms of the MIT License; see LICENSE file for more details.
8
+
9
+ name: CI
10
+
11
+ on:
12
+ push:
13
+ branches: master
14
+ pull_request:
15
+ branches: master
16
+ schedule:
17
+ # * is a special character in YAML so you have to quote this string
18
+ - cron: "0 3 * * 6"
19
+ workflow_dispatch:
20
+ inputs:
21
+ reason:
22
+ description: "Reason"
23
+ required: false
24
+ default: "Manual trigger"
25
+
26
+ jobs:
27
+ Python:
28
+ uses: inveniosoftware/workflows/.github/workflows/tests-python.yml@master
@@ -1,6 +1,5 @@
1
1
  ..
2
2
  Copyright (C) 2020-2024 CERN.
3
- Copyright (C) 2024 Northwestern University.
4
3
 
5
4
  Invenio-Banners is free software; you can redistribute it and/or modify
6
5
  it under the terms of the MIT License; see LICENSE file for more details.
@@ -8,10 +7,11 @@
8
7
  Changes
9
8
  =======
10
9
 
11
- Version v3.1.1 (released 2024-09-18)
10
+ Version v3.2.0 (released 2024-11-05)
12
11
 
13
- - admin: adjust + fix typos in descriptions of fields
14
- - i18n:push translations
12
+ - feat(administration): use html editor for message
13
+ - global: change the code to be compatible with sqlalchemy >= 2.0
14
+ - global: add compatibility layer to move to flask >= 3.0
15
15
 
16
16
  Version v3.1.0 (released 2024-08-07)
17
17
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: invenio-banners
3
- Version: 3.1.1
3
+ Version: 3.2.0
4
4
  Summary: Invenio-Banners is a module used to create and show banners with useful messages to users.
5
5
  Home-page: https://github.com/inveniosoftware/invenio-banners
6
6
  Author: CERN
@@ -38,7 +38,6 @@ Description: ..
38
38
 
39
39
  ..
40
40
  Copyright (C) 2020-2024 CERN.
41
- Copyright (C) 2024 Northwestern University.
42
41
 
43
42
  Invenio-Banners is free software; you can redistribute it and/or modify
44
43
  it under the terms of the MIT License; see LICENSE file for more details.
@@ -46,10 +45,11 @@ Description: ..
46
45
  Changes
47
46
  =======
48
47
 
49
- Version v3.1.1 (released 2024-09-18)
48
+ Version v3.2.0 (released 2024-11-05)
50
49
 
51
- - admin: adjust + fix typos in descriptions of fields
52
- - i18n:push translations
50
+ - feat(administration): use html editor for message
51
+ - global: change the code to be compatible with sqlalchemy >= 2.0
52
+ - global: add compatibility layer to move to flask >= 3.0
53
53
 
54
54
  Version v3.1.0 (released 2024-08-07)
55
55
 
@@ -1,6 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
3
  # Copyright (C) 2020-2024 CERN.
4
+ # Copyright (C) 2024 Graz University of Technology.
4
5
  #
5
6
  # Invenio-Banners is free software; you can redistribute it and/or modify it
6
7
  # under the terms of the MIT License; see LICENSE file for more details.
@@ -9,6 +10,6 @@
9
10
 
10
11
  from .ext import InvenioBanners
11
12
 
12
- __version__ = "3.1.1"
13
+ __version__ = "3.2.0"
13
14
 
14
15
  __all__ = ("__version__", "InvenioBanners")
@@ -1,6 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
3
  # Copyright (C) 2020-2023 CERN.
4
+ # Copyright (C) 2024 Graz University of Technology.
4
5
  #
5
6
  # Invenio-Banners is free software; you can redistribute it and/or modify it
6
7
  # under the terms of the MIT License; see LICENSE file for more details.
@@ -13,7 +14,6 @@ import sqlalchemy as sa
13
14
  from flask import current_app
14
15
  from invenio_db import db
15
16
  from sqlalchemy import or_
16
- from sqlalchemy.orm.exc import NoResultFound
17
17
  from sqlalchemy.sql import text
18
18
  from sqlalchemy_utils.models import Timestamp
19
19
 
@@ -24,7 +24,6 @@ class BannerModel(db.Model, Timestamp):
24
24
  """Defines a message to show to users."""
25
25
 
26
26
  __tablename__ = "banners"
27
- __versioned__ = {"versioning": False}
28
27
 
29
28
  id = db.Column(db.Integer, primary_key=True)
30
29
 
@@ -51,6 +50,7 @@ class BannerModel(db.Model, Timestamp):
51
50
  """Create a new banner."""
52
51
  _categories = [t[0] for t in current_app.config["BANNERS_CATEGORIES"]]
53
52
  assert data.get("category") in _categories
53
+
54
54
  with db.session.begin_nested():
55
55
  obj = cls(
56
56
  message=data.get("message"),
@@ -62,24 +62,24 @@ class BannerModel(db.Model, Timestamp):
62
62
  )
63
63
  db.session.add(obj)
64
64
 
65
- db.session.commit()
66
65
  return obj
67
66
 
68
67
  @classmethod
69
68
  def update(cls, data, id):
70
69
  """Update an existing banner."""
71
70
  with db.session.begin_nested():
72
- cls.query.filter_by(id=id).update(data)
73
-
74
- db.session.commit()
71
+ # NOTE:
72
+ # with db.session.get(cls, id) the model itself would be
73
+ # returned and this classmethod would be called
74
+ db.session.query(cls).filter_by(id=id).update(data)
75
75
 
76
76
  @classmethod
77
77
  def get(cls, id):
78
78
  """Get banner by its id."""
79
- try:
80
- return cls.query.filter_by(id=id).one()
81
- except NoResultFound:
82
- raise BannerNotExistsError(id)
79
+ if banner := db.session.get(cls, id):
80
+ return banner
81
+
82
+ raise BannerNotExistsError(id)
83
83
 
84
84
  @classmethod
85
85
  def delete(cls, banner):
@@ -87,15 +87,14 @@ class BannerModel(db.Model, Timestamp):
87
87
  with db.session.begin_nested():
88
88
  db.session.delete(banner)
89
89
 
90
- db.session.commit()
91
-
92
90
  @classmethod
93
91
  def get_active(cls, url_path):
94
92
  """Return active banners."""
95
93
  now = datetime.utcnow()
96
94
 
97
95
  query = (
98
- cls.query.filter(cls.active.is_(True))
96
+ db.session.query(cls)
97
+ .filter(cls.active.is_(True))
99
98
  .filter(cls.start_datetime <= now)
100
99
  .filter((cls.end_datetime.is_(None)) | (now <= cls.end_datetime))
101
100
  )
@@ -113,16 +112,17 @@ class BannerModel(db.Model, Timestamp):
113
112
  @classmethod
114
113
  def search(cls, search_params, filters):
115
114
  """Filter banners accordingly to query params."""
116
- banners = (
117
- BannerModel.query.filter(or_(*filters))
118
- .order_by(
119
- search_params["sort_direction"](text(",".join(search_params["sort"])))
120
- )
121
- .paginate(
122
- page=search_params["page"],
123
- per_page=search_params["size"],
124
- error_out=False,
125
- )
115
+ if filters == []:
116
+ filtered = db.session.query(BannerModel).filter()
117
+ else:
118
+ filtered = db.session.query(BannerModel).filter(or_(*filters))
119
+
120
+ banners = filtered.order_by(
121
+ search_params["sort_direction"](text(",".join(search_params["sort"])))
122
+ ).paginate(
123
+ page=search_params["page"],
124
+ per_page=search_params["size"],
125
+ error_out=False,
126
126
  )
127
127
 
128
128
  return banners
@@ -133,12 +133,11 @@ class BannerModel(db.Model, Timestamp):
133
133
  now = datetime.utcnow()
134
134
 
135
135
  query = (
136
- cls.query.filter(cls.active.is_(True))
136
+ db.session.query(cls)
137
+ .filter(cls.active.is_(True))
137
138
  .filter(cls.end_datetime.isnot(None))
138
139
  .filter(cls.end_datetime < now)
139
140
  )
140
141
 
141
142
  for old in query.all():
142
143
  old.active = False
143
-
144
- db.session.commit()
@@ -1,19 +1,19 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
3
  # Copyright (C) 2023 CERN.
4
+ # Copyright (C) 2024 Graz University of Technology.
4
5
  #
5
6
  # Invenio-Banners is free software; you can redistribute it and/or modify it
6
7
  # under the terms of the MIT License; see LICENSE file for more details.
7
8
 
8
9
  """Errors."""
9
10
 
10
- from flask_resources import HTTPJSONException, create_error_handler
11
-
12
- from ..services.errors import BannerNotExistsError
13
11
  import marshmallow as ma
14
12
  from flask_resources import HTTPJSONException, create_error_handler
15
13
  from invenio_records_resources.errors import validation_error_to_list_errors
16
14
 
15
+ from ..services.errors import BannerNotExistsError
16
+
17
17
 
18
18
  class HTTPJSONValidationException(HTTPJSONException):
19
19
  """HTTP exception serializing to JSON and reflecting Marshmallow errors."""
@@ -25,7 +25,7 @@ class HTTPJSONValidationException(HTTPJSONException):
25
25
  super().__init__(code=400, errors=validation_error_to_list_errors(exception))
26
26
 
27
27
 
28
- class ErrorHandlersMixin():
28
+ class ErrorHandlersMixin:
29
29
  """Mixin to define error handlers."""
30
30
 
31
31
  error_handlers = {
@@ -1,14 +1,22 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
3
  # Copyright (C) 2022-2023 CERN.
4
+ # Copyright (C) 2024 Graz University of Technology.
4
5
  #
5
6
  # Invenio-Banners is free software; you can redistribute it and/or modify it
6
7
  # under the terms of the MIT License; see LICENSE file for more details.
7
8
 
8
9
  """Service results."""
9
- from flask_sqlalchemy import Pagination
10
+
10
11
  from invenio_records_resources.services.records.results import RecordItem, RecordList
11
12
 
13
+ try:
14
+ # flask_sqlalchemy<3.0.0
15
+ from flask_sqlalchemy import Pagination
16
+ except ImportError:
17
+ # flask_sqlalchemy>=3.0.0
18
+ from flask_sqlalchemy.pagination import Pagination
19
+
12
20
 
13
21
  class BannerItem(RecordItem):
14
22
  """Single banner result."""
@@ -11,13 +11,13 @@ from datetime import datetime, timezone
11
11
 
12
12
  from invenio_records_resources.services.records.schema import BaseRecordSchema
13
13
  from marshmallow import fields, pre_load
14
- from marshmallow_utils.fields import TZDateTime
14
+ from marshmallow_utils.fields import SanitizedHTML, TZDateTime
15
15
 
16
16
 
17
17
  class BannerSchema(BaseRecordSchema):
18
18
  """Schema for banners."""
19
19
 
20
- message = fields.String(required=True)
20
+ message = SanitizedHTML(required=True)
21
21
  url_path = fields.String(allow_none=True)
22
22
  category = fields.String(required=True, metadata={"default": "info"})
23
23
  start_datetime = fields.DateTime(
@@ -1,6 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
3
  # Copyright (C) 2022-2023 CERN.
4
+ # Copyright (C) 2024 Graz University of Technology.
4
5
  #
5
6
  # Invenio-Banners is free software; you can redistribute it and/or modify it
6
7
  # under the terms of the MIT License; see LICENSE file for more details.
@@ -10,6 +11,7 @@
10
11
  import distutils.util
11
12
 
12
13
  import arrow
14
+ from invenio_db.uow import unit_of_work
13
15
  from invenio_records_resources.services import RecordService
14
16
  from invenio_records_resources.services.base import LinksTemplate
15
17
  from invenio_records_resources.services.base.utils import map_search_params
@@ -81,7 +83,8 @@ class BannerService(RecordService):
81
83
  links_item_tpl=self.links_item_tpl,
82
84
  )
83
85
 
84
- def create(self, identity, data, raise_errors=True):
86
+ @unit_of_work()
87
+ def create(self, identity, data, raise_errors=True, uow=None):
85
88
  """Create a banner."""
86
89
  self.require_permission(identity, "create")
87
90
 
@@ -99,17 +102,18 @@ class BannerService(RecordService):
99
102
  self, identity, banner, links_tpl=self.links_item_tpl, errors=errors
100
103
  )
101
104
 
102
- def delete(self, identity, id):
105
+ @unit_of_work()
106
+ def delete(self, identity, id, uow=None):
103
107
  """Delete a banner from database."""
104
108
  self.require_permission(identity, "delete")
105
109
 
106
110
  banner = self.record_cls.get(id)
107
-
108
111
  self.record_cls.delete(banner)
109
112
 
110
113
  return self.result_item(self, identity, banner, links_tpl=self.links_item_tpl)
111
114
 
112
- def update(self, identity, id, data):
115
+ @unit_of_work()
116
+ def update(self, identity, id, data, uow=None):
113
117
  """Update a banner."""
114
118
  self.require_permission(identity, "update")
115
119
 
@@ -131,7 +135,8 @@ class BannerService(RecordService):
131
135
  links_tpl=self.links_item_tpl,
132
136
  )
133
137
 
134
- def disable_expired(self, identity):
138
+ @unit_of_work()
139
+ def disable_expired(self, identity, uow=None):
135
140
  """Disable expired banners."""
136
141
  self.require_permission(identity, "disable")
137
142
  self.record_cls.disable_expired()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: invenio-banners
3
- Version: 3.1.1
3
+ Version: 3.2.0
4
4
  Summary: Invenio-Banners is a module used to create and show banners with useful messages to users.
5
5
  Home-page: https://github.com/inveniosoftware/invenio-banners
6
6
  Author: CERN
@@ -38,7 +38,6 @@ Description: ..
38
38
 
39
39
  ..
40
40
  Copyright (C) 2020-2024 CERN.
41
- Copyright (C) 2024 Northwestern University.
42
41
 
43
42
  Invenio-Banners is free software; you can redistribute it and/or modify
44
43
  it under the terms of the MIT License; see LICENSE file for more details.
@@ -46,10 +45,11 @@ Description: ..
46
45
  Changes
47
46
  =======
48
47
 
49
- Version v3.1.1 (released 2024-09-18)
48
+ Version v3.2.0 (released 2024-11-05)
50
49
 
51
- - admin: adjust + fix typos in descriptions of fields
52
- - i18n:push translations
50
+ - feat(administration): use html editor for message
51
+ - global: change the code to be compatible with sqlalchemy >= 2.0
52
+ - global: add compatibility layer to move to flask >= 3.0
53
53
 
54
54
  Version v3.1.0 (released 2024-08-07)
55
55
 
@@ -1,78 +1,96 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
3
  # Copyright (C) 2022 CERN.
4
+ # Copyright (C) 2024 Graz University of Technology.
4
5
  #
5
6
  # Invenio-Banners is free software; you can redistribute it and/or modify it
6
7
  # under the terms of the MIT License; see LICENSE file for more details.
7
8
 
8
9
  """Banner resource tests."""
9
- from datetime import date, datetime
10
+ from datetime import date, datetime, timedelta
10
11
 
11
12
  import pytest
13
+ from invenio_db import db
12
14
  from invenio_records_resources.services.errors import PermissionDeniedError
13
15
 
14
16
  from invenio_banners.records import BannerModel
15
17
 
16
18
  banners = {
19
+ "banner0": {
20
+ "message": "banner0",
21
+ "url_path": "/banner0",
22
+ "category": "info",
23
+ "active": True,
24
+ "start_datetime": date(2022, 7, 20).strftime("%Y-%m-%d %H:%M:%S"),
25
+ "end_datetime": (datetime.utcnow() - timedelta(days=20)).strftime(
26
+ "%Y-%m-%d %H:%M:%S"
27
+ ),
28
+ },
17
29
  "banner1": {
18
30
  "message": "banner1",
19
31
  "url_path": "/banner1",
20
32
  "category": "info",
21
33
  "active": True,
22
- "start_datetime": date(2022, 7, 20),
23
- "end_datetime": date(2023, 1, 29),
34
+ "start_datetime": date(2022, 7, 20).strftime("%Y-%m-%d %H:%M:%S"),
35
+ "end_datetime": (datetime.utcnow() + timedelta(days=20)).strftime(
36
+ "%Y-%m-%d %H:%M:%S"
37
+ ),
24
38
  },
25
39
  "banner2": {
26
40
  "message": "banner2",
27
41
  "url_path": "/banner2",
28
42
  "category": "other",
29
43
  "active": False,
30
- "start_datetime": date(2022, 12, 15),
31
- "end_datetime": date(2023, 1, 5),
44
+ "start_datetime": date(2022, 12, 15).strftime("%Y-%m-%d %H:%M:%S"),
45
+ "end_datetime": (datetime.utcnow() + timedelta(days=10)).strftime(
46
+ "%Y-%m-%d %H:%M:%S"
47
+ ),
32
48
  },
33
49
  "banner3": {
34
50
  "message": "banner3",
35
51
  "url_path": "/banner3",
36
52
  "category": "warning",
37
53
  "active": True,
38
- "start_datetime": date(2023, 1, 20),
39
- "end_datetime": date(2023, 2, 25),
54
+ "start_datetime": date(2023, 1, 20).strftime("%Y-%m-%d %H:%M:%S"),
55
+ "end_datetime": (datetime.utcnow() + timedelta(days=30)).strftime(
56
+ "%Y-%m-%d %H:%M:%S"
57
+ ),
58
+ },
59
+ "html_banner": {
60
+ "message": '<h1>HTML aware banner.</h1>.\n \'<p class="test">paragraph<br /></p><script '
61
+ "type=\"text/javascript\">alert('You won!')</script>",
62
+ "url_path": "/html_banner",
63
+ "category": "warning",
64
+ "active": True,
65
+ "start_datetime": datetime(2022, 7, 20, 20, 0, 0).strftime("%Y-%m-%d %H:%M:%S"),
40
66
  },
41
67
  }
42
68
 
43
69
 
44
70
  def _create_banner(client, data, headers, status_code=None):
45
71
  """Send POST request."""
46
- result = client.post(
47
- "/banners/",
48
- headers=headers,
49
- json=data,
50
- )
72
+ result = client.post("/banners/", headers=headers, json=data)
51
73
  assert result.status_code == status_code
52
74
  return result
53
75
 
54
76
 
55
77
  def _update_banner(client, id, data, headers, status_code=None):
56
78
  """Send PUT request."""
57
- result = client.put(
58
- "/banners/{0}".format(id),
59
- headers=headers,
60
- json=data,
61
- )
79
+ result = client.put(f"/banners/{id}", headers=headers, json=data)
62
80
  assert result.status_code == status_code
63
81
  return result
64
82
 
65
83
 
66
84
  def _delete_banner(client, id, headers, status_code=None):
67
85
  """Send DELETE request."""
68
- result = client.delete("/banners/{0}".format(id), headers=headers)
86
+ result = client.delete(f"/banners/{id}", headers=headers)
69
87
  assert result.status_code == status_code
70
88
  return result
71
89
 
72
90
 
73
91
  def _get_banner(client, id, status_code=None):
74
92
  """Send GET request."""
75
- result = client.get("/banners/{0}".format(id))
93
+ result = client.get(f"/banners/{id}")
76
94
  assert result.status_code == status_code
77
95
  return result
78
96
 
@@ -108,15 +126,15 @@ def test_create_banner(client, admin, headers):
108
126
  def test_disable_expired_after_create_action(client, admin, headers):
109
127
  """Disable expired banners after a create a banner action."""
110
128
  # create banner first
111
- banner1 = BannerModel.create(banners["banner1"])
112
- assert banner1.active is True
129
+ banner0 = BannerModel.create(banners["banner0"])
130
+ assert banner0.active is True
113
131
  banner_data = banners["banner2"]
114
132
 
115
133
  admin.login(client)
116
134
 
117
135
  _create_banner(client, banner_data, headers, 201).json
118
136
 
119
- expired_banner = BannerModel.get(banner1.id)
137
+ expired_banner = BannerModel.get(banner0.id)
120
138
  assert expired_banner.active is False
121
139
 
122
140
 
@@ -145,9 +163,9 @@ def test_update_banner(client, admin, headers):
145
163
  def test_disable_expired_after_update_action(client, admin, headers):
146
164
  """Disable expired banners after an update a banner action."""
147
165
  # create banner first
148
- banner1 = BannerModel.create(banners["banner1"])
166
+ banner0 = BannerModel.create(banners["banner0"])
149
167
  banner2 = BannerModel.create(banners["banner2"])
150
- assert banner1.active is True
168
+ assert banner0.active is True
151
169
 
152
170
  admin.login(client)
153
171
 
@@ -160,7 +178,7 @@ def test_disable_expired_after_update_action(client, admin, headers):
160
178
 
161
179
  _update_banner(client, banner2.id, new_data, headers, 200).json
162
180
 
163
- expired_banner = BannerModel.get(banner1.id)
181
+ expired_banner = BannerModel.get(banner0.id)
164
182
  assert expired_banner.active is False
165
183
 
166
184
 
@@ -200,7 +218,7 @@ def test_delete_banner(client, admin, headers):
200
218
  _delete_banner(client, banner.id, headers, 204)
201
219
 
202
220
  # check that it's not present in db
203
- assert BannerModel.query.filter_by(id=banner.id).one_or_none() is None
221
+ assert db.session.query(BannerModel).filter_by(id=banner.id).one_or_none() is None
204
222
 
205
223
 
206
224
  def test_delete_is_forbidden(client, user, headers):
@@ -366,3 +384,14 @@ def test_search_banner_empty_list(client, user):
366
384
  result = banners["hits"]
367
385
  assert len(result["hits"]) == 0
368
386
  assert result["total"] == 0
387
+
388
+
389
+ def test_html_banner(client, admin, headers):
390
+ banner_data = banners["html_banner"]
391
+ admin.login(client)
392
+
393
+ banner = _create_banner(client, banner_data, headers, 201).json
394
+ assert (
395
+ banner["message"]
396
+ == "<h1>HTML aware banner.</h1>.\n '<p>paragraph<br></p>alert('You won!')"
397
+ )
@@ -1,6 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
3
  # Copyright (C) 2022 CERN.
4
+ # Copyright (C) 2024 Graz University of Technology.
4
5
  #
5
6
  # Invenio-Banners is free software; you can redistribute it and/or modify it
6
7
  # under the terms of the MIT License; see LICENSE file for more details.
@@ -10,6 +11,7 @@
10
11
  from datetime import datetime, timedelta
11
12
 
12
13
  import pytest
14
+ from invenio_db import db
13
15
  from invenio_records_resources.services.errors import PermissionDeniedError
14
16
 
15
17
  from invenio_banners.proxies import current_banners_service as service
@@ -21,7 +23,10 @@ banners = {
21
23
  "message": "active",
22
24
  "url_path": "/active",
23
25
  "category": "info",
24
- "end_datetime": datetime.utcnow() + timedelta(days=1),
26
+ "start_datetime": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"),
27
+ "end_datetime": (datetime.utcnow() + timedelta(days=1)).strftime(
28
+ "%Y-%m-%d %H:%M:%S"
29
+ ),
25
30
  "active": True,
26
31
  },
27
32
  "inactive": {
@@ -127,7 +132,7 @@ def test_delete_banner(app, superuser_identity):
127
132
  service.delete(superuser_identity, banner.id)
128
133
 
129
134
  # check that it's not present in db
130
- assert BannerModel.query.filter_by(id=banner.id).one_or_none() is None
135
+ assert db.session.query(BannerModel).filter_by(id=banner.id).one_or_none() is None
131
136
 
132
137
 
133
138
  def test_delete_is_forbidden(app, simple_user_identity):
@@ -150,7 +155,7 @@ def test_delete_non_existing_banner(app, superuser_identity):
150
155
  def test_read_banner(app, simple_user_identity):
151
156
  """Read a banner by id."""
152
157
  # create banner first
153
- banner = BannerModel.create(banners["active"])
158
+ banner = BannerModel.create(banners["other"])
154
159
 
155
160
  banner_result = service.read(simple_user_identity, banner.id)
156
161
 
@@ -207,11 +212,12 @@ def test_disable_expired_banners(app, superuser_identity):
207
212
  BannerModel.create(banners["expired"])
208
213
  BannerModel.create(banners["active"])
209
214
 
210
- assert BannerModel.query.filter(BannerModel.active.is_(True)).count() == 2
211
-
215
+ assert (
216
+ db.session.query(BannerModel).filter(BannerModel.active.is_(True)).count() == 2
217
+ )
212
218
  service.disable_expired(superuser_identity)
213
219
 
214
- _banners = BannerModel.query.filter(BannerModel.active.is_(True)).all()
220
+ _banners = db.session.query(BannerModel).filter(BannerModel.active.is_(True)).all()
215
221
 
216
222
  assert len(_banners) == 1
217
223
  assert _banners[0].message == "active"
@@ -1,69 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # This file is part of Invenio.
4
- # Copyright (C) 2020-2024 CERN.
5
- #
6
- # Invenio-Banners is free software; you can redistribute it and/or modify it
7
- # under the terms of the MIT License; see LICENSE file for more details.
8
-
9
- name: CI
10
-
11
- on:
12
- push:
13
- branches: master
14
- pull_request:
15
- branches: master
16
- schedule:
17
- # * is a special character in YAML so you have to quote this string
18
- - cron: '0 3 * * 6'
19
- workflow_dispatch:
20
- inputs:
21
- reason:
22
- description: 'Reason'
23
- required: false
24
- default: 'Manual trigger'
25
-
26
- jobs:
27
- Tests:
28
- runs-on: ubuntu-20.04
29
- strategy:
30
- matrix:
31
- python-version: [3.8, 3.9]
32
- requirements-level: [pypi]
33
- db-service: [postgresql14]
34
- search-service: [opensearch2]
35
-
36
- env:
37
- DB: ${{ matrix.db-service }}
38
- EXTRAS: tests,${{ matrix.search-service }}
39
- steps:
40
- - name: Checkout
41
- uses: actions/checkout@v2
42
-
43
- - name: Set up Python ${{ matrix.python-version }}
44
- uses: actions/setup-python@v2
45
- with:
46
- python-version: ${{ matrix.python-version }}
47
-
48
- - name: Generate dependencies
49
- run: |
50
- python -m pip install --upgrade pip setuptools py wheel requirements-builder
51
- requirements-builder -e "$EXTRAS" --level=${{ matrix.requirements-level }} setup.py > .${{ matrix.requirements-level }}-${{ matrix.python-version }}-requirements.txt
52
-
53
- - name: Cache pip
54
- uses: actions/cache@v2
55
- with:
56
- path: ~/.cache/pip
57
- key: ${{ runner.os }}-pip-${{ hashFiles('.${{ matrix.requirements-level }}-${{ matrix.python-version }}-requirements.txt') }}
58
-
59
- - name: Install dependencies
60
- run: |
61
- pip install -r .${{ matrix.requirements-level }}-${{ matrix.python-version }}-requirements.txt
62
- pip install ".[$EXTRAS]"
63
- pip freeze
64
- docker --version
65
- docker-compose --version
66
-
67
- - name: Run tests
68
- run: |
69
- ./run-tests.sh
File without changes