forked from praekeltfoundation/vumi-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.py
194 lines (143 loc) · 6.4 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# -*- test-case-name: go.vumitools.tests.test_utils -*-
from twisted.internet.defer import succeed
from vumi.middleware.tagger import TaggingMiddleware
class MessageMetadataDictHelper(object):
"""Manage various bits of metadata for a Vumi Go message.
This version of the helper operates only on the `helper_metadata` dict and
thus has no access to a `VumiApi` object.
"""
def __init__(self, helper_metadata):
self._go_metadata = helper_metadata.setdefault('go', {})
def is_sensitive(self):
"""
Returns True if the contents of the message have been marked as
being sensitive. This could mean the SMS contains information such as
unique codes, airtime pins or other values that should not be displayed
in a UI
"""
return bool(self._go_metadata.get('sensitive'))
def set_sensitive(self, value):
self._go_metadata['sensitive'] = value
def has_user_account(self):
return 'user_account' in self._go_metadata
def get_account_key(self):
# TODO: Better exception.
return self._go_metadata['user_account']
def is_paid(self):
"""Return ``True`` if the message has been processed by the
``BillingWorker``, ``False`` otherwise
"""
return self._go_metadata.get('is_paid', False)
def get_conversation_info(self):
conversation_info = {}
for field in ['user_account', 'conversation_type', 'conversation_key']:
if field in self._go_metadata:
conversation_info[field] = self._go_metadata[field]
if len(conversation_info) != 3:
return None
return conversation_info
def get_conversation_key(self):
# TODO: Better exception.
return self._go_metadata['conversation_key']
def set_conversation_info(self, conversation_type, conversation_key):
self._go_metadata.update({
'conversation_type': conversation_type,
'conversation_key': conversation_key,
})
def set_user_account(self, user_account):
self._go_metadata.update({
'user_account': user_account,
})
def set_paid(self):
self._go_metadata.update({'is_paid': True})
def reset_paid(self):
self._go_metadata.pop('is_paid', None)
def get_router_key(self):
# TODO: Better exception.
return self._go_metadata['router_key']
def get_router_info(self):
router_info = {}
for field in ['user_account', 'router_type', 'router_key']:
if field in self._go_metadata:
router_info[field] = self._go_metadata[field]
if len(router_info) != 3:
return None
return router_info
def set_router_info(self, router_type, router_key):
self._go_metadata.update({
'router_type': router_type,
'router_key': router_key,
})
def add_conversation_metadata(self, conversation):
self.set_user_account(conversation.user_account.key)
self.set_conversation_info(
conversation.conversation_type, conversation.key)
def add_router_metadata(self, router):
self.set_user_account(router.user_account.key)
self.set_router_info(router.router_type, router.key)
class MessageMetadataHelper(MessageMetadataDictHelper):
"""Manage various bits of metadata for a Vumi Go message.
Any Go inbound message that has reached the main dispatcher, will already
have at least `user_account_key` in helper metadata. `conversation_type`
and `conversation_key` are set once the message gets routed to the
conversation.
TODO: Something about non-conversation routers.
We store metadata in two places:
1. Keys into the various stores go into the message helper_metadata.
This is helpful for preventing unnecessary duplicate lookups between
workers.
2. Objects retreived from those stores get stashed on the message object.
This is helpful for preventing duplicate lookups within a worker.
(Between different middlewares, for example.)
"""
def __init__(self, vumi_api, message):
self.vumi_api = vumi_api
self.message = message
super(MessageMetadataHelper, self).__init__(
message.get('helper_metadata', {}))
# A place to store objects we don't want serialised.
if not hasattr(message, '_store_objects'):
message._store_objects = {}
self._store_objects = message._store_objects
# If we don't have a tag, we want to blow up early in some places.
self.tag = TaggingMiddleware.map_msg_to_tag(message)
def clear_object_cache(self):
"""Clear any cached objects we might have.
This forces the next get call to fetch the object from the datastore
again.
"""
self._store_objects.clear()
def _stash_and_return_object(self, obj, key):
self._store_objects[key] = obj
return obj
def _get_if_not_stashed(self, key, func, *args, **kw):
if key in self._store_objects:
return succeed(self._store_objects[key])
return func(*args, **kw).addCallback(
self._stash_and_return_object, key)
def get_user_api(self):
return self.vumi_api.get_user_api(self.get_account_key())
def get_conversation(self):
return self._get_if_not_stashed(
'conversation', self.get_user_api().get_wrapped_conversation,
self.get_conversation_key())
def is_optout_message(self):
# To avoid circular imports.
from go.vumitools.middleware import OptOutMiddleware
return OptOutMiddleware.is_optout_message(self.message)
def get_router(self):
return self._get_if_not_stashed(
'router', self.get_user_api().get_router, self.get_router_key())
def set_tag(self, tag):
TaggingMiddleware.add_tag_to_msg(self.message, tag)
self.tag = TaggingMiddleware.map_msg_to_tag(self.message)
def get_tag_info(self):
if self.tag is None:
raise ValueError("No tag to look up metadata for.")
return self._get_if_not_stashed(
'tag_info', self.vumi_api.mdb.get_tag_info, tuple(self.tag))
def get_tagpool_metadata(self):
if self.tag is None:
raise ValueError("No tag to look up metadata for.")
return self._get_if_not_stashed(
'tagpool_metadata', self.vumi_api.tpm.get_metadata, self.tag[0])