File: common.py

package info (click to toggle)
imip-agent 0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 2,056 kB
  • sloc: python: 9,888; sh: 4,480; sql: 144; makefile: 8
file content (678 lines) | stat: -rw-r--r-- 18,507 bytes parent folder | download
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
#!/usr/bin/env python

"""
General support for calendar data storage.

Copyright (C) 2014, 2015, 2016 Paul Boddie <paul@boddie.org.uk>

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
details.

You should have received a copy of the GNU General Public License along with
this program.  If not, see <http://www.gnu.org/licenses/>.
"""

from imiptools.dates import format_datetime, get_datetime

class StoreBase:

    "The core operations of a data store."

    # User discovery.

    def get_users(self):

        "Return a list of users."

        pass

    # Event and event metadata access.

    def get_all_events(self, user, dirname=None):

        """
        Return a set of (uid, recurrenceid) tuples for all events. Unless
        'dirname' is specified, only active events are returned; otherwise,
        events from the given 'dirname' are returned.
        """

        cancelled = self.get_cancelled_events(user)
        active = self.get_events(user)

        if dirname == "cancellations":
            uids = cancelled
        else:
            uids = active

        if not uids:
            return set()

        all_events = set()

        # Add all qualifying parent events to the result set.

        for uid in uids:
            all_events.add((uid, None))

        # Process all parent events regardless of status to find those in the
        # category/directory of interest.

        for uid in active + cancelled:

            if dirname == "cancellations":
                recurrenceids = self.get_cancelled_recurrences(user, uid)
            else:
                recurrenceids = self.get_active_recurrences(user, uid)

            all_events.update([(uid, recurrenceid) for recurrenceid in recurrenceids])

        return all_events

    def get_events(self, user):

        "Return a list of event identifiers."

        pass

    def get_cancelled_events(self, user):

        "Return a list of event identifiers for cancelled events."

        pass

    def get_event(self, user, uid, recurrenceid=None, dirname=None):

        """
        Get the event for the given 'user' with the given 'uid'. If
        the optional 'recurrenceid' is specified, a specific instance or
        occurrence of an event is returned.
        """

        pass

    def get_complete_event(self, user, uid):

        "Get the event for the given 'user' with the given 'uid'."

        pass

    def set_event(self, user, uid, recurrenceid, node):

        """
        Set an event for 'user' having the given 'uid' and 'recurrenceid' (which
        if the latter is specified, a specific instance or occurrence of an
        event is referenced), using the given 'node' description.
        """

        if recurrenceid:
            return self.set_recurrence(user, uid, recurrenceid, node)
        else:
            return self.set_complete_event(user, uid, node)

    def set_complete_event(self, user, uid, node):

        "Set an event for 'user' having the given 'uid' and 'node'."

        pass

    def remove_event(self, user, uid, recurrenceid=None):

        """
        Remove an event for 'user' having the given 'uid'. If the optional
        'recurrenceid' is specified, a specific instance or occurrence of an
        event is removed.
        """

        if recurrenceid:
            return self.remove_recurrence(user, uid, recurrenceid)
        else:
            for recurrenceid in self.get_recurrences(user, uid) or []:
                self.remove_recurrence(user, uid, recurrenceid)
            return self.remove_complete_event(user, uid)

    def remove_complete_event(self, user, uid):

        "Remove an event for 'user' having the given 'uid'."

        self.remove_recurrences(user, uid)
        return self.remove_parent_event(user, uid)

    def remove_parent_event(self, user, uid):

        "Remove the parent event for 'user' having the given 'uid'."

        pass

    def get_recurrences(self, user, uid):

        """
        Get additional event instances for an event of the given 'user' with the
        indicated 'uid'. Both active and cancelled recurrences are returned.
        """

        return self.get_active_recurrences(user, uid) + self.get_cancelled_recurrences(user, uid)

    def get_active_recurrences(self, user, uid):

        """
        Get additional event instances for an event of the given 'user' with the
        indicated 'uid'. Cancelled recurrences are not returned.
        """

        pass

    def get_cancelled_recurrences(self, user, uid):

        """
        Get additional event instances for an event of the given 'user' with the
        indicated 'uid'. Only cancelled recurrences are returned.
        """

        pass

    def get_recurrence(self, user, uid, recurrenceid):

        """
        For the event of the given 'user' with the given 'uid', return the
        specific recurrence indicated by the 'recurrenceid'.
        """

        pass

    def set_recurrence(self, user, uid, recurrenceid, node):

        "Set an event for 'user' having the given 'uid' and 'node'."

        pass

    def remove_recurrence(self, user, uid, recurrenceid):

        """
        Remove a special recurrence from an event stored by 'user' having the
        given 'uid' and 'recurrenceid'.
        """

        pass

    def remove_recurrences(self, user, uid):

        """
        Remove all recurrences for an event stored by 'user' having the given
        'uid'.
        """

        for recurrenceid in self.get_recurrences(user, uid):
            self.remove_recurrence(user, uid, recurrenceid)

        return self.remove_recurrence_collection(user, uid)

    def remove_recurrence_collection(self, user, uid):

        """
        Remove the collection of recurrences stored by 'user' having the given
        'uid'.
        """

        pass

    # Free/busy period providers, upon extension of the free/busy records.

    def _get_freebusy_providers(self, user):

        """
        Return the free/busy providers for the given 'user'.

        This function returns any stored datetime and a list of providers as a
        2-tuple. Each provider is itself a (uid, recurrenceid) tuple.
        """

        pass

    def get_freebusy_providers(self, user, dt=None):

        """
        Return a set of uncancelled events of the form (uid, recurrenceid)
        providing free/busy details beyond the given datetime 'dt'.

        If 'dt' is not specified, all events previously found to provide
        details will be returned. Otherwise, if 'dt' is earlier than the
        datetime recorded for the known providers, None is returned, indicating
        that the list of providers must be recomputed.

        This function returns a list of (uid, recurrenceid) tuples upon success.
        """

        t = self._get_freebusy_providers(user)
        if not t:
            return None

        dt_string, t = t

        # If the requested datetime is earlier than the stated datetime, the
        # providers will need to be recomputed.

        if dt:
            providers_dt = get_datetime(dt_string)
            if not providers_dt or providers_dt > dt:
                return None

        # Otherwise, return the providers.

        return t

    def _set_freebusy_providers(self, user, dt_string, t):

        "Set the given provider timestamp 'dt_string' and table 't'."

        pass

    def set_freebusy_providers(self, user, dt, providers):

        """
        Define the uncancelled events providing free/busy details beyond the
        given datetime 'dt'.
        """

        t = []

        for obj in providers:
            t.append((obj.get_uid(), obj.get_recurrenceid()))

        return self._set_freebusy_providers(user, format_datetime(dt), t)

    def append_freebusy_provider(self, user, provider):

        "For the given 'user', append the free/busy 'provider'."

        t = self._get_freebusy_providers(user)
        if not t:
            return False

        dt_string, t = t
        details = (provider.get_uid(), provider.get_recurrenceid())

        if not details in t:
            t.append(details)

        return self._set_freebusy_providers(user, dt_string, t)

    def remove_freebusy_provider(self, user, provider):

        "For the given 'user', remove the free/busy 'provider'."

        t = self._get_freebusy_providers(user)
        if not t:
            return False

        dt_string, t = t
        try:
            t.remove((provider.get_uid(), provider.get_recurrenceid()))
        except ValueError:
            return False

        return self._set_freebusy_providers(user, dt_string, t)

    # Free/busy period access.

    def get_freebusy(self, user, name=None, mutable=False):

        "Get free/busy details for the given 'user'."

        pass

    def get_freebusy_for_other(self, user, other, mutable=False):

        "For the given 'user', get free/busy details for the 'other' user."

        pass

    def get_freebusy_for_update(self, user, name=None):

        """
        Get free/busy details for the given 'user' that may be updated,
        potentially affecting the stored information directly.
        """

        return self.get_freebusy(user, name, True)

    def get_freebusy_for_other_for_update(self, user, other):

        """
        For the given 'user', get free/busy details for the 'other' user
        that may be updated, potentially affecting the stored information
        directly.
        """

        return self.get_freebusy_for_other(user, other, True)

    def set_freebusy(self, user, freebusy, name=None):

        "For the given 'user', set 'freebusy' details."

        pass

    def set_freebusy_for_other(self, user, freebusy, other):

        "For the given 'user', set 'freebusy' details for the 'other' user."

        pass

    def get_freebusy_others(self, user):

        """
        For the given 'user', return a list of other users for whom free/busy
        information is retained.
        """

        pass

    # Tentative free/busy periods related to countering.

    def get_freebusy_offers(self, user, mutable=False):

        "Get free/busy offers for the given 'user'."

        pass

    def get_freebusy_offers_for_update(self, user):

        """
        Get free/busy offers for the given 'user' that may be updated,
        potentially affecting the stored information directly.
        """

        return self.get_freebusy_offers(user, True)

    def set_freebusy_offers(self, user, freebusy):

        "For the given 'user', set 'freebusy' offers."

        return self.set_freebusy(user, freebusy, "freebusy-offers")

    # Requests and counter-proposals.

    def get_requests(self, user):

        "Get requests for the given 'user'."

        pass

    def set_requests(self, user, requests):

        "For the given 'user', set the list of queued 'requests'."

        pass

    def set_request(self, user, uid, recurrenceid=None, type=None):

        """
        For the given 'user', set the queued 'uid' and 'recurrenceid',
        indicating a request, along with any given 'type'.
        """

        pass

    def queue_request(self, user, uid, recurrenceid=None, type=None):

        """
        Queue a request for 'user' having the given 'uid'. If the optional
        'recurrenceid' is specified, the entry refers to a specific instance
        or occurrence of an event. The 'type' parameter can be used to indicate
        a specific type of request.
        """

        requests = self.get_requests(user) or []

        if not self.have_request(requests, uid, recurrenceid):
            return self.set_request(user, uid, recurrenceid, type)

        return False

    def dequeue_request(self, user, uid, recurrenceid=None):

        """
        Dequeue all requests for 'user' having the given 'uid'. If the optional
        'recurrenceid' is specified, all requests for that specific instance or
        occurrence of an event are dequeued.
        """

        requests = self.get_requests(user) or []
        result = []

        for request in requests:
            if request[:2] != (uid, recurrenceid):
                result.append(request)

        self.set_requests(user, result)
        return True

    def has_request(self, user, uid, recurrenceid=None, type=None, strict=False):
        return self.have_request(self.get_requests(user) or [], uid, recurrenceid, type, strict)

    def have_request(self, requests, uid, recurrenceid=None, type=None, strict=False):

        """
        Return whether 'requests' contains a request with the given 'uid' and
        any specified 'recurrenceid' and 'type'. If 'strict' is set to a true
        value, the precise type of the request must match; otherwise, any type
        of request for the identified object may be matched.
        """

        for request in requests:
            if request[:2] == (uid, recurrenceid) and (
                not strict or
                not request[2:] and not type or
                request[2:] and request[2] == type):

                return True

        return False

    def get_counters(self, user, uid, recurrenceid=None):

        """
        For the given 'user', return a list of users from whom counter-proposals
        have been received for the given 'uid' and optional 'recurrenceid'.
        """

        pass

    def get_counter(self, user, other, uid, recurrenceid=None):

        """
        For the given 'user', return the counter-proposal from 'other' for the
        given 'uid' and optional 'recurrenceid'.
        """

        pass

    def set_counter(self, user, other, node, uid, recurrenceid=None):

        """
        For the given 'user', store a counter-proposal received from 'other' the
        given 'node' representing that proposal for the given 'uid' and
        'recurrenceid'.
        """

        pass

    def remove_counters(self, user, uid, recurrenceid=None):

        """
        For the given 'user', remove all counter-proposals associated with the
        given 'uid' and 'recurrenceid'.
        """

        pass

    def remove_counter(self, user, other, uid, recurrenceid=None):

        """
        For the given 'user', remove any counter-proposal from 'other'
        associated with the given 'uid' and 'recurrenceid'.
        """

        pass

    # Event cancellation.

    def cancel_event(self, user, uid, recurrenceid=None):

        """
        Cancel an event for 'user' having the given 'uid'. If the optional
        'recurrenceid' is specified, a specific instance or occurrence of an
        event is cancelled.
        """

        pass

    def uncancel_event(self, user, uid, recurrenceid=None):

        """
        Uncancel an event for 'user' having the given 'uid'. If the optional
        'recurrenceid' is specified, a specific instance or occurrence of an
        event is uncancelled.
        """

        pass

    def remove_cancellations(self, user, uid, recurrenceid=None):

        """
        Remove cancellations for 'user' for any event having the given 'uid'. If
        the optional 'recurrenceid' is specified, a specific instance or
        occurrence of an event is affected.
        """

        # Remove all recurrence cancellations if a general event is indicated.

        if not recurrenceid:
            for _recurrenceid in self.get_cancelled_recurrences(user, uid):
                self.remove_cancellation(user, uid, _recurrenceid)

        return self.remove_cancellation(user, uid, recurrenceid)

    def remove_cancellation(self, user, uid, recurrenceid=None):

        """
        Remove a cancellation for 'user' for the event having the given 'uid'.
        If the optional 'recurrenceid' is specified, a specific instance or
        occurrence of an event is affected.
        """

        pass

