imip-agent

imip_store.py

218:bb42d525c718
2015-02-01 Paul Boddie Handle free/busy messages without valid sender information.
     1 #!/usr/bin/env python     2      3 """     4 A simple filesystem-based store of calendar data.     5      6 Copyright (C) 2014, 2015 Paul Boddie <paul@boddie.org.uk>     7      8 This program is free software; you can redistribute it and/or modify it under     9 the terms of the GNU General Public License as published by the Free Software    10 Foundation; either version 3 of the License, or (at your option) any later    11 version.    12     13 This program is distributed in the hope that it will be useful, but WITHOUT    14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    15 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    16 details.    17     18 You should have received a copy of the GNU General Public License along with    19 this program.  If not, see <http://www.gnu.org/licenses/>.    20 """    21     22 from datetime import datetime    23 from imiptools.config import STORE_DIR, PUBLISH_DIR    24 from imiptools.data import make_calendar, to_stream    25 from imiptools.filesys import fix_permissions, FileBase    26 from os.path import exists, isfile, join    27 from os import listdir    28     29 class FileStore(FileBase):    30     31     "A file store of tabular free/busy data and objects."    32     33     def __init__(self, store_dir=STORE_DIR):    34         FileBase.__init__(self, store_dir)    35     36     def get_events(self, user):    37     38         "Return a list of event identifiers."    39     40         filename = self.get_object_in_store(user, "objects")    41         if not filename or not exists(filename):    42             return None    43     44         return [name for name in listdir(filename) if isfile(join(filename, name))]    45     46     def get_event(self, user, uid):    47     48         "Get the event for the given 'user' with the given 'uid'."    49     50         filename = self.get_object_in_store(user, "objects", uid)    51         if not filename or not exists(filename):    52             return None    53     54         return open(filename) or None    55     56     def set_event(self, user, uid, node):    57     58         "Set an event for 'user' having the given 'uid' and 'node'."    59     60         filename = self.get_object_in_store(user, "objects", uid)    61         if not filename:    62             return False    63     64         f = open(filename, "w")    65         try:    66             to_stream(f, node)    67         finally:    68             f.close()    69             fix_permissions(filename)    70     71         return True    72     73     def get_freebusy(self, user):    74     75         "Get free/busy details for the given 'user'."    76     77         filename = self.get_object_in_store(user, "freebusy")    78         if not filename or not exists(filename):    79             return []    80         else:    81             return self._get_freebusy(filename)    82     83     def get_freebusy_for_other(self, user, other):    84     85         "For the given 'user', get free/busy details for the 'other' user."    86     87         filename = self.get_object_in_store(user, "freebusy-other", other)    88         if not filename or not exists(filename):    89             return []    90         else:    91             return self._get_freebusy(filename)    92     93     def _get_freebusy(self, filename):    94         f = open(filename)    95         try:    96             l = []    97             for line in f.readlines():    98                 l.append(tuple(line.strip().split("\t")))    99             return l   100         finally:   101             f.close()   102    103     def set_freebusy(self, user, freebusy):   104    105         "For the given 'user', set 'freebusy' details."   106    107         filename = self.get_object_in_store(user, "freebusy")   108         if not filename:   109             return False   110    111         self._set_freebusy(filename, freebusy)   112         return True   113    114     def set_freebusy_for_other(self, user, freebusy, other):   115    116         "For the given 'user', set 'freebusy' details for the 'other' user."   117    118         filename = self.get_object_in_store(user, "freebusy-other", other)   119         if not filename:   120             return False   121    122         self._set_freebusy(filename, freebusy)   123         return True   124    125     def _set_freebusy(self, filename, freebusy):   126         f = open(filename, "w")   127         try:   128             for item in freebusy:   129                 f.write("\t".join([(value or "OPAQUE") for value in item]) + "\n")   130         finally:   131             f.close()   132             fix_permissions(filename)   133    134     def _get_requests(self, user, queue):   135    136         "Get requests for the given 'user' from the given 'queue'."   137    138         filename = self.get_object_in_store(user, queue)   139         if not filename or not exists(filename):   140             return None   141    142         f = open(filename)   143         try:   144             return [line.strip() for line in f.readlines()]   145         finally:   146             f.close()   147    148     def get_requests(self, user):   149    150         "Get requests for the given 'user'."   151    152         return self._get_requests(user, "requests")   153    154     def get_cancellations(self, user):   155    156         "Get cancellations for the given 'user'."   157    158         return self._get_requests(user, "cancellations")   159    160     def _set_requests(self, user, requests, queue):   161    162         """   163         For the given 'user', set the list of queued 'requests' in the given   164         'queue'.   165         """   166    167         filename = self.get_object_in_store(user, queue)   168         if not filename:   169             return False   170    171         f = open(filename, "w")   172         try:   173             for request in requests:   174                 print >>f, request   175         finally:   176             f.close()   177             fix_permissions(filename)   178    179         return True   180    181     def set_requests(self, user, requests):   182    183         "For the given 'user', set the list of queued 'requests'."   184    185         return self._set_requests(user, requests, "requests")   186    187     def set_cancellations(self, user, cancellations):   188    189         "For the given 'user', set the list of queued 'cancellations'."   190    191         return self._set_requests(user, cancellations, "cancellations")   192    193     def _set_request(self, user, request, queue):   194    195         "For the given 'user', set the queued 'request' in the given 'queue'."   196    197         filename = self.get_object_in_store(user, queue)   198         if not filename:   199             return False   200    201         f = open(filename, "a")   202         try:   203             print >>f, request   204         finally:   205             f.close()   206             fix_permissions(filename)   207    208         return True   209    210     def set_request(self, user, request):   211    212         "For the given 'user', set the queued 'request'."   213    214         return self._set_request(user, request, "requests")   215    216     def set_cancellation(self, user, cancellation):   217    218         "For the given 'user', set the queued 'cancellation'."   219    220         return self._set_request(user, cancellation, "cancellations")   221    222     def queue_request(self, user, uid):   223    224         "Queue a request for 'user' having the given 'uid'."   225    226         requests = self.get_requests(user) or []   227    228         if uid not in requests:   229             return self.set_request(user, uid)   230    231         return False   232    233     def dequeue_request(self, user, uid):   234    235         "Dequeue a request for 'user' having the given 'uid'."   236    237         requests = self.get_requests(user) or []   238    239         try:   240             requests.remove(uid)   241             self.set_requests(user, requests)   242         except ValueError:   243             return False   244         else:   245             return True   246    247     def cancel_event(self, user, uid):   248    249         "Queue an event for cancellation for 'user' having the given 'uid'."   250    251         cancellations = self.get_cancellations(user) or []   252    253         if uid not in cancellations:   254             return self.set_cancellation(user, uid)   255    256         return False   257    258 class FilePublisher(FileBase):   259    260     "A publisher of objects."   261    262     def __init__(self, store_dir=PUBLISH_DIR):   263         FileBase.__init__(self, store_dir)   264    265     def set_freebusy(self, user, freebusy):   266    267         "For the given 'user', set 'freebusy' details."   268    269         filename = self.get_object_in_store(user, "freebusy")   270         if not filename:   271             return False   272    273         record = []   274         rwrite = record.append   275    276         rwrite(("ORGANIZER", {}, user))   277         rwrite(("UID", {}, user))   278         rwrite(("DTSTAMP", {}, datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")))   279    280         for start, end, uid, transp in freebusy:   281             if not transp or transp == "OPAQUE":   282                 rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join([start, end])))   283    284         f = open(filename, "w")   285         try:   286             to_stream(f, make_calendar([("VFREEBUSY", {}, record)], "PUBLISH"))   287         finally:   288             f.close()   289             fix_permissions(filename)   290    291         return True   292    293 # vim: tabstop=4 expandtab shiftwidth=4