invenio-banners 5.2.1__py2.py3-none-any.whl
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.
- invenio_banners/__init__.py +16 -0
- invenio_banners/administration/__init__.py +8 -0
- invenio_banners/administration/banners.py +183 -0
- invenio_banners/alembic/5e02314da32e_create_invenio_banners_db_table.py +43 -0
- invenio_banners/alembic/e40d93d99040_create_invenio_banners_branch.py +27 -0
- invenio_banners/config.py +54 -0
- invenio_banners/ext.py +60 -0
- invenio_banners/proxies.py +19 -0
- invenio_banners/records/__init__.py +13 -0
- invenio_banners/records/models.py +143 -0
- invenio_banners/resources/__init__.py +16 -0
- invenio_banners/resources/config.py +51 -0
- invenio_banners/resources/errors.py +52 -0
- invenio_banners/resources/resource.py +107 -0
- invenio_banners/services/__init__.py +20 -0
- invenio_banners/services/config.py +85 -0
- invenio_banners/services/permissions.py +23 -0
- invenio_banners/services/results.py +124 -0
- invenio_banners/services/schemas.py +39 -0
- invenio_banners/services/service.py +170 -0
- invenio_banners/templates/semantic-ui/invenio_banners/banner.html +26 -0
- invenio_banners/translations/ar/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/ar/LC_MESSAGES/messages.po +193 -0
- invenio_banners/translations/bg/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/bg/LC_MESSAGES/messages.po +177 -0
- invenio_banners/translations/ca/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/ca/LC_MESSAGES/messages.po +178 -0
- invenio_banners/translations/cs/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/cs/LC_MESSAGES/messages.po +198 -0
- invenio_banners/translations/da/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/da/LC_MESSAGES/messages.po +173 -0
- invenio_banners/translations/de/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/de/LC_MESSAGES/messages.po +202 -0
- invenio_banners/translations/el/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/el/LC_MESSAGES/messages.po +178 -0
- invenio_banners/translations/es/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/es/LC_MESSAGES/messages.po +197 -0
- invenio_banners/translations/et/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/et/LC_MESSAGES/messages.po +177 -0
- invenio_banners/translations/fa/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/fa/LC_MESSAGES/messages.po +173 -0
- invenio_banners/translations/fi/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/fi/LC_MESSAGES/messages.po +194 -0
- invenio_banners/translations/fr/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/fr/LC_MESSAGES/messages.po +180 -0
- invenio_banners/translations/hr/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/hr/LC_MESSAGES/messages.po +177 -0
- invenio_banners/translations/hu/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/hu/LC_MESSAGES/messages.po +196 -0
- invenio_banners/translations/it/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/it/LC_MESSAGES/messages.po +179 -0
- invenio_banners/translations/ja/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/ja/LC_MESSAGES/messages.po +177 -0
- invenio_banners/translations/ka/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/ka/LC_MESSAGES/messages.po +177 -0
- invenio_banners/translations/ko/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/ko/LC_MESSAGES/messages.po +173 -0
- invenio_banners/translations/lt/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/lt/LC_MESSAGES/messages.po +177 -0
- invenio_banners/translations/messages.pot +174 -0
- invenio_banners/translations/no/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/no/LC_MESSAGES/messages.po +177 -0
- invenio_banners/translations/pl/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/pl/LC_MESSAGES/messages.po +177 -0
- invenio_banners/translations/pt/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/pt/LC_MESSAGES/messages.po +177 -0
- invenio_banners/translations/ro/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/ro/LC_MESSAGES/messages.po +179 -0
- invenio_banners/translations/ru/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/ru/LC_MESSAGES/messages.po +179 -0
- invenio_banners/translations/sk/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/sk/LC_MESSAGES/messages.po +178 -0
- invenio_banners/translations/sv/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/sv/LC_MESSAGES/messages.po +197 -0
- invenio_banners/translations/tr/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/tr/LC_MESSAGES/messages.po +196 -0
- invenio_banners/translations/uk/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/uk/LC_MESSAGES/messages.po +177 -0
- invenio_banners/translations/zh_CN/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/zh_CN/LC_MESSAGES/messages.po +179 -0
- invenio_banners/translations/zh_TW/LC_MESSAGES/messages.mo +0 -0
- invenio_banners/translations/zh_TW/LC_MESSAGES/messages.po +177 -0
- invenio_banners/utils.py +52 -0
- invenio_banners/views.py +14 -0
- invenio_banners-5.2.1.dist-info/METADATA +157 -0
- invenio_banners-5.2.1.dist-info/RECORD +91 -0
- invenio_banners-5.2.1.dist-info/WHEEL +6 -0
- invenio_banners-5.2.1.dist-info/entry_points.txt +23 -0
- invenio_banners-5.2.1.dist-info/licenses/AUTHORS.rst +12 -0
- invenio_banners-5.2.1.dist-info/licenses/LICENSE +21 -0
- invenio_banners-5.2.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2020-2024 CERN.
|
|
4
|
+
# Copyright (C) 2024-2025 Graz University of Technology.
|
|
5
|
+
# Copyright (C) 2025 KTH Royal Institute of Technology.
|
|
6
|
+
#
|
|
7
|
+
# Invenio-Banners is free software; you can redistribute it and/or modify it
|
|
8
|
+
# under the terms of the MIT License; see LICENSE file for more details.
|
|
9
|
+
|
|
10
|
+
"""Create and show banners with useful messages to users."""
|
|
11
|
+
|
|
12
|
+
from .ext import InvenioBanners
|
|
13
|
+
|
|
14
|
+
__version__ = "5.2.1"
|
|
15
|
+
|
|
16
|
+
__all__ = ("__version__", "InvenioBanners")
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2023 CERN.
|
|
4
|
+
# Copyright (C) 2024 KTH Royal Institute of Technology.
|
|
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
|
+
"""Invenio administration banners view module."""
|
|
10
|
+
|
|
11
|
+
from invenio_administration.views.base import (
|
|
12
|
+
AdminResourceCreateView,
|
|
13
|
+
AdminResourceDetailView,
|
|
14
|
+
AdminResourceEditView,
|
|
15
|
+
AdminResourceListView,
|
|
16
|
+
)
|
|
17
|
+
from invenio_i18n import lazy_gettext as _
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BannerListView(AdminResourceListView):
|
|
21
|
+
"""Search admin view."""
|
|
22
|
+
|
|
23
|
+
api_endpoint = "/banners"
|
|
24
|
+
name = "banners"
|
|
25
|
+
resource_config = "banners_resource"
|
|
26
|
+
title = _("Banners")
|
|
27
|
+
menu_label = _("Banners")
|
|
28
|
+
category = _("Site management")
|
|
29
|
+
pid_path = "id"
|
|
30
|
+
icon = "newspaper"
|
|
31
|
+
|
|
32
|
+
display_search = True
|
|
33
|
+
display_delete = True
|
|
34
|
+
display_create = True
|
|
35
|
+
display_edit = True
|
|
36
|
+
|
|
37
|
+
item_field_list = {
|
|
38
|
+
"id": {"text": _("Id"), "order": 1, "width": 1},
|
|
39
|
+
"start_datetime": {"text": _("Start time (UTC)"), "order": 2, "width": 2},
|
|
40
|
+
"end_datetime": {"text": _("End time (UTC)"), "order": 3, "width": 2},
|
|
41
|
+
"message": {"text": _("Message"), "order": 4, "width": 7},
|
|
42
|
+
"active": {"text": _("Active"), "order": 5, "width": 1},
|
|
43
|
+
"url_path": {"text": _("URL path"), "order": 6, "width": 2},
|
|
44
|
+
"category": {"text": _("Category"), "order": 7, "width": 1},
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
create_view_name = "banner_create"
|
|
48
|
+
|
|
49
|
+
search_config_name = "BANNERS_SEARCH"
|
|
50
|
+
search_sort_config_name = "BANNERS_SORT_OPTIONS"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
common_form_fields = {
|
|
54
|
+
"start_datetime": {
|
|
55
|
+
"order": 1,
|
|
56
|
+
"text": _("Start time"),
|
|
57
|
+
"description": _(
|
|
58
|
+
"Date/time to make the banner active. "
|
|
59
|
+
"Input format: yyyy-mm-dd hh:mm:ss. "
|
|
60
|
+
"Set to future date/time to delay the banner. "
|
|
61
|
+
"Note: specify time in UTC time standard."
|
|
62
|
+
),
|
|
63
|
+
"placeholder": _("YYYY-MM-DD hh:mm:ss"),
|
|
64
|
+
},
|
|
65
|
+
"end_datetime": {
|
|
66
|
+
"order": 2,
|
|
67
|
+
"text": _("End time"),
|
|
68
|
+
"description": _(
|
|
69
|
+
"Date/time to make the banner inactive. "
|
|
70
|
+
"Input format: yyyy-mm-dd hh:mm:ss. An empty value makes "
|
|
71
|
+
"the banner active until manually disabled via the active flag. "
|
|
72
|
+
"Note: specify time in UTC time standard."
|
|
73
|
+
),
|
|
74
|
+
"placeholder": _("YYYY-MM-DD hh:mm:ss"),
|
|
75
|
+
},
|
|
76
|
+
"message": {
|
|
77
|
+
"order": 3,
|
|
78
|
+
"text": _("Message"),
|
|
79
|
+
"description": _(
|
|
80
|
+
"Message to be displayed on the banner. HTML format is supported."
|
|
81
|
+
),
|
|
82
|
+
"rows": 10,
|
|
83
|
+
},
|
|
84
|
+
"url_path": {
|
|
85
|
+
"order": 4,
|
|
86
|
+
"text": _("URL path"),
|
|
87
|
+
"description": _(
|
|
88
|
+
"URL path prefix (including the first /) to define where "
|
|
89
|
+
"the message will be active on the site. For "
|
|
90
|
+
"example, if you enter `/records`, any URL starting with "
|
|
91
|
+
"`/records` will return an active banner (`/records`, "
|
|
92
|
+
"`/records/1234`, etc.). An empty value makes the banner "
|
|
93
|
+
"active for any URL."
|
|
94
|
+
),
|
|
95
|
+
},
|
|
96
|
+
"category": {
|
|
97
|
+
"order": 5,
|
|
98
|
+
"text": _("Category"),
|
|
99
|
+
"description": _(
|
|
100
|
+
"Banner category. `Info` option displays a blue banner. "
|
|
101
|
+
"`Warning` option displays an orange banner. "
|
|
102
|
+
"`Other` option displays a gray banner."
|
|
103
|
+
),
|
|
104
|
+
"options": [
|
|
105
|
+
{"title_l10n": "Info", "id": "info"},
|
|
106
|
+
{"title_l10n": "Warning", "id": "warning"},
|
|
107
|
+
{"title_l10n": "Other", "id": "other"},
|
|
108
|
+
],
|
|
109
|
+
"placeholder": "Select a category",
|
|
110
|
+
},
|
|
111
|
+
"active": {
|
|
112
|
+
"order": 6,
|
|
113
|
+
"text": _("Active"),
|
|
114
|
+
"description": _(
|
|
115
|
+
"Tick it to activate the banner: banner will be "
|
|
116
|
+
"displayed according to start/end times. If not "
|
|
117
|
+
"activated, start/end times will be ignored."
|
|
118
|
+
),
|
|
119
|
+
},
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class BannerEditView(AdminResourceEditView):
|
|
124
|
+
"""Configuration for Banner edit view."""
|
|
125
|
+
|
|
126
|
+
name = "banner_edit"
|
|
127
|
+
url = "/banners/<pid_value>/edit"
|
|
128
|
+
resource_config = "banners_resource"
|
|
129
|
+
pid_path = "id"
|
|
130
|
+
api_endpoint = "/banners"
|
|
131
|
+
title = _("Edit Banner")
|
|
132
|
+
|
|
133
|
+
list_view_name = "banners"
|
|
134
|
+
|
|
135
|
+
form_fields = {
|
|
136
|
+
**common_form_fields,
|
|
137
|
+
"created": {"order": 7},
|
|
138
|
+
"updated": {"order": 8},
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class BannerCreateView(AdminResourceCreateView):
|
|
143
|
+
"""Configuration for Banner create view."""
|
|
144
|
+
|
|
145
|
+
name = "banner_create"
|
|
146
|
+
url = "/banners/create"
|
|
147
|
+
resource_config = "banners_resource"
|
|
148
|
+
pid_path = "id"
|
|
149
|
+
api_endpoint = "/banners"
|
|
150
|
+
title = _("Create Banner")
|
|
151
|
+
|
|
152
|
+
list_view_name = "banners"
|
|
153
|
+
|
|
154
|
+
form_fields = {
|
|
155
|
+
**common_form_fields,
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class BannerDetailView(AdminResourceDetailView):
|
|
160
|
+
"""Admin banner detail view."""
|
|
161
|
+
|
|
162
|
+
url = "/banners/<pid_value>"
|
|
163
|
+
api_endpoint = "/banners"
|
|
164
|
+
name = "banner-details"
|
|
165
|
+
resource_config = "banners_resource"
|
|
166
|
+
title = _("Banner Details")
|
|
167
|
+
|
|
168
|
+
display_delete = True
|
|
169
|
+
display_edit = True
|
|
170
|
+
|
|
171
|
+
list_view_name = "banners"
|
|
172
|
+
pid_path = "id"
|
|
173
|
+
|
|
174
|
+
item_field_list = {
|
|
175
|
+
"start_datetime": {"text": _("Start time"), "order": 1},
|
|
176
|
+
"end_datetime": {"text": _("End time"), "order": 2},
|
|
177
|
+
"message": {"text": _("Message"), "order": 3},
|
|
178
|
+
"url_path": {"text": _("URL path"), "order": 4},
|
|
179
|
+
"category": {"text": _("Category"), "order": 5},
|
|
180
|
+
"active": {"text": _("Active"), "order": 6},
|
|
181
|
+
"created": {"text": _("Created"), "order": 7},
|
|
182
|
+
"updated": {"text": _("Updated"), "order": 8},
|
|
183
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This file is part of Invenio.
|
|
3
|
+
# Copyright (C) 2016-2018 CERN.
|
|
4
|
+
#
|
|
5
|
+
# Invenio is free software; you can redistribute it and/or modify it
|
|
6
|
+
# under the terms of the MIT License; see LICENSE file for more details.
|
|
7
|
+
|
|
8
|
+
"""Create invenio-banners db table."""
|
|
9
|
+
|
|
10
|
+
import sqlalchemy as sa
|
|
11
|
+
from alembic import op
|
|
12
|
+
|
|
13
|
+
# revision identifiers, used by Alembic.
|
|
14
|
+
revision = "5e02314da32e"
|
|
15
|
+
down_revision = "e40d93d99040"
|
|
16
|
+
branch_labels = ()
|
|
17
|
+
depends_on = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def upgrade():
|
|
21
|
+
"""Upgrade database."""
|
|
22
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
23
|
+
op.create_table(
|
|
24
|
+
"banners",
|
|
25
|
+
sa.Column("created", sa.DateTime(), nullable=False),
|
|
26
|
+
sa.Column("updated", sa.DateTime(), nullable=False),
|
|
27
|
+
sa.Column("id", sa.Integer(), nullable=False),
|
|
28
|
+
sa.Column("message", sa.Text(), nullable=False),
|
|
29
|
+
sa.Column("url_path", sa.String(length=255), nullable=True),
|
|
30
|
+
sa.Column("category", sa.String(length=20), nullable=False),
|
|
31
|
+
sa.Column("start_datetime", sa.DateTime(), nullable=False),
|
|
32
|
+
sa.Column("end_datetime", sa.DateTime(), nullable=True),
|
|
33
|
+
sa.Column("active", sa.Boolean(name="active"), nullable=False),
|
|
34
|
+
sa.PrimaryKeyConstraint("id", name=op.f("pk_banners")),
|
|
35
|
+
)
|
|
36
|
+
# ### end Alembic commands ###
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def downgrade():
|
|
40
|
+
"""Downgrade database."""
|
|
41
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
42
|
+
op.drop_table("banners")
|
|
43
|
+
# ### end Alembic commands ###
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This file is part of Invenio.
|
|
3
|
+
# Copyright (C) 2016-2018 CERN.
|
|
4
|
+
#
|
|
5
|
+
# Invenio is free software; you can redistribute it and/or modify it
|
|
6
|
+
# under the terms of the MIT License; see LICENSE file for more details.
|
|
7
|
+
|
|
8
|
+
"""Create invenio-banners branch."""
|
|
9
|
+
|
|
10
|
+
import sqlalchemy as sa
|
|
11
|
+
from alembic import op
|
|
12
|
+
|
|
13
|
+
# revision identifiers, used by Alembic.
|
|
14
|
+
revision = "e40d93d99040"
|
|
15
|
+
down_revision = None
|
|
16
|
+
branch_labels = ("invenio_banners",)
|
|
17
|
+
depends_on = "dbdbc1b19cf2"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def upgrade():
|
|
21
|
+
"""Upgrade database."""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def downgrade():
|
|
26
|
+
"""Downgrade database."""
|
|
27
|
+
pass
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2020-2023 CERN.
|
|
4
|
+
# Copyright (C) 2024 KTH Royal Institute of Technology.
|
|
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
|
+
"""Configuration variables."""
|
|
10
|
+
|
|
11
|
+
from invenio_i18n import lazy_gettext as _
|
|
12
|
+
|
|
13
|
+
from invenio_banners.utils import style_category
|
|
14
|
+
|
|
15
|
+
BANNERS_CATEGORIES = [
|
|
16
|
+
("info", _("Info")),
|
|
17
|
+
("warning", _("Warning")),
|
|
18
|
+
("other", _("Other")),
|
|
19
|
+
]
|
|
20
|
+
"""Categories to define different types of messages. List of (id, label)."""
|
|
21
|
+
|
|
22
|
+
BANNERS_CATEGORIES_TO_STYLE = style_category
|
|
23
|
+
"""Function to transform the banner category to a specific Semantic-UI class."""
|
|
24
|
+
|
|
25
|
+
BANNERS_SEARCH = {
|
|
26
|
+
"facets": [],
|
|
27
|
+
"sort": [
|
|
28
|
+
"url_path",
|
|
29
|
+
"start_datetime",
|
|
30
|
+
"end_datetime",
|
|
31
|
+
"active",
|
|
32
|
+
],
|
|
33
|
+
}
|
|
34
|
+
"""Banner search configuration (i.e list of banners)"""
|
|
35
|
+
|
|
36
|
+
BANNERS_SORT_OPTIONS = {
|
|
37
|
+
"url_path": dict(
|
|
38
|
+
title=_("URL path"),
|
|
39
|
+
fields=["url_path"],
|
|
40
|
+
),
|
|
41
|
+
"start_datetime": dict(
|
|
42
|
+
title=_("Start DateTime"),
|
|
43
|
+
fields=["start_datetime"],
|
|
44
|
+
),
|
|
45
|
+
"end_datetime": dict(
|
|
46
|
+
title=_("End DateTime"),
|
|
47
|
+
fields=["end_datetime"],
|
|
48
|
+
),
|
|
49
|
+
"active": dict(
|
|
50
|
+
title=_("Active"),
|
|
51
|
+
fields=["active"],
|
|
52
|
+
),
|
|
53
|
+
}
|
|
54
|
+
"""Definitions of available Banners sort options. """
|
invenio_banners/ext.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2020-2023 CERN.
|
|
4
|
+
#
|
|
5
|
+
# Invenio-Banners is free software; you can redistribute it and/or modify it
|
|
6
|
+
# under the terms of the MIT License; see LICENSE file for more details.
|
|
7
|
+
|
|
8
|
+
"""Invenio extension app."""
|
|
9
|
+
|
|
10
|
+
from flask import Blueprint
|
|
11
|
+
|
|
12
|
+
from . import config
|
|
13
|
+
from .resources import BannerResource, BannerResourceConfig
|
|
14
|
+
from .services import BannerService, BannerServiceConfig
|
|
15
|
+
from .utils import get_active_banners_for_request
|
|
16
|
+
|
|
17
|
+
blueprint = Blueprint(
|
|
18
|
+
"invenio_banners",
|
|
19
|
+
__name__,
|
|
20
|
+
template_folder="templates",
|
|
21
|
+
static_folder="static",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class InvenioBanners(object):
|
|
26
|
+
"""Invenio-Banners extension."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, app=None):
|
|
29
|
+
"""Extension initialization."""
|
|
30
|
+
if app:
|
|
31
|
+
self.init_app(app)
|
|
32
|
+
|
|
33
|
+
def init_app(self, app):
|
|
34
|
+
"""Flask application initialization."""
|
|
35
|
+
self.init_config(app)
|
|
36
|
+
self.init_services(app)
|
|
37
|
+
self.init_resources(app)
|
|
38
|
+
app.extensions["invenio-banners"] = self
|
|
39
|
+
app.register_blueprint(blueprint)
|
|
40
|
+
app.jinja_env.globals["get_active_banners"] = get_active_banners_for_request
|
|
41
|
+
app.jinja_env.filters["style_banner_category"] = app.config[
|
|
42
|
+
"BANNERS_CATEGORIES_TO_STYLE"
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
def init_config(self, app):
|
|
46
|
+
"""Initialize configuration."""
|
|
47
|
+
for k in dir(config):
|
|
48
|
+
if k.startswith("BANNERS_"):
|
|
49
|
+
app.config.setdefault(k, getattr(config, k))
|
|
50
|
+
|
|
51
|
+
def init_services(self, app):
|
|
52
|
+
"""Initialize the services for banners."""
|
|
53
|
+
self.banners_service = BannerService(config=BannerServiceConfig)
|
|
54
|
+
|
|
55
|
+
def init_resources(self, app):
|
|
56
|
+
"""Initialize the resources for banners."""
|
|
57
|
+
self.banners_resource = BannerResource(
|
|
58
|
+
service=self.banners_service,
|
|
59
|
+
config=BannerResourceConfig,
|
|
60
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2022 CERN.
|
|
4
|
+
#
|
|
5
|
+
# Invenio-Banners is free software; you can redistribute it and/or modify it
|
|
6
|
+
# under the terms of the MIT License; see LICENSE file for more details.
|
|
7
|
+
|
|
8
|
+
"""Proxies for accessing the current Banners extension."""
|
|
9
|
+
|
|
10
|
+
from flask import current_app
|
|
11
|
+
from werkzeug.local import LocalProxy
|
|
12
|
+
|
|
13
|
+
current_banners = LocalProxy(lambda: current_app.extensions["invenio-banners"])
|
|
14
|
+
"""Proxy for the instantiated Banners extension."""
|
|
15
|
+
|
|
16
|
+
current_banners_service = LocalProxy(
|
|
17
|
+
lambda: current_app.extensions["invenio-banners"].banners_service
|
|
18
|
+
)
|
|
19
|
+
"""Proxy for the currently instantiated banners service."""
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2020-2023 CERN.
|
|
4
|
+
#
|
|
5
|
+
# Invenio-Banners is free software; you can redistribute it and/or modify it
|
|
6
|
+
# under the terms of the MIT License; see LICENSE file for more details.
|
|
7
|
+
|
|
8
|
+
"""Records directory."""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
from .models import BannerModel
|
|
12
|
+
|
|
13
|
+
__all__ = ("BannerModel",)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2020-2023 CERN.
|
|
4
|
+
# Copyright (C) 2024-2025 Graz University of Technology.
|
|
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
|
+
"""Models."""
|
|
10
|
+
|
|
11
|
+
from datetime import datetime, timezone
|
|
12
|
+
|
|
13
|
+
import sqlalchemy as sa
|
|
14
|
+
from flask import current_app
|
|
15
|
+
from invenio_db import db
|
|
16
|
+
from sqlalchemy import or_
|
|
17
|
+
from sqlalchemy.sql import text
|
|
18
|
+
from sqlalchemy_utils.models import Timestamp
|
|
19
|
+
|
|
20
|
+
from ..resources.errors import BannerNotExistsError
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class BannerModel(db.Model, Timestamp):
|
|
24
|
+
"""Defines a message to show to users."""
|
|
25
|
+
|
|
26
|
+
__tablename__ = "banners"
|
|
27
|
+
|
|
28
|
+
id = db.Column(db.Integer, primary_key=True)
|
|
29
|
+
|
|
30
|
+
message = db.Column(db.Text, nullable=False)
|
|
31
|
+
"""The message content."""
|
|
32
|
+
|
|
33
|
+
url_path = db.Column(db.String(255), nullable=True)
|
|
34
|
+
"""Define in which URL /path the message will be visible."""
|
|
35
|
+
|
|
36
|
+
category = db.Column(db.String(20), nullable=False)
|
|
37
|
+
"""Category of the message, for styling messages per category."""
|
|
38
|
+
|
|
39
|
+
start_datetime = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
|
|
40
|
+
"""Start date and time (UTC), can be immediate or delayed."""
|
|
41
|
+
|
|
42
|
+
end_datetime = db.Column(db.DateTime, nullable=True)
|
|
43
|
+
"""End date and time (UTC), must be after `start` or forever if null."""
|
|
44
|
+
|
|
45
|
+
active = db.Column(db.Boolean(name="active"), nullable=False, default=True)
|
|
46
|
+
"""Defines if the message is active, only one at the same time."""
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def create(cls, data):
|
|
50
|
+
"""Create a new banner."""
|
|
51
|
+
_categories = [t[0] for t in current_app.config["BANNERS_CATEGORIES"]]
|
|
52
|
+
assert data.get("category") in _categories
|
|
53
|
+
|
|
54
|
+
with db.session.begin_nested():
|
|
55
|
+
obj = cls(
|
|
56
|
+
message=data.get("message"),
|
|
57
|
+
category=data.get("category"),
|
|
58
|
+
url_path=data.get("url_path"),
|
|
59
|
+
start_datetime=data.get("start_datetime"),
|
|
60
|
+
end_datetime=data.get("end_datetime"),
|
|
61
|
+
active=data.get("active"),
|
|
62
|
+
)
|
|
63
|
+
db.session.add(obj)
|
|
64
|
+
|
|
65
|
+
return obj
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def update(cls, data, id):
|
|
69
|
+
"""Update an existing banner."""
|
|
70
|
+
with db.session.begin_nested():
|
|
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
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def get(cls, id):
|
|
78
|
+
"""Get banner by its id."""
|
|
79
|
+
if banner := db.session.get(cls, id):
|
|
80
|
+
return banner
|
|
81
|
+
|
|
82
|
+
raise BannerNotExistsError(id)
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def delete(cls, banner):
|
|
86
|
+
"""Delete banner by its id."""
|
|
87
|
+
with db.session.begin_nested():
|
|
88
|
+
db.session.delete(banner)
|
|
89
|
+
|
|
90
|
+
@classmethod
|
|
91
|
+
def get_active(cls, url_path):
|
|
92
|
+
"""Return active banners."""
|
|
93
|
+
now = datetime.now(timezone.utc).replace(tzinfo=None)
|
|
94
|
+
|
|
95
|
+
query = (
|
|
96
|
+
db.session.query(cls)
|
|
97
|
+
.filter(cls.active.is_(True))
|
|
98
|
+
.filter(cls.start_datetime <= now)
|
|
99
|
+
.filter((cls.end_datetime.is_(None)) | (now <= cls.end_datetime))
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# filter by url_path
|
|
103
|
+
active_banners = query.filter(
|
|
104
|
+
sa.or_(
|
|
105
|
+
cls.url_path.is_(None),
|
|
106
|
+
sa.literal(url_path).startswith(cls.url_path),
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
return active_banners.all()
|
|
111
|
+
|
|
112
|
+
@classmethod
|
|
113
|
+
def search(cls, search_params, filters=None):
|
|
114
|
+
"""Filter banners accordingly to query params."""
|
|
115
|
+
if filters:
|
|
116
|
+
filtered = db.session.query(BannerModel).filter(or_(*filters))
|
|
117
|
+
else:
|
|
118
|
+
filtered = db.session.query(BannerModel).filter()
|
|
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
|
+
)
|
|
127
|
+
|
|
128
|
+
return banners
|
|
129
|
+
|
|
130
|
+
@classmethod
|
|
131
|
+
def disable_expired(cls):
|
|
132
|
+
"""Disable any old still active messages to keep everything clean."""
|
|
133
|
+
now = datetime.now(timezone.utc).replace(tzinfo=None)
|
|
134
|
+
|
|
135
|
+
query = (
|
|
136
|
+
db.session.query(cls)
|
|
137
|
+
.filter(cls.active.is_(True))
|
|
138
|
+
.filter(cls.end_datetime.isnot(None))
|
|
139
|
+
.filter(cls.end_datetime < now)
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
for old in query.all():
|
|
143
|
+
old.active = False
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2022 CERN.
|
|
4
|
+
#
|
|
5
|
+
# Invenio-Banners is free software; you can redistribute it and/or modify it
|
|
6
|
+
# under the terms of the MIT License; see LICENSE file for more details.
|
|
7
|
+
|
|
8
|
+
"""Invenio Resources module to create REST APIs."""
|
|
9
|
+
|
|
10
|
+
from .config import BannerResourceConfig
|
|
11
|
+
from .resource import BannerResource
|
|
12
|
+
|
|
13
|
+
__all__ = (
|
|
14
|
+
"BannerResource",
|
|
15
|
+
"BannerResourceConfig",
|
|
16
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2022-2025 CERN.
|
|
4
|
+
#
|
|
5
|
+
# Invenio-Banners is free software; you can redistribute it and/or modify it
|
|
6
|
+
# under the terms of the MIT License; see LICENSE file for more details.
|
|
7
|
+
|
|
8
|
+
"""Banner Resource Configuration."""
|
|
9
|
+
|
|
10
|
+
import marshmallow as ma
|
|
11
|
+
from flask_resources import JSONDeserializer, RequestBodyParser
|
|
12
|
+
from invenio_records_resources.resources import (
|
|
13
|
+
RecordResourceConfig,
|
|
14
|
+
SearchRequestArgsSchema,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BannerServerSearchRequestArgsSchema(SearchRequestArgsSchema):
|
|
19
|
+
"""Banner request parameters."""
|
|
20
|
+
|
|
21
|
+
sort_direction = ma.fields.Str()
|
|
22
|
+
active = ma.fields.Bool()
|
|
23
|
+
url_path = ma.fields.Str()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class BannerResourceConfig(RecordResourceConfig):
|
|
27
|
+
"""Banner resource config."""
|
|
28
|
+
|
|
29
|
+
# Blueprint configuration
|
|
30
|
+
blueprint_name = "banners"
|
|
31
|
+
url_prefix = "/banners"
|
|
32
|
+
routes = {
|
|
33
|
+
"item": "/<banner_id>",
|
|
34
|
+
"list": "/",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
request_view_args = {
|
|
38
|
+
"banner_id": ma.fields.String(),
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
request_search_args = BannerServerSearchRequestArgsSchema
|
|
42
|
+
|
|
43
|
+
request_body_parsers = {"application/json": RequestBodyParser(JSONDeserializer())}
|
|
44
|
+
default_content_type = "application/json"
|
|
45
|
+
|
|
46
|
+
response_handlers = {
|
|
47
|
+
"application/vnd.inveniordm.v1+json": RecordResourceConfig.response_handlers[
|
|
48
|
+
"application/json"
|
|
49
|
+
],
|
|
50
|
+
**RecordResourceConfig.response_handlers,
|
|
51
|
+
}
|