imip-agent

Annotated imiptools/stores/common.py

1339:b839e8ad5f77
2017-10-17 Paul Boddie Added notes about local Unix mailbox message storage.
paul@1069 1
#!/usr/bin/env python
paul@1069 2
paul@1069 3
"""
paul@1069 4
General support for calendar data storage.
paul@1069 5
paul@1305 6
Copyright (C) 2014, 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
paul@1069 7
paul@1069 8
This program is free software; you can redistribute it and/or modify it under
paul@1069 9
the terms of the GNU General Public License as published by the Free Software
paul@1069 10
Foundation; either version 3 of the License, or (at your option) any later
paul@1069 11
version.
paul@1069 12
paul@1069 13
This program is distributed in the hope that it will be useful, but WITHOUT
paul@1069 14
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
paul@1069 15
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
paul@1069 16
details.
paul@1069 17
paul@1069 18
You should have received a copy of the GNU General Public License along with
paul@1069 19
this program.  If not, see <http://www.gnu.org/licenses/>.
paul@1069 20
"""
paul@1069 21
paul@1089 22
from imiptools.dates import format_datetime, get_datetime
paul@1075 23
paul@1069 24
class StoreBase:
paul@1069 25
paul@1069 26
    "The core operations of a data store."
paul@1069 27
paul@1069 28
    # User discovery.
paul@1069 29
paul@1069 30
    def get_users(self):
paul@1069 31
paul@1069 32
        "Return a list of users."
paul@1069 33
paul@1069 34
        pass
paul@1069 35
paul@1069 36
    # Event and event metadata access.
paul@1069 37
paul@1142 38
    def get_all_events(self, user, dirname=None):
paul@1142 39
paul@1142 40
        """
paul@1142 41
        Return a set of (uid, recurrenceid) tuples for all events. Unless
paul@1142 42
        'dirname' is specified, only active events are returned; otherwise,
paul@1142 43
        events from the given 'dirname' are returned.
paul@1142 44
        """
paul@1142 45
paul@1142 46
        cancelled = self.get_cancelled_events(user)
paul@1142 47
        active = self.get_events(user)
paul@1142 48
paul@1142 49
        if dirname == "cancellations":
paul@1142 50
            uids = cancelled
paul@1142 51
        else:
paul@1142 52
            uids = active
paul@1142 53
paul@1142 54
        if not uids:
paul@1142 55
            return set()
paul@1142 56
paul@1142 57
        all_events = set()
paul@1142 58
paul@1142 59
        # Add all qualifying parent events to the result set.
paul@1142 60
paul@1142 61
        for uid in uids:
paul@1142 62
            all_events.add((uid, None))
paul@1142 63
paul@1142 64
        # Process all parent events regardless of status to find those in the
paul@1142 65
        # category/directory of interest.
paul@1142 66
paul@1142 67
        for uid in active + cancelled:
paul@1142 68
paul@1142 69
            if dirname == "cancellations":
paul@1142 70
                recurrenceids = self.get_cancelled_recurrences(user, uid)
paul@1142 71
            else:
paul@1142 72
                recurrenceids = self.get_active_recurrences(user, uid)
paul@1142 73
paul@1142 74
            all_events.update([(uid, recurrenceid) for recurrenceid in recurrenceids])
paul@1142 75
paul@1142 76
        return all_events
paul@1142 77
paul@1069 78
    def get_events(self, user):
paul@1069 79
paul@1069 80
        "Return a list of event identifiers."
paul@1069 81
paul@1069 82
        pass
paul@1069 83
paul@1142 84
    def get_cancelled_events(self, user):
paul@1069 85
paul@1142 86
        "Return a list of event identifiers for cancelled events."
paul@1069 87
paul@1142 88
        pass
paul@1069 89
paul@1069 90
    def get_event(self, user, uid, recurrenceid=None, dirname=None):
paul@1069 91
paul@1069 92
        """
paul@1069 93
        Get the event for the given 'user' with the given 'uid'. If
paul@1069 94
        the optional 'recurrenceid' is specified, a specific instance or
paul@1069 95
        occurrence of an event is returned.
paul@1069 96
        """
paul@1069 97
paul@1069 98
        pass
