django-slack-tools 0.1.0__py3-none-any.whl → 0.2.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 (28) hide show
  1. django_slack_tools/__init__.py +1 -1
  2. django_slack_tools/app_settings.py +29 -4
  3. django_slack_tools/slack_messages/admin/message.py +1 -1
  4. django_slack_tools/slack_messages/apps.py +9 -0
  5. django_slack_tools/slack_messages/backends/__init__.py +2 -2
  6. django_slack_tools/slack_messages/backends/base.py +182 -47
  7. django_slack_tools/slack_messages/backends/dummy.py +8 -9
  8. django_slack_tools/slack_messages/backends/slack.py +29 -91
  9. django_slack_tools/slack_messages/message.py +40 -58
  10. django_slack_tools/slack_messages/migrations/0001_initial.py +0 -2
  11. django_slack_tools/slack_messages/migrations/0002_default_policy.py +35 -0
  12. django_slack_tools/slack_messages/migrations/0003_default_recipient.py +35 -0
  13. django_slack_tools/slack_messages/migrations/0004_slackmessagingpolicy_template_type.py +23 -0
  14. django_slack_tools/slack_messages/models/messaging_policy.py +29 -3
  15. django_slack_tools/slack_messages/tasks.py +112 -0
  16. django_slack_tools/utils/slack/django.py +8 -24
  17. django_slack_tools/utils/slack/message.py +74 -25
  18. django_slack_tools/utils/template/__init__.py +5 -0
  19. django_slack_tools/utils/template/base.py +17 -0
  20. django_slack_tools/utils/template/dict.py +52 -0
  21. django_slack_tools/utils/template/django.py +140 -0
  22. django_slack_tools/views.py +1 -1
  23. {django_slack_tools-0.1.0.dist-info → django_slack_tools-0.2.0.dist-info}/METADATA +39 -21
  24. django_slack_tools-0.2.0.dist-info/RECORD +43 -0
  25. {django_slack_tools-0.1.0.dist-info → django_slack_tools-0.2.0.dist-info}/WHEEL +1 -1
  26. django_slack_tools/utils/dict_template.py +0 -55
  27. django_slack_tools-0.1.0.dist-info/RECORD +0 -36
  28. {django_slack_tools-0.1.0.dist-info → django_slack_tools-0.2.0.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,52 @@
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
@@ -0,0 +1,140 @@
1
+ # noqa: D100
2
+ from __future__ import annotations
3
+
4
+ import logging
5
+ import re
6
+ import xml.etree.ElementTree as ET
7
+ from textwrap import dedent
8
+ from typing import TYPE_CHECKING, overload
9
+
10
+ import xmltodict
11
+ from django.template import engines
12
+
13
+ from .base import BaseTemplate
14
+
15
+ if TYPE_CHECKING:
16
+ from typing import Any
17
+
18
+ from django.template.backends.base import BaseEngine
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class DjangoTemplate(BaseTemplate):
24
+ """Template utilizing Django built-in template engine."""
25
+
26
+ @overload
27
+ def __init__(self, *, file: str, engine: BaseEngine | None = None) -> None: ... # pragma: no cover
28
+
29
+ @overload
30
+ def __init__(self, *, inline: str, engine: BaseEngine | None = None) -> None: ... # pragma: no cover
31
+
32
+ def __init__(
33
+ self,
34
+ *,
35
+ file: str | None = None,
36
+ inline: str | None = None,
37
+ engine: BaseEngine | None = None,
38
+ ) -> None:
39
+ """Initialize template.
40
+
41
+ Args:
42
+ file: Path to file with template.
43
+ inline: XML inline template.
44
+ engine: Template engine to use. Defaults to Django engine.
45
+
46
+ Raises:
47
+ TypeError: Some of the arguments are missing or multiple are provided.
48
+ ValueError: Unsupported value provided.
49
+ """
50
+ engine = engines["django"] if engine is None else engine
51
+
52
+ if len([value for value in (file, inline) if value is not None]) != 1:
53
+ msg = "Exactly one of 'file' or 'inline' must be provided."
54
+ raise TypeError(msg)
55
+
56
+ if file:
57
+ template = engine.get_template(file)
58
+ elif inline:
59
+ template = engine.from_string(inline)
60
+ else: # pragma: no cover
61
+ msg = "Unreachable code"
62
+ raise NotImplementedError(msg)
63
+
64
+ self.template = template
65
+
66
+ def render(self, *, context: dict[str, Any] | None = None) -> dict: # noqa: D102
67
+ context = {} if context is None else context
68
+
69
+ logger.debug("Rendering template with context: %r", context)
70
+ rendered = self.template.render(context=context)
71
+ return _xml_to_dict(rendered)
72
+
73
+
74
+ def _xml_to_dict(xml: str) -> dict:
75
+ """Parse XML string to Python dictionary.
76
+
77
+ Following transformations are applied by default:
78
+
79
+ - Normalize text nodes: remove single newlines and dedent text, etc.
80
+ - Rename tags for syntactic comfort: block -> blocks, element -> elements
81
+
82
+ Please check the tests for more detailed examples.
83
+
84
+ Args:
85
+ xml: XML string.
86
+
87
+ Returns:
88
+ Parsed dictionary. Be aware, the returned value will be the child of
89
+ top-level node (e.g. <root>...</root>), regardless of its key name.
90
+ """
91
+ xml = _preprocess_xml(xml)
92
+ obj = xmltodict.parse(
93
+ xml,
94
+ attr_prefix="",
95
+ cdata_key="text",
96
+ force_list=("blocks", "elements"),
97
+ postprocessor=_xml_postprocessor,
98
+ )
99
+ return dict(next(iter(obj.values())))
100
+
101
+
102
+ def _preprocess_xml(xml: str) -> str:
103
+ """Normalize XML text nodes."""
104
+ root = ET.fromstring(xml) # noqa: S314; TODO(lasuillard): Naive belief that XML is safe
105
+ for node in root.iter():
106
+ node.tag = _rename_tag(node.tag)
107
+
108
+ if node.tag == "text" and node.text:
109
+ text = dedent(node.text)
110
+ text = _remove_single_newline(text)
111
+ logger.debug("Normalized text node: %r -> %r", node.text, text)
112
+ node.text = text
113
+
114
+ return ET.tostring(root, encoding="unicode")
115
+
116
+
117
+ def _rename_tag(tag: str) -> str:
118
+ """Rename tags."""
119
+ if tag == "block":
120
+ return "blocks"
121
+
122
+ if tag == "element":
123
+ return "elements"
124
+
125
+ return tag
126
+
127
+
128
+ def _remove_single_newline(text: str) -> str:
129
+ """Remove a single newline from repeated newlines. If the are just one newline, replace it with space."""
130
+ return re.sub(r"([\n]+)", lambda m: "\n" * (m.group(1).count("\n") - 1) or " ", text)
131
+
132
+
133
+ def _xml_postprocessor(path: Any, key: str, value: Any) -> tuple[str, Any]: # noqa: ARG001
134
+ if value == "true":
135
+ return key, True
136
+
137
+ if value == "false":
138
+ return key, False
139
+
140
+ return key, value
@@ -14,7 +14,7 @@ if TYPE_CHECKING:
14
14
  from slack_bolt import App
15
15
 
16
16
 
17
- class SlackEventHandlerView(View):
17
+ class SlackEventHandlerView(View): # pragma: no cover; TODO(lasuillard): deal with this in future
18
18
  """View for handling Slack events."""
19
19
 
20
20
  app: App | None = None
@@ -1,21 +1,34 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: django-slack-tools
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Little helpers working with Slack bot 🤖 in Django.
5
- License: MIT
6
- Author: Yuchan Lee
7
- Author-email: lasuillard@gmail.com
8
- Requires-Python: >=3.8,<4.0
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.8
12
- Classifier: Programming Language :: Python :: 3.9
13
- Classifier: Programming Language :: Python :: 3.10
14
- Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Programming Language :: Python :: 3.12
16
- Requires-Dist: django (>=3.2,<5)
17
- Requires-Dist: pydantic (>=2,<3)
18
- Requires-Dist: slack-bolt (>=1,<2)
5
+ Author-email: Yuchan Lee <lasuillard@gmail.com>
6
+ Requires-Python: <4.0,>=3.8
7
+ Requires-Dist: django<5.2,>=4.2
8
+ Requires-Dist: slack-bolt<2,>=1
9
+ Requires-Dist: xmltodict<1,>=0.14.1
10
+ Provides-Extra: celery
11
+ Requires-Dist: celery<6,>=5; extra == 'celery'
12
+ Provides-Extra: dev
13
+ Requires-Dist: django-debug-toolbar~=4.4; extra == 'dev'
14
+ Requires-Dist: django-extensions~=3.2; extra == 'dev'
15
+ Requires-Dist: django-stubs[compatible-mypy]~=5.1; extra == 'dev'
16
+ Requires-Dist: ipykernel~=6.27; extra == 'dev'
17
+ Requires-Dist: mkdocs-material~=9.5; extra == 'dev'
18
+ Requires-Dist: mkdocstrings[python]~=0.26; extra == 'dev'
19
+ Requires-Dist: mkdocs~=1.6; extra == 'dev'
20
+ Requires-Dist: mypy~=1.11; extra == 'dev'
21
+ Requires-Dist: ruff~=0.6; extra == 'dev'
22
+ Provides-Extra: test
23
+ Requires-Dist: coverage~=7.3; extra == 'test'
24
+ Requires-Dist: django-coverage-plugin~=3.1; extra == 'test'
25
+ Requires-Dist: factory-boy~=3.3; extra == 'test'
26
+ Requires-Dist: faker~=30.3; extra == 'test'
27
+ Requires-Dist: pytest-cov~=5.0; extra == 'test'
28
+ Requires-Dist: pytest-django~=4.9; extra == 'test'
29
+ Requires-Dist: pytest-sugar~=1.0; extra == 'test'
30
+ Requires-Dist: pytest-xdist~=3.6; extra == 'test'
31
+ Requires-Dist: pytest~=8.0; extra == 'test'
19
32
  Description-Content-Type: text/markdown
20
33
 
21
34
  # django-slack-tools
@@ -23,6 +36,7 @@ Description-Content-Type: text/markdown
23
36
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
24
37
  [![CI](https://github.com/lasuillard/django-slack-tools/actions/workflows/ci.yaml/badge.svg)](https://github.com/lasuillard/django-slack-tools/actions/workflows/ci.yaml)
25
38
  [![codecov](https://codecov.io/gh/lasuillard/django-slack-tools/graph/badge.svg?token=c8kzjqjplF)](https://codecov.io/gh/lasuillard/django-slack-tools)
39
+ ![PyPI - Version](https://img.shields.io/pypi/v/django-slack-tools)
26
40
 
27
41
  Little helpers working with Slack bot 🤖 in Django.
28
42
 
@@ -40,19 +54,24 @@ Key features are:
40
54
 
41
55
  - [x] Built-in admin for management working with Slack workspace
42
56
 
43
- And more in future roadmap...
57
+ - [x] Celery support for messaging backends, management and shortcut tasks, etc.
44
58
 
45
- - [ ] Celery support for messaging backends, management and shortcut tasks, etc.
59
+ - [x] Django template support
46
60
 
47
- - [ ] Django template support
61
+ And more in future roadmap...
48
62
 
49
63
  - [ ] New Django apps and helpers for Slack features such as modals, event subscription, etc.
50
64
 
65
+ - [ ] More fine working example with rich documentation
66
+
51
67
  Currently it is focused on messaging features. In future, hoping to bring more helpful features across Slack Bot ecosystem, such as event subscriptions, modals, bot interactions, etc.
52
68
 
53
69
  ## 🚀 Installation
54
70
 
55
- **django-slack-tools** supports Python 3.8+ and Django 3.2+. Supports for each deps will be dropped as soon as the ends of security updates.
71
+ **django-slack-tools** supports Python 3.8+ and Django 4.2+. Supports for each deps will be dropped as soon as the ends of security updates.
72
+
73
+ > [!WARNING]
74
+ > 0.x versions are for development. Breaking changes can be made at any time. If gonna use this package, recommend to pin down the version.
56
75
 
57
76
  Install the package:
58
77
 
@@ -110,4 +129,3 @@ All contributions and helps are welcome. Please check the [CONTRIBUTING.md](./CO
110
129
  ## 📜 License
111
130
 
112
131
  This project is licensed under the terms of the MIT license.
113
-
@@ -0,0 +1,43 @@
1
+ django_slack_tools/__init__.py,sha256=Zn1KFblwuFHiDRdRAiRnDBRkbPttWh44jKa5zG2ov0E,22
2
+ django_slack_tools/app_settings.py,sha256=l95cavui0BzvDLrz_DPB_rnci4iSV2THkdTWh3Pcx4U,3771
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.0.dist-info/METADATA,sha256=vD4jf9QTxIIEUXY-ep0OejeZcGDsGL4mowB0tQKO46A,4493
41
+ django_slack_tools-0.2.0.dist-info/WHEEL,sha256=3U_NnUcV_1B1kPkYaPzN-irRckL5VW_lytn0ytO_kRY,87
42
+ django_slack_tools-0.2.0.dist-info/licenses/LICENSE,sha256=lPgIV-vu4gapOeftp1Dp5RsN6zlsiMiubqCNeP466hw,1067
43
+ django_slack_tools-0.2.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.8.1
2
+ Generator: hatchling 1.26.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,55 +0,0 @@
1
- """Utils for dictionary-based templates."""
2
-
3
- from __future__ import annotations
4
-
5
- from typing import Any, TypeVar
6
-
7
- from django.core.exceptions import ValidationError
8
- from django.utils.translation import gettext_lazy as _
9
-
10
-
11
- def render(template: dict, **kwargs: Any) -> dict:
12
- """Render given dictionary template.
13
-
14
- Args:
15
- template: Dictionary template.
16
- kwargs: Keyword arguments passed to template.
17
-
18
- Returns:
19
- Rendered dictionary.
20
- """
21
- # Forget the original to format it in-place
22
- result = template.copy()
23
- for k, v in result.items():
24
- result[k] = _format_obj(v, **kwargs)
25
-
26
- return result
27
-
28
-
29
- def dict_template_validator(value: Any) -> None:
30
- """Validate given value is valid dictionary template."""
31
- if value is None: # No-op template, should work equally to empty dict `{}`
32
- return
33
-
34
- if not isinstance(value, dict):
35
- raise ValidationError(
36
- _("Given object is not a dictionary: %(value)r"),
37
- params={"value": value},
38
- )
39
-
40
-
41
- T = TypeVar("T", dict, list, str)
42
-
43
-
44
- def _format_obj(obj: T, **kwargs: Any) -> T:
45
- """Format object recursively."""
46
- if isinstance(obj, dict):
47
- return {k: _format_obj(v, **kwargs) for k, v in obj.items()}
48
-
49
- if isinstance(obj, str):
50
- return obj.format_map(kwargs)
51
-
52
- if isinstance(obj, list):
53
- return [_format_obj(item, **kwargs) for item in obj]
54
-
55
- return obj
@@ -1,36 +0,0 @@
1
- django_slack_tools/__init__.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
2
- django_slack_tools/app_settings.py,sha256=xpYTTXFXkxWuVRMdsEYAIURFEAzXcwh1T_57_kXN6Po,2770
3
- django_slack_tools/locale/ko_KR/LC_MESSAGES/django.po,sha256=ySlOJgCeqFzesrWLm1BugmdLb878GSGQJZp7a1uXopw,14864
4
- django_slack_tools/slack_messages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- django_slack_tools/slack_messages/admin/__init__.py,sha256=FEBZlgze8Nf5wn8ixm9FcsL3na2WYykmm2U-iJXh_mQ,305
6
- django_slack_tools/slack_messages/admin/mention.py,sha256=Z3Cx-6WKECsbXnyby1qCEMllvxJEIn_TdwexsjEaiIo,4399
7
- django_slack_tools/slack_messages/admin/message.py,sha256=htZcVsMbKgoaU0fHngtdFpko2-Zey4OSYiv5NIL0jkw,4105
8
- django_slack_tools/slack_messages/admin/message_recipient.py,sha256=CVhvUGT4_jD3kJ2CEW8f-DnG3hcsbFbtlccfL_TcS10,4035
9
- django_slack_tools/slack_messages/admin/messaging_policy.py,sha256=NRzKGgGMCMfABXZrN9okDXb9NvsyxWFLt8hBRfFzwug,4576
10
- django_slack_tools/slack_messages/apps.py,sha256=scqTS4E6J3q9GnGXYepS1m9j8gOXooFwgsvWk8EHdKM,336
11
- django_slack_tools/slack_messages/backends/__init__.py,sha256=KOMKqgsUkAqBG4jc2nvW4Y-6Msqhs38fdgW7HtB4YZc,276
12
- django_slack_tools/slack_messages/backends/base.py,sha256=GZuw3TS5rci-iP_jt-Sl6h0Tb0dedSJvVb7fxtJqZtc,3079
13
- django_slack_tools/slack_messages/backends/dummy.py,sha256=lpaWP56q7cOjfALQpGH-EjlI6IfOX0wXPIL6HXRb-H4,1196
14
- django_slack_tools/slack_messages/backends/logging.py,sha256=2P-pEJFI5r6-45rXt43tzQHzokT9wRlEmhSXZIWvvgU,903
15
- django_slack_tools/slack_messages/backends/slack.py,sha256=Af2so4fg2i9TGenH7CiVgBmmVyKNjJ9vmQ1IPnNKkLU,7414
16
- django_slack_tools/slack_messages/message.py,sha256=eNxxLFYL-0NnOC98Kevciny_JuP07Tyr9dxM5PuSM7o,4428
17
- django_slack_tools/slack_messages/migrations/0001_initial.py,sha256=hAh5QUeMnK5LkbtwXEWFbe1MrBIuI-t8oisHseozQkE,11741
18
- django_slack_tools/slack_messages/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
- django_slack_tools/slack_messages/models/__init__.py,sha256=5niO9vU-YMGRCt7wQMXbN-hSrLpJLtukMKjjv-aFeaQ,265
20
- django_slack_tools/slack_messages/models/mention.py,sha256=C_nowbRv7JU-tD-5boJKu-e3bqG_kTGrrB1WE0ZX1Us,2077
21
- django_slack_tools/slack_messages/models/message.py,sha256=Ih9lHqJ6M6kKuwRw5_mnoY2kT_RVglUJfOxxpd0vZE4,3644
22
- django_slack_tools/slack_messages/models/message_recipient.py,sha256=FxaSIOAhZPSa_Tib58P4WXAs0zn8GsK4UgxOjktyduE,1666
23
- django_slack_tools/slack_messages/models/messaging_policy.py,sha256=nK1gT25VnJeHCEXbu2RQIlrDVdnh6Yy568WR1nC3qYE,2356
24
- django_slack_tools/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
- django_slack_tools/utils/dict_template.py,sha256=smiSi0bUPT2dNKFzMjhAOFyxlKV9A8koHDas9u03Fp8,1421
26
- django_slack_tools/utils/model_mixins.py,sha256=bNPx3yudzUku8TnjstestOs6YEww58FmBUypL5caYdI,634
27
- django_slack_tools/utils/slack/__init__.py,sha256=_3oJZqfw3VpuXjDT3vEUnjGT3qK1rYhTwCh268f6Jmk,279
28
- django_slack_tools/utils/slack/django.py,sha256=tqVXM6mTZXWQk3AN73-7s-3ZZbsFASVwr9fxc7lOK8g,1289
29
- django_slack_tools/utils/slack/message.py,sha256=72ENRVJv8j2Yi88eYuyPCfi7TEPp01D-tCWbCUMr8PA,1541
30
- django_slack_tools/utils/slack/misc.py,sha256=bl7xp43IsTt0FUZWfGH9kk4qYMU0UjIhuGs35zkLyyE,1099
31
- django_slack_tools/utils/widgets.py,sha256=v1EorzDSDXn_ZZgBHVFYMhWPG5RsfEI3L3VFf282svg,876
32
- django_slack_tools/views.py,sha256=F1mWkKbyp9zn27DzoYe2rccD8O_M0ANSzBKhbaEOYC4,1104
33
- django_slack_tools-0.1.0.dist-info/LICENSE,sha256=lPgIV-vu4gapOeftp1Dp5RsN6zlsiMiubqCNeP466hw,1067
34
- django_slack_tools-0.1.0.dist-info/METADATA,sha256=DyhN8t2VPhUCkpdUpqw9fi71CA1eyFQ7jOhi1fmvO8Y,3574
35
- django_slack_tools-0.1.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
36
- django_slack_tools-0.1.0.dist-info/RECORD,,