1 #!/usr/bin/env python 2 3 from datetime import datetime 4 from imiptools.config import STORE_DIR, PUBLISH_DIR 5 from os.path import abspath, commonprefix, exists, join, split 6 from os import makedirs 7 from vCalendar import iterwrite 8 9 def check_dir(base, dir): 10 return commonprefix([base, abspath(dir)]) == base 11 12 def make_calendar(fragment, method=None): 13 return ("VCALENDAR", {}, 14 (method and [("METHOD", {}, method)] or []) + 15 [("VERSION", {}, "2.0")] + 16 fragment 17 ) 18 19 def to_stream(out, fragment, encoding="utf-8"): 20 iterwrite(out, encoding=encoding).append(fragment) 21 22 class FileBase: 23 24 "Basic filesystem operations." 25 26 def __init__(self, store_dir=STORE_DIR): 27 self.store_dir = store_dir 28 if not exists(self.store_dir): 29 makedirs(self.store_dir) 30 31 def get_file_object(self, base, *parts): 32 pathname = join(base, *parts) 33 return check_dir(base, pathname) and pathname or None 34 35 def get_object_in_store(self, *parts): 36 37 """ 38 Return the name of any valid object stored within a hierarchy specified 39 by the given 'parts'. 40 """ 41 42 parent = expected = self.store_dir 43 44 for part in parts: 45 filename = self.get_file_object(expected, part) 46 if not filename: 47 return False 48 parent = expected 49 expected = filename 50 51 if not exists(parent): 52 makedirs(parent) 53 54 return filename 55 56 class FileStore(FileBase): 57 58 "A file store of tabular free/busy data and objects." 59 60 def get_event(self, user, uid): 61 62 "Get the event for the given 'user' with the given 'uid'." 63 64 filename = self.get_object_in_store(user, uid) 65 if not filename or not exists(filename): 66 return None 67 68 return exists(filename) and open(filename) or None 69 70 def set_event(self, user, uid, node): 71 72 "Set an event for 'user' having the given 'uid' and 'node'." 73 74 filename = self.get_object_in_store(user, uid) 75 if not filename: 76 return False 77 78 f = open(filename, "w") 79 try: 80 to_stream(f, node) 81 finally: 82 f.close() 83 84 return True 85 86 def get_freebusy(self, user): 87 88 "Get free/busy details for the given 'user'." 89 90 filename = self.get_object_in_store(user, "freebusy") 91 if not filename or not exists(filename): 92 return None 93 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 f = open(filename, "w") 112 try: 113 for item in freebusy: 114 f.write("\t".join(item) + "\n") 115 finally: 116 f.close() 117 118 return True 119 120 def get_requests(self, user): 121 122 "Get requests for the given 'user'." 123 124 filename = self.get_object_in_store(user, "requests") 125 if not filename or not exists(filename): 126 return None 127 128 f = open(filename) 129 try: 130 return [line.strip() for line in f.readlines()] 131 finally: 132 f.close() 133 134 def set_requests(self, user, requests): 135 136 "For the given 'user', set the list of queued 'requests'." 137 138 filename = self.get_object_in_store(user, "requests") 139 if not filename: 140 return False 141 142 f = open(filename, "w") 143 try: 144 for request in requests: 145 print >>f, request 146 finally: 147 f.close() 148 149 return True 150 151 def set_request(self, user, request): 152 153 "For the given 'user', set the queued 'request'." 154 155 filename = self.get_object_in_store(user, "requests") 156 if not filename: 157 return False 158 159 f = open(filename, "a") 160 try: 161 print >>f, request 162 finally: 163 f.close() 164 165 return True 166 167 def queue_request(self, user, uid): 168 169 "Queue a request for 'user' having the given 'uid'." 170 171 requests = self.get_requests(user) or [] 172 173 if uid not in requests: 174 return self.set_request(user, uid) 175 176 return False 177 178 class FilePublisher(FileBase): 179 180 "A publisher of objects." 181 182 def __init__(self, store_dir=PUBLISH_DIR): 183 FileBase.__init__(self, store_dir) 184 185 def set_freebusy(self, user, freebusy): 186 187 "For the given 'user', set 'freebusy' details." 188 189 filename = self.get_object_in_store(user, "freebusy") 190 if not filename: 191 return False 192 193 record = [] 194 rwrite = record.append 195 196 rwrite(("ORGANIZER", {}, user)) 197 rwrite(("UID", {}, user)) 198 rwrite(("DTSTAMP", {}, datetime.utcnow().strftime("%Y%m%dT%H%M%SZ"))) 199 200 for start, end, uid in freebusy: 201 rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join([start, end]))) 202 203 f = open(filename, "w") 204 try: 205 to_stream(f, make_calendar([("VFREEBUSY", {}, record)], "PUBLISH")) 206 finally: 207 f.close() 208 209 return True 210 211 # vim: tabstop=4 expandtab shiftwidth=4