paul@1069 99
paul@1069 100
    def set_event(self, user, uid, recurrenceid, node):
paul@1069 101
paul@1069 102
        """
paul@1069 103
        Set an event for 'user' having the given 'uid' and 'recurrenceid' (which
paul@1069 104
        if the latter is specified, a specific instance or occurrence of an
paul@1069 105
        event is referenced), using the given 'node' description.
paul@1069 106
        """
paul@1069 107
paul@1069 108
        if recurrenceid:
paul@1069 109
            return self.set_recurrence(user, uid, recurrenceid, node)
paul@1069 110
        else:
paul@1324 111
            return self.set_parent_event(user, uid, node)
paul@1069 112
paul@1324 113
    def set_parent_event(self, user, uid, node):
paul@1069 114
paul@1069 115
        "Set an event for 'user' having the given 'uid' and 'node'."
paul@1069 116
paul@1069 117
        pass
paul@1069 118
paul@1069 119
    def remove_event(self, user, uid, recurrenceid=None):
paul@1069 120
paul@1069 121
        """
paul@1069 122
        Remove an event for 'user' having the given 'uid'. If the optional
paul@1069 123
        'recurrenceid' is specified, a specific instance or occurrence of an
paul@1069 124
        event is removed.
paul@1069 125
        """
paul@1069 126
paul@1069 127
        if recurrenceid:
paul@1069 128
            return self.remove_recurrence(user, uid, recurrenceid)
paul@1069 129
        else:
paul@1069 130
            for recurrenceid in self.get_recurrences(user, uid) or []:
paul@1069 131
                self.remove_recurrence(user, uid, recurrenceid)
paul@1069 132
            return self.remove_complete_event(user, uid)
paul@1069 133
paul@1069 134
    def remove_complete_event(self, user, uid):
paul@1069 135
paul@1069 136
        "Remove an event for 'user' having the given 'uid'."
paul@1069 137
paul@1069 138
        self.remove_recurrences(user, uid)
paul@1069 139
        return self.remove_parent_event(user, uid)
paul@1069 140
paul@1069 141
    def remove_parent_event(self, user, uid):
paul@1069 142
paul@1069 143
        "Remove the parent event for 'user' having the given 'uid'."
paul@1069 144
paul@1069 145
        pass
paul@1069 146
paul@1069 147
    def get_recurrences(self, user, uid):
paul@1069 148
paul@1069 149
        """
paul@1069 150
        Get additional event instances for an event of the given 'user' with the
paul@1069 151
        indicated 'uid'. Both active and cancelled recurrences are returned.
paul@1069 152
        """
paul@1069 153
paul@1069 154
        return self.get_active_recurrences(user, uid) + self.get_cancelled_recurrences(user, uid)
paul@1069 155
paul@1069 156
    def get_active_recurrences(self, user, uid):
paul@1069 157
paul@1069 158
        """
paul@1069 159
        Get additional event instances for an event of the given 'user' with the
paul@1069 160
        indicated 'uid'. Cancelled recurrences are not returned.
paul@1069 161
        """
paul@1069 162
paul@1069 163
        pass
paul@1069 164
paul@1069 165
    def get_cancelled_recurrences(self, user, uid):
paul@1069 166
paul@1069 167
        """
paul@1069 168
        Get additional event instances for an event of the given 'user' with the
paul@1069 169
        indicated 'uid'. Only cancelled recurrences are returned.
paul@1069 170
        """
paul@1069 171
paul@1069 172
        pass
paul@1069 173
paul@1069 174
    def get_recurrence(self, user, uid, recurrenceid):
paul@1069 175
paul@1069 176
        """
paul@1069 177
        For the event of the given 'user' with the given 'uid', return the
paul@1069 178
        specific recurrence indicated by the 'recurrenceid'.
paul@1069 179
        """
paul@1069 180
paul@1069 181
        pass
paul@1069 182
paul@1069 183
    def set_recurrence(self, user, uid, recurrenceid, node):
paul@1069 184
paul@1069 185
        "Set an event for 'user' having the given 'uid' and 'node'."
paul@1069 186
paul@1069 187
        pass
paul@1069 188
paul@1069 189
    def remove_recurrence(self, user, uid, recurrenceid):
