invenio-banners 3.3.0__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.
Potentially problematic release.
This version of invenio-banners might be problematic. Click here for more details.
- invenio_banners/__init__.py +15 -0
- invenio_banners/administration/__init__.py +8 -0
- invenio_banners/administration/banners.py +182 -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 +53 -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 +54 -0
- invenio_banners/resources/errors.py +41 -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/errors.py +21 -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 +156 -0
- invenio_banners/templates/semantic-ui/invenio_banners/banner.html +26 -0
- invenio_banners/translations/af/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/ar/LC_MESSAGES/messages.po +171 -0
- invenio_banners/translations/bg/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/ca/LC_MESSAGES/messages.po +165 -0
- invenio_banners/translations/cs/LC_MESSAGES/messages.po +165 -0
- invenio_banners/translations/da/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/de/LC_MESSAGES/messages.po +166 -0
- invenio_banners/translations/de_AT/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/de_DE/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/el/LC_MESSAGES/messages.po +165 -0
- invenio_banners/translations/en_AT/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/en_HU/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/es/LC_MESSAGES/messages.po +190 -0
- invenio_banners/translations/es_CU/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/es_MX/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/et/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/et_EE/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/fa/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/fa_IR/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/fr/LC_MESSAGES/messages.po +165 -0
- invenio_banners/translations/fr_CI/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/fr_FR/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/gl/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/hi_IN/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/hr/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/hu/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/hu_HU/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/it/LC_MESSAGES/messages.po +166 -0
- invenio_banners/translations/ja/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/ka/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/lt/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/messages.pot +165 -0
- invenio_banners/translations/ne/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/no/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/pl/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/pt/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/ro/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/ru/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/rw/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/sk/LC_MESSAGES/messages.po +165 -0
- invenio_banners/translations/sv/LC_MESSAGES/messages.po +185 -0
- invenio_banners/translations/sv_SE/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/tr/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/uk/LC_MESSAGES/messages.po +164 -0
- invenio_banners/translations/uk_UA/LC_MESSAGES/messages.po +160 -0
- invenio_banners/translations/zh_CN/LC_MESSAGES/messages.po +166 -0
- invenio_banners/translations/zh_TW/LC_MESSAGES/messages.po +164 -0
- invenio_banners/utils.py +30 -0
- invenio_banners/views.py +14 -0
- invenio_banners-3.3.0.dist-info/AUTHORS.rst +12 -0
- invenio_banners-3.3.0.dist-info/LICENSE +21 -0
- invenio_banners-3.3.0.dist-info/METADATA +114 -0
- invenio_banners-3.3.0.dist-info/RECORD +78 -0
- invenio_banners-3.3.0.dist-info/WHEEL +6 -0
- invenio_banners-3.3.0.dist-info/entry_points.txt +20 -0
- invenio_banners-3.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2022-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 Banners module to create REST APIs."""
|
|
9
|
+
|
|
10
|
+
from flask import g
|
|
11
|
+
from flask_resources import Resource, resource_requestctx, response_handler, route
|
|
12
|
+
from invenio_records_resources.resources.records.resource import (
|
|
13
|
+
request_data,
|
|
14
|
+
request_headers,
|
|
15
|
+
request_search_args,
|
|
16
|
+
request_view_args,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
from .errors import ErrorHandlersMixin
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# Resource
|
|
24
|
+
#
|
|
25
|
+
class BannerResource(ErrorHandlersMixin, Resource):
|
|
26
|
+
"""Banner resource."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, config, service):
|
|
29
|
+
"""Constructor."""
|
|
30
|
+
super(BannerResource, self).__init__(config)
|
|
31
|
+
self.service = service
|
|
32
|
+
|
|
33
|
+
def create_url_rules(self):
|
|
34
|
+
"""Create the URL rules for the record resource."""
|
|
35
|
+
routes = self.config.routes
|
|
36
|
+
return [
|
|
37
|
+
route("POST", routes["list"], self.create),
|
|
38
|
+
route("GET", routes["item"], self.read),
|
|
39
|
+
route("GET", routes["list"], self.search),
|
|
40
|
+
route("DELETE", routes["item"], self.delete),
|
|
41
|
+
route("PUT", routes["item"], self.update),
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
@request_view_args
|
|
45
|
+
@request_data
|
|
46
|
+
@response_handler()
|
|
47
|
+
def update(self):
|
|
48
|
+
"""Update a banner."""
|
|
49
|
+
banner = self.service.update(
|
|
50
|
+
id=resource_requestctx.view_args["banner_id"],
|
|
51
|
+
identity=g.identity,
|
|
52
|
+
data=resource_requestctx.data,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# disable expired banners
|
|
56
|
+
self.service.disable_expired(identity=g.identity)
|
|
57
|
+
|
|
58
|
+
return banner.to_dict(), 200
|
|
59
|
+
|
|
60
|
+
@request_view_args
|
|
61
|
+
@response_handler()
|
|
62
|
+
def read(self):
|
|
63
|
+
"""Read a banner."""
|
|
64
|
+
banner_id = resource_requestctx.view_args["banner_id"]
|
|
65
|
+
banner = self.service.read(
|
|
66
|
+
id=banner_id,
|
|
67
|
+
identity=g.identity,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return banner.to_dict(), 200
|
|
71
|
+
|
|
72
|
+
@request_search_args
|
|
73
|
+
@response_handler(many=True)
|
|
74
|
+
def search(self):
|
|
75
|
+
"""Perform a search over the banners."""
|
|
76
|
+
banners = self.service.search(
|
|
77
|
+
identity=g.identity,
|
|
78
|
+
params=resource_requestctx.args,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return banners.to_dict(), 200
|
|
82
|
+
|
|
83
|
+
@request_data
|
|
84
|
+
@response_handler()
|
|
85
|
+
def create(self):
|
|
86
|
+
"""Create a banner."""
|
|
87
|
+
banner = self.service.create(
|
|
88
|
+
g.identity,
|
|
89
|
+
resource_requestctx.data or {},
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# disable expired banners
|
|
93
|
+
self.service.disable_expired(identity=g.identity)
|
|
94
|
+
|
|
95
|
+
return banner.to_dict(), 201
|
|
96
|
+
|
|
97
|
+
@request_headers
|
|
98
|
+
@request_view_args
|
|
99
|
+
def delete(self):
|
|
100
|
+
"""Delete a banner."""
|
|
101
|
+
banner_id = resource_requestctx.view_args["banner_id"]
|
|
102
|
+
banner = self.service.delete(
|
|
103
|
+
id=banner_id,
|
|
104
|
+
identity=g.identity,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
return banner.to_dict(), 204
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
"""Banners Service API."""
|
|
9
|
+
|
|
10
|
+
from .config import BannerServiceConfig, BannersLink
|
|
11
|
+
from .results import BannerItem, BannerList
|
|
12
|
+
from .service import BannerService
|
|
13
|
+
|
|
14
|
+
__all__ = (
|
|
15
|
+
"BannerService",
|
|
16
|
+
"BannerServiceConfig",
|
|
17
|
+
"BannerList",
|
|
18
|
+
"BannerItem",
|
|
19
|
+
"BannersLink",
|
|
20
|
+
)
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2022-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
|
+
"""Banners Service configuration."""
|
|
9
|
+
|
|
10
|
+
from invenio_i18n import gettext as _
|
|
11
|
+
from invenio_records_resources.services import Link, RecordServiceConfig
|
|
12
|
+
from invenio_records_resources.services.records.links import pagination_links
|
|
13
|
+
from sqlalchemy import asc, desc
|
|
14
|
+
|
|
15
|
+
from ..records.models import BannerModel
|
|
16
|
+
from .permissions import BannersPermissionPolicy
|
|
17
|
+
from .results import BannerItem, BannerList
|
|
18
|
+
from .schemas import BannerSchema
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class BannersLink(Link):
|
|
22
|
+
"""Link variables setter for Banner links."""
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def vars(banner, vars):
|
|
26
|
+
"""Variables for the URI template."""
|
|
27
|
+
vars.update({"id": banner.id})
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class SearchOptions:
|
|
31
|
+
"""Search options."""
|
|
32
|
+
|
|
33
|
+
sort_direction_default = "asc"
|
|
34
|
+
sort_direction_options = {
|
|
35
|
+
"asc": dict(
|
|
36
|
+
title=_("Ascending"),
|
|
37
|
+
fn=asc,
|
|
38
|
+
),
|
|
39
|
+
"desc": dict(
|
|
40
|
+
title=_("Descending"),
|
|
41
|
+
fn=desc,
|
|
42
|
+
),
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
sort_default = "start_datetime"
|
|
46
|
+
sort_options = {
|
|
47
|
+
"url_path": dict(
|
|
48
|
+
title=_("Url path"),
|
|
49
|
+
fields=["url_path"],
|
|
50
|
+
),
|
|
51
|
+
"start_datetime": dict(
|
|
52
|
+
title=_("Start time"),
|
|
53
|
+
fields=["start_datetime"],
|
|
54
|
+
),
|
|
55
|
+
"end_datetime": dict(
|
|
56
|
+
title=_("End time"),
|
|
57
|
+
fields=["end_datetime"],
|
|
58
|
+
),
|
|
59
|
+
"active": dict(
|
|
60
|
+
title=_("Active"),
|
|
61
|
+
fields=["active"],
|
|
62
|
+
),
|
|
63
|
+
}
|
|
64
|
+
pagination_options = {
|
|
65
|
+
"default_results_per_page": 25,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class BannerServiceConfig(RecordServiceConfig):
|
|
70
|
+
"""Service factory configuration."""
|
|
71
|
+
|
|
72
|
+
result_item_cls = BannerItem
|
|
73
|
+
result_list_cls = BannerList
|
|
74
|
+
permission_policy_cls = BannersPermissionPolicy
|
|
75
|
+
schema = BannerSchema
|
|
76
|
+
|
|
77
|
+
# Search configuration
|
|
78
|
+
search = SearchOptions
|
|
79
|
+
|
|
80
|
+
# links configuration
|
|
81
|
+
links_item = {
|
|
82
|
+
"self": BannersLink("{+api}/banners/{id}"),
|
|
83
|
+
}
|
|
84
|
+
links_search = pagination_links("{+api}/banners{?args*}")
|
|
85
|
+
record_cls = BannerModel
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 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
|
+
"""Errors."""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BannerNotExistsError(Exception):
|
|
12
|
+
"""Banner not found exception."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, banner_id):
|
|
15
|
+
"""Constructor."""
|
|
16
|
+
self.banner_id = banner_id
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def description(self):
|
|
20
|
+
"""Exception's description."""
|
|
21
|
+
return f"Banner with id {self.banner_id} is not found."
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
"""Banners permissions."""
|
|
9
|
+
|
|
10
|
+
from invenio_administration.generators import Administration
|
|
11
|
+
from invenio_records_permissions import BasePermissionPolicy
|
|
12
|
+
from invenio_records_permissions.generators import AnyUser, SystemProcess
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BannersPermissionPolicy(BasePermissionPolicy):
|
|
16
|
+
"""Permission policy for banners."""
|
|
17
|
+
|
|
18
|
+
can_create = [Administration(), SystemProcess()]
|
|
19
|
+
can_read = [AnyUser(), SystemProcess()]
|
|
20
|
+
can_search = [AnyUser(), SystemProcess()]
|
|
21
|
+
can_update = [Administration(), SystemProcess()]
|
|
22
|
+
can_delete = [Administration(), SystemProcess()]
|
|
23
|
+
can_disable = [Administration(), SystemProcess()]
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2022-2023 CERN.
|
|
4
|
+
# Copyright (C) 2024 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
|
+
"""Service results."""
|
|
10
|
+
|
|
11
|
+
from invenio_records_resources.services.records.results import RecordItem, RecordList
|
|
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
|
+
|
|
20
|
+
|
|
21
|
+
class BannerItem(RecordItem):
|
|
22
|
+
"""Single banner result."""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
service,
|
|
27
|
+
identity,
|
|
28
|
+
banner,
|
|
29
|
+
links_tpl=None,
|
|
30
|
+
errors=None,
|
|
31
|
+
schema=None,
|
|
32
|
+
):
|
|
33
|
+
"""Constructor."""
|
|
34
|
+
super().__init__(service, identity, banner, errors, links_tpl, schema)
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def data(self):
|
|
38
|
+
"""Property to get the banner."""
|
|
39
|
+
if self._data:
|
|
40
|
+
return self._data
|
|
41
|
+
|
|
42
|
+
self._data = self._schema.dump(
|
|
43
|
+
self._obj,
|
|
44
|
+
context={
|
|
45
|
+
"identity": self._identity,
|
|
46
|
+
"record": self._record,
|
|
47
|
+
},
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
if self._links_tpl:
|
|
51
|
+
self._data["links"] = self.links
|
|
52
|
+
|
|
53
|
+
return self._data
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class BannerList(RecordList):
|
|
57
|
+
"""List of banner results."""
|
|
58
|
+
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
service,
|
|
62
|
+
identity,
|
|
63
|
+
banners,
|
|
64
|
+
params=None,
|
|
65
|
+
links_tpl=None,
|
|
66
|
+
links_item_tpl=None,
|
|
67
|
+
schema=None,
|
|
68
|
+
):
|
|
69
|
+
"""Constructor."""
|
|
70
|
+
super().__init__(
|
|
71
|
+
service, identity, banners, params, links_tpl, links_item_tpl, schema
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def hits(self):
|
|
76
|
+
"""Iterator over the hits."""
|
|
77
|
+
for record in self.banners_result():
|
|
78
|
+
# Project the record
|
|
79
|
+
projection = self._schema.dump(
|
|
80
|
+
record,
|
|
81
|
+
context=dict(
|
|
82
|
+
identity=self._identity,
|
|
83
|
+
record=record,
|
|
84
|
+
),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if self._links_item_tpl:
|
|
88
|
+
projection["links"] = self._links_item_tpl.expand(
|
|
89
|
+
self._identity, record
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
yield projection
|
|
93
|
+
|
|
94
|
+
def to_dict(self):
|
|
95
|
+
"""Return result as a dictionary."""
|
|
96
|
+
res = {
|
|
97
|
+
"hits": {
|
|
98
|
+
"hits": list(self.hits),
|
|
99
|
+
"total": self.total,
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if self._params:
|
|
104
|
+
if self._links_tpl:
|
|
105
|
+
res["links"] = self._links_tpl.expand(self._identity, self.pagination)
|
|
106
|
+
|
|
107
|
+
return res
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def total(self):
|
|
111
|
+
"""Get total number of banners."""
|
|
112
|
+
return (
|
|
113
|
+
self._results.total
|
|
114
|
+
if isinstance(self._results, Pagination)
|
|
115
|
+
else len(self._results)
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
def banners_result(self):
|
|
119
|
+
"""Get iterable banners list."""
|
|
120
|
+
return (
|
|
121
|
+
self._results.items
|
|
122
|
+
if isinstance(self._results, Pagination)
|
|
123
|
+
else self._results
|
|
124
|
+
)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2022-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
|
+
"""Banners schema."""
|
|
9
|
+
|
|
10
|
+
from datetime import datetime, timezone
|
|
11
|
+
|
|
12
|
+
from invenio_records_resources.services.records.schema import BaseRecordSchema
|
|
13
|
+
from marshmallow import fields, pre_load
|
|
14
|
+
from marshmallow_utils.fields import SanitizedHTML, TZDateTime
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BannerSchema(BaseRecordSchema):
|
|
18
|
+
"""Schema for banners."""
|
|
19
|
+
|
|
20
|
+
message = SanitizedHTML(required=True)
|
|
21
|
+
url_path = fields.String(allow_none=True)
|
|
22
|
+
category = fields.String(required=True, metadata={"default": "info"})
|
|
23
|
+
start_datetime = fields.DateTime(
|
|
24
|
+
required=True,
|
|
25
|
+
metadata={"default": datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")},
|
|
26
|
+
)
|
|
27
|
+
end_datetime = fields.DateTime(allow_none=True)
|
|
28
|
+
active = fields.Boolean(required=True, metadata={"default": True})
|
|
29
|
+
created = TZDateTime(timezone=timezone.utc, format="iso", dump_only=True)
|
|
30
|
+
updated = TZDateTime(timezone=timezone.utc, format="iso", dump_only=True)
|
|
31
|
+
|
|
32
|
+
@pre_load
|
|
33
|
+
def change_none_to_string(self, data, **kwargs):
|
|
34
|
+
"""Fix for empty strings not in line with allow_none=True."""
|
|
35
|
+
for field in data:
|
|
36
|
+
if field == "end_datetime" or field == "category":
|
|
37
|
+
if data[field] == "":
|
|
38
|
+
data[field] = None
|
|
39
|
+
return data
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2022-2023 CERN.
|
|
4
|
+
# Copyright (C) 2024 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
|
+
"""Banner Service API."""
|
|
10
|
+
|
|
11
|
+
import distutils.util
|
|
12
|
+
|
|
13
|
+
import arrow
|
|
14
|
+
from invenio_db.uow import unit_of_work
|
|
15
|
+
from invenio_records_resources.services import RecordService
|
|
16
|
+
from invenio_records_resources.services.base import LinksTemplate
|
|
17
|
+
from invenio_records_resources.services.base.utils import map_search_params
|
|
18
|
+
from sqlalchemy import func
|
|
19
|
+
|
|
20
|
+
from ..records.models import BannerModel
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class BannerService(RecordService):
|
|
24
|
+
"""Banner Service."""
|
|
25
|
+
|
|
26
|
+
def read(self, identity, id):
|
|
27
|
+
"""Retrieve a banner."""
|
|
28
|
+
self.require_permission(identity, "read")
|
|
29
|
+
|
|
30
|
+
banner = self.record_cls.get(id)
|
|
31
|
+
|
|
32
|
+
return self.result_item(
|
|
33
|
+
self,
|
|
34
|
+
identity,
|
|
35
|
+
banner,
|
|
36
|
+
links_tpl=self.links_item_tpl,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def search(self, identity, params):
|
|
40
|
+
"""Search for banners matching the querystring."""
|
|
41
|
+
self.require_permission(identity, "search")
|
|
42
|
+
|
|
43
|
+
search_params = map_search_params(self.config.search, params)
|
|
44
|
+
|
|
45
|
+
query_param = search_params["q"]
|
|
46
|
+
filters = []
|
|
47
|
+
|
|
48
|
+
if query_param:
|
|
49
|
+
filters.extend(
|
|
50
|
+
[
|
|
51
|
+
BannerModel.url_path.ilike(f"%{query_param}%"),
|
|
52
|
+
BannerModel.message.ilike(f"%{query_param}%"),
|
|
53
|
+
BannerModel.category.ilike(f"%{query_param}%"),
|
|
54
|
+
]
|
|
55
|
+
)
|
|
56
|
+
bool_value = self._validate_bool(query_param)
|
|
57
|
+
if bool_value is not None:
|
|
58
|
+
filters.extend(
|
|
59
|
+
[
|
|
60
|
+
BannerModel.active.is_(bool_value),
|
|
61
|
+
]
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
datetime_value = self._validate_datetime(query_param)
|
|
65
|
+
if datetime_value is not None:
|
|
66
|
+
filters.extend(
|
|
67
|
+
[
|
|
68
|
+
func.date(BannerModel.start_datetime) == datetime_value,
|
|
69
|
+
func.date(BannerModel.end_datetime) == datetime_value,
|
|
70
|
+
func.date(BannerModel.created) == datetime_value,
|
|
71
|
+
func.date(BannerModel.updated) == datetime_value,
|
|
72
|
+
]
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
banners = self.record_cls.search(search_params, filters)
|
|
76
|
+
|
|
77
|
+
return self.result_list(
|
|
78
|
+
self,
|
|
79
|
+
identity,
|
|
80
|
+
banners,
|
|
81
|
+
params=search_params,
|
|
82
|
+
links_tpl=LinksTemplate(self.config.links_search, context={"args": params}),
|
|
83
|
+
links_item_tpl=self.links_item_tpl,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
@unit_of_work()
|
|
87
|
+
def create(self, identity, data, raise_errors=True, uow=None):
|
|
88
|
+
"""Create a banner."""
|
|
89
|
+
self.require_permission(identity, "create")
|
|
90
|
+
|
|
91
|
+
# validate data
|
|
92
|
+
valid_data, errors = self.schema.load(
|
|
93
|
+
data,
|
|
94
|
+
context={"identity": identity},
|
|
95
|
+
raise_errors=raise_errors,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# create the banner with the specified data
|
|
99
|
+
banner = self.record_cls.create(valid_data)
|
|
100
|
+
|
|
101
|
+
return self.result_item(
|
|
102
|
+
self, identity, banner, links_tpl=self.links_item_tpl, errors=errors
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
@unit_of_work()
|
|
106
|
+
def delete(self, identity, id, uow=None):
|
|
107
|
+
"""Delete a banner from database."""
|
|
108
|
+
self.require_permission(identity, "delete")
|
|
109
|
+
|
|
110
|
+
banner = self.record_cls.get(id)
|
|
111
|
+
self.record_cls.delete(banner)
|
|
112
|
+
|
|
113
|
+
return self.result_item(self, identity, banner, links_tpl=self.links_item_tpl)
|
|
114
|
+
|
|
115
|
+
@unit_of_work()
|
|
116
|
+
def update(self, identity, id, data, uow=None):
|
|
117
|
+
"""Update a banner."""
|
|
118
|
+
self.require_permission(identity, "update")
|
|
119
|
+
|
|
120
|
+
banner = self.record_cls.get(id)
|
|
121
|
+
|
|
122
|
+
# validate data
|
|
123
|
+
valid_data, errors = self.schema.load(
|
|
124
|
+
data,
|
|
125
|
+
context={"identity": identity},
|
|
126
|
+
raise_errors=True,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
self.record_cls.update(valid_data, id)
|
|
130
|
+
|
|
131
|
+
return self.result_item(
|
|
132
|
+
self,
|
|
133
|
+
identity,
|
|
134
|
+
banner,
|
|
135
|
+
links_tpl=self.links_item_tpl,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
@unit_of_work()
|
|
139
|
+
def disable_expired(self, identity, uow=None):
|
|
140
|
+
"""Disable expired banners."""
|
|
141
|
+
self.require_permission(identity, "disable")
|
|
142
|
+
self.record_cls.disable_expired()
|
|
143
|
+
|
|
144
|
+
def _validate_bool(self, value):
|
|
145
|
+
try:
|
|
146
|
+
bool_value = distutils.util.strtobool(value)
|
|
147
|
+
except ValueError:
|
|
148
|
+
return None
|
|
149
|
+
return bool(bool_value)
|
|
150
|
+
|
|
151
|
+
def _validate_datetime(self, value):
|
|
152
|
+
try:
|
|
153
|
+
date_value = arrow.get(value).date()
|
|
154
|
+
except ValueError:
|
|
155
|
+
return None
|
|
156
|
+
return date_value
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
This file is part of Invenio.
|
|
4
|
+
Copyright (C) 2020-2023 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
|
+
|
|
10
|
+
{%- macro banner(ui_classes) -%}
|
|
11
|
+
{%- block banner %}
|
|
12
|
+
{%- set banners = get_active_banners() %}
|
|
13
|
+
{% if not ui_classes %}
|
|
14
|
+
{% set ui_classes = "top attached m-0" %}
|
|
15
|
+
{% endif %}
|
|
16
|
+
{% if banners %}
|
|
17
|
+
{% for banner in banners %}
|
|
18
|
+
<div class="ui {{ banner.category|style_banner_category }} message {{ ui_classes }} inv-banner" id="banner-{{ banner.id }}">
|
|
19
|
+
<div class="ui container">
|
|
20
|
+
{{ banner.message|safe }}
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
{% endfor %}
|
|
24
|
+
{% endif %}
|
|
25
|
+
{%- endblock banner %}
|
|
26
|
+
{%- endmacro %}
|