1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 from trac.util.datefmt import datetime_now, utc, to_utimestamp
16
17 __all__ = ['Subscription', 'Watch']
21
22 __slots__ = ('env', 'values')
23
24 fields = ('id', 'sid', 'authenticated', 'distributor', 'format',
25 'priority', 'adverb', 'class')
26
30
35
40
45
46 - def _from_database(self, id, sid, authenticated, distributor, format,
47 priority, adverb, class_):
48 self['id'] = id
49 self['sid'] = sid
50 self['authenticated'] = int(authenticated)
51 self['distributor'] = distributor
52 self['format'] = format or None
53 self['priority'] = int(priority)
54 self['adverb'] = adverb
55 self['class'] = class_
56
57 @classmethod
58 - def add(cls, env, subscription):
59 """id and priority overwritten."""
60 with env.db_transaction as db:
61 priority = len(cls.find_by_sid_and_distributor(
62 env, subscription['sid'], subscription['authenticated'],
63 subscription['distributor'])) + 1
64 now = to_utimestamp(datetime_now(utc))
65 cursor = db.cursor()
66 cursor.execute("""
67 INSERT INTO
68 notify_subscription (time, changetime, sid, authenticated,
69 distributor, format, priority, adverb,
70 class)
71 VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)""",
72 (now, now, subscription['sid'], int(subscription['authenticated']),
73 subscription['distributor'], subscription['format'] or None,
74 int(priority), subscription['adverb'],
75 subscription['class']))
76 return db.get_last_id(cursor, 'notify_subscription')
77
78 @classmethod
79 - def delete(cls, env, rule_id, sid=None, authenticated=None):
80 with env.db_transaction as db:
81 kwargs = {'id': rule_id}
82 if sid is not None or authenticated is not None:
83 kwargs['sid'] = sid
84 kwargs['authenticated'] = 1 if authenticated else 0
85 for sub in cls._find(env, **kwargs):
86 break
87 else:
88 return
89 db("DELETE FROM notify_subscription WHERE id=%s", (sub['id'],))
90 subs = cls.find_by_sid_and_distributor(
91 env, sub['sid'], sub['authenticated'], sub['distributor'])
92 now = to_utimestamp(datetime_now(utc))
93 values = [(new_priority, now, sub['id'])
94 for new_priority, sub in enumerate(subs, 1)
95 if new_priority != sub['priority']]
96 db.executemany("""
97 UPDATE notify_subscription
98 SET priority=%s, changetime=%s WHERE id=%s
99 """, values)
100
101 @classmethod
102 - def move(cls, env, rule_id, priority, sid=None, authenticated=None):
103 with env.db_transaction as db:
104 kwargs = {'id': rule_id}
105 if sid is not None or authenticated is not None:
106 kwargs['sid'] = sid
107 kwargs['authenticated'] = 1 if authenticated else 0
108 for sub in cls._find(env, **kwargs):
109 break
110 else:
111 return
112 subs = cls.find_by_sid_and_distributor(
113 env, sub['sid'], sub['authenticated'], sub['distributor'])
114 if not (1 <= priority <= len(subs)):
115 return
116 for idx, sub in enumerate(subs):
117 if sub['id'] == rule_id:
118 break
119 else:
120 return
121 subs.insert(priority - 1, subs.pop(idx))
122 now = to_utimestamp(datetime_now(utc))
123 values = [(new_priority, now, sub['id'])
124 for new_priority, sub in enumerate(subs, 1)
125 if new_priority != sub['priority']]
126 db.executemany("""
127 UPDATE notify_subscription
128 SET priority=%s, changetime=%s WHERE id=%s
129 """, values)
130
131 @classmethod
132 - def replace_all(cls, env, sid, authenticated, subscriptions):
133 authenticated = int(authenticated)
134 with env.db_transaction as db:
135 ids_map = {}
136 for id_, distributor, class_ in db("""\
137 SELECT id, distributor, class FROM notify_subscription
138 WHERE sid=%s AND authenticated=%s""",
139 (sid, authenticated)):
140 ids_map.setdefault((distributor, class_), []).append(id_)
141 for ids in ids_map.itervalues():
142 ids.sort(reverse=True)
143
144 priorities = {}
145 now = to_utimestamp(datetime_now(utc))
146 for sub in subscriptions:
147 distributor = sub['distributor']
148 priorities.setdefault(distributor, 0)
149 priorities[distributor] += 1
150 prio = priorities[distributor]
151 key = (distributor, sub['class'])
152 if ids_map.get(key):
153 id_ = ids_map[key].pop()
154 db("""\
155 UPDATE notify_subscription
156 SET changetime=%s,distributor=%s,format=%s,priority=%s,
157 adverb=%s,class=%s
158 WHERE id=%s""",
159 (now, sub['distributor'], sub['format'] or None, prio,
160 sub['adverb'], sub['class'], id_))
161 else:
162 db("""\
163 INSERT INTO notify_subscription (
164 time,changetime,sid,authenticated,distributor,
165 format,priority,adverb,class)
166 VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)""",
167 (now, now, sid, authenticated, sub['distributor'],
168 sub['format'] or None, prio, sub['adverb'],
169 sub['class']))
170
171 delete_ids = []
172 for ids in ids_map.itervalues():
173 delete_ids.extend(ids)
174 if delete_ids:
175 db("DELETE FROM notify_subscription WHERE id IN (%s)" %
176 ','.join(('%s',) * len(delete_ids)), delete_ids)
177
178
179 @classmethod
190
191 @classmethod
192 - def _find(cls, env, order=None, **kwargs):
193 with env.db_query as db:
194 conditions = []
195 args = []
196 for name, value in sorted(kwargs.iteritems()):
197 if name.endswith('_'):
198 name = name[:-1]
199 if name == 'authenticated':
200 value = int(value)
201 conditions.append(db.quote(name) + '=%s')
202 args.append(value)
203 query = 'SELECT id, sid, authenticated, distributor, format, ' \
204 'priority, adverb, class FROM notify_subscription'
205 if conditions:
206 query += ' WHERE ' + ' AND '.join(conditions)
207 if order:
208 if not isinstance(order, (tuple, list)):
209 order = (order,)
210 query += ' ORDER BY ' + \
211 ', '.join(db.quote(name) for name in order)
212 cursor = db.cursor()
213 cursor.execute(query, args)
214 for row in cursor:
215 sub = Subscription(env)
216 sub._from_database(*row)
217 yield sub
218
219 @classmethod
221 return list(cls._find(env, sid=sid, authenticated=authenticated,
222 distributor=distributor, order='priority'))
223
224 @classmethod
226 """uids should be a collection to tuples (sid, auth)"""
227 subs = []
228 for sid, authenticated in uids:
229 subs.extend(cls._find(env, class_=class_, sid=sid,
230 authenticated=authenticated,
231 order='priority'))
232 return subs
233
234 @classmethod
236 return list(cls._find(env, class_=class_))
237
239 return (
240 self.values['class'],
241 self.values['distributor'],
242 self.values['sid'],
243 self.values['authenticated'],
244 None,
245 self.values['format'] or None,
246 int(self.values['priority']),
247 self.values['adverb']
248 )
249
259
262
263 __slots__ = ('env', 'values')
264
265 fields = ('id', 'sid', 'authenticated', 'class', 'realm', 'target')
266
270
275
280
281 - def _from_database(self, id, sid, authenticated, class_, realm, target):
282 self['id'] = id
283 self['sid'] = sid
284 self['authenticated'] = int(authenticated)
285 self['class'] = class_
286 self['realm'] = realm
287 self['target'] = target
288
289 @classmethod
290 - def add(cls, env, sid, authenticated, class_, realm, targets):
291 with env.db_transaction as db:
292 for target in targets:
293 db("""
294 INSERT INTO notify_watch (sid, authenticated, class,
295 realm, target)
296 VALUES (%s, %s, %s, %s, %s)
297 """, (sid, int(authenticated), class_, realm, target))
298
299 @classmethod
300 - def delete(cls, env, watch_id):
303
304 @classmethod
306 with env.db_transaction as db:
307 db("""
308 DELETE FROM notify_watch
309 WHERE sid = %s AND authenticated = %s AND class = %s
310 """, (sid, int(authenticated), class_))
311
312 @classmethod
314 with env.db_transaction as db:
315 db("""
316 DELETE FROM notify_watch
317 WHERE class = %s AND realm = %s AND target = %s
318 """, (realm, class_, target))
319
320 @classmethod
321 - def _find(cls, env, order=None, **kwargs):
322 with env.db_query as db:
323 conditions = []
324 args = []
325 for name, value in sorted(kwargs.iteritems()):
326 if name.endswith('_'):
327 name = name[:-1]
328 if name == 'authenticated':
329 value = int(value)
330 conditions.append(db.quote(name) + '=%s')
331 if name == 'authenticated':
332 value = int(value)
333 args.append(value)
334 query = 'SELECT id, sid, authenticated, class, realm, target ' \
335 'FROM notify_watch'
336 if conditions:
337 query += ' WHERE ' + ' AND '.join(conditions)
338 if order:
339 if not isinstance(order, (tuple, list)):
340 order = (order,)
341 query += ' ORDER BY ' + \
342 ', '.join(db.quote(name) for name in order)
343 cursor = db.cursor()
344 cursor.execute(query, args)
345 for row in cursor:
346 watch = Watch(env)
347 watch._from_database(*row)
348 yield watch
349
350 @classmethod
352 return list(cls._find(env, sid=sid, authenticated=authenticated,
353 class_=class_, order='target'))
354
355 @classmethod
358 return list(cls._find(env, sid=sid, authenticated=authenticated,
359 class_=class_, realm=realm, order='target'))
360
361 @classmethod
364
365 @classmethod
368