paul@1069 190
paul@1069 191
        """
paul@1069 192
        Remove a special recurrence from an event stored by 'user' having the
paul@1069 193
        given 'uid' and 'recurrenceid'.
paul@1069 194
        """
paul@1069 195
paul@1069 196
        pass
paul@1069 197
paul@1069 198
    def remove_recurrences(self, user, uid):
paul@1069 199
paul@1069 200
        """
paul@1069 201
        Remove all recurrences for an event stored by 'user' having the given
paul@1069 202
        'uid'.
paul@1069 203
        """
paul@1069 204
paul@1069 205
        for recurrenceid in self.get_recurrences(user, uid):
paul@1069 206
            self.remove_recurrence(user, uid, recurrenceid)
paul@1069 207
paul@1069 208
        return self.remove_recurrence_collection(user, uid)
paul@1069 209
paul@1069 210
    def remove_recurrence_collection(self, user, uid):
paul@1069 211
paul@1069 212
        """
paul@1069 213
        Remove the collection of recurrences stored by 'user' having the given
paul@1069 214
        'uid'.
paul@1069 215
        """
paul@1069 216
paul@1069 217
        pass
paul@1069 218
paul@1069 219
    # Free/busy period providers, upon extension of the free/busy records.
paul@1069 220
paul@1075 221
    def _get_freebusy_providers(self, user):
paul@1075 222
paul@1075 223
        """
paul@1075 224
        Return the free/busy providers for the given 'user'.
paul@1075 225
paul@1075 226
        This function returns any stored datetime and a list of providers as a
paul@1075 227
        2-tuple. Each provider is itself a (uid, recurrenceid) tuple.
paul@1075 228
        """
paul@1075 229
paul@1075 230
        pass
paul@1075 231
paul@1069 232
    def get_freebusy_providers(self, user, dt=None):
paul@1069 233
paul@1069 234
        """
paul@1069 235
        Return a set of uncancelled events of the form (uid, recurrenceid)
paul@1069 236
        providing free/busy details beyond the given datetime 'dt'.
paul@1069 237
paul@1069 238
        If 'dt' is not specified, all events previously found to provide
paul@1069 239
        details will be returned. Otherwise, if 'dt' is earlier than the
paul@1069 240
        datetime recorded for the known providers, None is returned, indicating
paul@1069 241
        that the list of providers must be recomputed.
paul@1069 242
paul@1069 243
        This function returns a list of (uid, recurrenceid) tuples upon success.
paul@1069 244
        """
paul@1069 245
paul@1075 246
        t = self._get_freebusy_providers(user)
paul@1075 247
        if not t:
paul@1075 248
            return None
paul@1075 249
paul@1075 250
        dt_string, t = t
paul@1075 251
paul@1075 252
        # If the requested datetime is earlier than the stated datetime, the
paul@1075 253
        # providers will need to be recomputed.
paul@1075 254
paul@1075 255
        if dt:
paul@1075 256
            providers_dt = get_datetime(dt_string)
paul@1075 257
            if not providers_dt or providers_dt > dt:
paul@1075 258
                return None
paul@1075 259
paul@1075 260
        # Otherwise, return the providers.
paul@1075 261
paul@1089 262
        return t
paul@1075 263
paul@1075 264
    def _set_freebusy_providers(self, user, dt_string, t):
paul@1075 265
paul@1075 266
        "Set the given provider timestamp 'dt_string' and table 't'."
paul@1075 267
paul@1069 268
        pass
paul@1069 269
paul@1069 270
    def set_freebusy_providers(self, user, dt, providers):
paul@1069 271
paul@1069 272
        """
paul@1069 273
        Define the uncancelled events providing free/busy details beyond the
paul@1069 274
        given datetime 'dt'.
paul@1069 275
        """
paul@1069 276
paul@1075 277
        t = []
paul@1075 278
paul@1075 279
        for obj in providers:
paul@1075 280
            t.append((obj.get_uid(), obj.get_recurrenceid()))
paul@1075 281
paul@1075 282
        return self._set_freebusy_providers(user, format_datetime(dt), t)
paul@1069 283
paul@1069 284
    def append_freebusy_provider(self, user, provider):
paul@1069 285
paul@1069 286
        "For the given 'user', append the free/busy 'provider'."