class PublisherBase:

    "The core operations of a data publisher."

    def set_freebusy(self, user, freebusy):

        "For the given 'user', set 'freebusy' details."

        pass

class JournalBase:

    "The core operations of a journal system supporting quotas."

    # Quota and user identity/group discovery.

    def get_quotas(self):

        "Return a list of quotas."

        pass

    def get_quota_users(self, quota):

        "Return a list of quota users."

        pass

    # Delegate information for the quota.

    def get_delegates(self, quota):

        "Return a list of delegates for 'quota'."

        pass

    def set_delegates(self, quota, delegates):

        "For the given 'quota', set the list of 'delegates'."

        pass

    # Groups of users sharing quotas.

    def get_groups(self, quota):

        "Return the identity mappings for the given 'quota' as a dictionary."

        pass

    def set_group(self, quota, store_user, user_group):

        """
        For the given 'quota', set a mapping from 'store_user' to 'user_group'.
        """

        pass

    def get_limits(self, quota):

        """
        Return the limits for the 'quota' as a dictionary mapping identities or
        groups to durations.
        """

        pass

    def set_limit(self, quota, group, limit):

        """
        For the given 'quota', set for a user 'group' the given 'limit' on
        resource usage.
        """

        pass

    # Journal entry methods.

    def get_entries(self, quota, group, mutable=False):

        """
        Return a list of journal entries for the given 'quota' for the indicated
        'group'.
        """

        pass

    def get_entries_for_update(self, quota, group):

        """
        Return a list of journal entries for the given 'quota' for the indicated
        'group' that may be updated, potentially affecting the stored
        information directly.
        """

        return self.get_entries(quota, group, True)

    def set_entries(self, quota, group, entries):

        """
        For the given 'quota' and indicated 'group', set the list of journal
        'entries'.
        """

        pass

# vim: tabstop=4 expandtab shiftwidth=4