django-slack-tools 0.2.2__py3-none-any.whl → 0.3.0__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.
Files changed (52) hide show
  1. django_slack_tools/__init__.py +0 -1
  2. django_slack_tools/app_settings.py +54 -90
  3. django_slack_tools/locale/ko_KR/LC_MESSAGES/django.po +150 -186
  4. django_slack_tools/py.typed +0 -0
  5. django_slack_tools/slack_messages/admin/message.py +1 -52
  6. django_slack_tools/slack_messages/admin/message_recipient.py +2 -2
  7. django_slack_tools/slack_messages/admin/messaging_policy.py +5 -5
  8. django_slack_tools/slack_messages/backends/__init__.py +3 -3
  9. django_slack_tools/slack_messages/backends/base.py +39 -203
  10. django_slack_tools/slack_messages/backends/dummy.py +0 -12
  11. django_slack_tools/slack_messages/backends/{logging.py → logging_.py} +0 -6
  12. django_slack_tools/slack_messages/backends/slack.py +21 -75
  13. django_slack_tools/slack_messages/message_templates/__init__.py +5 -0
  14. django_slack_tools/slack_messages/message_templates/base.py +17 -0
  15. django_slack_tools/{utils/template → slack_messages/message_templates}/django.py +30 -25
  16. django_slack_tools/slack_messages/message_templates/python.py +38 -0
  17. django_slack_tools/slack_messages/messenger.py +158 -0
  18. django_slack_tools/slack_messages/middlewares/__init__.py +4 -0
  19. django_slack_tools/slack_messages/middlewares/base.py +34 -0
  20. django_slack_tools/slack_messages/middlewares/django.py +218 -0
  21. django_slack_tools/slack_messages/migrations/0001_initial.py +4 -4
  22. django_slack_tools/slack_messages/migrations/0005_alter_slackmessagingpolicy_template_type.py +46 -0
  23. django_slack_tools/slack_messages/migrations/0006_alter_slackmessage_id.py +26 -0
  24. django_slack_tools/slack_messages/models/mention.py +1 -1
  25. django_slack_tools/slack_messages/models/message.py +5 -2
  26. django_slack_tools/slack_messages/models/message_recipient.py +1 -1
  27. django_slack_tools/slack_messages/models/messaging_policy.py +4 -4
  28. django_slack_tools/slack_messages/request.py +91 -0
  29. django_slack_tools/slack_messages/response.py +21 -0
  30. django_slack_tools/slack_messages/shortcuts.py +78 -0
  31. django_slack_tools/slack_messages/tasks.py +16 -49
  32. django_slack_tools/slack_messages/template_loaders/__init__.py +11 -0
  33. django_slack_tools/slack_messages/template_loaders/base.py +16 -0
  34. django_slack_tools/slack_messages/template_loaders/django.py +74 -0
  35. django_slack_tools/slack_messages/template_loaders/errors.py +9 -0
  36. django_slack_tools/{utils/slack/django.py → slack_messages/validators.py} +1 -1
  37. django_slack_tools/utils/django/__init__.py +0 -0
  38. django_slack_tools/utils/import_helper.py +37 -0
  39. django_slack_tools/utils/repr.py +10 -0
  40. django_slack_tools/utils/slack/__init__.py +1 -9
  41. {django_slack_tools-0.2.2.dist-info → django_slack_tools-0.3.0.dist-info}/METADATA +12 -60
  42. django_slack_tools-0.3.0.dist-info/RECORD +58 -0
  43. {django_slack_tools-0.2.2.dist-info → django_slack_tools-0.3.0.dist-info}/WHEEL +1 -1
  44. django_slack_tools/slack_messages/message.py +0 -110
  45. django_slack_tools/utils/slack/message.py +0 -93
  46. django_slack_tools/utils/template/__init__.py +0 -5
  47. django_slack_tools/utils/template/base.py +0 -17
  48. django_slack_tools/utils/template/dict.py +0 -52
  49. django_slack_tools-0.2.2.dist-info/RECORD +0 -43
  50. /django_slack_tools/utils/{model_mixins.py → django/model_mixins.py} +0 -0
  51. /django_slack_tools/utils/{widgets.py → django/widgets.py} +0 -0
  52. {django_slack_tools-0.2.2.dist-info → django_slack_tools-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,110 +0,0 @@
1
- """Handy APIs for sending Slack messages."""
2
-
3
- from __future__ import annotations
4
-
5
- import logging
6
- from typing import TYPE_CHECKING, Any
7
-
8
- from django_slack_tools.app_settings import app_settings
9
- from django_slack_tools.slack_messages.models.message_recipient import SlackMessageRecipient
10
- from django_slack_tools.utils.slack import MessageBody, MessageHeader
11
-
12
- from .models import SlackMessagingPolicy
13
-
14
- logger = logging.getLogger(__name__)
15
-
16
- if TYPE_CHECKING:
17
- from django_slack_tools.slack_messages.backends.base import BaseBackend
18
-
19
- from .models import SlackMessage
20
-
21
-
22
- def slack_message( # noqa: PLR0913
23
- body: str | MessageBody | dict[str, Any],
24
- *,
25
- channel: str,
26
- header: MessageHeader | dict[str, Any] | None = None,
27
- raise_exception: bool = False,
28
- get_permalink: bool = False,
29
- backend: BaseBackend = app_settings.backend,
30
- ) -> SlackMessage:
31
- """Send a simple text message.
32
-
33
- Args:
34
- body: Message content, simple message or full request body.
35
- channel: Channel to send message.
36
- header: Slack message control header.
37
- raise_exception: Whether to re-raise caught exception while sending messages.
38
- get_permalink: Try to get the message permalink via extraneous Slack API calls.
39
- backend: Messaging backend. If not set, use `app_settings.backend`.
40
-
41
- Returns:
42
- Sent message instance or `None`.
43
- """
44
- body = MessageBody.from_any(body)
45
- header = MessageHeader.from_any(header)
46
- message = backend.prepare_message(channel=channel, header=header, body=body)
47
-
48
- return backend.send_message(message, raise_exception=raise_exception, get_permalink=get_permalink)
49
-
50
-
51
- def slack_message_via_policy( # noqa: PLR0913
52
- policy: str | SlackMessagingPolicy = app_settings.default_policy_code,
53
- *,
54
- header: MessageHeader | dict[str, Any] | None = None,
55
- raise_exception: bool = False,
56
- lazy: bool = False,
57
- get_permalink: bool = False,
58
- context: dict[str, Any] | None = None,
59
- backend: BaseBackend = app_settings.backend,
60
- ) -> int:
61
- """Send a simple text message.
62
-
63
- Some default context variables are populated and available for use in templates.
64
- See corresponding backend implementation for available context variables.
65
-
66
- Args:
67
- policy: Messaging policy code or policy instance. Defaults to app's default policy.
68
- header: Slack message control header.
69
- raise_exception: Whether to re-raise caught exception while sending messages.
70
- lazy: Decide whether try create policy with disabled, if not exists.
71
- get_permalink: Try to get the message permalink via extraneous Slack API calls.
72
- context: Dictionary to pass to template for rendering.
73
- backend: Messaging backend. If not set, use `app_settings.backend`.
74
-
75
- Returns:
76
- Count of messages sent successfully.
77
-
78
- Raises:
79
- SlackMessagingPolicy.DoesNotExist: Policy for given code does not exists.
80
- """
81
- if isinstance(policy, str):
82
- if lazy:
83
- policy, created = SlackMessagingPolicy.objects.get_or_create(
84
- code=policy,
85
- defaults={
86
- "enabled": app_settings.lazy_policy_enabled,
87
- "template": app_settings.default_template,
88
- },
89
- )
90
- if created:
91
- # Add default recipient for created policy
92
- recipient = SlackMessageRecipient.objects.get(alias=app_settings.default_recipient)
93
- policy.recipients.add(recipient)
94
- logger.warning("Policy for code %r created because `lazy` is set.", policy)
95
- else:
96
- policy = SlackMessagingPolicy.objects.get(code=policy)
97
-
98
- header = MessageHeader.from_any(header)
99
- context = context or {}
100
-
101
- messages = backend.prepare_messages_from_policy(policy, header=header, context=context)
102
- if not policy.enabled:
103
- logger.warning(
104
- "Created %d messages but not sending because policy %s is not enabled.",
105
- len(messages),
106
- policy.code,
107
- )
108
- return 0
109
-
110
- return backend.send_messages(*messages, raise_exception=raise_exception, get_permalink=get_permalink)
@@ -1,93 +0,0 @@
1
- """Utils for Slack messaging."""
2
-
3
- from __future__ import annotations
4
-
5
- from dataclasses import dataclass, field
6
- from typing import TYPE_CHECKING
7
-
8
- if TYPE_CHECKING:
9
- from typing import Any, List, Optional
10
-
11
- NoneType = type(None)
12
-
13
-
14
- @dataclass
15
- class MessageHeader:
16
- """Message header data definition."""
17
-
18
- mrkdwn: Optional[str] = field(default=None) # noqa: UP007
19
- parse: Optional[str] = field(default=None) # noqa: UP007
20
- reply_broadcast: Optional[bool] = field(default=None) # noqa: UP007
21
- thread_ts: Optional[str] = field(default=None) # noqa: UP007
22
- unfurl_links: Optional[bool] = field(default=None) # noqa: UP007
23
- unfurl_media: Optional[bool] = field(default=None) # noqa: UP007
24
-
25
- def __post_init__(self) -> None:
26
- _assert_type(self.mrkdwn, (str, NoneType))
27
- _assert_type(self.parse, (str, NoneType))
28
- _assert_type(self.reply_broadcast, (bool, NoneType))
29
- _assert_type(self.thread_ts, (str, NoneType))
30
- _assert_type(self.unfurl_links, (bool, NoneType))
31
- _assert_type(self.unfurl_media, (bool, NoneType))
32
-
33
- @classmethod
34
- def from_any(
35
- cls,
36
- obj: MessageHeader | dict[str, Any] | None = None,
37
- ) -> MessageHeader:
38
- """Create instance from compatible types."""
39
- if obj is None:
40
- return cls()
41
-
42
- if isinstance(obj, dict):
43
- return cls(**obj)
44
-
45
- msg = f"Unsupported type {type(obj)}"
46
- raise TypeError(msg)
47
-
48
-
49
- @dataclass
50
- class MessageBody:
51
- """Data definition for message body."""
52
-
53
- attachments: Optional[List[dict]] = field(default=None) # noqa: UP006, UP007
54
-
55
- # See more about blocks at https://api.slack.com/reference/block-kit/blocks
56
- blocks: Optional[List[dict]] = field(default=None) # noqa: UP006, UP007
57
-
58
- text: Optional[str] = field(default=None) # noqa: UP007
59
- icon_emoji: Optional[str] = field(default=None) # noqa: UP007
60
- icon_url: Optional[str] = field(default=None) # noqa: UP007
61
- metadata: Optional[dict] = field(default=None) # noqa: UP007
62
- username: Optional[str] = field(default=None) # noqa: UP007
63
-
64
- def __post_init__(self) -> None:
65
- _assert_type(self.attachments, (list, NoneType))
66
- _assert_type(self.blocks, (list, NoneType))
67
- _assert_type(self.text, (str, NoneType))
68
- _assert_type(self.icon_emoji, (str, NoneType))
69
- _assert_type(self.icon_url, (str, NoneType))
70
- _assert_type(self.metadata, (dict, NoneType))
71
- _assert_type(self.username, (str, NoneType))
72
-
73
- if not any((self.attachments, self.blocks, self.text)):
74
- msg = "At least one of `attachments`, `blocks` and `text` must set"
75
- raise ValueError(msg)
76
-
77
- @classmethod
78
- def from_any(cls, obj: str | MessageBody | dict[str, Any]) -> MessageBody:
79
- """Create instance from compatible types."""
80
- if isinstance(obj, dict):
81
- return cls(**obj)
82
-
83
- if isinstance(obj, str):
84
- return cls(text=obj)
85
-
86
- msg = f"Unsupported type {type(obj)}"
87
- raise TypeError(msg)
88
-
89
-
90
- def _assert_type(obj: Any, cls: type | tuple[type, ...]) -> None:
91
- if not isinstance(obj, cls):
92
- msg = f"Invalid value type, expected {cls}, got {type(obj)}"
93
- raise TypeError(msg)
@@ -1,5 +0,0 @@
1
- from .base import BaseTemplate
2
- from .dict import DictTemplate
3
- from .django import DjangoTemplate
4
-
5
- __all__ = ("BaseTemplate", "DictTemplate", "DjangoTemplate")
@@ -1,17 +0,0 @@
1
- """Abstraction for dictionary templates."""
2
-
3
- from __future__ import annotations
4
-
5
- from abc import ABC, abstractmethod
6
- from typing import TYPE_CHECKING
7
-
8
- if TYPE_CHECKING:
9
- from typing import Any
10
-
11
-
12
- class BaseTemplate(ABC):
13
- """Abstract base class for dictionary templates."""
14
-
15
- @abstractmethod
16
- def render(self, *, context: dict[str, Any] | None = None) -> dict:
17
- """Render template with given context."""
@@ -1,52 +0,0 @@
1
- # noqa: D100
2
- from __future__ import annotations
3
-
4
- from typing import TYPE_CHECKING, TypeVar
5
-
6
- from .base import BaseTemplate
7
-
8
- if TYPE_CHECKING:
9
- from typing import Any
10
-
11
-
12
- import logging
13
-
14
- logger = logging.getLogger(__name__)
15
-
16
-
17
- class DictTemplate(BaseTemplate):
18
- """Simple dictionary-based template."""
19
-
20
- def __init__(self, template: dict) -> None:
21
- """Initialize template.
22
-
23
- Args:
24
- template: Dictionary template.
25
- kwargs: Keyword arguments passed to template.
26
- """
27
- self.template = template
28
-
29
- def render(self, *, context: dict[str, Any] | None = None) -> dict: # noqa: D102
30
- context = {} if context is None else context
31
- result = self.template.copy()
32
- for k, v in result.items():
33
- result[k] = _format_obj(v, context=context)
34
-
35
- return result
36
-
37
-
38
- T = TypeVar("T", dict, list, str)
39
-
40
-
41
- def _format_obj(obj: T, *, context: dict[str, Any]) -> T:
42
- """Format object recursively."""
43
- if isinstance(obj, dict):
44
- return {k: _format_obj(v, context=context) for k, v in obj.items()}
45
-
46
- if isinstance(obj, str):
47
- return obj.format_map(context)
48
-
49
- if isinstance(obj, list):
50
- return [_format_obj(item, context=context) for item in obj]
51
-
52
- return obj
@@ -1,43 +0,0 @@
1
- django_slack_tools/__init__.py,sha256=m6kyaNpwBcP1XYcqrelX2oS3PJuOnElOcRdBa9pEb8c,22
2
- django_slack_tools/app_settings.py,sha256=N_xWW1TxkvF1-LuDjuNZFiE0XKpQiVmse2_ZH3lbUok,3837
3
- django_slack_tools/views.py,sha256=XuQh0g9A2O51DVkMUhm8x8cswZytZcECNIsDuLsM0UI,1168
4
- django_slack_tools/locale/ko_KR/LC_MESSAGES/django.po,sha256=ySlOJgCeqFzesrWLm1BugmdLb878GSGQJZp7a1uXopw,14864
5
- django_slack_tools/slack_messages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- django_slack_tools/slack_messages/apps.py,sha256=nLVxuLE-1VIqkcVYEdtlg6ffD3blonGCMKaTd_F5jis,610
7
- django_slack_tools/slack_messages/message.py,sha256=W6ZiwUF9R4jFNLdoUxUmNZdLHr4qENFJzVREd1yalRM,4170
8
- django_slack_tools/slack_messages/tasks.py,sha256=EOj84Svncpa3I1ZWSKqlzYydFMhT59z2XkOro0ZwIv8,3316
9
- django_slack_tools/slack_messages/admin/__init__.py,sha256=FEBZlgze8Nf5wn8ixm9FcsL3na2WYykmm2U-iJXh_mQ,305
10
- django_slack_tools/slack_messages/admin/mention.py,sha256=Z3Cx-6WKECsbXnyby1qCEMllvxJEIn_TdwexsjEaiIo,4399
11
- django_slack_tools/slack_messages/admin/message.py,sha256=bC4LHhUc07oq2RaWDPZnxAqrthXXofjqlTpfkkADs2o,4126
12
- django_slack_tools/slack_messages/admin/message_recipient.py,sha256=CVhvUGT4_jD3kJ2CEW8f-DnG3hcsbFbtlccfL_TcS10,4035
13
- django_slack_tools/slack_messages/admin/messaging_policy.py,sha256=NRzKGgGMCMfABXZrN9okDXb9NvsyxWFLt8hBRfFzwug,4576
14
- django_slack_tools/slack_messages/backends/__init__.py,sha256=5wIJbp1n6_3kp1nk8x4LyFDqiHw1H13XsqwuIUiqeJo,276
15
- django_slack_tools/slack_messages/backends/base.py,sha256=VE1xjxrlaE-4fv_ynf-3S6f7h6NXiQIUdcc-yPVsFN4,8179
16
- django_slack_tools/slack_messages/backends/dummy.py,sha256=OE9pMhAZH8sAewseK_yuPXDgkSHvLH_X_vIItbwpaMc,1155
17
- django_slack_tools/slack_messages/backends/logging.py,sha256=2P-pEJFI5r6-45rXt43tzQHzokT9wRlEmhSXZIWvvgU,903
18
- django_slack_tools/slack_messages/backends/slack.py,sha256=uRfrQSDj7Tf2lB76uD_Ma51dplsoIKViolGR26-KOL4,4948
19
- django_slack_tools/slack_messages/migrations/0001_initial.py,sha256=mLH8mk__OajzisYuO5j0Y-hmgMOM9ANJSKV-q32-FVY,11594
20
- django_slack_tools/slack_messages/migrations/0002_default_policy.py,sha256=a1pf6bGhFszOz2awUudQnm9FyxIdWcs3ILsWCADG4YU,1145
21
- django_slack_tools/slack_messages/migrations/0003_default_recipient.py,sha256=SqqawYxEHItmCYAgfv-EAsnc7Fxg3mJtKw6ccDCF1Eo,1153
22
- django_slack_tools/slack_messages/migrations/0004_slackmessagingpolicy_template_type.py,sha256=u5WkhdPxzXLraw8oTvC0sBV5GUFR0fDghtoc2RvTFQU,679
23
- django_slack_tools/slack_messages/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
- django_slack_tools/slack_messages/models/__init__.py,sha256=5niO9vU-YMGRCt7wQMXbN-hSrLpJLtukMKjjv-aFeaQ,265
25
- django_slack_tools/slack_messages/models/mention.py,sha256=C_nowbRv7JU-tD-5boJKu-e3bqG_kTGrrB1WE0ZX1Us,2077
26
- django_slack_tools/slack_messages/models/message.py,sha256=Ih9lHqJ6M6kKuwRw5_mnoY2kT_RVglUJfOxxpd0vZE4,3644
27
- django_slack_tools/slack_messages/models/message_recipient.py,sha256=FxaSIOAhZPSa_Tib58P4WXAs0zn8GsK4UgxOjktyduE,1666
28
- django_slack_tools/slack_messages/models/messaging_policy.py,sha256=Za0wJs5xQ2TWAwUzHuHom98FxdTW4TspgUL387c4mmE,2954
29
- django_slack_tools/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
- django_slack_tools/utils/model_mixins.py,sha256=bNPx3yudzUku8TnjstestOs6YEww58FmBUypL5caYdI,634
31
- django_slack_tools/utils/widgets.py,sha256=v1EorzDSDXn_ZZgBHVFYMhWPG5RsfEI3L3VFf282svg,876
32
- django_slack_tools/utils/slack/__init__.py,sha256=_3oJZqfw3VpuXjDT3vEUnjGT3qK1rYhTwCh268f6Jmk,279
33
- django_slack_tools/utils/slack/django.py,sha256=H6OiGyMYLD6mpZhpPSiosSd7AczBoCXqQHEKhW_LSQE,743
34
- django_slack_tools/utils/slack/message.py,sha256=FkbM9okHOwJ1NDcg8eX3H3uCA47L-jzu6P-70AFtpqQ,3243
35
- django_slack_tools/utils/slack/misc.py,sha256=bl7xp43IsTt0FUZWfGH9kk4qYMU0UjIhuGs35zkLyyE,1099
36
- django_slack_tools/utils/template/__init__.py,sha256=4aMW_Qum7p_-5hm0s5rQXOVSikAwzVBM0MWLmQY93Mo,159
37
- django_slack_tools/utils/template/base.py,sha256=Ql14Z_ZRnsXS3W724hTbPebzqBoxewf98GaXyny8rYg,422
38
- django_slack_tools/utils/template/dict.py,sha256=99vNwlO4WzDZuhPvPIcrwkB-sRYl0Ci5tOnW4sqYNTY,1262
39
- django_slack_tools/utils/template/django.py,sha256=971UIqU8wMtcPT_K2yhn4VdnZB8fOAe28q1YbSoKS58,4104
40
- django_slack_tools-0.2.2.dist-info/METADATA,sha256=aOFCx3nd4sfcD1M8aE1HyDNvao61BioAPnkAcUcjNZM,4493
41
- django_slack_tools-0.2.2.dist-info/WHEEL,sha256=3U_NnUcV_1B1kPkYaPzN-irRckL5VW_lytn0ytO_kRY,87
42
- django_slack_tools-0.2.2.dist-info/licenses/LICENSE,sha256=lPgIV-vu4gapOeftp1Dp5RsN6zlsiMiubqCNeP466hw,1067
43
- django_slack_tools-0.2.2.dist-info/RECORD,,