paul@1069 287
paul@1075 288
        t = self._get_freebusy_providers(user)
paul@1075 289
        if not t:
paul@1075 290
            return False
paul@1075 291
paul@1075 292
        dt_string, t = t
paul@1197 293
        details = (provider.get_uid(), provider.get_recurrenceid())
paul@1197 294
paul@1197 295
        if not details in t:
paul@1197 296
            t.append(details)
paul@1075 297
paul@1075 298
        return self._set_freebusy_providers(user, dt_string, t)
paul@1069 299
paul@1069 300
    def remove_freebusy_provider(self, user, provider):
paul@1069 301
paul@1069 302
        "For the given 'user', remove the free/busy 'provider'."
paul@1069 303
paul@1075 304
        t = self._get_freebusy_providers(user)
paul@1075 305
        if not t:
paul@1075 306
            return False
paul@1075 307
paul@1075 308
        dt_string, t = t
paul@1075 309
        try:
paul@1075 310
            t.remove((provider.get_uid(), provider.get_recurrenceid()))
paul@1075 311
        except ValueError:
paul@1075 312
            return False
paul@1075 313
paul@1075 314
        return self._set_freebusy_providers(user, dt_string, t)
paul@1069 315
paul@1069 316
    # Free/busy period access.
paul@1069 317
paul@1077 318
    def get_freebusy(self, user, name=None, mutable=False):
paul@1069 319
paul@1069 320
        "Get free/busy details for the given 'user'."
paul@1069 321
paul@1069 322
        pass
paul@1069 323
paul@1077 324
    def get_freebusy_for_other(self, user, other, mutable=False):
paul@1069 325
paul@1069 326
        "For the given 'user', get free/busy details for the 'other' user."
paul@1069 327
paul@1069 328
        pass
paul@1069 329
paul@1071 330
    def get_freebusy_for_update(self, user, name=None):
paul@1071 331
paul@1142 332
        """
paul@1142 333
        Get free/busy details for the given 'user' that may be updated,
paul@1142 334
        potentially affecting the stored information directly.
paul@1142 335
        """
paul@1071 336
paul@1077 337
        return self.get_freebusy(user, name, True)
paul@1071 338
paul@1071 339
    def get_freebusy_for_other_for_update(self, user, other):
paul@1071 340
paul@1142 341
        """
paul@1142 342
        For the given 'user', get free/busy details for the 'other' user
paul@1142 343
        that may be updated, potentially affecting the stored information
paul@1142 344
        directly.
paul@1142 345
        """
paul@1071 346
paul@1077 347
        return self.get_freebusy_for_other(user, other, True)
paul@1071 348
paul@1069 349
    def set_freebusy(self, user, freebusy, name=None):
paul@1069 350
paul@1069 351
        "For the given 'user', set 'freebusy' details."
paul@1069 352
paul@1069 353
        pass
paul@1069 354
paul@1069 355
    def set_freebusy_for_other(self, user, freebusy, other):
paul@1069 356
paul@1069 357
        "For the given 'user', set 'freebusy' details for the 'other' user."
paul@1069 358
paul@1069 359
        pass
paul@1069 360
paul@1142 361
    def get_freebusy_others(self, user):
paul@1142 362
paul@1142 363
        """
paul@1142 364
        For the given 'user', return a list of other users for whom free/busy
paul@1142 365
        information is retained.
paul@1142 366
        """
paul@1142 367
paul@1142 368
        pass
paul@1142 369
paul@1069 370
    # Tentative free/busy periods related to countering.
paul@1069 371
paul@1077 372
    def get_freebusy_offers(self, user, mutable=False):
paul@1069 373
paul@1069 374
        "Get free/busy offers for the given 'user'."
paul@1069 375
paul@1069 376
        pass
paul@1069 377
paul@1071 378
    def get_freebusy_offers_for_update(self, user):
paul@1071 379
paul@1142 380
        """
paul@1142 381
        Get free/busy offers for the given 'user' that may be updated,
paul@1142 382
        potentially affecting the stored information directly.
paul@1142 383
        """
paul@1071 384
paul@1077 385
        return self.get_freebusy_offers(user, True)
