dmart 1.4.40.post6__py3-none-any.whl → 1.4.40.post7__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.
- dmart/sample/spaces/applications/.dm/meta.space.json +30 -0
- dmart/sample/spaces/applications/api/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/applications/api/.dm/query_all_applications/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/.dm/test_by_saad/attachments.media/meta.warframe.json +1 -0
- dmart/sample/spaces/applications/api/.dm/test_by_saad/attachments.media/warframe.png +0 -0
- dmart/sample/spaces/applications/api/.dm/test_by_saad/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/.dm/user_profile/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/applications/.dm/create_log/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/applications/.dm/create_public_logs/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/applications/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/applications/api/applications/.dm/query_all_translated_data/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/applications/.dm/query_logs/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/applications/.dm/query_translated_enums/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/applications/.dm/query_translated_others/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/applications/.dm/query_translated_resolution/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/applications/create_log.json +1 -0
- dmart/sample/spaces/applications/api/applications/create_public_logs.json +1 -0
- dmart/sample/spaces/applications/api/applications/query_all_translated_data.json +1 -0
- dmart/sample/spaces/applications/api/applications/query_logs.json +1 -0
- dmart/sample/spaces/applications/api/applications/query_translated_enums.json +1 -0
- dmart/sample/spaces/applications/api/applications/query_translated_others.json +1 -0
- dmart/sample/spaces/applications/api/applications/query_translated_resolution.json +1 -0
- dmart/sample/spaces/applications/api/applications.json +1 -0
- dmart/sample/spaces/applications/api/management/.dm/create_subaccount/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/management/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/applications/api/management/.dm/update_password/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/management/create_subaccount.json +53 -0
- dmart/sample/spaces/applications/api/management/update_password.json +1 -0
- dmart/sample/spaces/applications/api/management.json +1 -0
- dmart/sample/spaces/applications/api/query_all_applications.json +15 -0
- dmart/sample/spaces/applications/api/test_by_saad.json +1 -0
- dmart/sample/spaces/applications/api/user/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/applications/api/user/.dm/test_by_saad/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/user/.dm/user_profile/meta.content.json +1 -0
- dmart/sample/spaces/applications/api/user/test_by_saad.json +1 -0
- dmart/sample/spaces/applications/api/user/user_profile.json +1 -0
- dmart/sample/spaces/applications/api/user_profile.json +1 -0
- dmart/sample/spaces/applications/api.json +1 -0
- dmart/sample/spaces/applications/collections/.dm/meta.folder.json +19 -0
- dmart/sample/spaces/applications/collections.json +1 -0
- dmart/sample/spaces/applications/configurations/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/applications/configurations/time_out.json +1 -0
- dmart/sample/spaces/applications/configurations.json +19 -0
- dmart/sample/spaces/applications/errors.json +1 -0
- dmart/sample/spaces/applications/logs/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/applications/logs.json +1 -0
- dmart/sample/spaces/applications/queries/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/applications/queries/.dm/order/meta.content.json +1 -0
- dmart/sample/spaces/applications/queries/order.json +1 -0
- dmart/sample/spaces/applications/queries.json +1 -0
- dmart/sample/spaces/applications/schema/.dm/api/meta.schema.json +1 -0
- dmart/sample/spaces/applications/schema/.dm/configuration/meta.schema.json +1 -0
- dmart/sample/spaces/applications/schema/.dm/error/meta.schema.json +1 -0
- dmart/sample/spaces/applications/schema/.dm/log/meta.schema.json +1 -0
- dmart/sample/spaces/applications/schema/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/applications/schema/.dm/query/meta.schema.json +16 -0
- dmart/sample/spaces/applications/schema/.dm/translation/meta.schema.json +1 -0
- dmart/sample/spaces/applications/schema/api.json +28 -0
- dmart/sample/spaces/applications/schema/configuration.json +1 -0
- dmart/sample/spaces/applications/schema/error.json +43 -0
- dmart/sample/spaces/applications/schema/log.json +1 -0
- dmart/sample/spaces/applications/schema/query.json +118 -0
- dmart/sample/spaces/applications/schema/translation.json +26 -0
- dmart/sample/spaces/applications/schema.json +1 -0
- dmart/sample/spaces/applications/translations/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/applications/translations.json +1 -0
- dmart/sample/spaces/archive/.dm/meta.space.json +27 -0
- dmart/sample/spaces/custom_plugins/dummy/__pycache__/plugin.cpython-314.pyc +0 -0
- dmart/sample/spaces/custom_plugins/dummy/config.json +28 -0
- dmart/sample/spaces/custom_plugins/dummy/plugin.py +6 -0
- dmart/sample/spaces/custom_plugins/missed_entry/config.json +12 -0
- dmart/sample/spaces/custom_plugins/missed_entry/plugin.py +119 -0
- dmart/sample/spaces/custom_plugins/own_changed_notification/__pycache__/plugin.cpython-314.pyc +0 -0
- dmart/sample/spaces/custom_plugins/own_changed_notification/config.json +12 -0
- dmart/sample/spaces/custom_plugins/own_changed_notification/plugin.py +65 -0
- dmart/sample/spaces/custom_plugins/reports_stats/config.json +14 -0
- dmart/sample/spaces/custom_plugins/reports_stats/plugin.py +82 -0
- dmart/sample/spaces/custom_plugins/system_notification_sender/config.json +22 -0
- dmart/sample/spaces/custom_plugins/system_notification_sender/notification.py +268 -0
- dmart/sample/spaces/custom_plugins/system_notification_sender/plugin.py +98 -0
- dmart/sample/spaces/management/.dm/events.jsonl +32 -0
- dmart/sample/spaces/management/.dm/meta.space.json +48 -0
- dmart/sample/spaces/management/.dm/notifications/attachments.view.json/admin.json +36 -0
- dmart/sample/spaces/management/.dm/notifications/attachments.view.json/meta.admin.json +1 -0
- dmart/sample/spaces/management/.dm/notifications/attachments.view.json/meta.system.json +1 -0
- dmart/sample/spaces/management/.dm/notifications/attachments.view.json/system.json +32 -0
- dmart/sample/spaces/management/collections/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/management/collections.json +1 -0
- dmart/sample/spaces/management/groups/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/management/groups.json +1 -0
- dmart/sample/spaces/management/health_check/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/management/health_check.json +1 -0
- dmart/sample/spaces/management/notifications/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/management/notifications/admin/.dm/meta.folder.json +9 -0
- dmart/sample/spaces/management/notifications/system/.dm/meta.folder.json +9 -0
- dmart/sample/spaces/management/notifications.json +1 -0
- dmart/sample/spaces/management/permissions/.dm/access_applications/meta.permission.json +31 -0
- dmart/sample/spaces/management/permissions/.dm/access_applications_world/meta.permission.json +31 -0
- dmart/sample/spaces/management/permissions/.dm/access_messages/meta.permission.json +23 -0
- dmart/sample/spaces/management/permissions/.dm/access_personal/meta.permission.json +40 -0
- dmart/sample/spaces/management/permissions/.dm/access_protected/meta.permission.json +33 -0
- dmart/sample/spaces/management/permissions/.dm/access_public/meta.permission.json +24 -0
- dmart/sample/spaces/management/permissions/.dm/browse_all_folders/meta.permission.json +23 -0
- dmart/sample/spaces/management/permissions/.dm/create_log/meta.permission.json +24 -0
- dmart/sample/spaces/management/permissions/.dm/interviewer/meta.permission.json +1 -0
- dmart/sample/spaces/management/permissions/.dm/manage_applications/meta.permission.json +1 -0
- dmart/sample/spaces/management/permissions/.dm/manage_debug/meta.permission.json +25 -0
- dmart/sample/spaces/management/permissions/.dm/manage_spaces/meta.permission.json +24 -0
- dmart/sample/spaces/management/permissions/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/management/permissions/.dm/rules_management_default/meta.permission.json +32 -0
- dmart/sample/spaces/management/permissions/.dm/super_manager/meta.permission.json +52 -0
- dmart/sample/spaces/management/permissions/.dm/view_activity_log/meta.permission.json +26 -0
- dmart/sample/spaces/management/permissions/.dm/view_collections/meta.permission.json +29 -0
- dmart/sample/spaces/management/permissions/.dm/view_logs/meta.permission.json +30 -0
- dmart/sample/spaces/management/permissions/.dm/view_roles/meta.permission.json +29 -0
- dmart/sample/spaces/management/permissions/.dm/view_users/meta.permission.json +25 -0
- dmart/sample/spaces/management/permissions/.dm/view_world/meta.permission.json +31 -0
- dmart/sample/spaces/management/permissions/.dm/world/meta.permission.json +35 -0
- dmart/sample/spaces/management/permissions.json +1 -0
- dmart/sample/spaces/management/requests.json +1 -0
- dmart/sample/spaces/management/roles/.dm/dummy/meta.role.json +12 -0
- dmart/sample/spaces/management/roles/.dm/logged_in/meta.role.json +18 -0
- dmart/sample/spaces/management/roles/.dm/manager/meta.role.json +13 -0
- dmart/sample/spaces/management/roles/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/management/roles/.dm/moderator/meta.role.json +13 -0
- dmart/sample/spaces/management/roles/.dm/super_admin/meta.role.json +14 -0
- dmart/sample/spaces/management/roles/.dm/test_role/meta.role.json +13 -0
- dmart/sample/spaces/management/roles/.dm/world/meta.role.json +15 -0
- dmart/sample/spaces/management/roles.json +1 -0
- dmart/sample/spaces/management/schema/.dm/admin_notification_request/attachments.media/meta.ui_schema.json +10 -0
- dmart/sample/spaces/management/schema/.dm/admin_notification_request/attachments.media/ui_schema.json +32 -0
- dmart/sample/spaces/management/schema/.dm/admin_notification_request/meta.schema.json +1 -0
- dmart/sample/spaces/management/schema/.dm/api/meta.schema.json +1 -0
- dmart/sample/spaces/management/schema/.dm/folder_rendering/meta.schema.json +1 -0
- dmart/sample/spaces/management/schema/.dm/health_check/meta.schema.json +17 -0
- dmart/sample/spaces/management/schema/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/management/schema/.dm/meta_schema/meta.schema.json +1 -0
- dmart/sample/spaces/management/schema/.dm/metafile/meta.schema.json +14 -0
- dmart/sample/spaces/management/schema/.dm/notification/meta.schema.json +1 -0
- dmart/sample/spaces/management/schema/.dm/system_notification_request/attachments.media/meta.ui_schema.json +10 -0
- dmart/sample/spaces/management/schema/.dm/system_notification_request/attachments.media/ui_schema.json +32 -0
- dmart/sample/spaces/management/schema/.dm/system_notification_request/meta.schema.json +1 -0
- dmart/sample/spaces/management/schema/.dm/view/meta.schema.json +1 -0
- dmart/sample/spaces/management/schema/.dm/workflow/meta.schema.json +1 -0
- dmart/sample/spaces/management/schema/admin_notification_request.json +89 -0
- dmart/sample/spaces/management/schema/api.json +1 -0
- dmart/sample/spaces/management/schema/folder_rendering.json +238 -0
- dmart/sample/spaces/management/schema/health_check.json +8 -0
- dmart/sample/spaces/management/schema/meta_schema.json +74 -0
- dmart/sample/spaces/management/schema/metafile.json +153 -0
- dmart/sample/spaces/management/schema/notification.json +28 -0
- dmart/sample/spaces/management/schema/system_notification_request.json +57 -0
- dmart/sample/spaces/management/schema/view.json +23 -0
- dmart/sample/spaces/management/schema/workflow.json +87 -0
- dmart/sample/spaces/management/schema.json +1 -0
- dmart/sample/spaces/management/users/.dm/alibaba/meta.user.json +23 -0
- dmart/sample/spaces/management/users/.dm/anonymous/meta.user.json +18 -0
- dmart/sample/spaces/management/users/.dm/dmart/meta.user.json +26 -0
- dmart/sample/spaces/management/users/.dm/meta.folder.json +14 -0
- dmart/sample/spaces/management/workflows/.dm/channel/meta.content.json +1 -0
- dmart/sample/spaces/management/workflows/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/management/workflows/channel.json +148 -0
- dmart/sample/spaces/management/workflows.json +1 -0
- dmart/sample/spaces/maqola/.dm/meta.space.json +33 -0
- dmart/sample/spaces/personal/.dm/meta.space.json +24 -0
- dmart/sample/spaces/personal/people/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/personal/people/dmart/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/personal/people/dmart/messages/.dm/0b5f7e7f/meta.content.json +1 -0
- dmart/sample/spaces/personal/people/dmart/messages/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/personal/people/dmart/messages/.dm/mytest/meta.content.json +1 -0
- dmart/sample/spaces/personal/people/dmart/messages/0b5f7e7f.json +1 -0
- dmart/sample/spaces/personal/people/dmart/messages/mytest.json +1 -0
- dmart/sample/spaces/personal/people/dmart/notifications/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/personal/people/dmart/private/.dm/inner/meta.content.json +1 -0
- dmart/sample/spaces/personal/people/dmart/private/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/personal/people/dmart/private/inner.json +1 -0
- dmart/sample/spaces/personal/people/dmart/protected/.dm/avatar/meta.content.json +1 -0
- dmart/sample/spaces/personal/people/dmart/protected/.dm/meta.folder.json +1 -0
- dmart/sample/spaces/personal/people/dmart/protected/avatar.png +0 -0
- dmart/sample/spaces/personal/people/dmart/public/.dm/meta.folder.json +1 -0
- dmart/sample/test/.gitignore +2 -0
- dmart/sample/test/createcontent.json +9 -0
- dmart/sample/test/createmedia.json +9 -0
- dmart/sample/test/createmedia_entry.json +6 -0
- dmart/sample/test/createschema.json +8 -0
- dmart/sample/test/createschemawork.json +11 -0
- dmart/sample/test/createticket.json +13 -0
- dmart/sample/test/data.json +4 -0
- dmart/sample/test/deletecontent.json +12 -0
- dmart/sample/test/logo.jpeg +0 -0
- dmart/sample/test/my.jpg +0 -0
- dmart/sample/test/myticket.json +23 -0
- dmart/sample/test/resources.csv +12 -0
- dmart/sample/test/schema.json +16 -0
- dmart/sample/test/temp.json +1 -0
- dmart/sample/test/test.dmart +45 -0
- dmart/sample/test/ticket_schema.json +23 -0
- dmart/sample/test/ticket_workflow.json +85 -0
- dmart/sample/test/ticketbody.json +4 -0
- dmart/sample/test/ticketcontent.json +14 -0
- dmart/sample/test/updatecontent.json +20 -0
- dmart/sample/test/workflow_schema.json +68 -0
- {dmart-1.4.40.post6.dist-info → dmart-1.4.40.post7.dist-info}/METADATA +1 -1
- {dmart-1.4.40.post6.dist-info → dmart-1.4.40.post7.dist-info}/RECORD +207 -5
- {dmart-1.4.40.post6.dist-info → dmart-1.4.40.post7.dist-info}/WHEEL +0 -0
- {dmart-1.4.40.post6.dist-info → dmart-1.4.40.post7.dist-info}/entry_points.txt +0 -0
- {dmart-1.4.40.post6.dist-info → dmart-1.4.40.post7.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"uuid": "4a001e1f-a844-4bb9-a340-7f8eb1a77480",
|
|
3
|
+
"shortname": "archive",
|
|
4
|
+
"is_active": true,
|
|
5
|
+
"displayname": {
|
|
6
|
+
"en": "archive"
|
|
7
|
+
},
|
|
8
|
+
"tags": [],
|
|
9
|
+
"created_at": "2024-09-02T12:55:00.899747",
|
|
10
|
+
"updated_at": "2024-09-02T12:55:00.906988",
|
|
11
|
+
"owner_shortname": "dmart",
|
|
12
|
+
"root_registration_signature": "",
|
|
13
|
+
"primary_website": "",
|
|
14
|
+
"indexing_enabled": false,
|
|
15
|
+
"capture_misses": false,
|
|
16
|
+
"check_health": false,
|
|
17
|
+
"languages": [
|
|
18
|
+
"english"
|
|
19
|
+
],
|
|
20
|
+
"icon": "",
|
|
21
|
+
"mirrors": [],
|
|
22
|
+
"hide_folders": [],
|
|
23
|
+
"hide_space": true,
|
|
24
|
+
"active_plugins": [
|
|
25
|
+
],
|
|
26
|
+
"ordinal": 1
|
|
27
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"shortname": "dummy",
|
|
3
|
+
"is_active": true,
|
|
4
|
+
"filters": {
|
|
5
|
+
"subpaths": [
|
|
6
|
+
"__ALL__"
|
|
7
|
+
],
|
|
8
|
+
"resource_types": [
|
|
9
|
+
"__ALL__"
|
|
10
|
+
],
|
|
11
|
+
"schema_shortnames": [
|
|
12
|
+
"__ALL__"
|
|
13
|
+
],
|
|
14
|
+
"actions": [
|
|
15
|
+
"query",
|
|
16
|
+
"view",
|
|
17
|
+
"update",
|
|
18
|
+
"create",
|
|
19
|
+
"delete",
|
|
20
|
+
"move",
|
|
21
|
+
"progress_ticket",
|
|
22
|
+
"lock",
|
|
23
|
+
"unlock"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
"type": "hook",
|
|
27
|
+
"listen_time": "after"
|
|
28
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import sys
|
|
3
|
+
import aiofiles
|
|
4
|
+
from models.core import ActionType, PluginBase, Event, Space
|
|
5
|
+
from utils.helpers import camel_case
|
|
6
|
+
from utils.redis_services import RedisServices
|
|
7
|
+
from utils.spaces import get_spaces
|
|
8
|
+
from data_adapters.adapter import data_adapter as db
|
|
9
|
+
from models import core
|
|
10
|
+
from models.enums import ContentType, ResourceType
|
|
11
|
+
from utils.settings import settings
|
|
12
|
+
from fastapi.logger import logger
|
|
13
|
+
|
|
14
|
+
class Plugin(PluginBase):
|
|
15
|
+
|
|
16
|
+
def __init__(self) -> None:
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async def hook(self, data: Event):
|
|
21
|
+
|
|
22
|
+
# Type narrowing for PyRight
|
|
23
|
+
if not isinstance(data.shortname, str) and not isinstance(data.attributes, dict):
|
|
24
|
+
logger.error(f"invalid data at missed_entry")
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
spaces = await get_spaces()
|
|
28
|
+
if not Space.parse_raw(spaces[data.space_name]).capture_misses:
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
if data.action_type == ActionType.query and "filter_shortnames" in data.attributes:
|
|
32
|
+
for shortname in data.attributes["filter_shortnames"]:
|
|
33
|
+
data.shortname = shortname
|
|
34
|
+
data.resource_type = data.resource_type or ResourceType.content
|
|
35
|
+
await self.check_miss(data)
|
|
36
|
+
|
|
37
|
+
else:
|
|
38
|
+
await self.check_miss(data)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
async def check_miss(self, data: Event):
|
|
43
|
+
# Type narrowing for PyRight
|
|
44
|
+
if not isinstance(data.shortname, str):
|
|
45
|
+
logger.error(f"data.shortname is None and str is required at missed_entry")
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
class_type = getattr(
|
|
49
|
+
sys.modules["models.core"], camel_case(core.ResourceType(data.resource_type))
|
|
50
|
+
)
|
|
51
|
+
path, filename = db.metapath(data.space_name, data.subpath, data.shortname, class_type)
|
|
52
|
+
if (path/filename).is_file():
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
if data.subpath[0] == "/":
|
|
56
|
+
data.subpath = data.subpath.replace("/", "", 1)
|
|
57
|
+
|
|
58
|
+
miss_shortname = f"{data.subpath}_{data.shortname}"
|
|
59
|
+
if len(miss_shortname) > 32:
|
|
60
|
+
miss_shortname = miss_shortname[:32]
|
|
61
|
+
|
|
62
|
+
miss_file = (
|
|
63
|
+
settings.spaces_folder /
|
|
64
|
+
data.space_name /
|
|
65
|
+
f"misses/{miss_shortname}.json"
|
|
66
|
+
)
|
|
67
|
+
miss_content = None
|
|
68
|
+
if miss_file.is_file():
|
|
69
|
+
async with aiofiles.open(miss_file, "r") as file:
|
|
70
|
+
miss_content = json.loads(await file.read())
|
|
71
|
+
|
|
72
|
+
missed_obj_meta = core.Content(
|
|
73
|
+
shortname=miss_shortname,
|
|
74
|
+
owner_shortname=data.user_shortname,
|
|
75
|
+
is_active=True,
|
|
76
|
+
payload=core.Payload(
|
|
77
|
+
content_type=ContentType.json,
|
|
78
|
+
schema_shortname="miss",
|
|
79
|
+
body=miss_shortname + ".json",
|
|
80
|
+
),
|
|
81
|
+
)
|
|
82
|
+
async with RedisServices() as redis_services:
|
|
83
|
+
meta_doc_id, meta_json = redis_services.prepate_meta_doc(
|
|
84
|
+
data.space_name, "misses", missed_obj_meta
|
|
85
|
+
)
|
|
86
|
+
if not miss_content:
|
|
87
|
+
await db.save(data.space_name, "misses", missed_obj_meta)
|
|
88
|
+
await redis_services.save_doc(meta_doc_id, meta_json)
|
|
89
|
+
num_of_requests = 1
|
|
90
|
+
|
|
91
|
+
else:
|
|
92
|
+
num_of_requests = miss_content["num_of_requests"] + 1
|
|
93
|
+
|
|
94
|
+
await db.save_payload_from_json(
|
|
95
|
+
data.space_name,
|
|
96
|
+
"misses",
|
|
97
|
+
missed_obj_meta,
|
|
98
|
+
{
|
|
99
|
+
"requested_subpath": data.subpath,
|
|
100
|
+
"requested_shortname": data.shortname,
|
|
101
|
+
"num_of_requests": num_of_requests,
|
|
102
|
+
"actioned": "No",
|
|
103
|
+
},
|
|
104
|
+
)
|
|
105
|
+
payload_dict = {
|
|
106
|
+
**meta_json,
|
|
107
|
+
"requested_subpath": data.subpath,
|
|
108
|
+
"requested_shortname": data.shortname,
|
|
109
|
+
"num_of_requests": num_of_requests,
|
|
110
|
+
"actioned": "No"
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
await redis_services.save_payload_doc(
|
|
114
|
+
space_name=data.space_name,
|
|
115
|
+
subpath="misses",
|
|
116
|
+
meta=missed_obj_meta,
|
|
117
|
+
payload=payload_dict,
|
|
118
|
+
resource_type=ResourceType.content
|
|
119
|
+
)
|
dmart/sample/spaces/custom_plugins/own_changed_notification/__pycache__/plugin.cpython-314.pyc
ADDED
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"shortname": "own_changed_notification",
|
|
3
|
+
"is_active": true,
|
|
4
|
+
"filters": {
|
|
5
|
+
"subpaths": ["__ALL__"],
|
|
6
|
+
"resource_types": ["__ALL__"],
|
|
7
|
+
"schema_shortnames": ["__ALL__"],
|
|
8
|
+
"actions": ["update", "delete"]
|
|
9
|
+
},
|
|
10
|
+
"type": "hook",
|
|
11
|
+
"listen_time": "after"
|
|
12
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from models.core import Content, Payload, PluginBase, Event
|
|
3
|
+
from models.enums import ContentType, ResourceType
|
|
4
|
+
from utils.helpers import camel_case
|
|
5
|
+
from data_adapters.adapter import data_adapter as db
|
|
6
|
+
from uuid import uuid4
|
|
7
|
+
from fastapi.logger import logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Plugin(PluginBase):
|
|
11
|
+
|
|
12
|
+
async def hook(self, data: Event):
|
|
13
|
+
|
|
14
|
+
# Type narrowing for PyRight
|
|
15
|
+
if not isinstance(data.shortname, str):
|
|
16
|
+
logger.error(f"data.shortname is None and str is required at system_notification_sender")
|
|
17
|
+
return
|
|
18
|
+
|
|
19
|
+
class_type = getattr(
|
|
20
|
+
sys.modules["models.core"], camel_case(ResourceType(data.resource_type))
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
entry = await db.load(
|
|
24
|
+
space_name=data.space_name,
|
|
25
|
+
subpath=data.subpath,
|
|
26
|
+
shortname=data.shortname,
|
|
27
|
+
class_type=class_type,
|
|
28
|
+
user_shortname=data.user_shortname
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
if not entry.owner_shortname or entry.owner_shortname == data.user_shortname:
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
uuid = uuid4()
|
|
36
|
+
meta_obj = Content(
|
|
37
|
+
uuid=uuid,
|
|
38
|
+
shortname=str(uuid)[:8],
|
|
39
|
+
owner_shortname=data.user_shortname,
|
|
40
|
+
payload=Payload(
|
|
41
|
+
content_type=ContentType.json,
|
|
42
|
+
schema_shortname="notification",
|
|
43
|
+
body=f"{str(uuid)[:8]}.json"
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
await db.save(
|
|
47
|
+
"personal",
|
|
48
|
+
f"people/{entry.owner_shortname}/notifications",
|
|
49
|
+
meta_obj,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
notification_obj = {
|
|
53
|
+
"entry_space": data.space_name,
|
|
54
|
+
"entry_subpath": data.subpath,
|
|
55
|
+
"entry_shortname": data.shortname,
|
|
56
|
+
"action_by": data.user_shortname,
|
|
57
|
+
"action_type": data.action_type,
|
|
58
|
+
"is_read": "no"
|
|
59
|
+
}
|
|
60
|
+
await db.save_payload_from_json(
|
|
61
|
+
"personal",
|
|
62
|
+
f"people/{entry.owner_shortname}/notifications",
|
|
63
|
+
meta_obj,
|
|
64
|
+
notification_obj, # type: ignore
|
|
65
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"shortname": "reports_stats",
|
|
3
|
+
"is_active": false,
|
|
4
|
+
"filters": {
|
|
5
|
+
"subpaths": [
|
|
6
|
+
"reports"
|
|
7
|
+
],
|
|
8
|
+
"resource_types": ["__ALL__"],
|
|
9
|
+
"schema_shortnames": ["__ALL__"],
|
|
10
|
+
"actions": ["query"]
|
|
11
|
+
},
|
|
12
|
+
"listen_time": "before",
|
|
13
|
+
"type": "hook"
|
|
14
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from os import scandir
|
|
2
|
+
from re import sub
|
|
3
|
+
from models.core import PluginBase, Event
|
|
4
|
+
from utils.access_control import access_control
|
|
5
|
+
from data_adapters.adapter import data_adapter as db
|
|
6
|
+
from models.core import Content
|
|
7
|
+
from models.api import Query
|
|
8
|
+
from utils.repository import get_last_updated_entry, serve_query, internal_sys_update_model
|
|
9
|
+
from utils.settings import settings
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Plugin(PluginBase):
|
|
14
|
+
async def hook(self, data: Event):
|
|
15
|
+
if data.subpath[0] == "/":
|
|
16
|
+
data.subpath = data.subpath[1:]
|
|
17
|
+
reports_path = (
|
|
18
|
+
settings.spaces_folder
|
|
19
|
+
/ data.space_name
|
|
20
|
+
/ data.subpath
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
reports_iterator = scandir(reports_path)
|
|
24
|
+
for report_entry in reports_iterator:
|
|
25
|
+
if not report_entry.is_file():
|
|
26
|
+
continue
|
|
27
|
+
|
|
28
|
+
shortname, _ = report_entry.name.split(".")
|
|
29
|
+
subpath, class_type = "reports", Content
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
report_meta = await db.load(
|
|
33
|
+
space_name=data.space_name,
|
|
34
|
+
subpath=subpath,
|
|
35
|
+
shortname=shortname, # type: ignore
|
|
36
|
+
class_type=class_type,
|
|
37
|
+
user_shortname=data.user_shortname,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
report_payload = await db.load_resource_payload(
|
|
41
|
+
space_name=data.space_name,
|
|
42
|
+
subpath=subpath,
|
|
43
|
+
filename=report_meta.payload.body, # type: ignore
|
|
44
|
+
class_type=class_type,
|
|
45
|
+
)
|
|
46
|
+
except Exception:
|
|
47
|
+
continue
|
|
48
|
+
|
|
49
|
+
report_payload["query"]["search"] = sub(
|
|
50
|
+
r"\$\w*", "", report_payload["query"]["search"]
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
report_query = Query(**report_payload["query"])
|
|
54
|
+
report_query.limit = 0
|
|
55
|
+
redis_query_policies = await access_control.get_user_query_policies(
|
|
56
|
+
data.user_shortname, report_query.space_name, report_query.subpath
|
|
57
|
+
)
|
|
58
|
+
total, records = await serve_query(
|
|
59
|
+
report_query, data.user_shortname, redis_query_policies
|
|
60
|
+
)
|
|
61
|
+
report_last_updated_entry = await get_last_updated_entry(
|
|
62
|
+
data.space_name,
|
|
63
|
+
report_payload["query"]["filter_schema_names"],
|
|
64
|
+
False,
|
|
65
|
+
data.user_shortname,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
report_updates: dict = {
|
|
69
|
+
"number_of_records": total
|
|
70
|
+
}
|
|
71
|
+
if report_last_updated_entry:
|
|
72
|
+
report_updates["last_updated"] = str(
|
|
73
|
+
report_last_updated_entry.attributes["updated_at"]
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
await internal_sys_update_model(
|
|
77
|
+
data.space_name,
|
|
78
|
+
"reports",
|
|
79
|
+
report_meta,
|
|
80
|
+
report_updates
|
|
81
|
+
)
|
|
82
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"shortname": "system_notification_sender",
|
|
3
|
+
"is_active": false,
|
|
4
|
+
"filters": {
|
|
5
|
+
"subpaths": ["__ALL__"],
|
|
6
|
+
"resource_types": ["__ALL__"],
|
|
7
|
+
"schema_shortnames": ["__ALL__"],
|
|
8
|
+
"actions": [
|
|
9
|
+
"progress_ticket",
|
|
10
|
+
"view",
|
|
11
|
+
"create",
|
|
12
|
+
"update",
|
|
13
|
+
"delete",
|
|
14
|
+
"attach",
|
|
15
|
+
"move"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"type": "hook",
|
|
19
|
+
"listen_time": "after",
|
|
20
|
+
"created_at": "2022-08-11T11:27:28.866048",
|
|
21
|
+
"updated_at": "2022-08-11T11:27:28.866052"
|
|
22
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import requests
|
|
3
|
+
from uuid import uuid4
|
|
4
|
+
from api.user.service import send_sms
|
|
5
|
+
from api.user.router import MANAGEMENT_SPACE, USERS_SUBPATH
|
|
6
|
+
from models.core import Notification, Locator, Translation, User
|
|
7
|
+
from models.enums import NotificationType
|
|
8
|
+
from utils.db import save
|
|
9
|
+
from re import sub as res_sub
|
|
10
|
+
from firebase_admin import credentials, messaging, initialize_app
|
|
11
|
+
from utils.helpers import divide_chunks, flatten_dict, lang_code
|
|
12
|
+
from utils.redis_services import RedisServices
|
|
13
|
+
from utils.settings import settings
|
|
14
|
+
from utils.regex import FILENAME
|
|
15
|
+
import os
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
import utils.db as db
|
|
18
|
+
from fastapi.logger import logger
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def send_notification(
|
|
22
|
+
notification_dict: dict,
|
|
23
|
+
receivers: set,
|
|
24
|
+
entry: dict = {},
|
|
25
|
+
):
|
|
26
|
+
notification_required_keys = [
|
|
27
|
+
"displayname",
|
|
28
|
+
"description",
|
|
29
|
+
"priority",
|
|
30
|
+
"types",
|
|
31
|
+
]
|
|
32
|
+
if not all(key in notification_dict for key in notification_required_keys):
|
|
33
|
+
raise Exception(
|
|
34
|
+
"One or more of the Main keys 'displayname', 'description', or 'priority' are missing"
|
|
35
|
+
)
|
|
36
|
+
if isinstance(notification_dict["displayname"], Translation):
|
|
37
|
+
notification_dict["displayname"] = notification_dict["displayname"].dict()
|
|
38
|
+
if isinstance(notification_dict["description"], Translation):
|
|
39
|
+
notification_dict["description"] = notification_dict["description"].dict()
|
|
40
|
+
|
|
41
|
+
for locale in ["ar", "en", "ku"]:
|
|
42
|
+
notification_dict["displayname"][locale] = translate_message_vars(
|
|
43
|
+
notification_dict["displayname"][locale], entry, locale
|
|
44
|
+
)
|
|
45
|
+
notification_dict["description"][locale] = translate_message_vars(
|
|
46
|
+
notification_dict["description"][locale], entry, locale
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
for receiver in receivers:
|
|
50
|
+
if "web" in notification_dict["types"]:
|
|
51
|
+
try:
|
|
52
|
+
if not notification_dict.get("push_only", False):
|
|
53
|
+
await store_notification(notification_dict, receiver, entry)
|
|
54
|
+
|
|
55
|
+
# Send push notification
|
|
56
|
+
requests.post(
|
|
57
|
+
url=f"{settings.websocket_url}/send-message/{receiver}",
|
|
58
|
+
data=json.dumps(
|
|
59
|
+
{
|
|
60
|
+
"title": notification_dict["displayname"],
|
|
61
|
+
"description": notification_dict["description"],
|
|
62
|
+
}
|
|
63
|
+
),
|
|
64
|
+
)
|
|
65
|
+
except Exception as e:
|
|
66
|
+
logger.error(
|
|
67
|
+
"Notification",
|
|
68
|
+
extra={
|
|
69
|
+
"props": {"title": "FAIL at store_notification", "message": e}
|
|
70
|
+
},
|
|
71
|
+
)
|
|
72
|
+
user = None
|
|
73
|
+
if "mobile" in notification_dict["types"]:
|
|
74
|
+
try:
|
|
75
|
+
user = await db.load(
|
|
76
|
+
space_name=MANAGEMENT_SPACE,
|
|
77
|
+
subpath=USERS_SUBPATH,
|
|
78
|
+
shortname=receiver,
|
|
79
|
+
class_type=User,
|
|
80
|
+
user_shortname="dmart",
|
|
81
|
+
)
|
|
82
|
+
await send_notification_firebase(user, notification_dict, entry)
|
|
83
|
+
except Exception as e:
|
|
84
|
+
logger.error(
|
|
85
|
+
"Notification",
|
|
86
|
+
extra={
|
|
87
|
+
"props": {
|
|
88
|
+
"title": "FAIL at send_notification_firebase",
|
|
89
|
+
"message": e,
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
)
|
|
93
|
+
if "sms" in notification_dict["types"]:
|
|
94
|
+
try:
|
|
95
|
+
user = (
|
|
96
|
+
user
|
|
97
|
+
if user
|
|
98
|
+
else await db.load(
|
|
99
|
+
space_name=MANAGEMENT_SPACE,
|
|
100
|
+
subpath=USERS_SUBPATH,
|
|
101
|
+
shortname=receiver,
|
|
102
|
+
class_type=User,
|
|
103
|
+
user_shortname="dmart",
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
user_lang_code = lang_code(user.language)
|
|
107
|
+
await send_sms(
|
|
108
|
+
user.msisdn or "",
|
|
109
|
+
notification_dict["displayname"][user_lang_code],
|
|
110
|
+
)
|
|
111
|
+
except Exception as e:
|
|
112
|
+
logger.error(
|
|
113
|
+
"Notification",
|
|
114
|
+
extra={"props": {"title": "FAIL at send_sms", "message": e}},
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def translate_message_vars(message: str, entry: dict, locale: str):
|
|
119
|
+
entry_dict = flatten_dict(entry)
|
|
120
|
+
for field, value in entry_dict.items():
|
|
121
|
+
if type(value) == dict and locale in value:
|
|
122
|
+
value = value[locale]
|
|
123
|
+
if field in ["created_at", "updated_at"]:
|
|
124
|
+
message = message.replace(
|
|
125
|
+
f"{{{field}}}", str(value.strftime("%Y-%m-%d %H:%M:%S"))
|
|
126
|
+
)
|
|
127
|
+
else:
|
|
128
|
+
message = message.replace(f"{{{field}}}", str(value))
|
|
129
|
+
|
|
130
|
+
return res_sub(r"\{\w*.*\}", "", message)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
async def store_notification(
|
|
134
|
+
notification_dict: dict, receiver_shortname: str, entry: dict = {}
|
|
135
|
+
):
|
|
136
|
+
if notification_dict["payload"]["schema_shortname"] == "admin_notification_request":
|
|
137
|
+
notification_type = NotificationType.admin
|
|
138
|
+
else:
|
|
139
|
+
notification_type = NotificationType.system
|
|
140
|
+
|
|
141
|
+
entry_locator = None
|
|
142
|
+
if entry:
|
|
143
|
+
entry_locator = Locator(
|
|
144
|
+
space_name=entry["space_name"],
|
|
145
|
+
type=entry["resource_type"],
|
|
146
|
+
schema_shortname=entry["payload"]["schema_shortname"],
|
|
147
|
+
subpath=entry["subpath"],
|
|
148
|
+
shortname=entry["shortname"],
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
uuid = uuid4()
|
|
152
|
+
notification_obj = Notification(
|
|
153
|
+
uuid=uuid,
|
|
154
|
+
shortname=str(uuid)[:8],
|
|
155
|
+
is_active=True,
|
|
156
|
+
displayname=notification_dict["displayname"],
|
|
157
|
+
description=notification_dict["description"],
|
|
158
|
+
owner_shortname=notification_dict["owner_shortname"],
|
|
159
|
+
type=notification_type,
|
|
160
|
+
is_read=False,
|
|
161
|
+
priority=notification_dict["priority"],
|
|
162
|
+
entry=entry_locator,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
await save(
|
|
166
|
+
space_name="personal",
|
|
167
|
+
subpath=f"people/{receiver_shortname}/notifications",
|
|
168
|
+
meta=notification_obj,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
async with await RedisServices() as redis:
|
|
172
|
+
await redis.save_meta_doc(
|
|
173
|
+
"personal",
|
|
174
|
+
f"people/{receiver_shortname}/notifications",
|
|
175
|
+
notification_obj,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
firebase_app = None
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def init_firbase_app():
|
|
183
|
+
global firebase_app
|
|
184
|
+
firebase_cred = credentials.Certificate(settings.google_application_credentials)
|
|
185
|
+
firebase_app = initialize_app(firebase_cred, name="[DEFAULT]")
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
async def send_notification_firebase(user: User, data, entry):
|
|
189
|
+
users_fcm_tokens = {}
|
|
190
|
+
|
|
191
|
+
firebase_token, msisdn = user.firebase_token, user.msisdn
|
|
192
|
+
|
|
193
|
+
lang = lang_code(user.language)
|
|
194
|
+
# if lang not in users_fcm_tokens:
|
|
195
|
+
users_fcm_tokens[lang] = {}
|
|
196
|
+
users_fcm_tokens[lang][msisdn] = firebase_token
|
|
197
|
+
|
|
198
|
+
images: dict = {}
|
|
199
|
+
images_folder = Path(
|
|
200
|
+
f"{settings.spaces_folder}/{settings.management_space}/{data['subpath']}/.dm/{data['shortname']}/attachments.media"
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
if images_folder.is_dir():
|
|
204
|
+
images_files = os.scandir(images_folder)
|
|
205
|
+
for image_file in images_files:
|
|
206
|
+
match = FILENAME.search(str(image_file.name))
|
|
207
|
+
if not match or not image_file.is_file():
|
|
208
|
+
continue
|
|
209
|
+
|
|
210
|
+
images[
|
|
211
|
+
image_file.name.split("_")[0]
|
|
212
|
+
] = f"{settings.listening_host}/public/payload/media/{settings.management_space}/{data['subpath']}/{data['shortname']}/{image_file.name}"
|
|
213
|
+
|
|
214
|
+
for lang, fcm_token_per_lang in users_fcm_tokens.items():
|
|
215
|
+
res = send_multiple_notifications(
|
|
216
|
+
tokens=list(fcm_token_per_lang.values()),
|
|
217
|
+
title=data.get("displayname", {}).get(lang, ""),
|
|
218
|
+
body=data.get("description", {}).get(lang, ""),
|
|
219
|
+
image=images.get(lang, ""),
|
|
220
|
+
data={
|
|
221
|
+
**data.get("deep_link"),
|
|
222
|
+
"id": entry.get("shortname"),
|
|
223
|
+
"space_name": entry.get("space_name"),
|
|
224
|
+
"subpath": entry.get("subpath"),
|
|
225
|
+
},
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def send_multiple_notifications(
|
|
230
|
+
tokens: list, title: str, body: str, data: dict, image: str, sound="default"
|
|
231
|
+
) -> list:
|
|
232
|
+
if not firebase_app:
|
|
233
|
+
init_firbase_app()
|
|
234
|
+
alert = messaging.ApsAlert(title=title, body=body)
|
|
235
|
+
aps = messaging.Aps(alert=alert, sound="default", content_available=True)
|
|
236
|
+
apns = messaging.APNSConfig(
|
|
237
|
+
payload=messaging.APNSPayload(aps),
|
|
238
|
+
fcm_options=messaging.APNSFCMOptions(image=image),
|
|
239
|
+
)
|
|
240
|
+
android_notification_settings = messaging.AndroidNotification(
|
|
241
|
+
priority="high", channel_id="FCM_CHANNEL_ID", visibility="public", image=image
|
|
242
|
+
)
|
|
243
|
+
android_config = messaging.AndroidConfig(
|
|
244
|
+
priority="high", notification=android_notification_settings
|
|
245
|
+
)
|
|
246
|
+
web_push = messaging.WebpushConfig(headers={"image": image})
|
|
247
|
+
# Firebase sends message to max of 500 registration tokens.
|
|
248
|
+
tokens_chunks = divide_chunks(tokens, 500)
|
|
249
|
+
failed_tokens = []
|
|
250
|
+
for tokens in tokens_chunks:
|
|
251
|
+
message = messaging.MulticastMessage(
|
|
252
|
+
notification=messaging.Notification(title=title, body=body),
|
|
253
|
+
tokens=tokens,
|
|
254
|
+
data=data,
|
|
255
|
+
apns=apns,
|
|
256
|
+
android=android_config,
|
|
257
|
+
webpush=web_push,
|
|
258
|
+
)
|
|
259
|
+
response = messaging.send_multicast(message)
|
|
260
|
+
|
|
261
|
+
if response.failure_count > 0:
|
|
262
|
+
responses = response.responses
|
|
263
|
+
for idx, resp in enumerate(responses):
|
|
264
|
+
if not resp.success:
|
|
265
|
+
# The order of responses corresponds to the order of the registration tokens.
|
|
266
|
+
failed_tokens.append(tokens[idx])
|
|
267
|
+
|
|
268
|
+
return failed_tokens
|