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 chmod, 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 chmod(filename, 0660) 84 85 return True 86 87 def get_freebusy(self, user): 88 89 "Get free/busy details for the given 'user'." 90 91 filename = self.get_object_in_store(user, "freebusy") 92 if not filename or not exists(filename): 93 return None 94 95 f = open(filename) 96 try: 97 l = [] 98 for line in f.readlines(): 99 l.append(tuple(line.strip().split("\t"))) 100 return l 101 finally: 102 f.close() 103 104 def set_freebusy(self, user, freebusy): 105 106 "For the given 'user', set 'freebusy' details." 107 108 filename = self.get_object_in_store(user, "freebusy") 109 if not filename: 110 return False 111 112 f = open(filename, "w") 113 try: 114 for item in freebusy: 115 f.write("\t".join(item) + "\n") 116 finally: 117 f.close() 118 chmod(filename, 0660) 119 120 return True 121 122 def get_requests(self, user): 123 124 "Get requests for the given 'user'." 125 126 filename = self.get_object_in_store(user, "requests") 127 if not filename or not exists(filename): 128 return None 129 130 f = open(filename) 131 try: 132 return [line.strip() for line in f.readlines()] 133 finally: 134 f.close() 135 136 def set_requests(self, user, requests): 137 138 "For the given 'user', set the list of queued 'requests'." 139 140 filename = self.get_object_in_store(user, "requests") 141 if not filename: 142 return False 143 144 f = open(filename, "w") 145 try: 146 for request in requests: 147 print >>f, request 148 finally: 149 f.close() 150 chmod(filename, 0660) 151 152 return True 153 154 def set_request(self, user, request): 155 156 "For the given 'user', set the queued 'request'." 157 158 filename = self.get_object_in_store(user, "requests") 159 if not filename: 160 return False 161 162 f = open(filename, "a") 163 try: 164 print >>f, request 165 finally: 166 f.close() 167 chmod(filename, 0660) 168 169 return True 170 171 def queue_request(self, user, uid): 172 173 "Queue a request for 'user' having the given 'uid'." 174 175 requests = self.get_requests(user) or [] 176 177 if uid not in requests: 178 return self.set_request(user, uid) 179 180 return False 181 182 class FilePublisher(FileBase): 183 184 "A publisher of objects." 185 186 def __init__(self, store_dir=PUBLISH_DIR): 187 FileBase.__init__(self, store_dir) 188 189 def set_freebusy(self, user, freebusy): 190 191 "For the given 'user', set 'freebusy' details." 192 193 filename = self.get_object_in_store(user, "freebusy") 194 if not filename: 195 return False 196 197 record = [] 198 rwrite = record.append 199 200 rwrite(("ORGANIZER", {}, user)) 201 rwrite(("UID", {}, user)) 202 rwrite(("DTSTAMP", {}, datetime.utcnow().strftime("%Y%m%dT%H%M%SZ"))) 203 204 for start, end, uid in freebusy: 205 rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join([start, end]))) 206 207 f = open(filename, "w") 208 try: 209 to_stream(f, make_calendar([("VFREEBUSY", {}, record)], "PUBLISH")) 210 finally: 211 f.close() 212 chmod(filename, 0660) 213 214 return True 215 216 # vim: tabstop=4 expandtab shiftwidth=4