paul@1071 386
paul@1069 387
    def set_freebusy_offers(self, user, freebusy):
paul@1069 388
paul@1069 389
        "For the given 'user', set 'freebusy' offers."
paul@1069 390
paul@1069 391
        return self.set_freebusy(user, freebusy, "freebusy-offers")
paul@1069 392
paul@1069 393
    # Requests and counter-proposals.
paul@1069 394
paul@1069 395
    def get_requests(self, user):
paul@1069 396
paul@1069 397
        "Get requests for the given 'user'."
paul@1069 398
paul@1069 399
        pass
paul@1069 400
paul@1069 401
    def set_requests(self, user, requests):
paul@1069 402
paul@1069 403
        "For the given 'user', set the list of queued 'requests'."
paul@1069 404
paul@1069 405
        pass
paul@1069 406
paul@1069 407
    def set_request(self, user, uid, recurrenceid=None, type=None):
paul@1069 408
paul@1069 409
        """
paul@1069 410
        For the given 'user', set the queued 'uid' and 'recurrenceid',
paul@1069 411
        indicating a request, along with any given 'type'.
paul@1069 412
        """
paul@1069 413
paul@1069 414
        pass
paul@1069 415
paul@1069 416
    def queue_request(self, user, uid, recurrenceid=None, type=None):
paul@1069 417
paul@1069 418
        """
paul@1069 419
        Queue a request for 'user' having the given 'uid'. If the optional
paul@1069 420
        'recurrenceid' is specified, the entry refers to a specific instance
paul@1069 421
        or occurrence of an event. The 'type' parameter can be used to indicate
paul@1069 422
        a specific type of request.
paul@1069 423
        """
paul@1069 424
paul@1069 425
        requests = self.get_requests(user) or []
paul@1069 426
paul@1069 427
        if not self.have_request(requests, uid, recurrenceid):
paul@1069 428
            return self.set_request(user, uid, recurrenceid, type)
paul@1069 429
paul@1069 430
        return False
paul@1069 431
paul@1069 432
    def dequeue_request(self, user, uid, recurrenceid=None):
paul@1069 433
paul@1069 434
        """
paul@1069 435
        Dequeue all requests for 'user' having the given 'uid'. If the optional
paul@1069 436
        'recurrenceid' is specified, all requests for that specific instance or
paul@1069 437
        occurrence of an event are dequeued.
paul@1069 438
        """
paul@1069 439
paul@1069 440
        requests = self.get_requests(user) or []
paul@1069 441
        result = []
paul@1069 442
paul@1069 443
        for request in requests:
paul@1069 444
            if request[:2] != (uid, recurrenceid):
paul@1069 445
                result.append(request)
paul@1069 446
paul@1069 447
        self.set_requests(user, result)
paul@1069 448
        return True
paul@1069 449
paul@1069 450
    def has_request(self, user, uid, recurrenceid=None, type=None, strict=False):
paul@1069 451
        return self.have_request(self.get_requests(user) or [], uid, recurrenceid, type, strict)
paul@1069 452
paul@1069 453
    def have_request(self, requests, uid, recurrenceid=None, type=None, strict=False):
paul@1069 454
paul@1069 455
        """
paul@1069 456
        Return whether 'requests' contains a request with the given 'uid' and
paul@1069 457
        any specified 'recurrenceid' and 'type'. If 'strict' is set to a true
paul@1069 458
        value, the precise type of the request must match; otherwise, any type
paul@1069 459
        of request for the identified object may be matched.
paul@1069 460
        """
paul@1069 461
paul@1069 462
        for request in requests:
paul@1069 463
            if request[:2] == (uid, recurrenceid) and (
paul@1069 464
                not strict or
paul@1069 465
                not request[2:] and not type or
paul@1069 466
                request[2:] and request[2] == type):
paul@1069 467
paul@1069 468
                return True
paul@1069 469
paul@1069 470
        return False
paul@1069 471
paul@1069 472
    def get_counters(self, user, uid, recurrenceid=None):
paul@1069 473
paul@1069 474
        """
paul@1069 475
        For the given 'user', return a list of users from whom counter-proposals
paul@1069 476
        have been received for the given 'uid' and optional 'recurrenceid'.
paul@1069 477
        """
paul@1069 478
paul@1069 479
        pass
paul@1069 480
paul@1305 481
    def get_counter_recurrences(self, user, uid):
paul@1305 482
paul@1305 483
        """
paul@1305 484
        For the given 'user', return a list of recurrence identifiers describing
paul@1305 485
        counter-proposals for the parent event with the given 'uid'.
paul@1305 486
        """
paul@1305 487
paul@1305 488
        pass
paul@1305 489
paul@1069 490
    def get_counter(self, user, other, uid, recurrenceid=None):
paul@1069 491
paul@1069 492
        """
paul@1069 493
        For the given 'user', return the counter-proposal from 'other' for the
paul@1069 494
        given 'uid' and optional 'recurrenceid'.
paul@1069 495
        """
paul@1069 496
paul@1069 497
        pass
paul@1069 498
paul@1069 499
    def set_counter(self, user, other, node, uid, recurrenceid=None):
paul@1069 500
paul@1069 501
        """
paul@1069 502
        For the given 'user', store a counter-proposal received from 'other' the
paul@1069 503
        given 'node' representing that proposal for the given 'uid' and
paul@1069 504
        'recurrenceid'.
paul@1069 505
        """
paul@1069 506
paul@1069 507
        pass
paul@1069 508
paul@1306 509
    def remove_counters(self, user, uid, recurrenceid=None, attendee=None):
paul@1069 510
paul@1069 511
        """
paul@1069 512
        For the given 'user', remove all counter-proposals associated with the
paul@1306 513
        given 'uid' and 'recurrenceid'. If 'attendee' is specified, only objects
paul@1306 514
        provided by this attendee will be removed.
paul@1069 515
        """
paul@1069 516
paul@1069 517
        pass
paul@1069 518
paul@1069 519
    def remove_counter(self, user, other, uid, recurrenceid=None):
paul@1069 520
paul@1069 521
        """
paul@1069 522
        For the given 'user', remove any counter-proposal from 'other'
paul@1069 523
        associated with the given 'uid' and 'recurrenceid'.
paul@1069 524
        """
paul@1069 525
paul@1069 526
        pass
paul@1069 527
paul@1069 528
    # Event cancellation.
paul@1069 529
paul@1069 530
    def cancel_event(self, user, uid, recurrenceid=None):
paul@1069 531
paul@1069 532
        """
paul@1069 533
        Cancel an event for 'user' having the given 'uid'. If the optional
paul@1069 534
        'recurrenceid' is specified, a specific instance or occurrence of an
paul@1069 535
        event is cancelled.
paul@1069 536
        """
paul@1069 537
paul@1069 538
        pass
paul@1069 539
paul@1069 540
    def uncancel_event(self, user, uid, recurrenceid=None):
paul@1069 541
paul@1069 542
        """
paul@1069 543
        Uncancel an event for 'user' having the given 'uid'. If the optional
paul@1069 544
        'recurrenceid' is specified, a specific instance or occurrence of an
paul@1069 545
        event is uncancelled.
paul@1069 546
        """
paul@1069 547
paul@1069 548
        pass
paul@1069 549
paul@1069 550
    def remove_cancellations(self, user, uid, recurrenceid=None):
paul@1069 551
paul@1069 552
        """
paul@1069 553
        Remove cancellations for 'user' for any event having the given 'uid'. If
paul@1069 554
        the optional 'recurrenceid' is specified, a specific instance or
paul@1069 555
        occurrence of an event is affected.
paul@1069 556
        """
paul@1069 557
paul@1069 558
        # Remove all recurrence cancellations if a general event is indicated.
paul@1069 559
paul@1069 560
        if not recurrenceid:
paul@1069 561
            for _recurrenceid in self.get_cancelled_recurrences(user, uid):
paul@1069 562
                self.remove_cancellation(user, uid, _recurrenceid)
paul@1069 563
paul@1069 564
        return self.remove_cancellation(user, uid, recurrenceid)
paul@1069 565
paul@1069 566
    def remove_cancellation(self, user, uid, recurrenceid=None):
paul@1069 567
paul@1069 568
        """
paul@1069 569
        Remove a cancellation for 'user' for the event having the given 'uid'.
paul@1069 570
        If the optional 'recurrenceid' is specified, a specific instance or
paul@1069 571
        occurrence of an event is affected.
paul@1069 572
        """
paul@1069 573
paul@1069 574
        pass
paul@1069 575
paul@1069 576
class PublisherBase:
paul@1069 577
paul@1069 578
    "The core operations of a data publisher."
paul@1069 579
paul@1069 580
    def set_freebusy(self, user, freebusy):
paul@1069 581
paul@1069 582
        "For the given 'user', set 'freebusy' details."
paul@1069 583
paul@1069 584
        pass
paul@1069 585
paul@1069 586
class JournalBase:
paul@1069 587
paul@1069 588
    "The core operations of a journal system supporting quotas."
paul@1069 589
paul@1069 590
    # Quota and user identity/group discovery.
paul@1069 591
paul@1069 592
    def get_quotas(self):
paul@1069 593
paul@1069 594
        "Return a list of quotas."
paul@1069 595
paul@1069 596
        pass
paul@1069 597
paul@1069 598
    def get_quota_users(self, quota):
paul@1069 599
paul@1069 600
        "Return a list of quota users."
paul@1069 601
paul@1069 602
        pass
paul@1069 603
paul@1195 604
    # Delegate information for the quota.
paul@1195 605
paul@1195 606
    def get_delegates(self, quota):
paul@1195 607
paul@1195 608
        "Return a list of delegates for 'quota'."
paul@1195 609
paul@1195 610
        pass
paul@1195 611
paul@1195 612
    def set_delegates(self, quota, delegates):
paul@1195 613
paul@1195 614
        "For the given 'quota', set the list of 'delegates'."
paul@1195 615
paul@1195 616
        pass
paul@1195 617
paul@1069 618
    # Groups of users sharing quotas.
paul@1069 619
paul@1069 620
    def get_groups(self, quota):
paul@1069 621
paul@1069 622
        "Return the identity mappings for the given 'quota' as a dictionary."
paul@1069 623
paul@1069 624
        pass
paul@1069 625
paul@1142 626
    def set_group(self, quota, store_user, user_group):
paul@1142 627
paul@1142 628
        """
paul@1142 629
        For the given 'quota', set a mapping from 'store_user' to 'user_group'.
paul@1142 630
        """
paul@1142 631
paul@1142 632
        pass
paul@1142 633
paul@1069 634
    def get_limits(self, quota):
paul@1069 635
paul@1069 636
        """
paul@1069 637
        Return the limits for the 'quota' as a dictionary mapping identities or
paul@1069 638
        groups to durations.
paul@1069 639
        """
paul@1069 640
paul@1069 641
        pass
paul@1069 642
paul@1089 643
    def set_limit(self, quota, group, limit):
paul@1089 644
paul@1089 645
        """
paul@1089 646
        For the given 'quota', set for a user 'group' the given 'limit' on
paul@1089 647
        resource usage.
paul@1089 648
        """
paul@1089 649
paul@1089 650
        pass
paul@1089 651
paul@1069 652
    # Journal entry methods.
paul@1069 653
paul@1077 654
    def get_entries(self, quota, group, mutable=False):
paul@1069 655
paul@1069 656
        """
paul@1069 657
        Return a list of journal entries for the given 'quota' for the indicated
paul@1069 658
        'group'.
paul@1069 659
        """
paul@1069 660
paul@1069 661
        pass
paul@1069 662
paul@1071 663
    def get_entries_for_update(self, quota, group):
paul@1071 664
paul@1071 665
        """
paul@1071 666
        Return a list of journal entries for the given 'quota' for the indicated
paul@1142 667
        'group' that may be updated, potentially affecting the stored
paul@1142 668
        information directly.
paul@1071 669
        """
paul@1071 670
paul@1077 671
        return self.get_entries(quota, group, True)
paul@1071 672
paul@1069 673
    def set_entries(self, quota, group, entries):
paul@1069 674
paul@1069 675
        """
paul@1069 676
        For the given 'quota' and indicated 'group', set the list of journal
paul@1069 677
        'entries'.
paul@1069 678
        """
paul@1069 679
paul@1069 680
        pass
paul@1069 681
paul@1069 682
# vim: tabstop=4 expandtab shiftwidth=4