1.1 --- a/imiptools/__init__.py Wed Mar 09 21:38:56 2016 +0100 1.2 +++ b/imiptools/__init__.py Thu Mar 10 01:43:31 2016 +0100 1.3 @@ -25,7 +25,7 @@ 1.4 from imiptools.content import handle_itip_part 1.5 from imiptools.data import get_address, get_addresses, get_uri 1.6 from imiptools.mail import Messenger 1.7 -import imiptools.stores.file 1.8 +from imiptools.stores import get_store, get_publisher, get_journal 1.9 import sys, os 1.10 1.11 # Postfix exit codes. 1.12 @@ -56,6 +56,7 @@ 1.13 self.outgoing_only = outgoing_only 1.14 self.messenger = None 1.15 self.lmtp_socket = None 1.16 + self.store_type = None 1.17 self.store_dir = None 1.18 self.publishing_dir = None 1.19 self.journal_dir = None 1.20 @@ -63,13 +64,13 @@ 1.21 self.debug = False 1.22 1.23 def get_store(self): 1.24 - return imiptools.stores.file.FileStore(self.store_dir) 1.25 + return get_store(self.store_type, self.store_dir) 1.26 1.27 def get_publisher(self): 1.28 - return self.publishing_dir and imiptools.stores.file.FilePublisher(self.publishing_dir) or None 1.29 + return self.publishing_dir and get_publisher(self.publishing_dir) or None 1.30 1.31 def get_journal(self): 1.32 - return imiptools.stores.file.FileJournal(self.journal_dir) 1.33 + return get_journal(self.store_type, self.journal_dir) 1.34 1.35 def process(self, f, original_recipients): 1.36 1.37 @@ -122,6 +123,7 @@ 1.38 recipients = [] 1.39 senders = [] 1.40 lmtp = [] 1.41 + store_type = [] 1.42 store_dir = [] 1.43 publishing_dir = [] 1.44 preferences_dir = [] 1.45 @@ -152,6 +154,11 @@ 1.46 elif arg == "-L": 1.47 local_smtp = True 1.48 1.49 + # Switch to getting the store type. 1.50 + 1.51 + elif arg == "-T": 1.52 + l = store_type 1.53 + 1.54 # Switch to getting the store directory. 1.55 1.56 elif arg == "-S": 1.57 @@ -179,11 +186,14 @@ 1.58 else: 1.59 l.append(arg) 1.60 1.61 - self.messenger = Messenger(lmtp_socket=lmtp and lmtp[0] or None, local_smtp=local_smtp, sender=senders and senders[0] or None) 1.62 - self.store_dir = store_dir and store_dir[0] or None 1.63 - self.publishing_dir = publishing_dir and publishing_dir[0] or None 1.64 - self.preferences_dir = preferences_dir and preferences_dir[0] or None 1.65 - self.journal_dir = journal_dir and journal_dir[0] or None 1.66 + getvalue = lambda value, default=None: value and value[0] or default 1.67 + 1.68 + self.messenger = Messenger(lmtp_socket=getvalue(lmtp), local_smtp=local_smtp, sender=getvalue(senders)) 1.69 + self.store_type = getvalue(store_type, config.STORE_TYPE) 1.70 + self.store_dir = getvalue(store_dir) 1.71 + self.publishing_dir = getvalue(publishing_dir) 1.72 + self.preferences_dir = getvalue(preferences_dir) 1.73 + self.journal_dir = getvalue(journal_dir) 1.74 self.process(stream, original_recipients) 1.75 1.76 def __call__(self): 1.77 @@ -198,6 +208,7 @@ 1.78 if "--help" in args: 1.79 print >>sys.stderr, """\ 1.80 Usage: %s [ -o <recipient> ... ] [-s <sender> ... ] [ -l <socket> | -L ] \\ 1.81 + [ -T <store type ] \\ 1.82 [ -S <store directory> ] [ -P <publishing directory> ] \\ 1.83 [ -p <preferences directory> ] [ -j <journal directory> ] [ -d ] 1.84 1.85 @@ -225,6 +236,7 @@ 1.86 -p Indicates the location of user preference directories 1.87 -S Indicates the location of the calendar data store containing user storage 1.88 directories 1.89 +-T Indicates the store and journal type (the configured value if omitted) 1.90 1.91 Output options: 1.92
2.1 --- a/imiptools/client.py Wed Mar 09 21:38:56 2016 +0100 2.2 +++ b/imiptools/client.py Thu Mar 10 01:43:31 2016 +0100 2.3 @@ -28,7 +28,7 @@ 2.4 get_duration, get_timestamp 2.5 from imiptools.i18n import get_translator 2.6 from imiptools.profile import Preferences 2.7 -import imiptools.stores.file 2.8 +from imiptools.stores import get_store, get_publisher, get_journal 2.9 2.10 class Client: 2.11 2.12 @@ -48,11 +48,11 @@ 2.13 2.14 self.user = user 2.15 self.messenger = messenger 2.16 - self.store = store or imiptools.stores.file.FileStore() 2.17 - self.journal = journal or imiptools.stores.file.FileJournal() 2.18 + self.store = store or get_store(config.STORE_TYPE, config.STORE_DIR) 2.19 + self.journal = journal or get_journal(config.STORE_TYPE, config.JOURNAL_DIR) 2.20 2.21 try: 2.22 - self.publisher = publisher or imiptools.stores.file.FilePublisher() 2.23 + self.publisher = publisher or get_publisher(config.PUBLISH_DIR) 2.24 except OSError: 2.25 self.publisher = None 2.26
3.1 --- a/imiptools/config.py Wed Mar 09 21:38:56 2016 +0100 3.2 +++ b/imiptools/config.py Thu Mar 10 01:43:31 2016 +0100 3.3 @@ -14,6 +14,10 @@ 3.4 3.5 OUTGOING_PREFIX = "people-outgoing" 3.6 3.7 +# The store (and journal) type. 3.8 + 3.9 +STORE_TYPE = "file" 3.10 + 3.11 # The location of the stored calendar information. 3.12 3.13 STORE_DIR = "/var/lib/imip-agent/store"
4.1 --- a/imiptools/period.py Wed Mar 09 21:38:56 2016 +0100 4.2 +++ b/imiptools/period.py Thu Mar 10 01:43:31 2016 +0100 4.3 @@ -957,7 +957,7 @@ 4.4 4.5 self._check_mutable() 4.6 4.7 - if recurrenceids is None: 4.8 + if not recurrenceids: 4.9 columns, values = ["object_uid", "object_recurrenceid is not null"], [uid] 4.10 else: 4.11 columns, values = ["object_uid", "object_recurrenceid not in ?", "object_recurrenceid is not null"], [uid, tuple(recurrenceids)]
5.1 --- a/imiptools/stores/__init__.py Wed Mar 09 21:38:56 2016 +0100 5.2 +++ b/imiptools/stores/__init__.py Thu Mar 10 01:43:31 2016 +0100 5.3 @@ -3,7 +3,7 @@ 5.4 """ 5.5 General support for calendar data storage. 5.6 5.7 -Copyright (C) 2014, 2015, 2016 Paul Boddie <paul@boddie.org.uk> 5.8 +Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk> 5.9 5.10 This program is free software; you can redistribute it and/or modify it under 5.11 the terms of the GNU General Public License as published by the Free Software 5.12 @@ -19,601 +19,25 @@ 5.13 this program. If not, see <http://www.gnu.org/licenses/>. 5.14 """ 5.15 5.16 -from imiptools.dates import format_datetime 5.17 - 5.18 -class StoreBase: 5.19 - 5.20 - "The core operations of a data store." 5.21 - 5.22 - def acquire_lock(self, user, timeout=None): 5.23 - pass 5.24 - 5.25 - def release_lock(self, user): 5.26 - pass 5.27 - 5.28 - # User discovery. 5.29 - 5.30 - def get_users(self): 5.31 - 5.32 - "Return a list of users." 5.33 - 5.34 - pass 5.35 - 5.36 - # Event and event metadata access. 5.37 - 5.38 - def get_events(self, user): 5.39 - 5.40 - "Return a list of event identifiers." 5.41 - 5.42 - pass 5.43 - 5.44 - def get_all_events(self, user): 5.45 - 5.46 - "Return a set of (uid, recurrenceid) tuples for all events." 5.47 - 5.48 - uids = self.get_events(user) 5.49 - if not uids: 5.50 - return set() 5.51 - 5.52 - all_events = set() 5.53 - for uid in uids: 5.54 - all_events.add((uid, None)) 5.55 - all_events.update([(uid, recurrenceid) for recurrenceid in self.get_recurrences(user, uid)]) 5.56 - 5.57 - return all_events 5.58 - 5.59 - def get_event(self, user, uid, recurrenceid=None, dirname=None): 5.60 - 5.61 - """ 5.62 - Get the event for the given 'user' with the given 'uid'. If 5.63 - the optional 'recurrenceid' is specified, a specific instance or 5.64 - occurrence of an event is returned. 5.65 - """ 5.66 - 5.67 - pass 5.68 - 5.69 - def get_complete_event(self, user, uid): 5.70 - 5.71 - "Get the event for the given 'user' with the given 'uid'." 5.72 - 5.73 - pass 5.74 - 5.75 - def set_event(self, user, uid, recurrenceid, node): 5.76 - 5.77 - """ 5.78 - Set an event for 'user' having the given 'uid' and 'recurrenceid' (which 5.79 - if the latter is specified, a specific instance or occurrence of an 5.80 - event is referenced), using the given 'node' description. 5.81 - """ 5.82 - 5.83 - if recurrenceid: 5.84 - return self.set_recurrence(user, uid, recurrenceid, node) 5.85 - else: 5.86 - return self.set_complete_event(user, uid, node) 5.87 - 5.88 - def set_complete_event(self, user, uid, node): 5.89 +from imiptools.stores import file 5.90 +from imiptools.stores.database import stores as database_stores 5.91 5.92 - "Set an event for 'user' having the given 'uid' and 'node'." 5.93 - 5.94 - pass 5.95 - 5.96 - def remove_event(self, user, uid, recurrenceid=None): 5.97 - 5.98 - """ 5.99 - Remove an event for 'user' having the given 'uid'. If the optional 5.100 - 'recurrenceid' is specified, a specific instance or occurrence of an 5.101 - event is removed. 5.102 - """ 5.103 - 5.104 - if recurrenceid: 5.105 - return self.remove_recurrence(user, uid, recurrenceid) 5.106 - else: 5.107 - for recurrenceid in self.get_recurrences(user, uid) or []: 5.108 - self.remove_recurrence(user, uid, recurrenceid) 5.109 - return self.remove_complete_event(user, uid) 5.110 - 5.111 - def remove_complete_event(self, user, uid): 5.112 - 5.113 - "Remove an event for 'user' having the given 'uid'." 5.114 - 5.115 - self.remove_recurrences(user, uid) 5.116 - return self.remove_parent_event(user, uid) 5.117 - 5.118 - def remove_parent_event(self, user, uid): 5.119 - 5.120 - "Remove the parent event for 'user' having the given 'uid'." 5.121 - 5.122 - pass 5.123 - 5.124 - def get_recurrences(self, user, uid): 5.125 - 5.126 - """ 5.127 - Get additional event instances for an event of the given 'user' with the 5.128 - indicated 'uid'. Both active and cancelled recurrences are returned. 5.129 - """ 5.130 - 5.131 - return self.get_active_recurrences(user, uid) + self.get_cancelled_recurrences(user, uid) 5.132 - 5.133 - def get_active_recurrences(self, user, uid): 5.134 - 5.135 - """ 5.136 - Get additional event instances for an event of the given 'user' with the 5.137 - indicated 'uid'. Cancelled recurrences are not returned. 5.138 - """ 5.139 - 5.140 - pass 5.141 - 5.142 - def get_cancelled_recurrences(self, user, uid): 5.143 - 5.144 - """ 5.145 - Get additional event instances for an event of the given 'user' with the 5.146 - indicated 'uid'. Only cancelled recurrences are returned. 5.147 - """ 5.148 - 5.149 - pass 5.150 - 5.151 - def get_recurrence(self, user, uid, recurrenceid): 5.152 - 5.153 - """ 5.154 - For the event of the given 'user' with the given 'uid', return the 5.155 - specific recurrence indicated by the 'recurrenceid'. 5.156 - """ 5.157 - 5.158 - pass 5.159 - 5.160 - def set_recurrence(self, user, uid, recurrenceid, node): 5.161 - 5.162 - "Set an event for 'user' having the given 'uid' and 'node'." 5.163 - 5.164 - pass 5.165 +# Build a catalogue of store types. 5.166 5.167 - def remove_recurrence(self, user, uid, recurrenceid): 5.168 - 5.169 - """ 5.170 - Remove a special recurrence from an event stored by 'user' having the 5.171 - given 'uid' and 'recurrenceid'. 5.172 - """ 5.173 - 5.174 - pass 5.175 - 5.176 - def remove_recurrences(self, user, uid): 5.177 - 5.178 - """ 5.179 - Remove all recurrences for an event stored by 'user' having the given 5.180 - 'uid'. 5.181 - """ 5.182 - 5.183 - for recurrenceid in self.get_recurrences(user, uid): 5.184 - self.remove_recurrence(user, uid, recurrenceid) 5.185 - 5.186 - return self.remove_recurrence_collection(user, uid) 5.187 - 5.188 - def remove_recurrence_collection(self, user, uid): 5.189 - 5.190 - """ 5.191 - Remove the collection of recurrences stored by 'user' having the given 5.192 - 'uid'. 5.193 - """ 5.194 - 5.195 - pass 5.196 - 5.197 - # Free/busy period providers, upon extension of the free/busy records. 5.198 - 5.199 - def _get_freebusy_providers(self, user): 5.200 - 5.201 - """ 5.202 - Return the free/busy providers for the given 'user'. 5.203 - 5.204 - This function returns any stored datetime and a list of providers as a 5.205 - 2-tuple. Each provider is itself a (uid, recurrenceid) tuple. 5.206 - """ 5.207 - 5.208 - pass 5.209 - 5.210 - def get_freebusy_providers(self, user, dt=None): 5.211 - 5.212 - """ 5.213 - Return a set of uncancelled events of the form (uid, recurrenceid) 5.214 - providing free/busy details beyond the given datetime 'dt'. 5.215 - 5.216 - If 'dt' is not specified, all events previously found to provide 5.217 - details will be returned. Otherwise, if 'dt' is earlier than the 5.218 - datetime recorded for the known providers, None is returned, indicating 5.219 - that the list of providers must be recomputed. 5.220 - 5.221 - This function returns a list of (uid, recurrenceid) tuples upon success. 5.222 - """ 5.223 - 5.224 - t = self._get_freebusy_providers(user) 5.225 - if not t: 5.226 - return None 5.227 - 5.228 - dt_string, t = t 5.229 - 5.230 - # If the requested datetime is earlier than the stated datetime, the 5.231 - # providers will need to be recomputed. 5.232 - 5.233 - if dt: 5.234 - providers_dt = get_datetime(dt_string) 5.235 - if not providers_dt or providers_dt > dt: 5.236 - return None 5.237 - 5.238 - # Otherwise, return the providers. 5.239 - 5.240 - return t[1:] 5.241 - 5.242 - def _set_freebusy_providers(self, user, dt_string, t): 5.243 - 5.244 - "Set the given provider timestamp 'dt_string' and table 't'." 5.245 - 5.246 - pass 5.247 - 5.248 - def set_freebusy_providers(self, user, dt, providers): 5.249 - 5.250 - """ 5.251 - Define the uncancelled events providing free/busy details beyond the 5.252 - given datetime 'dt'. 5.253 - """ 5.254 - 5.255 - t = [] 5.256 - 5.257 - for obj in providers: 5.258 - t.append((obj.get_uid(), obj.get_recurrenceid())) 5.259 - 5.260 - return self._set_freebusy_providers(user, format_datetime(dt), t) 5.261 - 5.262 - def append_freebusy_provider(self, user, provider): 5.263 - 5.264 - "For the given 'user', append the free/busy 'provider'." 5.265 - 5.266 - t = self._get_freebusy_providers(user) 5.267 - if not t: 5.268 - return False 5.269 - 5.270 - dt_string, t = t 5.271 - t.append((provider.get_uid(), provider.get_recurrenceid())) 5.272 - 5.273 - return self._set_freebusy_providers(user, dt_string, t) 5.274 - 5.275 - def remove_freebusy_provider(self, user, provider): 5.276 - 5.277 - "For the given 'user', remove the free/busy 'provider'." 5.278 - 5.279 - t = self._get_freebusy_providers(user) 5.280 - if not t: 5.281 - return False 5.282 - 5.283 - dt_string, t = t 5.284 - try: 5.285 - t.remove((provider.get_uid(), provider.get_recurrenceid())) 5.286 - except ValueError: 5.287 - return False 5.288 - 5.289 - return self._set_freebusy_providers(user, dt_string, t) 5.290 - 5.291 - # Free/busy period access. 5.292 - 5.293 - def get_freebusy(self, user, name=None, mutable=False): 5.294 - 5.295 - "Get free/busy details for the given 'user'." 5.296 - 5.297 - pass 5.298 - 5.299 - def get_freebusy_for_other(self, user, other, mutable=False): 5.300 - 5.301 - "For the given 'user', get free/busy details for the 'other' user." 5.302 - 5.303 - pass 5.304 - 5.305 - def get_freebusy_for_update(self, user, name=None): 5.306 - 5.307 - "Get free/busy details for the given 'user'." 5.308 - 5.309 - return self.get_freebusy(user, name, True) 5.310 - 5.311 - def get_freebusy_for_other_for_update(self, user, other): 5.312 - 5.313 - "For the given 'user', get free/busy details for the 'other' user." 5.314 - 5.315 - return self.get_freebusy_for_other(user, other, True) 5.316 +stores = { 5.317 + "file" : file, 5.318 + } 5.319 +stores.update(database_stores) 5.320 5.321 - def set_freebusy(self, user, freebusy, name=None): 5.322 - 5.323 - "For the given 'user', set 'freebusy' details." 5.324 - 5.325 - pass 5.326 - 5.327 - def set_freebusy_for_other(self, user, freebusy, other): 5.328 - 5.329 - "For the given 'user', set 'freebusy' details for the 'other' user." 5.330 - 5.331 - pass 5.332 - 5.333 - # Tentative free/busy periods related to countering. 5.334 - 5.335 - def get_freebusy_offers(self, user, mutable=False): 5.336 - 5.337 - "Get free/busy offers for the given 'user'." 5.338 - 5.339 - pass 5.340 - 5.341 - def get_freebusy_offers_for_update(self, user): 5.342 - 5.343 - "Get free/busy offers for the given 'user'." 5.344 - 5.345 - return self.get_freebusy_offers(user, True) 5.346 - 5.347 - def set_freebusy_offers(self, user, freebusy): 5.348 - 5.349 - "For the given 'user', set 'freebusy' offers." 5.350 - 5.351 - return self.set_freebusy(user, freebusy, "freebusy-offers") 5.352 - 5.353 - # Requests and counter-proposals. 5.354 - 5.355 - def get_requests(self, user): 5.356 - 5.357 - "Get requests for the given 'user'." 5.358 - 5.359 - pass 5.360 - 5.361 - def set_requests(self, user, requests): 5.362 - 5.363 - "For the given 'user', set the list of queued 'requests'." 5.364 - 5.365 - pass 5.366 - 5.367 - def set_request(self, user, uid, recurrenceid=None, type=None): 5.368 - 5.369 - """ 5.370 - For the given 'user', set the queued 'uid' and 'recurrenceid', 5.371 - indicating a request, along with any given 'type'. 5.372 - """ 5.373 - 5.374 - pass 5.375 - 5.376 - def queue_request(self, user, uid, recurrenceid=None, type=None): 5.377 - 5.378 - """ 5.379 - Queue a request for 'user' having the given 'uid'. If the optional 5.380 - 'recurrenceid' is specified, the entry refers to a specific instance 5.381 - or occurrence of an event. The 'type' parameter can be used to indicate 5.382 - a specific type of request. 5.383 - """ 5.384 - 5.385 - requests = self.get_requests(user) or [] 5.386 - 5.387 - if not self.have_request(requests, uid, recurrenceid): 5.388 - return self.set_request(user, uid, recurrenceid, type) 5.389 - 5.390 - return False 5.391 - 5.392 - def dequeue_request(self, user, uid, recurrenceid=None): 5.393 +# Access functions. 5.394 5.395 - """ 5.396 - Dequeue all requests for 'user' having the given 'uid'. If the optional 5.397 - 'recurrenceid' is specified, all requests for that specific instance or 5.398 - occurrence of an event are dequeued. 5.399 - """ 5.400 - 5.401 - requests = self.get_requests(user) or [] 5.402 - result = [] 5.403 - 5.404 - for request in requests: 5.405 - if request[:2] != (uid, recurrenceid): 5.406 - result.append(request) 5.407 - 5.408 - self.set_requests(user, result) 5.409 - return True 5.410 - 5.411 - def has_request(self, user, uid, recurrenceid=None, type=None, strict=False): 5.412 - return self.have_request(self.get_requests(user) or [], uid, recurrenceid, type, strict) 5.413 - 5.414 - def have_request(self, requests, uid, recurrenceid=None, type=None, strict=False): 5.415 - 5.416 - """ 5.417 - Return whether 'requests' contains a request with the given 'uid' and 5.418 - any specified 'recurrenceid' and 'type'. If 'strict' is set to a true 5.419 - value, the precise type of the request must match; otherwise, any type 5.420 - of request for the identified object may be matched. 5.421 - """ 5.422 - 5.423 - for request in requests: 5.424 - if request[:2] == (uid, recurrenceid) and ( 5.425 - not strict or 5.426 - not request[2:] and not type or 5.427 - request[2:] and request[2] == type): 5.428 - 5.429 - return True 5.430 - 5.431 - return False 5.432 - 5.433 - def get_counters(self, user, uid, recurrenceid=None): 5.434 - 5.435 - """ 5.436 - For the given 'user', return a list of users from whom counter-proposals 5.437 - have been received for the given 'uid' and optional 'recurrenceid'. 5.438 - """ 5.439 - 5.440 - pass 5.441 - 5.442 - def get_counter(self, user, other, uid, recurrenceid=None): 5.443 - 5.444 - """ 5.445 - For the given 'user', return the counter-proposal from 'other' for the 5.446 - given 'uid' and optional 'recurrenceid'. 5.447 - """ 5.448 - 5.449 - pass 5.450 - 5.451 - def set_counter(self, user, other, node, uid, recurrenceid=None): 5.452 - 5.453 - """ 5.454 - For the given 'user', store a counter-proposal received from 'other' the 5.455 - given 'node' representing that proposal for the given 'uid' and 5.456 - 'recurrenceid'. 5.457 - """ 5.458 - 5.459 - pass 5.460 - 5.461 - def remove_counters(self, user, uid, recurrenceid=None): 5.462 - 5.463 - """ 5.464 - For the given 'user', remove all counter-proposals associated with the 5.465 - given 'uid' and 'recurrenceid'. 5.466 - """ 5.467 - 5.468 - pass 5.469 +def get_store(store_type, store_dir): 5.470 + return stores[store_type].Store(store_dir) 5.471 5.472 - def remove_counter(self, user, other, uid, recurrenceid=None): 5.473 - 5.474 - """ 5.475 - For the given 'user', remove any counter-proposal from 'other' 5.476 - associated with the given 'uid' and 'recurrenceid'. 5.477 - """ 5.478 - 5.479 - pass 5.480 - 5.481 - # Event cancellation. 5.482 - 5.483 - def cancel_event(self, user, uid, recurrenceid=None): 5.484 - 5.485 - """ 5.486 - Cancel an event for 'user' having the given 'uid'. If the optional 5.487 - 'recurrenceid' is specified, a specific instance or occurrence of an 5.488 - event is cancelled. 5.489 - """ 5.490 - 5.491 - pass 5.492 - 5.493 - def uncancel_event(self, user, uid, recurrenceid=None): 5.494 - 5.495 - """ 5.496 - Uncancel an event for 'user' having the given 'uid'. If the optional 5.497 - 'recurrenceid' is specified, a specific instance or occurrence of an 5.498 - event is uncancelled. 5.499 - """ 5.500 - 5.501 - pass 5.502 - 5.503 - def remove_cancellations(self, user, uid, recurrenceid=None): 5.504 - 5.505 - """ 5.506 - Remove cancellations for 'user' for any event having the given 'uid'. If 5.507 - the optional 'recurrenceid' is specified, a specific instance or 5.508 - occurrence of an event is affected. 5.509 - """ 5.510 - 5.511 - # Remove all recurrence cancellations if a general event is indicated. 5.512 - 5.513 - if not recurrenceid: 5.514 - for _recurrenceid in self.get_cancelled_recurrences(user, uid): 5.515 - self.remove_cancellation(user, uid, _recurrenceid) 5.516 - 5.517 - return self.remove_cancellation(user, uid, recurrenceid) 5.518 - 5.519 - def remove_cancellation(self, user, uid, recurrenceid=None): 5.520 - 5.521 - """ 5.522 - Remove a cancellation for 'user' for the event having the given 'uid'. 5.523 - If the optional 'recurrenceid' is specified, a specific instance or 5.524 - occurrence of an event is affected. 5.525 - """ 5.526 - 5.527 - pass 5.528 - 5.529 -class PublisherBase: 5.530 - 5.531 - "The core operations of a data publisher." 5.532 - 5.533 - def set_freebusy(self, user, freebusy): 5.534 - 5.535 - "For the given 'user', set 'freebusy' details." 5.536 - 5.537 - pass 5.538 - 5.539 -class JournalBase: 5.540 - 5.541 - "The core operations of a journal system supporting quotas." 5.542 - 5.543 - # Quota and user identity/group discovery. 5.544 - 5.545 - def get_quotas(self): 5.546 +def get_publisher(publishing_dir): 5.547 + return file.Publisher(publishing_dir) 5.548 5.549 - "Return a list of quotas." 5.550 - 5.551 - pass 5.552 - 5.553 - def get_quota_users(self, quota): 5.554 - 5.555 - "Return a list of quota users." 5.556 - 5.557 - pass 5.558 - 5.559 - # Groups of users sharing quotas. 5.560 - 5.561 - def get_groups(self, quota): 5.562 - 5.563 - "Return the identity mappings for the given 'quota' as a dictionary." 5.564 - 5.565 - pass 5.566 - 5.567 - def get_limits(self, quota): 5.568 - 5.569 - """ 5.570 - Return the limits for the 'quota' as a dictionary mapping identities or 5.571 - groups to durations. 5.572 - """ 5.573 - 5.574 - pass 5.575 - 5.576 - # Free/busy period access for users within quota groups. 5.577 - 5.578 - def get_freebusy(self, quota, user, mutable=False): 5.579 - 5.580 - "Get free/busy details for the given 'quota' and 'user'." 5.581 - 5.582 - pass 5.583 - 5.584 - def get_freebusy_for_update(self, quota, user): 5.585 - 5.586 - "Get free/busy details for the given 'quota' and 'user'." 5.587 - 5.588 - return self.get_freebusy(quota, user, True) 5.589 - 5.590 - def set_freebusy(self, quota, user, freebusy): 5.591 - 5.592 - "For the given 'quota' and 'user', set 'freebusy' details." 5.593 - 5.594 - pass 5.595 - 5.596 - # Journal entry methods. 5.597 - 5.598 - def get_entries(self, quota, group, mutable=False): 5.599 - 5.600 - """ 5.601 - Return a list of journal entries for the given 'quota' for the indicated 5.602 - 'group'. 5.603 - """ 5.604 - 5.605 - pass 5.606 - 5.607 - def get_entries_for_update(self, quota, group): 5.608 - 5.609 - """ 5.610 - Return a list of journal entries for the given 'quota' for the indicated 5.611 - 'group'. 5.612 - """ 5.613 - 5.614 - return self.get_entries(quota, group, True) 5.615 - 5.616 - def set_entries(self, quota, group, entries): 5.617 - 5.618 - """ 5.619 - For the given 'quota' and indicated 'group', set the list of journal 5.620 - 'entries'. 5.621 - """ 5.622 - 5.623 - pass 5.624 +def get_journal(store_type, journal_dir): 5.625 + return stores[store_type].Journal(journal_dir) 5.626 5.627 # vim: tabstop=4 expandtab shiftwidth=4
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/imiptools/stores/common.py Thu Mar 10 01:43:31 2016 +0100 6.3 @@ -0,0 +1,619 @@ 6.4 +#!/usr/bin/env python 6.5 + 6.6 +""" 6.7 +General support for calendar data storage. 6.8 + 6.9 +Copyright (C) 2014, 2015, 2016 Paul Boddie <paul@boddie.org.uk> 6.10 + 6.11 +This program is free software; you can redistribute it and/or modify it under 6.12 +the terms of the GNU General Public License as published by the Free Software 6.13 +Foundation; either version 3 of the License, or (at your option) any later 6.14 +version. 6.15 + 6.16 +This program is distributed in the hope that it will be useful, but WITHOUT 6.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 6.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 6.19 +details. 6.20 + 6.21 +You should have received a copy of the GNU General Public License along with 6.22 +this program. If not, see <http://www.gnu.org/licenses/>. 6.23 +""" 6.24 + 6.25 +from imiptools.dates import format_datetime 6.26 + 6.27 +class StoreBase: 6.28 + 6.29 + "The core operations of a data store." 6.30 + 6.31 + def acquire_lock(self, user, timeout=None): 6.32 + pass 6.33 + 6.34 + def release_lock(self, user): 6.35 + pass 6.36 + 6.37 + # User discovery. 6.38 + 6.39 + def get_users(self): 6.40 + 6.41 + "Return a list of users." 6.42 + 6.43 + pass 6.44 + 6.45 + # Event and event metadata access. 6.46 + 6.47 + def get_events(self, user): 6.48 + 6.49 + "Return a list of event identifiers." 6.50 + 6.51 + pass 6.52 + 6.53 + def get_all_events(self, user): 6.54 + 6.55 + "Return a set of (uid, recurrenceid) tuples for all events." 6.56 + 6.57 + uids = self.get_events(user) 6.58 + if not uids: 6.59 + return set() 6.60 + 6.61 + all_events = set() 6.62 + for uid in uids: 6.63 + all_events.add((uid, None)) 6.64 + all_events.update([(uid, recurrenceid) for recurrenceid in self.get_recurrences(user, uid)]) 6.65 + 6.66 + return all_events 6.67 + 6.68 + def get_event(self, user, uid, recurrenceid=None, dirname=None): 6.69 + 6.70 + """ 6.71 + Get the event for the given 'user' with the given 'uid'. If 6.72 + the optional 'recurrenceid' is specified, a specific instance or 6.73 + occurrence of an event is returned. 6.74 + """ 6.75 + 6.76 + pass 6.77 + 6.78 + def get_complete_event(self, user, uid): 6.79 + 6.80 + "Get the event for the given 'user' with the given 'uid'." 6.81 + 6.82 + pass 6.83 + 6.84 + def set_event(self, user, uid, recurrenceid, node): 6.85 + 6.86 + """ 6.87 + Set an event for 'user' having the given 'uid' and 'recurrenceid' (which 6.88 + if the latter is specified, a specific instance or occurrence of an 6.89 + event is referenced), using the given 'node' description. 6.90 + """ 6.91 + 6.92 + if recurrenceid: 6.93 + return self.set_recurrence(user, uid, recurrenceid, node) 6.94 + else: 6.95 + return self.set_complete_event(user, uid, node) 6.96 + 6.97 + def set_complete_event(self, user, uid, node): 6.98 + 6.99 + "Set an event for 'user' having the given 'uid' and 'node'." 6.100 + 6.101 + pass 6.102 + 6.103 + def remove_event(self, user, uid, recurrenceid=None): 6.104 + 6.105 + """ 6.106 + Remove an event for 'user' having the given 'uid'. If the optional 6.107 + 'recurrenceid' is specified, a specific instance or occurrence of an 6.108 + event is removed. 6.109 + """ 6.110 + 6.111 + if recurrenceid: 6.112 + return self.remove_recurrence(user, uid, recurrenceid) 6.113 + else: 6.114 + for recurrenceid in self.get_recurrences(user, uid) or []: 6.115 + self.remove_recurrence(user, uid, recurrenceid) 6.116 + return self.remove_complete_event(user, uid) 6.117 + 6.118 + def remove_complete_event(self, user, uid): 6.119 + 6.120 + "Remove an event for 'user' having the given 'uid'." 6.121 + 6.122 + self.remove_recurrences(user, uid) 6.123 + return self.remove_parent_event(user, uid) 6.124 + 6.125 + def remove_parent_event(self, user, uid): 6.126 + 6.127 + "Remove the parent event for 'user' having the given 'uid'." 6.128 + 6.129 + pass 6.130 + 6.131 + def get_recurrences(self, user, uid): 6.132 + 6.133 + """ 6.134 + Get additional event instances for an event of the given 'user' with the 6.135 + indicated 'uid'. Both active and cancelled recurrences are returned. 6.136 + """ 6.137 + 6.138 + return self.get_active_recurrences(user, uid) + self.get_cancelled_recurrences(user, uid) 6.139 + 6.140 + def get_active_recurrences(self, user, uid): 6.141 + 6.142 + """ 6.143 + Get additional event instances for an event of the given 'user' with the 6.144 + indicated 'uid'. Cancelled recurrences are not returned. 6.145 + """ 6.146 + 6.147 + pass 6.148 + 6.149 + def get_cancelled_recurrences(self, user, uid): 6.150 + 6.151 + """ 6.152 + Get additional event instances for an event of the given 'user' with the 6.153 + indicated 'uid'. Only cancelled recurrences are returned. 6.154 + """ 6.155 + 6.156 + pass 6.157 + 6.158 + def get_recurrence(self, user, uid, recurrenceid): 6.159 + 6.160 + """ 6.161 + For the event of the given 'user' with the given 'uid', return the 6.162 + specific recurrence indicated by the 'recurrenceid'. 6.163 + """ 6.164 + 6.165 + pass 6.166 + 6.167 + def set_recurrence(self, user, uid, recurrenceid, node): 6.168 + 6.169 + "Set an event for 'user' having the given 'uid' and 'node'." 6.170 + 6.171 + pass 6.172 + 6.173 + def remove_recurrence(self, user, uid, recurrenceid): 6.174 + 6.175 + """ 6.176 + Remove a special recurrence from an event stored by 'user' having the 6.177 + given 'uid' and 'recurrenceid'. 6.178 + """ 6.179 + 6.180 + pass 6.181 + 6.182 + def remove_recurrences(self, user, uid): 6.183 + 6.184 + """ 6.185 + Remove all recurrences for an event stored by 'user' having the given 6.186 + 'uid'. 6.187 + """ 6.188 + 6.189 + for recurrenceid in self.get_recurrences(user, uid): 6.190 + self.remove_recurrence(user, uid, recurrenceid) 6.191 + 6.192 + return self.remove_recurrence_collection(user, uid) 6.193 + 6.194 + def remove_recurrence_collection(self, user, uid): 6.195 + 6.196 + """ 6.197 + Remove the collection of recurrences stored by 'user' having the given 6.198 + 'uid'. 6.199 + """ 6.200 + 6.201 + pass 6.202 + 6.203 + # Free/busy period providers, upon extension of the free/busy records. 6.204 + 6.205 + def _get_freebusy_providers(self, user): 6.206 + 6.207 + """ 6.208 + Return the free/busy providers for the given 'user'. 6.209 + 6.210 + This function returns any stored datetime and a list of providers as a 6.211 + 2-tuple. Each provider is itself a (uid, recurrenceid) tuple. 6.212 + """ 6.213 + 6.214 + pass 6.215 + 6.216 + def get_freebusy_providers(self, user, dt=None): 6.217 + 6.218 + """ 6.219 + Return a set of uncancelled events of the form (uid, recurrenceid) 6.220 + providing free/busy details beyond the given datetime 'dt'. 6.221 + 6.222 + If 'dt' is not specified, all events previously found to provide 6.223 + details will be returned. Otherwise, if 'dt' is earlier than the 6.224 + datetime recorded for the known providers, None is returned, indicating 6.225 + that the list of providers must be recomputed. 6.226 + 6.227 + This function returns a list of (uid, recurrenceid) tuples upon success. 6.228 + """ 6.229 + 6.230 + t = self._get_freebusy_providers(user) 6.231 + if not t: 6.232 + return None 6.233 + 6.234 + dt_string, t = t 6.235 + 6.236 + # If the requested datetime is earlier than the stated datetime, the 6.237 + # providers will need to be recomputed. 6.238 + 6.239 + if dt: 6.240 + providers_dt = get_datetime(dt_string) 6.241 + if not providers_dt or providers_dt > dt: 6.242 + return None 6.243 + 6.244 + # Otherwise, return the providers. 6.245 + 6.246 + return t[1:] 6.247 + 6.248 + def _set_freebusy_providers(self, user, dt_string, t): 6.249 + 6.250 + "Set the given provider timestamp 'dt_string' and table 't'." 6.251 + 6.252 + pass 6.253 + 6.254 + def set_freebusy_providers(self, user, dt, providers): 6.255 + 6.256 + """ 6.257 + Define the uncancelled events providing free/busy details beyond the 6.258 + given datetime 'dt'. 6.259 + """ 6.260 + 6.261 + t = [] 6.262 + 6.263 + for obj in providers: 6.264 + t.append((obj.get_uid(), obj.get_recurrenceid())) 6.265 + 6.266 + return self._set_freebusy_providers(user, format_datetime(dt), t) 6.267 + 6.268 + def append_freebusy_provider(self, user, provider): 6.269 + 6.270 + "For the given 'user', append the free/busy 'provider'." 6.271 + 6.272 + t = self._get_freebusy_providers(user) 6.273 + if not t: 6.274 + return False 6.275 + 6.276 + dt_string, t = t 6.277 + t.append((provider.get_uid(), provider.get_recurrenceid())) 6.278 + 6.279 + return self._set_freebusy_providers(user, dt_string, t) 6.280 + 6.281 + def remove_freebusy_provider(self, user, provider): 6.282 + 6.283 + "For the given 'user', remove the free/busy 'provider'." 6.284 + 6.285 + t = self._get_freebusy_providers(user) 6.286 + if not t: 6.287 + return False 6.288 + 6.289 + dt_string, t = t 6.290 + try: 6.291 + t.remove((provider.get_uid(), provider.get_recurrenceid())) 6.292 + except ValueError: 6.293 + return False 6.294 + 6.295 + return self._set_freebusy_providers(user, dt_string, t) 6.296 + 6.297 + # Free/busy period access. 6.298 + 6.299 + def get_freebusy(self, user, name=None, mutable=False): 6.300 + 6.301 + "Get free/busy details for the given 'user'." 6.302 + 6.303 + pass 6.304 + 6.305 + def get_freebusy_for_other(self, user, other, mutable=False): 6.306 + 6.307 + "For the given 'user', get free/busy details for the 'other' user." 6.308 + 6.309 + pass 6.310 + 6.311 + def get_freebusy_for_update(self, user, name=None): 6.312 + 6.313 + "Get free/busy details for the given 'user'." 6.314 + 6.315 + return self.get_freebusy(user, name, True) 6.316 + 6.317 + def get_freebusy_for_other_for_update(self, user, other): 6.318 + 6.319 + "For the given 'user', get free/busy details for the 'other' user." 6.320 + 6.321 + return self.get_freebusy_for_other(user, other, True) 6.322 + 6.323 + def set_freebusy(self, user, freebusy, name=None): 6.324 + 6.325 + "For the given 'user', set 'freebusy' details." 6.326 + 6.327 + pass 6.328 + 6.329 + def set_freebusy_for_other(self, user, freebusy, other): 6.330 + 6.331 + "For the given 'user', set 'freebusy' details for the 'other' user." 6.332 + 6.333 + pass 6.334 + 6.335 + # Tentative free/busy periods related to countering. 6.336 + 6.337 + def get_freebusy_offers(self, user, mutable=False): 6.338 + 6.339 + "Get free/busy offers for the given 'user'." 6.340 + 6.341 + pass 6.342 + 6.343 + def get_freebusy_offers_for_update(self, user): 6.344 + 6.345 + "Get free/busy offers for the given 'user'." 6.346 + 6.347 + return self.get_freebusy_offers(user, True) 6.348 + 6.349 + def set_freebusy_offers(self, user, freebusy): 6.350 + 6.351 + "For the given 'user', set 'freebusy' offers." 6.352 + 6.353 + return self.set_freebusy(user, freebusy, "freebusy-offers") 6.354 + 6.355 + # Requests and counter-proposals. 6.356 + 6.357 + def get_requests(self, user): 6.358 + 6.359 + "Get requests for the given 'user'." 6.360 + 6.361 + pass 6.362 + 6.363 + def set_requests(self, user, requests): 6.364 + 6.365 + "For the given 'user', set the list of queued 'requests'." 6.366 + 6.367 + pass 6.368 + 6.369 + def set_request(self, user, uid, recurrenceid=None, type=None): 6.370 + 6.371 + """ 6.372 + For the given 'user', set the queued 'uid' and 'recurrenceid', 6.373 + indicating a request, along with any given 'type'. 6.374 + """ 6.375 + 6.376 + pass 6.377 + 6.378 + def queue_request(self, user, uid, recurrenceid=None, type=None): 6.379 + 6.380 + """ 6.381 + Queue a request for 'user' having the given 'uid'. If the optional 6.382 + 'recurrenceid' is specified, the entry refers to a specific instance 6.383 + or occurrence of an event. The 'type' parameter can be used to indicate 6.384 + a specific type of request. 6.385 + """ 6.386 + 6.387 + requests = self.get_requests(user) or [] 6.388 + 6.389 + if not self.have_request(requests, uid, recurrenceid): 6.390 + return self.set_request(user, uid, recurrenceid, type) 6.391 + 6.392 + return False 6.393 + 6.394 + def dequeue_request(self, user, uid, recurrenceid=None): 6.395 + 6.396 + """ 6.397 + Dequeue all requests for 'user' having the given 'uid'. If the optional 6.398 + 'recurrenceid' is specified, all requests for that specific instance or 6.399 + occurrence of an event are dequeued. 6.400 + """ 6.401 + 6.402 + requests = self.get_requests(user) or [] 6.403 + result = [] 6.404 + 6.405 + for request in requests: 6.406 + if request[:2] != (uid, recurrenceid): 6.407 + result.append(request) 6.408 + 6.409 + self.set_requests(user, result) 6.410 + return True 6.411 + 6.412 + def has_request(self, user, uid, recurrenceid=None, type=None, strict=False): 6.413 + return self.have_request(self.get_requests(user) or [], uid, recurrenceid, type, strict) 6.414 + 6.415 + def have_request(self, requests, uid, recurrenceid=None, type=None, strict=False): 6.416 + 6.417 + """ 6.418 + Return whether 'requests' contains a request with the given 'uid' and 6.419 + any specified 'recurrenceid' and 'type'. If 'strict' is set to a true 6.420 + value, the precise type of the request must match; otherwise, any type 6.421 + of request for the identified object may be matched. 6.422 + """ 6.423 + 6.424 + for request in requests: 6.425 + if request[:2] == (uid, recurrenceid) and ( 6.426 + not strict or 6.427 + not request[2:] and not type or 6.428 + request[2:] and request[2] == type): 6.429 + 6.430 + return True 6.431 + 6.432 + return False 6.433 + 6.434 + def get_counters(self, user, uid, recurrenceid=None): 6.435 + 6.436 + """ 6.437 + For the given 'user', return a list of users from whom counter-proposals 6.438 + have been received for the given 'uid' and optional 'recurrenceid'. 6.439 + """ 6.440 + 6.441 + pass 6.442 + 6.443 + def get_counter(self, user, other, uid, recurrenceid=None): 6.444 + 6.445 + """ 6.446 + For the given 'user', return the counter-proposal from 'other' for the 6.447 + given 'uid' and optional 'recurrenceid'. 6.448 + """ 6.449 + 6.450 + pass 6.451 + 6.452 + def set_counter(self, user, other, node, uid, recurrenceid=None): 6.453 + 6.454 + """ 6.455 + For the given 'user', store a counter-proposal received from 'other' the 6.456 + given 'node' representing that proposal for the given 'uid' and 6.457 + 'recurrenceid'. 6.458 + """ 6.459 + 6.460 + pass 6.461 + 6.462 + def remove_counters(self, user, uid, recurrenceid=None): 6.463 + 6.464 + """ 6.465 + For the given 'user', remove all counter-proposals associated with the 6.466 + given 'uid' and 'recurrenceid'. 6.467 + """ 6.468 + 6.469 + pass 6.470 + 6.471 + def remove_counter(self, user, other, uid, recurrenceid=None): 6.472 + 6.473 + """ 6.474 + For the given 'user', remove any counter-proposal from 'other' 6.475 + associated with the given 'uid' and 'recurrenceid'. 6.476 + """ 6.477 + 6.478 + pass 6.479 + 6.480 + # Event cancellation. 6.481 + 6.482 + def cancel_event(self, user, uid, recurrenceid=None): 6.483 + 6.484 + """ 6.485 + Cancel an event for 'user' having the given 'uid'. If the optional 6.486 + 'recurrenceid' is specified, a specific instance or occurrence of an 6.487 + event is cancelled. 6.488 + """ 6.489 + 6.490 + pass 6.491 + 6.492 + def uncancel_event(self, user, uid, recurrenceid=None): 6.493 + 6.494 + """ 6.495 + Uncancel an event for 'user' having the given 'uid'. If the optional 6.496 + 'recurrenceid' is specified, a specific instance or occurrence of an 6.497 + event is uncancelled. 6.498 + """ 6.499 + 6.500 + pass 6.501 + 6.502 + def remove_cancellations(self, user, uid, recurrenceid=None): 6.503 + 6.504 + """ 6.505 + Remove cancellations for 'user' for any event having the given 'uid'. If 6.506 + the optional 'recurrenceid' is specified, a specific instance or 6.507 + occurrence of an event is affected. 6.508 + """ 6.509 + 6.510 + # Remove all recurrence cancellations if a general event is indicated. 6.511 + 6.512 + if not recurrenceid: 6.513 + for _recurrenceid in self.get_cancelled_recurrences(user, uid): 6.514 + self.remove_cancellation(user, uid, _recurrenceid) 6.515 + 6.516 + return self.remove_cancellation(user, uid, recurrenceid) 6.517 + 6.518 + def remove_cancellation(self, user, uid, recurrenceid=None): 6.519 + 6.520 + """ 6.521 + Remove a cancellation for 'user' for the event having the given 'uid'. 6.522 + If the optional 'recurrenceid' is specified, a specific instance or 6.523 + occurrence of an event is affected. 6.524 + """ 6.525 + 6.526 + pass 6.527 + 6.528 +class PublisherBase: 6.529 + 6.530 + "The core operations of a data publisher." 6.531 + 6.532 + def set_freebusy(self, user, freebusy): 6.533 + 6.534 + "For the given 'user', set 'freebusy' details." 6.535 + 6.536 + pass 6.537 + 6.538 +class JournalBase: 6.539 + 6.540 + "The core operations of a journal system supporting quotas." 6.541 + 6.542 + # Quota and user identity/group discovery. 6.543 + 6.544 + def get_quotas(self): 6.545 + 6.546 + "Return a list of quotas." 6.547 + 6.548 + pass 6.549 + 6.550 + def get_quota_users(self, quota): 6.551 + 6.552 + "Return a list of quota users." 6.553 + 6.554 + pass 6.555 + 6.556 + # Groups of users sharing quotas. 6.557 + 6.558 + def get_groups(self, quota): 6.559 + 6.560 + "Return the identity mappings for the given 'quota' as a dictionary." 6.561 + 6.562 + pass 6.563 + 6.564 + def get_limits(self, quota): 6.565 + 6.566 + """ 6.567 + Return the limits for the 'quota' as a dictionary mapping identities or 6.568 + groups to durations. 6.569 + """ 6.570 + 6.571 + pass 6.572 + 6.573 + # Free/busy period access for users within quota groups. 6.574 + 6.575 + def get_freebusy(self, quota, user, mutable=False): 6.576 + 6.577 + "Get free/busy details for the given 'quota' and 'user'." 6.578 + 6.579 + pass 6.580 + 6.581 + def get_freebusy_for_update(self, quota, user): 6.582 + 6.583 + "Get free/busy details for the given 'quota' and 'user'." 6.584 + 6.585 + return self.get_freebusy(quota, user, True) 6.586 + 6.587 + def set_freebusy(self, quota, user, freebusy): 6.588 + 6.589 + "For the given 'quota' and 'user', set 'freebusy' details." 6.590 + 6.591 + pass 6.592 + 6.593 + # Journal entry methods. 6.594 + 6.595 + def get_entries(self, quota, group, mutable=False): 6.596 + 6.597 + """ 6.598 + Return a list of journal entries for the given 'quota' for the indicated 6.599 + 'group'. 6.600 + """ 6.601 + 6.602 + pass 6.603 + 6.604 + def get_entries_for_update(self, quota, group): 6.605 + 6.606 + """ 6.607 + Return a list of journal entries for the given 'quota' for the indicated 6.608 + 'group'. 6.609 + """ 6.610 + 6.611 + return self.get_entries(quota, group, True) 6.612 + 6.613 + def set_entries(self, quota, group, entries): 6.614 + 6.615 + """ 6.616 + For the given 'quota' and indicated 'group', set the list of journal 6.617 + 'entries'. 6.618 + """ 6.619 + 6.620 + pass 6.621 + 6.622 +# vim: tabstop=4 expandtab shiftwidth=4
7.1 --- a/imiptools/stores/database.py Wed Mar 09 21:38:56 2016 +0100 7.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 7.3 @@ -1,845 +0,0 @@ 7.4 -#!/usr/bin/env python 7.5 - 7.6 -""" 7.7 -A database store of calendar data. 7.8 - 7.9 -Copyright (C) 2014, 2015, 2016 Paul Boddie <paul@boddie.org.uk> 7.10 - 7.11 -This program is free software; you can redistribute it and/or modify it under 7.12 -the terms of the GNU General Public License as published by the Free Software 7.13 -Foundation; either version 3 of the License, or (at your option) any later 7.14 -version. 7.15 - 7.16 -This program is distributed in the hope that it will be useful, but WITHOUT 7.17 -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 7.18 -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 7.19 -details. 7.20 - 7.21 -You should have received a copy of the GNU General Public License along with 7.22 -this program. If not, see <http://www.gnu.org/licenses/>. 7.23 -""" 7.24 - 7.25 -from imiptools.stores import StoreBase, JournalBase 7.26 - 7.27 -from datetime import datetime 7.28 -from imiptools.data import parse_string, to_string 7.29 -from imiptools.dates import format_datetime, get_datetime, to_timezone 7.30 -from imiptools.period import FreeBusyPeriod, FreeBusyDatabaseCollection 7.31 -from imiptools.sql import DatabaseOperations 7.32 - 7.33 -class DatabaseStoreBase: 7.34 - 7.35 - "A database store supporting user-specific locking." 7.36 - 7.37 - def __init__(self, connection, paramstyle=None): 7.38 - DatabaseOperations.__init__(self, paramstyle=paramstyle) 7.39 - self.connection = connection 7.40 - self.cursor = connection.cursor() 7.41 - 7.42 - def acquire_lock(self, user, timeout=None): 7.43 - pass 7.44 - 7.45 - def release_lock(self, user): 7.46 - pass 7.47 - 7.48 -class DatabaseStore(DatabaseStoreBase, StoreBase, DatabaseOperations): 7.49 - 7.50 - "A database store of tabular free/busy data and objects." 7.51 - 7.52 - # User discovery. 7.53 - 7.54 - def get_users(self): 7.55 - 7.56 - "Return a list of users." 7.57 - 7.58 - query = "select distinct store_user from freebusy" 7.59 - self.cursor.execute(query) 7.60 - return [r[0] for r in self.cursor.fetchall()] 7.61 - 7.62 - # Event and event metadata access. 7.63 - 7.64 - def get_events(self, user): 7.65 - 7.66 - "Return a list of event identifiers." 7.67 - 7.68 - columns = ["store_user", "status"] 7.69 - values = [user, "active"] 7.70 - 7.71 - query, values = self.get_query( 7.72 - "select object_uid from objects :condition", 7.73 - columns, values) 7.74 - 7.75 - self.cursor.execute(query, values) 7.76 - return [r[0] for r in self.cursor.fetchall()] 7.77 - 7.78 - def get_all_events(self, user): 7.79 - 7.80 - "Return a set of (uid, recurrenceid) tuples for all events." 7.81 - 7.82 - query, values = self.get_query( 7.83 - "select object_uid, null as object_recurrenceid from objects :condition " 7.84 - "union all " 7.85 - "select object_uid, object_recurrenceid from recurrences :condition", 7.86 - ["store_user"], [user]) 7.87 - 7.88 - self.cursor.execute(query, values) 7.89 - return self.cursor.fetchall() 7.90 - 7.91 - def get_event_table(self, recurrenceid=None, dirname=None): 7.92 - 7.93 - "Get the table providing events for any specified 'dirname'." 7.94 - 7.95 - if recurrenceid: 7.96 - return self.get_recurrence_table(dirname) 7.97 - else: 7.98 - return self.get_complete_event_table(dirname) 7.99 - 7.100 - def get_event_table_filters(self, dirname=None): 7.101 - 7.102 - "Get filter details for any specified 'dirname'." 7.103 - 7.104 - if dirname == "cancellations": 7.105 - return ["status"], ["cancelled"] 7.106 - else: 7.107 - return [], [] 7.108 - 7.109 - def get_event(self, user, uid, recurrenceid=None, dirname=None): 7.110 - 7.111 - """ 7.112 - Get the event for the given 'user' with the given 'uid'. If 7.113 - the optional 'recurrenceid' is specified, a specific instance or 7.114 - occurrence of an event is returned. 7.115 - """ 7.116 - 7.117 - table = self.get_event_table(recurrenceid, dirname) 7.118 - columns, values = self.get_event_table_filters(dirname) 7.119 - 7.120 - if recurrenceid: 7.121 - columns += ["store_user", "object_uid", "object_recurrenceid"] 7.122 - values += [user, uid, recurrenceid] 7.123 - else: 7.124 - columns += ["store_user", "object_uid"] 7.125 - values += [user, uid] 7.126 - 7.127 - query, values = self.get_query( 7.128 - "select object_text from %(table)s :condition" % { 7.129 - "table" : table 7.130 - }, 7.131 - columns, values) 7.132 - 7.133 - self.cursor.execute(query, values) 7.134 - result = self.cursor.fetchone() 7.135 - return result and parse_string(result[0], "utf-8") 7.136 - 7.137 - def get_complete_event_table(self, dirname=None): 7.138 - 7.139 - "Get the table providing events for any specified 'dirname'." 7.140 - 7.141 - if dirname == "counters": 7.142 - return "countered_objects" 7.143 - else: 7.144 - return "objects" 7.145 - 7.146 - def get_complete_event(self, user, uid): 7.147 - 7.148 - "Get the event for the given 'user' with the given 'uid'." 7.149 - 7.150 - columns = ["store_user", "object_uid"] 7.151 - values = [user, uid] 7.152 - 7.153 - query, values = self.get_query( 7.154 - "select object_text from objects :condition", 7.155 - columns, values) 7.156 - 7.157 - self.cursor.execute(query, values) 7.158 - result = self.cursor.fetchone() 7.159 - return result and parse_string(result[0], "utf-8") 7.160 - 7.161 - def set_complete_event(self, user, uid, node): 7.162 - 7.163 - "Set an event for 'user' having the given 'uid' and 'node'." 7.164 - 7.165 - columns = ["store_user", "object_uid"] 7.166 - values = [user, uid] 7.167 - setcolumns = ["object_text", "status"] 7.168 - setvalues = [to_string(node, "utf-8"), "active"] 7.169 - 7.170 - query, values = self.get_query( 7.171 - "update objects :set :condition", 7.172 - columns, values, setcolumns, setvalues) 7.173 - 7.174 - self.cursor.execute(query, values) 7.175 - 7.176 - if self.cursor.rowcount > 0 or self.get_complete_event(user, uid): 7.177 - return True 7.178 - 7.179 - columns = ["store_user", "object_uid", "object_text", "status"] 7.180 - values = [user, uid, to_string(node, "utf-8"), "active"] 7.181 - 7.182 - query, values = self.get_query( 7.183 - "insert into objects (:columns) values (:values)", 7.184 - columns, values) 7.185 - 7.186 - self.cursor.execute(query, values) 7.187 - return True 7.188 - 7.189 - def remove_parent_event(self, user, uid): 7.190 - 7.191 - "Remove the parent event for 'user' having the given 'uid'." 7.192 - 7.193 - columns = ["store_user", "object_uid"] 7.194 - values = [user, uid] 7.195 - 7.196 - query, values = self.get_query( 7.197 - "delete from objects :condition", 7.198 - columns, values) 7.199 - 7.200 - self.cursor.execute(query, values) 7.201 - return self.cursor.rowcount > 0 7.202 - 7.203 - def get_active_recurrences(self, user, uid): 7.204 - 7.205 - """ 7.206 - Get additional event instances for an event of the given 'user' with the 7.207 - indicated 'uid'. Cancelled recurrences are not returned. 7.208 - """ 7.209 - 7.210 - columns = ["store_user", "object_uid", "status"] 7.211 - values = [user, uid, "active"] 7.212 - 7.213 - query, values = self.get_query( 7.214 - "select object_recurrenceid from recurrences :condition", 7.215 - columns, values) 7.216 - 7.217 - self.cursor.execute(query, values) 7.218 - return [t[0] for t in self.cursor.fetchall() or []] 7.219 - 7.220 - def get_cancelled_recurrences(self, user, uid): 7.221 - 7.222 - """ 7.223 - Get additional event instances for an event of the given 'user' with the 7.224 - indicated 'uid'. Only cancelled recurrences are returned. 7.225 - """ 7.226 - 7.227 - columns = ["store_user", "object_uid", "status"] 7.228 - values = [user, uid, "cancelled"] 7.229 - 7.230 - query, values = self.get_query( 7.231 - "select object_recurrenceid from recurrences :condition", 7.232 - columns, values) 7.233 - 7.234 - self.cursor.execute(query, values) 7.235 - return [t[0] for t in self.cursor.fetchall() or []] 7.236 - 7.237 - def get_recurrence_table(self, dirname=None): 7.238 - 7.239 - "Get the table providing recurrences for any specified 'dirname'." 7.240 - 7.241 - if dirname == "counters": 7.242 - return "countered_recurrences" 7.243 - else: 7.244 - return "recurrences" 7.245 - 7.246 - def get_recurrence(self, user, uid, recurrenceid): 7.247 - 7.248 - """ 7.249 - For the event of the given 'user' with the given 'uid', return the 7.250 - specific recurrence indicated by the 'recurrenceid'. 7.251 - """ 7.252 - 7.253 - columns = ["store_user", "object_uid", "object_recurrenceid"] 7.254 - values = [user, uid, recurrenceid] 7.255 - 7.256 - query, values = self.get_query( 7.257 - "select object_text from recurrences :condition", 7.258 - columns, values) 7.259 - 7.260 - self.cursor.execute(query, values) 7.261 - result = self.cursor.fetchone() 7.262 - return result and parse_string(result[0], "utf-8") 7.263 - 7.264 - def set_recurrence(self, user, uid, recurrenceid, node): 7.265 - 7.266 - "Set an event for 'user' having the given 'uid' and 'node'." 7.267 - 7.268 - columns = ["store_user", "object_uid", "object_recurrenceid"] 7.269 - values = [user, uid, recurrenceid] 7.270 - setcolumns = ["object_text", "status"] 7.271 - setvalues = [to_string(node, "utf-8"), "active"] 7.272 - 7.273 - query, values = self.get_query( 7.274 - "update recurrences :set :condition", 7.275 - columns, values, setcolumns, setvalues) 7.276 - 7.277 - self.cursor.execute(query, values) 7.278 - 7.279 - if self.cursor.rowcount > 0 or self.get_recurrence(user, uid, recurrenceid): 7.280 - return True 7.281 - 7.282 - columns = ["store_user", "object_uid", "object_recurrenceid", "object_text", "status"] 7.283 - values = [user, uid, recurrenceid, to_string(node, "utf-8"), "active"] 7.284 - 7.285 - query, values = self.get_query( 7.286 - "insert into recurrences (:columns) values (:values)", 7.287 - columns, values) 7.288 - 7.289 - self.cursor.execute(query, values) 7.290 - return True 7.291 - 7.292 - def remove_recurrence(self, user, uid, recurrenceid): 7.293 - 7.294 - """ 7.295 - Remove a special recurrence from an event stored by 'user' having the 7.296 - given 'uid' and 'recurrenceid'. 7.297 - """ 7.298 - 7.299 - columns = ["store_user", "object_uid", "object_recurrenceid"] 7.300 - values = [user, uid, recurrenceid] 7.301 - 7.302 - query, values = self.get_query( 7.303 - "delete from recurrences :condition", 7.304 - columns, values) 7.305 - 7.306 - self.cursor.execute(query, values) 7.307 - return True 7.308 - 7.309 - def remove_recurrences(self, user, uid): 7.310 - 7.311 - """ 7.312 - Remove all recurrences for an event stored by 'user' having the given 7.313 - 'uid'. 7.314 - """ 7.315 - 7.316 - columns = ["store_user", "object_uid"] 7.317 - values = [user, uid] 7.318 - 7.319 - query, values = self.get_query( 7.320 - "delete from recurrences :condition", 7.321 - columns, values) 7.322 - 7.323 - self.cursor.execute(query, values) 7.324 - return True 7.325 - 7.326 - # Free/busy period providers, upon extension of the free/busy records. 7.327 - 7.328 - def _get_freebusy_providers(self, user): 7.329 - 7.330 - """ 7.331 - Return the free/busy providers for the given 'user'. 7.332 - 7.333 - This function returns any stored datetime and a list of providers as a 7.334 - 2-tuple. Each provider is itself a (uid, recurrenceid) tuple. 7.335 - """ 7.336 - 7.337 - columns = ["store_user"] 7.338 - values = [user] 7.339 - 7.340 - query, values = self.get_query( 7.341 - "select object_uid, object_recurrenceid from freebusy_providers :condition", 7.342 - columns, values) 7.343 - 7.344 - self.cursor.execute(query, values) 7.345 - providers = self.cursor.fetchall() 7.346 - 7.347 - columns = ["store_user"] 7.348 - values = [user] 7.349 - 7.350 - query, values = self.get_query( 7.351 - "select start from freebusy_provider_datetimes :condition", 7.352 - columns, values) 7.353 - 7.354 - self.cursor.execute(query, values) 7.355 - result = self.cursor.fetchone() 7.356 - dt_string = result and result[0] 7.357 - 7.358 - return dt_string, providers 7.359 - 7.360 - def _set_freebusy_providers(self, user, dt_string, t): 7.361 - 7.362 - "Set the given provider timestamp 'dt_string' and table 't'." 7.363 - 7.364 - # NOTE: Locking? 7.365 - 7.366 - columns = ["store_user"] 7.367 - values = [user] 7.368 - 7.369 - query, values = self.get_query( 7.370 - "delete from freebusy_providers :condition", 7.371 - columns, values) 7.372 - 7.373 - self.cursor.execute(query, values) 7.374 - 7.375 - columns = ["store_user", "object_uid", "object_recurrenceid"] 7.376 - 7.377 - for uid, recurrenceid in t: 7.378 - values = [user, uid, recurrenceid] 7.379 - 7.380 - query, values = self.get_query( 7.381 - "insert into freebusy_providers (:columns) values (:values)", 7.382 - columns, values) 7.383 - 7.384 - self.cursor.execute(query, values) 7.385 - 7.386 - columns = ["store_user"] 7.387 - values = [user] 7.388 - setcolumns = ["start"] 7.389 - setvalues = [dt_string] 7.390 - 7.391 - query, values = self.get_query( 7.392 - "update freebusy_provider_datetimes :set :condition", 7.393 - columns, values, setcolumns, setvalues) 7.394 - 7.395 - self.cursor.execute(query, values) 7.396 - 7.397 - if self.cursor.rowcount > 0: 7.398 - return True 7.399 - 7.400 - columns = ["store_user", "start"] 7.401 - values = [user, dt_string] 7.402 - 7.403 - query, values = self.get_query( 7.404 - "insert into freebusy_provider_datetimes (:columns) values (:values)", 7.405 - columns, values) 7.406 - 7.407 - self.cursor.execute(query, values) 7.408 - return True 7.409 - 7.410 - # Free/busy period access. 7.411 - 7.412 - def get_freebusy(self, user, name=None, mutable=False): 7.413 - 7.414 - "Get free/busy details for the given 'user'." 7.415 - 7.416 - table = name or "freebusy" 7.417 - return FreeBusyDatabaseCollection(self.cursor, table, ["store_user"], [user], mutable, self.paramstyle) 7.418 - 7.419 - def get_freebusy_for_other(self, user, other, mutable=False): 7.420 - 7.421 - "For the given 'user', get free/busy details for the 'other' user." 7.422 - 7.423 - table = "freebusy" 7.424 - return FreeBusyDatabaseCollection(self.cursor, table, ["store_user", "other"], [user, other], mutable, self.paramstyle) 7.425 - 7.426 - def set_freebusy(self, user, freebusy, name=None): 7.427 - 7.428 - "For the given 'user', set 'freebusy' details." 7.429 - 7.430 - table = name or "freebusy" 7.431 - 7.432 - if not isinstance(freebusy, FreeBusyDatabaseCollection) or freebusy.table_name != table: 7.433 - fbc = FreeBusyDatabaseCollection(self.cursor, table, ["store_user"], [user], True, self.paramstyle) 7.434 - fbc += freebusy 7.435 - 7.436 - return True 7.437 - 7.438 - def set_freebusy_for_other(self, user, freebusy, other): 7.439 - 7.440 - "For the given 'user', set 'freebusy' details for the 'other' user." 7.441 - 7.442 - table = "freebusy" 7.443 - 7.444 - if not isinstance(freebusy, FreeBusyDatabaseCollection) or freebusy.table_name != table: 7.445 - fbc = FreeBusyDatabaseCollection(self.cursor, table, ["store_user", "other"], [user, other], True, self.paramstyle) 7.446 - fbc += freebusy 7.447 - 7.448 - return True 7.449 - 7.450 - # Tentative free/busy periods related to countering. 7.451 - 7.452 - def get_freebusy_offers(self, user, mutable=False): 7.453 - 7.454 - "Get free/busy offers for the given 'user'." 7.455 - 7.456 - # Expire old offers and save the collection if modified. 7.457 - 7.458 - now = format_datetime(to_timezone(datetime.utcnow(), "UTC")) 7.459 - columns = ["store_user", "expires"] 7.460 - values = [user, now] 7.461 - 7.462 - query, values = self.get_query( 7.463 - "delete from freebusy_offers :condition", 7.464 - columns, values) 7.465 - 7.466 - self.cursor.execute(query, values) 7.467 - 7.468 - return self.get_freebusy(user, "freebusy_offers", mutable) 7.469 - 7.470 - # Requests and counter-proposals. 7.471 - 7.472 - def get_requests(self, user): 7.473 - 7.474 - "Get requests for the given 'user'." 7.475 - 7.476 - columns = ["store_user"] 7.477 - values = [user] 7.478 - 7.479 - query, values = self.get_query( 7.480 - "select object_uid, object_recurrenceid from requests :condition", 7.481 - columns, values) 7.482 - 7.483 - self.cursor.execute(query, values) 7.484 - return self.cursor.fetchall() 7.485 - 7.486 - def set_requests(self, user, requests): 7.487 - 7.488 - "For the given 'user', set the list of queued 'requests'." 7.489 - 7.490 - # NOTE: Locking? 7.491 - 7.492 - columns = ["store_user"] 7.493 - values = [user] 7.494 - 7.495 - query, values = self.get_query( 7.496 - "delete from requests :condition", 7.497 - columns, values) 7.498 - 7.499 - self.cursor.execute(query, values) 7.500 - 7.501 - for uid, recurrenceid, type in requests: 7.502 - columns = ["store_user", "object_uid", "object_recurrenceid", "request_type"] 7.503 - values = [user, uid, recurrenceid, type] 7.504 - 7.505 - query, values = self.get_query( 7.506 - "insert into requests (:columns) values (:values)", 7.507 - columns, values) 7.508 - 7.509 - self.cursor.execute(query, values) 7.510 - 7.511 - return True 7.512 - 7.513 - def set_request(self, user, uid, recurrenceid=None, type=None): 7.514 - 7.515 - """ 7.516 - For the given 'user', set the queued 'uid' and 'recurrenceid', 7.517 - indicating a request, along with any given 'type'. 7.518 - """ 7.519 - 7.520 - columns = ["store_user", "object_uid", "object_recurrenceid", "request_type"] 7.521 - values = [user, uid, recurrenceid, type] 7.522 - 7.523 - query, values = self.get_query( 7.524 - "insert into requests (:columns) values (:values)", 7.525 - columns, values) 7.526 - 7.527 - self.cursor.execute(query, values) 7.528 - return True 7.529 - 7.530 - def get_counters(self, user, uid, recurrenceid=None): 7.531 - 7.532 - """ 7.533 - For the given 'user', return a list of users from whom counter-proposals 7.534 - have been received for the given 'uid' and optional 'recurrenceid'. 7.535 - """ 7.536 - 7.537 - table = self.get_event_table(recurrenceid, "counters") 7.538 - 7.539 - if recurrenceid: 7.540 - columns = ["store_user", "object_uid", "object_recurrenceid"] 7.541 - values = [user, uid, recurrenceid] 7.542 - else: 7.543 - columns = ["store_user", "object_uid"] 7.544 - values = [user, uid] 7.545 - 7.546 - query, values = self.get_query( 7.547 - "select other from %(table)s :condition" % { 7.548 - "table" : table 7.549 - }, 7.550 - columns, values) 7.551 - 7.552 - self.cursor.execute(query, values) 7.553 - return self.cursor.fetchall() 7.554 - 7.555 - def get_counter(self, user, other, uid, recurrenceid=None): 7.556 - 7.557 - """ 7.558 - For the given 'user', return the counter-proposal from 'other' for the 7.559 - given 'uid' and optional 'recurrenceid'. 7.560 - """ 7.561 - 7.562 - table = self.get_event_table(recurrenceid, "counters") 7.563 - 7.564 - if recurrenceid: 7.565 - columns = ["store_user", "other", "object_uid", "object_recurrenceid"] 7.566 - values = [user, other, uid, recurrenceid] 7.567 - else: 7.568 - columns = ["store_user", "other", "object_uid"] 7.569 - values = [user, other, uid] 7.570 - 7.571 - query, values = self.get_query( 7.572 - "select object_text from %(table)s :condition" % { 7.573 - "table" : table 7.574 - }, 7.575 - columns, values) 7.576 - 7.577 - self.cursor.execute(query, values) 7.578 - result = self.cursor.fetchall() 7.579 - return result and parse_string(result[0], "utf-8") 7.580 - 7.581 - def set_counter(self, user, other, node, uid, recurrenceid=None): 7.582 - 7.583 - """ 7.584 - For the given 'user', store a counter-proposal received from 'other' the 7.585 - given 'node' representing that proposal for the given 'uid' and 7.586 - 'recurrenceid'. 7.587 - """ 7.588 - 7.589 - table = self.get_event_table(recurrenceid, "counters") 7.590 - 7.591 - columns = ["store_user", "other", "object_uid", "object_recurrenceid", "object_text"] 7.592 - values = [user, other, uid, recurrenceid, to_string(node, "utf-8")] 7.593 - 7.594 - query, values = self.get_query( 7.595 - "insert into %(table)s (:columns) values (:values)" % { 7.596 - "table" : table 7.597 - }, 7.598 - columns, values) 7.599 - 7.600 - self.cursor.execute(query, values) 7.601 - return True 7.602 - 7.603 - def remove_counters(self, user, uid, recurrenceid=None): 7.604 - 7.605 - """ 7.606 - For the given 'user', remove all counter-proposals associated with the 7.607 - given 'uid' and 'recurrenceid'. 7.608 - """ 7.609 - 7.610 - table = self.get_event_table(recurrenceid, "counters") 7.611 - 7.612 - if recurrenceid: 7.613 - columns = ["store_user", "object_uid", "object_recurrenceid"] 7.614 - values = [user, uid, recurrenceid] 7.615 - else: 7.616 - columns = ["store_user", "object_uid"] 7.617 - values = [user, uid] 7.618 - 7.619 - query, values = self.get_query( 7.620 - "delete from %(table)s :condition" % { 7.621 - "table" : table 7.622 - }, 7.623 - columns, values) 7.624 - 7.625 - self.cursor.execute(query, values) 7.626 - return True 7.627 - 7.628 - def remove_counter(self, user, other, uid, recurrenceid=None): 7.629 - 7.630 - """ 7.631 - For the given 'user', remove any counter-proposal from 'other' 7.632 - associated with the given 'uid' and 'recurrenceid'. 7.633 - """ 7.634 - 7.635 - table = self.get_event_table(recurrenceid, "counters") 7.636 - 7.637 - if recurrenceid: 7.638 - columns = ["store_user", "other", "object_uid", "object_recurrenceid"] 7.639 - values = [user, other, uid, recurrenceid] 7.640 - else: 7.641 - columns = ["store_user", "other", "object_uid"] 7.642 - values = [user, other, uid] 7.643 - 7.644 - query, values = self.get_query( 7.645 - "delete from %(table)s :condition" % { 7.646 - "table" : table 7.647 - }, 7.648 - columns, values) 7.649 - 7.650 - self.cursor.execute(query, values) 7.651 - return True 7.652 - 7.653 - # Event cancellation. 7.654 - 7.655 - def cancel_event(self, user, uid, recurrenceid=None): 7.656 - 7.657 - """ 7.658 - Cancel an event for 'user' having the given 'uid'. If the optional 7.659 - 'recurrenceid' is specified, a specific instance or occurrence of an 7.660 - event is cancelled. 7.661 - """ 7.662 - 7.663 - table = self.get_event_table(recurrenceid) 7.664 - 7.665 - if recurrenceid: 7.666 - columns = ["store_user", "object_uid", "object_recurrenceid"] 7.667 - values = [user, uid, recurrenceid] 7.668 - else: 7.669 - columns = ["store_user", "object_uid"] 7.670 - values = [user, uid] 7.671 - 7.672 - setcolumns = ["status"] 7.673 - setvalues = ["cancelled"] 7.674 - 7.675 - query, values = self.get_query( 7.676 - "update %(table)s :set :condition" % { 7.677 - "table" : table 7.678 - }, 7.679 - columns, values, setcolumns, setvalues) 7.680 - 7.681 - self.cursor.execute(query, values) 7.682 - return True 7.683 - 7.684 - def uncancel_event(self, user, uid, recurrenceid=None): 7.685 - 7.686 - """ 7.687 - Uncancel an event for 'user' having the given 'uid'. If the optional 7.688 - 'recurrenceid' is specified, a specific instance or occurrence of an 7.689 - event is uncancelled. 7.690 - """ 7.691 - 7.692 - table = self.get_event_table(recurrenceid) 7.693 - 7.694 - if recurrenceid: 7.695 - columns = ["store_user", "object_uid", "object_recurrenceid"] 7.696 - values = [user, uid, recurrenceid] 7.697 - else: 7.698 - columns = ["store_user", "object_uid"] 7.699 - values = [user, uid] 7.700 - 7.701 - setcolumns = ["status"] 7.702 - setvalues = ["active"] 7.703 - 7.704 - query, values = self.get_query( 7.705 - "update %(table)s :set :condition" % { 7.706 - "table" : table 7.707 - }, 7.708 - columns, values, setcolumns, setvalues) 7.709 - 7.710 - self.cursor.execute(query, values) 7.711 - return True 7.712 - 7.713 - def remove_cancellation(self, user, uid, recurrenceid=None): 7.714 - 7.715 - """ 7.716 - Remove a cancellation for 'user' for the event having the given 'uid'. 7.717 - If the optional 'recurrenceid' is specified, a specific instance or 7.718 - occurrence of an event is affected. 7.719 - """ 7.720 - 7.721 - table = self.get_event_table(recurrenceid) 7.722 - 7.723 - if recurrenceid: 7.724 - columns = ["store_user", "object_uid", "object_recurrenceid", "status"] 7.725 - values = [user, uid, recurrenceid, "cancelled"] 7.726 - else: 7.727 - columns = ["store_user", "object_uid", "status"] 7.728 - values = [user, uid, "cancelled"] 7.729 - 7.730 - query, values = self.get_query( 7.731 - "delete from %(table)s :condition" % { 7.732 - "table" : table 7.733 - }, 7.734 - columns, values) 7.735 - 7.736 - self.cursor.execute(query, values) 7.737 - return True 7.738 - 7.739 -class DatabaseJournal(DatabaseStoreBase, JournalBase): 7.740 - 7.741 - "A journal system to support quotas." 7.742 - 7.743 - # Quota and user identity/group discovery. 7.744 - 7.745 - def get_quotas(self): 7.746 - 7.747 - "Return a list of quotas." 7.748 - 7.749 - query = "select distinct journal_quota from quota_freebusy" 7.750 - self.cursor.execute(query) 7.751 - return [r[0] for r in self.cursor.fetchall()] 7.752 - 7.753 - def get_quota_users(self, quota): 7.754 - 7.755 - "Return a list of quota users." 7.756 - 7.757 - columns = ["quota"] 7.758 - values = [quota] 7.759 - 7.760 - query, values = self.get_query( 7.761 - "select distinct user_group from quota_freebusy :condition", 7.762 - columns, values) 7.763 - 7.764 - self.cursor.execute(query) 7.765 - return [r[0] for r in self.cursor.fetchall()] 7.766 - 7.767 - # Groups of users sharing quotas. 7.768 - 7.769 - def get_groups(self, quota): 7.770 - 7.771 - "Return the identity mappings for the given 'quota' as a dictionary." 7.772 - 7.773 - columns = ["quota"] 7.774 - values = [quota] 7.775 - 7.776 - query, values = self.get_query( 7.777 - "select store_user, user_group from user_groups :condition", 7.778 - columns, values) 7.779 - 7.780 - self.cursor.execute(query) 7.781 - return dict(self.cursor.fetchall()) 7.782 - 7.783 - def get_limits(self, quota): 7.784 - 7.785 - """ 7.786 - Return the limits for the 'quota' as a dictionary mapping identities or 7.787 - groups to durations. 7.788 - """ 7.789 - 7.790 - columns = ["quota"] 7.791 - values = [quota] 7.792 - 7.793 - query, values = self.get_query( 7.794 - "select user_group, quota_limit from quota_limits :condition", 7.795 - columns, values) 7.796 - 7.797 - self.cursor.execute(query) 7.798 - return dict(self.cursor.fetchall()) 7.799 - 7.800 - # Free/busy period access for users within quota groups. 7.801 - 7.802 - def get_freebusy(self, quota, user, mutable=False): 7.803 - 7.804 - "Get free/busy details for the given 'quota' and 'user'." 7.805 - 7.806 - table = "user_freebusy" 7.807 - return FreeBusyDatabaseCollection(self.cursor, table, ["quota", "store_user"], [quota, user], mutable, self.paramstyle) 7.808 - 7.809 - def set_freebusy(self, quota, user, freebusy): 7.810 - 7.811 - "For the given 'quota' and 'user', set 'freebusy' details." 7.812 - 7.813 - table = "user_freebusy" 7.814 - 7.815 - if not isinstance(freebusy, FreeBusyDatabaseCollection) or freebusy.table_name != table: 7.816 - fbc = FreeBusyDatabaseCollection(self.cursor, table, ["quota", "store_user"], [quota, user], True, self.paramstyle) 7.817 - fbc += freebusy 7.818 - 7.819 - return True 7.820 - 7.821 - # Journal entry methods. 7.822 - 7.823 - def get_entries(self, quota, group, mutable=False): 7.824 - 7.825 - """ 7.826 - Return a list of journal entries for the given 'quota' for the indicated 7.827 - 'group'. 7.828 - """ 7.829 - 7.830 - table = "quota_freebusy" 7.831 - return FreeBusyDatabaseCollection(self.cursor, table, ["quota", "user_group"], [quota, group], mutable, self.paramstyle) 7.832 - 7.833 - def set_entries(self, quota, group, entries): 7.834 - 7.835 - """ 7.836 - For the given 'quota' and indicated 'group', set the list of journal 7.837 - 'entries'. 7.838 - """ 7.839 - 7.840 - table = "quota_freebusy" 7.841 - 7.842 - if not isinstance(entries, FreeBusyDatabaseCollection) or entries.table_name != table: 7.843 - fbc = FreeBusyDatabaseCollection(self.cursor, table, ["quota", "user_group"], [quota, group], True, self.paramstyle) 7.844 - fbc += entries 7.845 - 7.846 - return True 7.847 - 7.848 -# vim: tabstop=4 expandtab shiftwidth=4
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/imiptools/stores/database/__init__.py Thu Mar 10 01:43:31 2016 +0100 8.3 @@ -0,0 +1,28 @@ 8.4 +#!/usr/bin/env python 8.5 + 8.6 +""" 8.7 +General support for database stores. 8.8 + 8.9 +Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk> 8.10 + 8.11 +This program is free software; you can redistribute it and/or modify it under 8.12 +the terms of the GNU General Public License as published by the Free Software 8.13 +Foundation; either version 3 of the License, or (at your option) any later 8.14 +version. 8.15 + 8.16 +This program is distributed in the hope that it will be useful, but WITHOUT 8.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 8.19 +details. 8.20 + 8.21 +You should have received a copy of the GNU General Public License along with 8.22 +this program. If not, see <http://www.gnu.org/licenses/>. 8.23 +""" 8.24 + 8.25 +from imiptools.stores.database import postgresql 8.26 + 8.27 +stores = { 8.28 + "postgresql" : postgresql, 8.29 + } 8.30 + 8.31 +# vim: tabstop=4 expandtab shiftwidth=4
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/imiptools/stores/database/common.py Thu Mar 10 01:43:31 2016 +0100 9.3 @@ -0,0 +1,880 @@ 9.4 +#!/usr/bin/env python 9.5 + 9.6 +""" 9.7 +A database store of calendar data. 9.8 + 9.9 +Copyright (C) 2014, 2015, 2016 Paul Boddie <paul@boddie.org.uk> 9.10 + 9.11 +This program is free software; you can redistribute it and/or modify it under 9.12 +the terms of the GNU General Public License as published by the Free Software 9.13 +Foundation; either version 3 of the License, or (at your option) any later 9.14 +version. 9.15 + 9.16 +This program is distributed in the hope that it will be useful, but WITHOUT 9.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 9.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 9.19 +details. 9.20 + 9.21 +You should have received a copy of the GNU General Public License along with 9.22 +this program. If not, see <http://www.gnu.org/licenses/>. 9.23 +""" 9.24 + 9.25 +from imiptools.stores.common import StoreBase, JournalBase 9.26 + 9.27 +from datetime import datetime 9.28 +from imiptools.data import parse_string, to_string 9.29 +from imiptools.dates import format_datetime, get_datetime, to_timezone 9.30 +from imiptools.period import FreeBusyDatabaseCollection 9.31 +from imiptools.sql import DatabaseOperations 9.32 + 9.33 +class DatabaseStoreBase(DatabaseOperations): 9.34 + 9.35 + "A database store supporting user-specific locking." 9.36 + 9.37 + def __init__(self, connection, paramstyle=None): 9.38 + DatabaseOperations.__init__(self, paramstyle=paramstyle) 9.39 + self.connection = connection 9.40 + self.cursor = connection.cursor() 9.41 + 9.42 + def acquire_lock(self, user, timeout=None): 9.43 + pass 9.44 + 9.45 + def release_lock(self, user): 9.46 + pass 9.47 + 9.48 +class DatabaseStore(DatabaseStoreBase, StoreBase): 9.49 + 9.50 + "A database store of tabular free/busy data and objects." 9.51 + 9.52 + # User discovery. 9.53 + 9.54 + def get_users(self): 9.55 + 9.56 + "Return a list of users." 9.57 + 9.58 + query = "select distinct store_user from freebusy" 9.59 + self.cursor.execute(query) 9.60 + return [r[0] for r in self.cursor.fetchall()] 9.61 + 9.62 + # Event and event metadata access. 9.63 + 9.64 + def get_events(self, user): 9.65 + 9.66 + "Return a list of event identifiers." 9.67 + 9.68 + columns = ["store_user", "status"] 9.69 + values = [user, "active"] 9.70 + 9.71 + query, values = self.get_query( 9.72 + "select object_uid from objects :condition", 9.73 + columns, values) 9.74 + 9.75 + self.cursor.execute(query, values) 9.76 + return [r[0] for r in self.cursor.fetchall()] 9.77 + 9.78 + def get_all_events(self, user): 9.79 + 9.80 + "Return a set of (uid, recurrenceid) tuples for all events." 9.81 + 9.82 + query, values = self.get_query( 9.83 + "select object_uid, null as object_recurrenceid from objects :condition " 9.84 + "union all " 9.85 + "select object_uid, object_recurrenceid from recurrences :condition", 9.86 + ["store_user"], [user]) 9.87 + 9.88 + self.cursor.execute(query, values) 9.89 + return self.cursor.fetchall() 9.90 + 9.91 + def get_event_table(self, recurrenceid=None, dirname=None): 9.92 + 9.93 + "Get the table providing events for any specified 'dirname'." 9.94 + 9.95 + if recurrenceid: 9.96 + return self.get_recurrence_table(dirname) 9.97 + else: 9.98 + return self.get_complete_event_table(dirname) 9.99 + 9.100 + def get_event_table_filters(self, dirname=None): 9.101 + 9.102 + "Get filter details for any specified 'dirname'." 9.103 + 9.104 + if dirname == "cancellations": 9.105 + return ["status"], ["cancelled"] 9.106 + else: 9.107 + return ["status"], ["active"] 9.108 + 9.109 + def get_event(self, user, uid, recurrenceid=None, dirname=None): 9.110 + 9.111 + """ 9.112 + Get the event for the given 'user' with the given 'uid'. If 9.113 + the optional 'recurrenceid' is specified, a specific instance or 9.114 + occurrence of an event is returned. 9.115 + """ 9.116 + 9.117 + table = self.get_event_table(recurrenceid, dirname) 9.118 + columns, values = self.get_event_table_filters(dirname) 9.119 + 9.120 + if recurrenceid: 9.121 + columns += ["store_user", "object_uid", "object_recurrenceid"] 9.122 + values += [user, uid, recurrenceid] 9.123 + else: 9.124 + columns += ["store_user", "object_uid"] 9.125 + values += [user, uid] 9.126 + 9.127 + query, values = self.get_query( 9.128 + "select object_text from %(table)s :condition" % { 9.129 + "table" : table 9.130 + }, 9.131 + columns, values) 9.132 + 9.133 + self.cursor.execute(query, values) 9.134 + result = self.cursor.fetchone() 9.135 + return result and parse_string(result[0], "utf-8") 9.136 + 9.137 + def get_complete_event_table(self, dirname=None): 9.138 + 9.139 + "Get the table providing events for any specified 'dirname'." 9.140 + 9.141 + if dirname == "counters": 9.142 + return "countered_objects" 9.143 + else: 9.144 + return "objects" 9.145 + 9.146 + def get_complete_event(self, user, uid): 9.147 + 9.148 + "Get the event for the given 'user' with the given 'uid'." 9.149 + 9.150 + columns = ["store_user", "object_uid"] 9.151 + values = [user, uid] 9.152 + 9.153 + query, values = self.get_query( 9.154 + "select object_text from objects :condition", 9.155 + columns, values) 9.156 + 9.157 + self.cursor.execute(query, values) 9.158 + result = self.cursor.fetchone() 9.159 + return result and parse_string(result[0], "utf-8") 9.160 + 9.161 + def set_complete_event(self, user, uid, node): 9.162 + 9.163 + "Set an event for 'user' having the given 'uid' and 'node'." 9.164 + 9.165 + columns = ["store_user", "object_uid"] 9.166 + values = [user, uid] 9.167 + setcolumns = ["object_text", "status"] 9.168 + setvalues = [to_string(node, "utf-8"), "active"] 9.169 + 9.170 + query, values = self.get_query( 9.171 + "update objects :set :condition", 9.172 + columns, values, setcolumns, setvalues) 9.173 + 9.174 + self.cursor.execute(query, values) 9.175 + 9.176 + if self.cursor.rowcount > 0 or self.get_complete_event(user, uid): 9.177 + return True 9.178 + 9.179 + columns = ["store_user", "object_uid", "object_text", "status"] 9.180 + values = [user, uid, to_string(node, "utf-8"), "active"] 9.181 + 9.182 + query, values = self.get_query( 9.183 + "insert into objects (:columns) values (:values)", 9.184 + columns, values) 9.185 + 9.186 + self.cursor.execute(query, values) 9.187 + return True 9.188 + 9.189 + def remove_parent_event(self, user, uid): 9.190 + 9.191 + "Remove the parent event for 'user' having the given 'uid'." 9.192 + 9.193 + columns = ["store_user", "object_uid"] 9.194 + values = [user, uid] 9.195 + 9.196 + query, values = self.get_query( 9.197 + "delete from objects :condition", 9.198 + columns, values) 9.199 + 9.200 + self.cursor.execute(query, values) 9.201 + return self.cursor.rowcount > 0 9.202 + 9.203 + def get_active_recurrences(self, user, uid): 9.204 + 9.205 + """ 9.206 + Get additional event instances for an event of the given 'user' with the 9.207 + indicated 'uid'. Cancelled recurrences are not returned. 9.208 + """ 9.209 + 9.210 + columns = ["store_user", "object_uid", "status"] 9.211 + values = [user, uid, "active"] 9.212 + 9.213 + query, values = self.get_query( 9.214 + "select object_recurrenceid from recurrences :condition", 9.215 + columns, values) 9.216 + 9.217 + self.cursor.execute(query, values) 9.218 + return [t[0] for t in self.cursor.fetchall() or []] 9.219 + 9.220 + def get_cancelled_recurrences(self, user, uid): 9.221 + 9.222 + """ 9.223 + Get additional event instances for an event of the given 'user' with the 9.224 + indicated 'uid'. Only cancelled recurrences are returned. 9.225 + """ 9.226 + 9.227 + columns = ["store_user", "object_uid", "status"] 9.228 + values = [user, uid, "cancelled"] 9.229 + 9.230 + query, values = self.get_query( 9.231 + "select object_recurrenceid from recurrences :condition", 9.232 + columns, values) 9.233 + 9.234 + self.cursor.execute(query, values) 9.235 + return [t[0] for t in self.cursor.fetchall() or []] 9.236 + 9.237 + def get_recurrence_table(self, dirname=None): 9.238 + 9.239 + "Get the table providing recurrences for any specified 'dirname'." 9.240 + 9.241 + if dirname == "counters": 9.242 + return "countered_recurrences" 9.243 + else: 9.244 + return "recurrences" 9.245 + 9.246 + def get_recurrence(self, user, uid, recurrenceid): 9.247 + 9.248 + """ 9.249 + For the event of the given 'user' with the given 'uid', return the 9.250 + specific recurrence indicated by the 'recurrenceid'. 9.251 + """ 9.252 + 9.253 + columns = ["store_user", "object_uid", "object_recurrenceid"] 9.254 + values = [user, uid, recurrenceid] 9.255 + 9.256 + query, values = self.get_query( 9.257 + "select object_text from recurrences :condition", 9.258 + columns, values) 9.259 + 9.260 + self.cursor.execute(query, values) 9.261 + result = self.cursor.fetchone() 9.262 + return result and parse_string(result[0], "utf-8") 9.263 + 9.264 + def set_recurrence(self, user, uid, recurrenceid, node): 9.265 + 9.266 + "Set an event for 'user' having the given 'uid' and 'node'." 9.267 + 9.268 + columns = ["store_user", "object_uid", "object_recurrenceid"] 9.269 + values = [user, uid, recurrenceid] 9.270 + setcolumns = ["object_text", "status"] 9.271 + setvalues = [to_string(node, "utf-8"), "active"] 9.272 + 9.273 + query, values = self.get_query( 9.274 + "update recurrences :set :condition", 9.275 + columns, values, setcolumns, setvalues) 9.276 + 9.277 + self.cursor.execute(query, values) 9.278 + 9.279 + if self.cursor.rowcount > 0 or self.get_recurrence(user, uid, recurrenceid): 9.280 + return True 9.281 + 9.282 + columns = ["store_user", "object_uid", "object_recurrenceid", "object_text", "status"] 9.283 + values = [user, uid, recurrenceid, to_string(node, "utf-8"), "active"] 9.284 + 9.285 + query, values = self.get_query( 9.286 + "insert into recurrences (:columns) values (:values)", 9.287 + columns, values) 9.288 + 9.289 + self.cursor.execute(query, values) 9.290 + return True 9.291 + 9.292 + def remove_recurrence(self, user, uid, recurrenceid): 9.293 + 9.294 + """ 9.295 + Remove a special recurrence from an event stored by 'user' having the 9.296 + given 'uid' and 'recurrenceid'. 9.297 + """ 9.298 + 9.299 + columns = ["store_user", "object_uid", "object_recurrenceid"] 9.300 + values = [user, uid, recurrenceid] 9.301 + 9.302 + query, values = self.get_query( 9.303 + "delete from recurrences :condition", 9.304 + columns, values) 9.305 + 9.306 + self.cursor.execute(query, values) 9.307 + return True 9.308 + 9.309 + def remove_recurrences(self, user, uid): 9.310 + 9.311 + """ 9.312 + Remove all recurrences for an event stored by 'user' having the given 9.313 + 'uid'. 9.314 + """ 9.315 + 9.316 + columns = ["store_user", "object_uid"] 9.317 + values = [user, uid] 9.318 + 9.319 + query, values = self.get_query( 9.320 + "delete from recurrences :condition", 9.321 + columns, values) 9.322 + 9.323 + self.cursor.execute(query, values) 9.324 + return True 9.325 + 9.326 + # Free/busy period providers, upon extension of the free/busy records. 9.327 + 9.328 + def _get_freebusy_providers(self, user): 9.329 + 9.330 + """ 9.331 + Return the free/busy providers for the given 'user'. 9.332 + 9.333 + This function returns any stored datetime and a list of providers as a 9.334 + 2-tuple. Each provider is itself a (uid, recurrenceid) tuple. 9.335 + """ 9.336 + 9.337 + columns = ["store_user"] 9.338 + values = [user] 9.339 + 9.340 + query, values = self.get_query( 9.341 + "select object_uid, object_recurrenceid from freebusy_providers :condition", 9.342 + columns, values) 9.343 + 9.344 + self.cursor.execute(query, values) 9.345 + providers = self.cursor.fetchall() 9.346 + 9.347 + columns = ["store_user"] 9.348 + values = [user] 9.349 + 9.350 + query, values = self.get_query( 9.351 + "select start from freebusy_provider_datetimes :condition", 9.352 + columns, values) 9.353 + 9.354 + self.cursor.execute(query, values) 9.355 + result = self.cursor.fetchone() 9.356 + dt_string = result and result[0] 9.357 + 9.358 + return dt_string, providers 9.359 + 9.360 + def _set_freebusy_providers(self, user, dt_string, t): 9.361 + 9.362 + "Set the given provider timestamp 'dt_string' and table 't'." 9.363 + 9.364 + # NOTE: Locking? 9.365 + 9.366 + columns = ["store_user"] 9.367 + values = [user] 9.368 + 9.369 + query, values = self.get_query( 9.370 + "delete from freebusy_providers :condition", 9.371 + columns, values) 9.372 + 9.373 + self.cursor.execute(query, values) 9.374 + 9.375 + columns = ["store_user", "object_uid", "object_recurrenceid"] 9.376 + 9.377 + for uid, recurrenceid in t: 9.378 + values = [user, uid, recurrenceid] 9.379 + 9.380 + query, values = self.get_query( 9.381 + "insert into freebusy_providers (:columns) values (:values)", 9.382 + columns, values) 9.383 + 9.384 + self.cursor.execute(query, values) 9.385 + 9.386 + columns = ["store_user"] 9.387 + values = [user] 9.388 + setcolumns = ["start"] 9.389 + setvalues = [dt_string] 9.390 + 9.391 + query, values = self.get_query( 9.392 + "update freebusy_provider_datetimes :set :condition", 9.393 + columns, values, setcolumns, setvalues) 9.394 + 9.395 + self.cursor.execute(query, values) 9.396 + 9.397 + if self.cursor.rowcount > 0: 9.398 + return True 9.399 + 9.400 + columns = ["store_user", "start"] 9.401 + values = [user, dt_string] 9.402 + 9.403 + query, values = self.get_query( 9.404 + "insert into freebusy_provider_datetimes (:columns) values (:values)", 9.405 + columns, values) 9.406 + 9.407 + self.cursor.execute(query, values) 9.408 + return True 9.409 + 9.410 + # Free/busy period access. 9.411 + 9.412 + def get_freebusy(self, user, name=None, mutable=False): 9.413 + 9.414 + "Get free/busy details for the given 'user'." 9.415 + 9.416 + table = name or "freebusy" 9.417 + return FreeBusyDatabaseCollection(self.cursor, table, ["store_user"], [user], mutable, self.paramstyle) 9.418 + 9.419 + def get_freebusy_for_other(self, user, other, mutable=False): 9.420 + 9.421 + "For the given 'user', get free/busy details for the 'other' user." 9.422 + 9.423 + table = "freebusy_other" 9.424 + return FreeBusyDatabaseCollection(self.cursor, table, ["store_user", "other"], [user, other], mutable, self.paramstyle) 9.425 + 9.426 + def set_freebusy(self, user, freebusy, name=None): 9.427 + 9.428 + "For the given 'user', set 'freebusy' details." 9.429 + 9.430 + table = name or "freebusy" 9.431 + 9.432 + if not isinstance(freebusy, FreeBusyDatabaseCollection) or freebusy.table_name != table: 9.433 + fbc = FreeBusyDatabaseCollection(self.cursor, table, ["store_user"], [user], True, self.paramstyle) 9.434 + fbc += freebusy 9.435 + 9.436 + return True 9.437 + 9.438 + def set_freebusy_for_other(self, user, freebusy, other): 9.439 + 9.440 + "For the given 'user', set 'freebusy' details for the 'other' user." 9.441 + 9.442 + table = "freebusy_other" 9.443 + 9.444 + if not isinstance(freebusy, FreeBusyDatabaseCollection) or freebusy.table_name != table: 9.445 + fbc = FreeBusyDatabaseCollection(self.cursor, table, ["store_user", "other"], [user, other], True, self.paramstyle) 9.446 + fbc += freebusy 9.447 + 9.448 + return True 9.449 + 9.450 + # Tentative free/busy periods related to countering. 9.451 + 9.452 + def get_freebusy_offers(self, user, mutable=False): 9.453 + 9.454 + "Get free/busy offers for the given 'user'." 9.455 + 9.456 + # Expire old offers and save the collection if modified. 9.457 + 9.458 + now = format_datetime(to_timezone(datetime.utcnow(), "UTC")) 9.459 + columns = ["store_user", "expires"] 9.460 + values = [user, now] 9.461 + 9.462 + query, values = self.get_query( 9.463 + "delete from freebusy_offers :condition", 9.464 + columns, values) 9.465 + 9.466 + self.cursor.execute(query, values) 9.467 + 9.468 + return self.get_freebusy(user, "freebusy_offers", mutable) 9.469 + 9.470 + def set_freebusy_offers(self, user, freebusy): 9.471 + 9.472 + "For the given 'user', set 'freebusy' offers." 9.473 + 9.474 + return self.set_freebusy(user, freebusy, "freebusy_offers") 9.475 + 9.476 + # Requests and counter-proposals. 9.477 + 9.478 + def get_requests(self, user): 9.479 + 9.480 + "Get requests for the given 'user'." 9.481 + 9.482 + columns = ["store_user"] 9.483 + values = [user] 9.484 + 9.485 + query, values = self.get_query( 9.486 + "select object_uid, object_recurrenceid, request_type from requests :condition", 9.487 + columns, values) 9.488 + 9.489 + self.cursor.execute(query, values) 9.490 + return self.cursor.fetchall() 9.491 + 9.492 + def set_request(self, user, uid, recurrenceid=None, type=None): 9.493 + 9.494 + """ 9.495 + For the given 'user', set the queued 'uid' and 'recurrenceid', 9.496 + indicating a request, along with any given 'type'. 9.497 + """ 9.498 + 9.499 + columns = ["store_user", "object_uid", "object_recurrenceid", "request_type"] 9.500 + values = [user, uid, recurrenceid, type] 9.501 + 9.502 + query, values = self.get_query( 9.503 + "insert into requests (:columns) values (:values)", 9.504 + columns, values) 9.505 + 9.506 + self.cursor.execute(query, values) 9.507 + return True 9.508 + 9.509 + def queue_request(self, user, uid, recurrenceid=None, type=None): 9.510 + 9.511 + """ 9.512 + Queue a request for 'user' having the given 'uid'. If the optional 9.513 + 'recurrenceid' is specified, the entry refers to a specific instance 9.514 + or occurrence of an event. The 'type' parameter can be used to indicate 9.515 + a specific type of request. 9.516 + """ 9.517 + 9.518 + if recurrenceid: 9.519 + columns = ["store_user", "object_uid", "object_recurrenceid"] 9.520 + values = [user, uid, recurrenceid] 9.521 + else: 9.522 + columns = ["store_user", "object_uid"] 9.523 + values = [user, uid] 9.524 + 9.525 + setcolumns = ["request_type"] 9.526 + setvalues = [type] 9.527 + 9.528 + query, values = self.get_query( 9.529 + "update requests :set :condition", 9.530 + columns, values, setcolumns, setvalues) 9.531 + 9.532 + self.cursor.execute(query, values) 9.533 + 9.534 + if self.cursor.rowcount > 0: 9.535 + return 9.536 + 9.537 + self.set_request(user, uid, recurrenceid, type) 9.538 + 9.539 + def dequeue_request(self, user, uid, recurrenceid=None): 9.540 + 9.541 + """ 9.542 + Dequeue all requests for 'user' having the given 'uid'. If the optional 9.543 + 'recurrenceid' is specified, all requests for that specific instance or 9.544 + occurrence of an event are dequeued. 9.545 + """ 9.546 + 9.547 + if recurrenceid: 9.548 + columns = ["store_user", "object_uid", "object_recurrenceid"] 9.549 + values = [user, uid, recurrenceid] 9.550 + else: 9.551 + columns = ["store_user", "object_uid"] 9.552 + values = [user, uid] 9.553 + 9.554 + query, values = self.get_query( 9.555 + "delete from requests :condition", 9.556 + columns, values) 9.557 + 9.558 + self.cursor.execute(query, values) 9.559 + return True 9.560 + 9.561 + def get_counters(self, user, uid, recurrenceid=None): 9.562 + 9.563 + """ 9.564 + For the given 'user', return a list of users from whom counter-proposals 9.565 + have been received for the given 'uid' and optional 'recurrenceid'. 9.566 + """ 9.567 + 9.568 + table = self.get_event_table(recurrenceid, "counters") 9.569 + 9.570 + if recurrenceid: 9.571 + columns = ["store_user", "object_uid", "object_recurrenceid"] 9.572 + values = [user, uid, recurrenceid] 9.573 + else: 9.574 + columns = ["store_user", "object_uid"] 9.575 + values = [user, uid] 9.576 + 9.577 + query, values = self.get_query( 9.578 + "select other from %(table)s :condition" % { 9.579 + "table" : table 9.580 + }, 9.581 + columns, values) 9.582 + 9.583 + self.cursor.execute(query, values) 9.584 + return self.cursor.fetchall() 9.585 + 9.586 + def get_counter(self, user, other, uid, recurrenceid=None): 9.587 + 9.588 + """ 9.589 + For the given 'user', return the counter-proposal from 'other' for the 9.590 + given 'uid' and optional 'recurrenceid'. 9.591 + """ 9.592 + 9.593 + table = self.get_event_table(recurrenceid, "counters") 9.594 + 9.595 + if recurrenceid: 9.596 + columns = ["store_user", "other", "object_uid", "object_recurrenceid"] 9.597 + values = [user, other, uid, recurrenceid] 9.598 + else: 9.599 + columns = ["store_user", "other", "object_uid"] 9.600 + values = [user, other, uid] 9.601 + 9.602 + query, values = self.get_query( 9.603 + "select object_text from %(table)s :condition" % { 9.604 + "table" : table 9.605 + }, 9.606 + columns, values) 9.607 + 9.608 + self.cursor.execute(query, values) 9.609 + result = self.cursor.fetchone() 9.610 + return result and parse_string(result[0], "utf-8") 9.611 + 9.612 + def set_counter(self, user, other, node, uid, recurrenceid=None): 9.613 + 9.614 + """ 9.615 + For the given 'user', store a counter-proposal received from 'other' the 9.616 + given 'node' representing that proposal for the given 'uid' and 9.617 + 'recurrenceid'. 9.618 + """ 9.619 + 9.620 + table = self.get_event_table(recurrenceid, "counters") 9.621 + 9.622 + if recurrenceid: 9.623 + columns = ["store_user", "other", "object_uid", "object_recurrenceid", "object_text"] 9.624 + values = [user, other, uid, recurrenceid, to_string(node, "utf-8")] 9.625 + else: 9.626 + columns = ["store_user", "other", "object_uid", "object_text"] 9.627 + values = [user, other, uid, to_string(node, "utf-8")] 9.628 + 9.629 + query, values = self.get_query( 9.630 + "insert into %(table)s (:columns) values (:values)" % { 9.631 + "table" : table 9.632 + }, 9.633 + columns, values) 9.634 + 9.635 + self.cursor.execute(query, values) 9.636 + return True 9.637 + 9.638 + def remove_counters(self, user, uid, recurrenceid=None): 9.639 + 9.640 + """ 9.641 + For the given 'user', remove all counter-proposals associated with the 9.642 + given 'uid' and 'recurrenceid'. 9.643 + """ 9.644 + 9.645 + table = self.get_event_table(recurrenceid, "counters") 9.646 + 9.647 + if recurrenceid: 9.648 + columns = ["store_user", "object_uid", "object_recurrenceid"] 9.649 + values = [user, uid, recurrenceid] 9.650 + else: 9.651 + columns = ["store_user", "object_uid"] 9.652 + values = [user, uid] 9.653 + 9.654 + query, values = self.get_query( 9.655 + "delete from %(table)s :condition" % { 9.656 + "table" : table 9.657 + }, 9.658 + columns, values) 9.659 + 9.660 + self.cursor.execute(query, values) 9.661 + return True 9.662 + 9.663 + def remove_counter(self, user, other, uid, recurrenceid=None): 9.664 + 9.665 + """ 9.666 + For the given 'user', remove any counter-proposal from 'other' 9.667 + associated with the given 'uid' and 'recurrenceid'. 9.668 + """ 9.669 + 9.670 + table = self.get_event_table(recurrenceid, "counters") 9.671 + 9.672 + if recurrenceid: 9.673 + columns = ["store_user", "other", "object_uid", "object_recurrenceid"] 9.674 + values = [user, other, uid, recurrenceid] 9.675 + else: 9.676 + columns = ["store_user", "other", "object_uid"] 9.677 + values = [user, other, uid] 9.678 + 9.679 + query, values = self.get_query( 9.680 + "delete from %(table)s :condition" % { 9.681 + "table" : table 9.682 + }, 9.683 + columns, values) 9.684 + 9.685 + self.cursor.execute(query, values) 9.686 + return True 9.687 + 9.688 + # Event cancellation. 9.689 + 9.690 + def cancel_event(self, user, uid, recurrenceid=None): 9.691 + 9.692 + """ 9.693 + Cancel an event for 'user' having the given 'uid'. If the optional 9.694 + 'recurrenceid' is specified, a specific instance or occurrence of an 9.695 + event is cancelled. 9.696 + """ 9.697 + 9.698 + table = self.get_event_table(recurrenceid) 9.699 + 9.700 + if recurrenceid: 9.701 + columns = ["store_user", "object_uid", "object_recurrenceid"] 9.702 + values = [user, uid, recurrenceid] 9.703 + else: 9.704 + columns = ["store_user", "object_uid"] 9.705 + values = [user, uid] 9.706 + 9.707 + setcolumns = ["status"] 9.708 + setvalues = ["cancelled"] 9.709 + 9.710 + query, values = self.get_query( 9.711 + "update %(table)s :set :condition" % { 9.712 + "table" : table 9.713 + }, 9.714 + columns, values, setcolumns, setvalues) 9.715 + 9.716 + self.cursor.execute(query, values) 9.717 + return True 9.718 + 9.719 + def uncancel_event(self, user, uid, recurrenceid=None): 9.720 + 9.721 + """ 9.722 + Uncancel an event for 'user' having the given 'uid'. If the optional 9.723 + 'recurrenceid' is specified, a specific instance or occurrence of an 9.724 + event is uncancelled. 9.725 + """ 9.726 + 9.727 + table = self.get_event_table(recurrenceid) 9.728 + 9.729 + if recurrenceid: 9.730 + columns = ["store_user", "object_uid", "object_recurrenceid"] 9.731 + values = [user, uid, recurrenceid] 9.732 + else: 9.733 + columns = ["store_user", "object_uid"] 9.734 + values = [user, uid] 9.735 + 9.736 + setcolumns = ["status"] 9.737 + setvalues = ["active"] 9.738 + 9.739 + query, values = self.get_query( 9.740 + "update %(table)s :set :condition" % { 9.741 + "table" : table 9.742 + }, 9.743 + columns, values, setcolumns, setvalues) 9.744 + 9.745 + self.cursor.execute(query, values) 9.746 + return True 9.747 + 9.748 + def remove_cancellation(self, user, uid, recurrenceid=None): 9.749 + 9.750 + """ 9.751 + Remove a cancellation for 'user' for the event having the given 'uid'. 9.752 + If the optional 'recurrenceid' is specified, a specific instance or 9.753 + occurrence of an event is affected. 9.754 + """ 9.755 + 9.756 + table = self.get_event_table(recurrenceid) 9.757 + 9.758 + if recurrenceid: 9.759 + columns = ["store_user", "object_uid", "object_recurrenceid", "status"] 9.760 + values = [user, uid, recurrenceid, "cancelled"] 9.761 + else: 9.762 + columns = ["store_user", "object_uid", "status"] 9.763 + values = [user, uid, "cancelled"] 9.764 + 9.765 + query, values = self.get_query( 9.766 + "delete from %(table)s :condition" % { 9.767 + "table" : table 9.768 + }, 9.769 + columns, values) 9.770 + 9.771 + self.cursor.execute(query, values) 9.772 + return True 9.773 + 9.774 +class DatabaseJournal(DatabaseStoreBase, JournalBase): 9.775 + 9.776 + "A journal system to support quotas." 9.777 + 9.778 + # Quota and user identity/group discovery. 9.779 + 9.780 + def get_quotas(self): 9.781 + 9.782 + "Return a list of quotas." 9.783 + 9.784 + query = "select distinct journal_quota from quota_freebusy" 9.785 + self.cursor.execute(query) 9.786 + return [r[0] for r in self.cursor.fetchall()] 9.787 + 9.788 + def get_quota_users(self, quota): 9.789 + 9.790 + "Return a list of quota users." 9.791 + 9.792 + columns = ["quota"] 9.793 + values = [quota] 9.794 + 9.795 + query, values = self.get_query( 9.796 + "select distinct user_group from quota_freebusy :condition", 9.797 + columns, values) 9.798 + 9.799 + self.cursor.execute(query) 9.800 + return [r[0] for r in self.cursor.fetchall()] 9.801 + 9.802 + # Groups of users sharing quotas. 9.803 + 9.804 + def get_groups(self, quota): 9.805 + 9.806 + "Return the identity mappings for the given 'quota' as a dictionary." 9.807 + 9.808 + columns = ["quota"] 9.809 + values = [quota] 9.810 + 9.811 + query, values = self.get_query( 9.812 + "select store_user, user_group from user_groups :condition", 9.813 + columns, values) 9.814 + 9.815 + self.cursor.execute(query) 9.816 + return dict(self.cursor.fetchall()) 9.817 + 9.818 + def get_limits(self, quota): 9.819 + 9.820 + """ 9.821 + Return the limits for the 'quota' as a dictionary mapping identities or 9.822 + groups to durations. 9.823 + """ 9.824 + 9.825 + columns = ["quota"] 9.826 + values = [quota] 9.827 + 9.828 + query, values = self.get_query( 9.829 + "select user_group, quota_limit from quota_limits :condition", 9.830 + columns, values) 9.831 + 9.832 + self.cursor.execute(query) 9.833 + return dict(self.cursor.fetchall()) 9.834 + 9.835 + # Free/busy period access for users within quota groups. 9.836 + 9.837 + def get_freebusy(self, quota, user, mutable=False): 9.838 + 9.839 + "Get free/busy details for the given 'quota' and 'user'." 9.840 + 9.841 + table = "user_freebusy" 9.842 + return FreeBusyDatabaseCollection(self.cursor, table, ["quota", "store_user"], [quota, user], mutable, self.paramstyle) 9.843 + 9.844 + def set_freebusy(self, quota, user, freebusy): 9.845 + 9.846 + "For the given 'quota' and 'user', set 'freebusy' details." 9.847 + 9.848 + table = "user_freebusy" 9.849 + 9.850 + if not isinstance(freebusy, FreeBusyDatabaseCollection) or freebusy.table_name != table: 9.851 + fbc = FreeBusyDatabaseCollection(self.cursor, table, ["quota", "store_user"], [quota, user], True, self.paramstyle) 9.852 + fbc += freebusy 9.853 + 9.854 + return True 9.855 + 9.856 + # Journal entry methods. 9.857 + 9.858 + def get_entries(self, quota, group, mutable=False): 9.859 + 9.860 + """ 9.861 + Return a list of journal entries for the given 'quota' for the indicated 9.862 + 'group'. 9.863 + """ 9.864 + 9.865 + table = "quota_freebusy" 9.866 + return FreeBusyDatabaseCollection(self.cursor, table, ["quota", "user_group"], [quota, group], mutable, self.paramstyle) 9.867 + 9.868 + def set_entries(self, quota, group, entries): 9.869 + 9.870 + """ 9.871 + For the given 'quota' and indicated 'group', set the list of journal 9.872 + 'entries'. 9.873 + """ 9.874 + 9.875 + table = "quota_freebusy" 9.876 + 9.877 + if not isinstance(entries, FreeBusyDatabaseCollection) or entries.table_name != table: 9.878 + fbc = FreeBusyDatabaseCollection(self.cursor, table, ["quota", "user_group"], [quota, group], True, self.paramstyle) 9.879 + fbc += entries 9.880 + 9.881 + return True 9.882 + 9.883 +# vim: tabstop=4 expandtab shiftwidth=4
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/imiptools/stores/database/postgresql.py Thu Mar 10 01:43:31 2016 +0100 10.3 @@ -0,0 +1,49 @@ 10.4 +#!/usr/bin/env python 10.5 + 10.6 +""" 10.7 +A PostgreSQL database store of calendar data. 10.8 + 10.9 +Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk> 10.10 + 10.11 +This program is free software; you can redistribute it and/or modify it under 10.12 +the terms of the GNU General Public License as published by the Free Software 10.13 +Foundation; either version 3 of the License, or (at your option) any later 10.14 +version. 10.15 + 10.16 +This program is distributed in the hope that it will be useful, but WITHOUT 10.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 10.19 +details. 10.20 + 10.21 +You should have received a copy of the GNU General Public License along with 10.22 +this program. If not, see <http://www.gnu.org/licenses/>. 10.23 +""" 10.24 + 10.25 +from imiptools.stores.database.common import DatabaseStore, DatabaseJournal 10.26 +import psycopg2 10.27 + 10.28 +class Store(DatabaseStore): 10.29 + 10.30 + "A PostgreSQL database store of calendar objects and free/busy data." 10.31 + 10.32 + def __init__(self, store_dir): 10.33 + 10.34 + "Interpret 'store_dir' as a connection string." 10.35 + 10.36 + connection = psycopg2.connect(store_dir) 10.37 + connection.autocommit = True 10.38 + DatabaseStore.__init__(self, connection, psycopg2.paramstyle) 10.39 + 10.40 +class Journal(DatabaseJournal): 10.41 + 10.42 + "A PostgreSQL journal system supporting quotas." 10.43 + 10.44 + def __init__(self, store_dir): 10.45 + 10.46 + "Interpret 'store_dir' as a connection string." 10.47 + 10.48 + connection = psycopg2.connect(store_dir) 10.49 + connection.autocommit = True 10.50 + DatabaseJournal.__init__(self, connection, psycopg2.paramstyle) 10.51 + 10.52 +# vim: tabstop=4 expandtab shiftwidth=4
11.1 --- a/imiptools/stores/file.py Wed Mar 09 21:38:56 2016 +0100 11.2 +++ b/imiptools/stores/file.py Thu Mar 10 01:43:31 2016 +0100 11.3 @@ -19,7 +19,7 @@ 11.4 this program. If not, see <http://www.gnu.org/licenses/>. 11.5 """ 11.6 11.7 -from imiptools.stores import StoreBase, PublisherBase, JournalBase 11.8 +from imiptools.stores.common import StoreBase, PublisherBase, JournalBase 11.9 11.10 from datetime import datetime 11.11 from imiptools.config import STORE_DIR, PUBLISH_DIR, JOURNAL_DIR 11.12 @@ -148,7 +148,7 @@ 11.13 finally: 11.14 self.release_lock(user) 11.15 11.16 -class FileStore(FileStoreBase, StoreBase): 11.17 +class Store(FileStoreBase, StoreBase): 11.18 11.19 "A file store of tabular free/busy data and objects." 11.20 11.21 @@ -724,7 +724,7 @@ 11.22 11.23 return False 11.24 11.25 -class FilePublisher(FileBase, PublisherBase): 11.26 +class Publisher(FileBase, PublisherBase): 11.27 11.28 "A publisher of objects." 11.29 11.30 @@ -760,7 +760,7 @@ 11.31 11.32 return True 11.33 11.34 -class FileJournal(FileStoreBase, JournalBase): 11.35 +class Journal(FileStoreBase, JournalBase): 11.36 11.37 "A journal system to support quotas." 11.38
12.1 --- a/tests/common.sh Wed Mar 09 21:38:56 2016 +0100 12.2 +++ b/tests/common.sh Thu Mar 10 01:43:31 2016 +0100 12.3 @@ -3,25 +3,37 @@ 12.4 THIS_DIR=`dirname "$0"` 12.5 BASE_DIR="$THIS_DIR/.." 12.6 12.7 -STORE=/tmp/store 12.8 +STORETYPE=file 12.9 + 12.10 +if [ "$STORETYPE" = "file" ]; then 12.11 + STORE=/tmp/store 12.12 + JOURNAL=/tmp/journal 12.13 +elif [ "$STORETYPE" = "postgresql" ]; then 12.14 + DBNAME='test' 12.15 + STORE="dbname=$DBNAME" 12.16 + JOURNAL="$STORE" 12.17 +fi 12.18 + 12.19 STATIC=/tmp/static 12.20 PREFS=/tmp/prefs 12.21 -JOURNAL=/tmp/journal 12.22 12.23 -ARGS="-S $STORE -P $STATIC -p $PREFS -j $JOURNAL -d" 12.24 +ARGS="-T $STORETYPE -S $STORE -P $STATIC -p $PREFS -j $JOURNAL -d" 12.25 12.26 ACCEPT_SCRIPT="$THIS_DIR/test_handle.py" 12.27 -ACCEPT_ARGS="accept $STORE $JOURNAL $PREFS" 12.28 +ACCEPT_ARGS="accept $STORETYPE $STORE $JOURNAL $PREFS" 12.29 12.30 COUNTER_SCRIPT="$THIS_DIR/test_handle.py" 12.31 -COUNTER_ARGS="counter $STORE $JOURNAL $PREFS" 12.32 +COUNTER_ARGS="counter $STORETYPE $STORE $JOURNAL $PREFS" 12.33 12.34 DECLINE_SCRIPT="$THIS_DIR/test_handle.py" 12.35 -DECLINE_ARGS="decline $STORE $JOURNAL $PREFS" 12.36 +DECLINE_ARGS="decline $STORETYPE $STORE $JOURNAL $PREFS" 12.37 12.38 FREEBUSY_SCRIPT="$BASE_DIR/tools/make_freebusy.py" 12.39 FREEBUSY_ARGS="-s -n" 12.40 12.41 +LIST_SCRIPT="$THIS_DIR/list_table.py" 12.42 +LIST_ARGS="$STORETYPE $STORE $JOURNAL" 12.43 + 12.44 OUTGOING_SCRIPT="$BASE_DIR/imip_person_outgoing.py" 12.45 12.46 PERSON_SCRIPT="$BASE_DIR/imip_person.py" 12.47 @@ -39,9 +51,16 @@ 12.48 PYTHONPATH="$BASE_DIR" 12.49 export PYTHONPATH 12.50 12.51 -rm -rf "$STORE" 12.52 +if [ "$STORETYPE" = "file" ]; then 12.53 + rm -rf "$STORE" 12.54 + rm -rf "$JOURNAL" 12.55 +elif [ "$STORETYPE" = "postgresql" ]; then 12.56 + dropdb "$DBNAME" 12.57 + createdb "$DBNAME" 12.58 + psql -f "$BASE_DIR/conf/postgresql/schema.sql" "$DBNAME" 12.59 +fi 12.60 + 12.61 rm -rf "$STATIC" 12.62 rm -rf "$PREFS" 12.63 -rm -rf "$JOURNAL" 12.64 rm -f "$ERROR" 12.65 rm -f out*.tmp
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/tests/list_table.py Thu Mar 10 01:43:31 2016 +0100 13.3 @@ -0,0 +1,105 @@ 13.4 +#!/usr/bin/env python 13.5 + 13.6 +""" 13.7 +Show the contents of a table. 13.8 + 13.9 +Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk> 13.10 + 13.11 +This program is free software; you can redistribute it and/or modify it under 13.12 +the terms of the GNU General Public License as published by the Free Software 13.13 +Foundation; either version 3 of the License, or (at your option) any later 13.14 +version. 13.15 + 13.16 +This program is distributed in the hope that it will be useful, but WITHOUT 13.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 13.19 +details. 13.20 + 13.21 +You should have received a copy of the GNU General Public License along with 13.22 +this program. If not, see <http://www.gnu.org/licenses/>. 13.23 +""" 13.24 + 13.25 +from imiptools.data import Object 13.26 +from imiptools.stores import get_store, get_journal 13.27 +import sys 13.28 + 13.29 +def show_list(data): 13.30 + for row in data: 13.31 + print row or "" 13.32 + 13.33 +def show_object(data): 13.34 + if data: 13.35 + print Object(data).to_string() 13.36 + 13.37 +def show_periods(data): 13.38 + for row in data: 13.39 + print "\t".join(row.as_tuple(strings_only=True)) 13.40 + 13.41 +def show_tuples(data): 13.42 + for row in data: 13.43 + print "\t".join([(column or "") for column in row]) 13.44 + 13.45 +if __name__ == "__main__": 13.46 + try: 13.47 + store_type, store_dir, journal_dir, user, table = sys.argv[1:6] 13.48 + args = sys.argv[6:] 13.49 + except ValueError: 13.50 + print >>sys.stderr, """\ 13.51 +Need a store type, a store directory, a journal directory, a user URI, and a 13.52 +table to show. Other arguments may be needed for certain tables. 13.53 +""" 13.54 + sys.exit(1) 13.55 + 13.56 + store = get_store(store_type, store_dir) 13.57 + journal = get_journal(store_type, journal_dir) 13.58 + 13.59 + # Periods. 13.60 + 13.61 + if table == "entries": 13.62 + data = journal.get_entries(user) 13.63 + show_periods(data) 13.64 + 13.65 + elif table == "freebusy": 13.66 + data = store.get_freebusy(user) 13.67 + show_periods(data) 13.68 + 13.69 + elif table == "freebusy_offers": 13.70 + data = store.get_freebusy_offers(user) 13.71 + show_periods(data) 13.72 + 13.73 + elif table == "freebusy_other": 13.74 + other = args[0] 13.75 + data = store.get_freebusy_for_other(user, other) 13.76 + show_periods(data) 13.77 + 13.78 + # Tuples. 13.79 + 13.80 + elif table == "requests": 13.81 + data = store.get_requests(user) 13.82 + show_tuples(data) 13.83 + 13.84 + # Objects. 13.85 + 13.86 + elif table == "countered_object": 13.87 + uid = args[0] 13.88 + other = args[1] 13.89 + data = store.get_counter(user, other, uid) 13.90 + show_object(data) 13.91 + 13.92 + elif table == "object": 13.93 + uid = args[0] 13.94 + data = store.get_event(user, uid) 13.95 + show_object(data) 13.96 + 13.97 + elif table == "recurrence": 13.98 + uid = args[0] 13.99 + recurrenceid = args[1] 13.100 + data = store.get_event(user, uid, recurrenceid) 13.101 + show_object(data) 13.102 + 13.103 + elif table == "cancelled_recurrences": 13.104 + uid = args[0] 13.105 + data = store.get_cancelled_recurrences(user, uid) 13.106 + show_list(data) 13.107 + 13.108 +# vim: tabstop=4 expandtab shiftwidth=4
14.1 --- a/tests/test_freebusy_publishing.sh Wed Mar 09 21:38:56 2016 +0100 14.2 +++ b/tests/test_freebusy_publishing.sh Thu Mar 10 01:43:31 2016 +0100 14.3 @@ -4,8 +4,6 @@ 14.4 14.5 USER="mailto:paul.boddie@example.com" 14.6 SENDER="mailto:resource-room-confroom@example.com" 14.7 -FBFILE="$STORE/$USER/freebusy" 14.8 -FBOTHERFILE="$STORE/$USER/freebusy-other/$SENDER" 14.9 14.10 mkdir -p "$PREFS/$USER" 14.11 echo 'Europe/Oslo' > "$PREFS/$USER/TZID" 14.12 @@ -15,17 +13,23 @@ 14.13 | "$SHOWMAIL" \ 14.14 > out0.tmp 14.15 14.16 - grep -q "^20140401T070000Z${TAB}20140401T080000Z" "$FBOTHERFILE" \ 14.17 -&& grep -q "^20140401T080000Z${TAB}20140401T100000Z" "$FBOTHERFILE" \ 14.18 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 14.19 +> out1.tmp 14.20 + 14.21 + grep -q "^20140401T070000Z${TAB}20140401T080000Z" "out1.tmp" \ 14.22 +&& grep -q "^20140401T080000Z${TAB}20140401T100000Z" "out1.tmp" \ 14.23 && echo "Success" \ 14.24 || echo "Failed" 14.25 14.26 "$PERSON_SCRIPT" $ARGS < "$TEMPLATES/fb-publish-again.txt" 2>> $ERROR \ 14.27 | "$SHOWMAIL" \ 14.28 -> out0.tmp 14.29 +> out2.tmp 14.30 14.31 - grep -q "^20140401T070000Z${TAB}20140401T080000Z" "$FBOTHERFILE" \ 14.32 -&& ! grep -q "^20140401T080000Z${TAB}20140401T100000Z" "$FBOTHERFILE" \ 14.33 -&& grep -q "^20140401T083000Z${TAB}20140401T100000Z" "$FBOTHERFILE" \ 14.34 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 14.35 +> out3.tmp 14.36 + 14.37 + grep -q "^20140401T070000Z${TAB}20140401T080000Z" "out3.tmp" \ 14.38 +&& ! grep -q "^20140401T080000Z${TAB}20140401T100000Z" "out3.tmp" \ 14.39 +&& grep -q "^20140401T083000Z${TAB}20140401T100000Z" "out3.tmp" \ 14.40 && echo "Success" \ 14.41 || echo "Failed"
15.1 --- a/tests/test_handle.py Wed Mar 09 21:38:56 2016 +0100 15.2 +++ b/tests/test_handle.py Thu Mar 10 01:43:31 2016 +0100 15.3 @@ -24,7 +24,7 @@ 15.4 from imiptools.dates import get_datetime, to_timezone 15.5 from imiptools.mail import Messenger 15.6 from imiptools.period import RecurringPeriod 15.7 -import imiptools.stores.file 15.8 +from imiptools.stores import get_store, get_journal 15.9 import sys 15.10 15.11 class TestClient(ClientForObject): 15.12 @@ -94,19 +94,20 @@ 15.13 15.14 if __name__ == "__main__": 15.15 try: 15.16 - action, store_dir, journal_dir, preferences_dir, user = sys.argv[1:6] 15.17 + action, store_type, store_dir, journal_dir, preferences_dir, user = sys.argv[1:7] 15.18 if action == "counter": 15.19 - start, end = sys.argv[6:8] 15.20 - i = 8 15.21 + start, end = sys.argv[7:9] 15.22 + i = 9 15.23 else: 15.24 start, end = None, None 15.25 - i = 6 15.26 + i = 7 15.27 uid, recurrenceid = (sys.argv[i:i+2] + [None] * 2)[:2] 15.28 except ValueError: 15.29 print >>sys.stderr, """\ 15.30 -Need 'accept', 'counter' or 'decline', a store directory, a preferences 15.31 -directory, user URI, any counter-proposal datetimes (see below), plus the 15.32 -appropriate event UID and RECURRENCE-ID (if a recurrence is involved). 15.33 +Need 'accept', 'counter' or 'decline', a store type, a store directory, a 15.34 +journal directory, a preferences directory, user URI, any counter-proposal 15.35 +datetimes (see below), plus the appropriate event UID and RECURRENCE-ID (if a 15.36 +recurrence is involved). 15.37 15.38 The RECURRENCE-ID must be in exactly the form employed by the store, not a 15.39 different but equivalent representation. 15.40 @@ -120,8 +121,8 @@ 15.41 """ 15.42 sys.exit(1) 15.43 15.44 - store = imiptools.stores.file.FileStore(store_dir) 15.45 - journal = imiptools.stores.file.FileJournal(journal_dir) 15.46 + store = get_store(store_type, store_dir) 15.47 + journal = get_journal(store_type, journal_dir) 15.48 15.49 if uid is not None: 15.50 fragment = store.get_event(user, uid, recurrenceid)
16.1 --- a/tests/test_outgoing_invitation.sh Wed Mar 09 21:38:56 2016 +0100 16.2 +++ b/tests/test_outgoing_invitation.sh Thu Mar 10 01:43:31 2016 +0100 16.3 @@ -3,70 +3,84 @@ 16.4 . "`dirname \"$0\"`/common.sh" 16.5 16.6 USER="mailto:paul.boddie@example.com" 16.7 -FBFILE="$STORE/$USER/freebusy" 16.8 16.9 mkdir -p "$PREFS/$USER" 16.10 echo 'Europe/Oslo' > "$PREFS/$USER/TZID" 16.11 echo 'share' > "$PREFS/$USER/freebusy_sharing" 16.12 16.13 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request.txt" 2>> $ERROR 16.14 -cp "$FBFILE" out1.tmp 16.15 16.16 - grep -q "^20141126T150000Z${TAB}20141126T160000Z" "$FBFILE" \ 16.17 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 16.18 +| tee out1.tmp \ 16.19 +| grep -q "^20141126T150000Z${TAB}20141126T160000Z" \ 16.20 && echo "Success" \ 16.21 || echo "Failed" 16.22 16.23 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-cancel.txt" 2>> $ERROR 16.24 echo "Cancel..." 16.25 -cp "$FBFILE" out2.tmp 16.26 16.27 - ! grep -q '^2' "$FBFILE" \ 16.28 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 16.29 +> out2.tmp 16.30 + 16.31 + ! grep -q '^2' "out2.tmp" \ 16.32 && echo "Success" \ 16.33 || echo "Failed" 16.34 16.35 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-recurring.txt" 2>> $ERROR 16.36 -cp "$FBFILE" out3.tmp 16.37 16.38 - [ `cat "$FBFILE" | wc -l` = '3' ] \ 16.39 -&& grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ 16.40 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 16.41 +> out3.tmp 16.42 + 16.43 + [ `cat "out3.tmp" | wc -l` = '3' ] \ 16.44 +&& grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out3.tmp" \ 16.45 && echo "Success" \ 16.46 || echo "Failed" 16.47 16.48 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-cancel-recurring-instance.txt" 2>> $ERROR 16.49 -cp "$FBFILE" out4.tmp 16.50 16.51 - [ `cat "$FBFILE" | wc -l` = '2' ] \ 16.52 -&& ! grep -q "^20141114T090000Z${TAB}20141114T100000Z" "$FBFILE" \ 16.53 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 16.54 +> out4.tmp 16.55 + 16.56 + [ `cat "out4.tmp" | wc -l` = '2' ] \ 16.57 +&& ! grep -q "^20141114T090000Z${TAB}20141114T100000Z" "out4.tmp" \ 16.58 && echo "Success" \ 16.59 || echo "Failed" 16.60 16.61 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-recurring-reschedule-instance.txt" 2>> $ERROR 16.62 -cp "$FBFILE" out5.tmp 16.63 16.64 - grep -q "^20141011T080000Z${TAB}20141011T090000Z" "$FBFILE" \ 16.65 -&& ! grep -q "^20141010T090000Z${TAB}20141010T100000Z" "$FBFILE" \ 16.66 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 16.67 +> out5.tmp 16.68 + 16.69 + grep -q "^20141011T080000Z${TAB}20141011T090000Z" "out5.tmp" \ 16.70 +&& ! grep -q "^20141010T090000Z${TAB}20141010T100000Z" "out5.tmp" \ 16.71 && echo "Success" \ 16.72 || echo "Failed" 16.73 16.74 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-cancel-recurring.txt" 2>> $ERROR 16.75 -cp "$FBFILE" out6.tmp 16.76 16.77 - ! grep -q '^2' "$FBFILE" \ 16.78 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 16.79 +> out6.tmp 16.80 + 16.81 + ! grep -q '^2' "out6.tmp" \ 16.82 && echo "Success" \ 16.83 || echo "Failed" 16.84 16.85 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-recurring-day.txt" 2>> $ERROR 16.86 -cp "$FBFILE" out7.tmp 16.87 16.88 - [ `cat "$FBFILE" | wc -l` = '3' ] \ 16.89 -&& grep -q "^20141211T230000Z${TAB}20141212T230000Z" "$FBFILE" \ 16.90 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 16.91 +> out7.tmp 16.92 + 16.93 + [ `cat "out7.tmp" | wc -l` = '3' ] \ 16.94 +&& grep -q "^20141211T230000Z${TAB}20141212T230000Z" "out7.tmp" \ 16.95 && echo "Success" \ 16.96 || echo "Failed" 16.97 16.98 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-cancel-recurring-day.txt" 2>> $ERROR 16.99 -cp "$FBFILE" out8.tmp 16.100 16.101 - ! grep -q '^2' "$FBFILE" \ 16.102 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 16.103 +> out8.tmp 16.104 + 16.105 + ! grep -q '^2' "out8.tmp" \ 16.106 && echo "Success" \ 16.107 || echo "Failed" 16.108 16.109 @@ -75,31 +89,39 @@ 16.110 echo 'Europe/Mariehamn' > "$PREFS/$USER/TZID" 16.111 16.112 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-recurring.txt" 2>> $ERROR 16.113 -cp "$FBFILE" out9.tmp 16.114 16.115 - [ `cat "$FBFILE" | wc -l` = '3' ] \ 16.116 -&& grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ 16.117 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 16.118 +> out9.tmp 16.119 + 16.120 + [ `cat "out9.tmp" | wc -l` = '3' ] \ 16.121 +&& grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out9.tmp" \ 16.122 && echo "Success" \ 16.123 || echo "Failed" 16.124 16.125 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-cancel-recurring.txt" 2>> $ERROR 16.126 -cp "$FBFILE" out10.tmp 16.127 16.128 - ! grep -q '^2' "$FBFILE" \ 16.129 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 16.130 +> out10.tmp 16.131 + 16.132 + ! grep -q '^2' "out10.tmp" \ 16.133 && echo "Success" \ 16.134 || echo "Failed" 16.135 16.136 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-recurring-day.txt" 2>> $ERROR 16.137 -cp "$FBFILE" out11.tmp 16.138 16.139 - [ `cat "$FBFILE" | wc -l` = '3' ] \ 16.140 -&& grep -q "^20141211T230000Z${TAB}20141212T230000Z" "$FBFILE" \ 16.141 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 16.142 +> out11.tmp 16.143 + 16.144 + [ `cat "out11.tmp" | wc -l` = '3' ] \ 16.145 +&& grep -q "^20141211T230000Z${TAB}20141212T230000Z" "out11.tmp" \ 16.146 && echo "Success" \ 16.147 || echo "Failed" 16.148 16.149 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-cancel-recurring-day.txt" 2>> $ERROR 16.150 -cp "$FBFILE" out12.tmp 16.151 16.152 - ! grep -q '^2' "$FBFILE" \ 16.153 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 16.154 +> out12.tmp 16.155 + 16.156 + ! grep -q '^2' "out12.tmp" \ 16.157 && echo "Success" \ 16.158 || echo "Failed"
17.1 --- a/tests/test_person_invitation.sh Wed Mar 09 21:38:56 2016 +0100 17.2 +++ b/tests/test_person_invitation.sh Thu Mar 10 01:43:31 2016 +0100 17.3 @@ -4,8 +4,6 @@ 17.4 17.5 USER="mailto:vincent.vole@example.com" 17.6 SENDER="mailto:paul.boddie@example.com" 17.7 -FBFILE="$STORE/$USER/freebusy" 17.8 -FBOTHERFILE="$STORE/$USER/freebusy-other/$SENDER" 17.9 17.10 mkdir -p "$PREFS/$USER" 17.11 echo 'Europe/Oslo' > "$PREFS/$USER/TZID" 17.12 @@ -37,12 +35,17 @@ 17.13 && echo "Success" \ 17.14 || echo "Failed" 17.15 17.16 - ! [ -e "$FBFILE" ] \ 17.17 -|| ! grep -q "^20141126T150000Z${TAB}20141126T160000Z" "$FBFILE" \ 17.18 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 17.19 +> out2f.tmp 17.20 + 17.21 + ! grep -q "^20141126T150000Z${TAB}20141126T160000Z" "out2f.tmp" \ 17.22 && echo "Success" \ 17.23 || echo "Failed" 17.24 17.25 - grep -q "^20141126T150000Z${TAB}20141126T160000Z" "$FBOTHERFILE" \ 17.26 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 17.27 +> out2fo.tmp 17.28 + 17.29 + grep -q "^20141126T150000Z${TAB}20141126T160000Z" "out2fo.tmp" \ 17.30 && echo "Success" \ 17.31 || echo "Failed" 17.32 17.33 @@ -50,7 +53,10 @@ 17.34 | tee out3.tmp \ 17.35 | "$OUTGOING_SCRIPT" $ARGS 2>> $ERROR 17.36 17.37 - grep -q "^20141126T150000Z${TAB}20141126T160000Z" "$FBFILE" \ 17.38 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 17.39 +> out3f.tmp 17.40 + 17.41 + grep -q "^20141126T150000Z${TAB}20141126T160000Z" "out3f.tmp" \ 17.42 && echo "Success" \ 17.43 || echo "Failed" 17.44 17.45 @@ -62,11 +68,17 @@ 17.46 && echo "Success" \ 17.47 || echo "Failed" 17.48 17.49 - ! grep -q "event7@example.com" "$FBFILE" \ 17.50 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 17.51 +> out4f.tmp 17.52 + 17.53 + ! grep -q "event7@example.com" "out4f.tmp" \ 17.54 && echo "Success" \ 17.55 || echo "Failed" 17.56 17.57 - grep -q "event7@example.com" "$FBOTHERFILE" \ 17.58 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 17.59 +> out4fo.tmp 17.60 + 17.61 + grep -q "event7@example.com" "out4fo.tmp" \ 17.62 && echo "Success" \ 17.63 || echo "Failed" 17.64 17.65 @@ -74,8 +86,11 @@ 17.66 | tee out5.tmp \ 17.67 | "$OUTGOING_SCRIPT" $ARGS 2>> $ERROR 17.68 17.69 - grep -q "event6@example.com" "$FBFILE" \ 17.70 -&& ! grep -q "event7@example.com" "$FBFILE" \ 17.71 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 17.72 +> out5f.tmp 17.73 + 17.74 + grep -q "event6@example.com" "out5f.tmp" \ 17.75 +&& ! grep -q "event7@example.com" "out5f.tmp" \ 17.76 && echo "Success" \ 17.77 || echo "Failed" 17.78 17.79 @@ -87,11 +102,17 @@ 17.80 && echo "Success" \ 17.81 || echo "Failed" 17.82 17.83 - ! grep -q "event6@example.com" "$FBFILE" \ 17.84 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 17.85 +> out6f.tmp 17.86 + 17.87 + ! grep -q "event6@example.com" "out6f.tmp" \ 17.88 && echo "Success" \ 17.89 || echo "Failed" 17.90 17.91 - grep -q "event6@example.com" "$FBOTHERFILE" \ 17.92 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 17.93 +> out6fo.tmp 17.94 + 17.95 + grep -q "event6@example.com" "out6fo.tmp" \ 17.96 && echo "Success" \ 17.97 || echo "Failed" 17.98 17.99 @@ -103,11 +124,17 @@ 17.100 && echo "Success" \ 17.101 || echo "Failed" 17.102 17.103 - ! grep -q "event6@example.com" "$FBFILE" \ 17.104 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 17.105 +> out7f.tmp 17.106 + 17.107 + ! grep -q "event6@example.com" "out7f.tmp" \ 17.108 && echo "Success" \ 17.109 || echo "Failed" 17.110 17.111 - ! grep -q "event6@example.com" "$FBOTHERFILE" \ 17.112 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 17.113 +> out7fo.tmp 17.114 + 17.115 + ! grep -q "event6@example.com" "out7fo.tmp" \ 17.116 && echo "Success" \ 17.117 || echo "Failed" 17.118 17.119 @@ -119,10 +146,16 @@ 17.120 && echo "Success" \ 17.121 || echo "Failed" 17.122 17.123 - ! grep -q "spoof2@example.com" "$FBFILE" \ 17.124 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 17.125 +> out8f.tmp 17.126 + 17.127 + ! grep -q "spoof2@example.com" "out8f.tmp" \ 17.128 && echo "Success" \ 17.129 || echo "Failed" 17.130 17.131 - ! grep -q "spoof2@example.com" "$FBOTHERFILE" \ 17.132 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 17.133 +> out8fo.tmp 17.134 + 17.135 + ! grep -q "spoof2@example.com" "out8fo.tmp" \ 17.136 && echo "Success" \ 17.137 || echo "Failed"
18.1 --- a/tests/test_person_invitation_add.sh Wed Mar 09 21:38:56 2016 +0100 18.2 +++ b/tests/test_person_invitation_add.sh Thu Mar 10 01:43:31 2016 +0100 18.3 @@ -4,10 +4,6 @@ 18.4 18.5 USER="mailto:vincent.vole@example.com" 18.6 SENDER="mailto:paul.boddie@example.com" 18.7 -FBFILE="$STORE/$USER/freebusy" 18.8 -FBOTHERFILE="$STORE/$USER/freebusy-other/$SENDER" 18.9 -FBSENDERFILE="$STORE/$SENDER/freebusy" 18.10 -FBSENDEROTHERFILE="$STORE/$SENDER/freebusy-other/$USER" 18.11 18.12 mkdir -p "$PREFS/$USER" 18.13 echo 'Europe/Oslo' > "$PREFS/$USER/TZID" 18.14 @@ -21,7 +17,10 @@ 18.15 18.16 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-person-recurring.txt" 2>> $ERROR 18.17 18.18 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBSENDERFILE" \ 18.19 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 18.20 +> out1f.tmp 18.21 + 18.22 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out1f.tmp" \ 18.23 && echo "Success" \ 18.24 || echo "Failed" 18.25 18.26 @@ -35,12 +34,17 @@ 18.27 && echo "Success" \ 18.28 || echo "Failed" 18.29 18.30 - ! [ -e "$FBFILE" ] \ 18.31 -|| ! grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ 18.32 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 18.33 +> out2f.tmp 18.34 + 18.35 + ! grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out2f.tmp" \ 18.36 && echo "Success" \ 18.37 || echo "Failed" 18.38 18.39 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBOTHERFILE" \ 18.40 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 18.41 +> out2fo.tmp 18.42 + 18.43 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out2fo.tmp" \ 18.44 && echo "Success" \ 18.45 || echo "Failed" 18.46 18.47 @@ -54,7 +58,10 @@ 18.48 && echo "Success" \ 18.49 || echo "Failed" 18.50 18.51 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ 18.52 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 18.53 +> out3f.tmp 18.54 + 18.55 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out3f.tmp" \ 18.56 && echo "Success" \ 18.57 || echo "Failed" 18.58 18.59 @@ -64,7 +71,10 @@ 18.60 | "$SHOWMAIL" \ 18.61 > out4.tmp 18.62 18.63 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBSENDEROTHERFILE" \ 18.64 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy_other" "$USER" \ 18.65 +> out4fo.tmp 18.66 + 18.67 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out4fo.tmp" \ 18.68 && echo "Success" \ 18.69 || echo "Failed" 18.70 18.71 @@ -72,8 +82,11 @@ 18.72 18.73 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-add-person-recurring.txt" 2>> $ERROR 18.74 18.75 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBSENDERFILE" \ 18.76 -&& grep -q "^20150109T090000Z${TAB}20150109T100000Z" "$FBSENDERFILE" \ 18.77 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 18.78 +> out4f.tmp 18.79 + 18.80 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out4f.tmp" \ 18.81 +&& grep -q "^20150109T090000Z${TAB}20150109T100000Z" "out4f.tmp" \ 18.82 && echo "Success" \ 18.83 || echo "Failed" 18.84 18.85 @@ -87,13 +100,19 @@ 18.86 && echo "Success" \ 18.87 || echo "Failed" 18.88 18.89 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ 18.90 -&& ! grep -q "^20150109T090000Z${TAB}20150109T100000Z" "$FBFILE" \ 18.91 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 18.92 +> out5f.tmp 18.93 + 18.94 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out5f.tmp" \ 18.95 +&& ! grep -q "^20150109T090000Z${TAB}20150109T100000Z" "out5f.tmp" \ 18.96 && echo "Success" \ 18.97 || echo "Failed" 18.98 18.99 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBOTHERFILE" \ 18.100 -&& ! grep -q "^20150109T090000Z${TAB}20150109T100000Z" "$FBOTHERFILE" \ 18.101 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 18.102 +> out5fo.tmp 18.103 + 18.104 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out5fo.tmp" \ 18.105 +&& ! grep -q "^20150109T090000Z${TAB}20150109T100000Z" "out5fo.tmp" \ 18.106 && echo "Success" \ 18.107 || echo "Failed" 18.108 18.109 @@ -118,13 +137,19 @@ 18.110 && echo "Success" \ 18.111 || echo "Failed" 18.112 18.113 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ 18.114 -&& ! grep -q "^20150109T090000Z${TAB}20150109T100000Z" "$FBFILE" \ 18.115 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 18.116 +> out7f.tmp 18.117 + 18.118 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out7f.tmp" \ 18.119 +&& ! grep -q "^20150109T090000Z${TAB}20150109T100000Z" "out7f.tmp" \ 18.120 && echo "Success" \ 18.121 || echo "Failed" 18.122 18.123 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBOTHERFILE" \ 18.124 -&& grep -q "^20150109T090000Z${TAB}20150109T100000Z" "$FBOTHERFILE" \ 18.125 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 18.126 +> out7fo.tmp 18.127 + 18.128 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out7fo.tmp" \ 18.129 +&& grep -q "^20150109T090000Z${TAB}20150109T100000Z" "out7fo.tmp" \ 18.130 && echo "Success" \ 18.131 || echo "Failed" 18.132 18.133 @@ -146,7 +171,10 @@ 18.134 && echo "Success" \ 18.135 || echo "Failed" 18.136 18.137 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ 18.138 -&& grep -q "^20150109T090000Z${TAB}20150109T100000Z" "$FBFILE" \ 18.139 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 18.140 +> out9f.tmp 18.141 + 18.142 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out9f.tmp" \ 18.143 +&& grep -q "^20150109T090000Z${TAB}20150109T100000Z" "out9f.tmp" \ 18.144 && echo "Success" \ 18.145 || echo "Failed"
19.1 --- a/tests/test_person_invitation_counter.sh Wed Mar 09 21:38:56 2016 +0100 19.2 +++ b/tests/test_person_invitation_counter.sh Thu Mar 10 01:43:31 2016 +0100 19.3 @@ -4,11 +4,6 @@ 19.4 19.5 USER="mailto:vincent.vole@example.com" 19.6 SENDER="mailto:paul.boddie@example.com" 19.7 -FBFILE="$STORE/$USER/freebusy" 19.8 -FBOFFERFILE="$STORE/$USER/freebusy-offers" 19.9 -FBSENDERFILE="$STORE/$SENDER/freebusy" 19.10 -FBSENDEROTHERFILE="$STORE/$SENDER/freebusy-other/$USER" 19.11 -FBSENDERREQUESTS="$STORE/$SENDER/requests" 19.12 19.13 mkdir -p "$PREFS/$USER" 19.14 echo 'Europe/Oslo' > "$PREFS/$USER/TZID" 19.15 @@ -28,7 +23,10 @@ 19.16 19.17 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-person.txt" 2>> $ERROR 19.18 19.19 - grep -q "^20141126T150000Z${TAB}20141126T160000Z" "$FBSENDERFILE" \ 19.20 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 19.21 +> out0f.tmp 19.22 + 19.23 + grep -q "^20141126T150000Z${TAB}20141126T160000Z" "out0f.tmp" \ 19.24 && echo "Success" \ 19.25 || echo "Failed" 19.26 19.27 @@ -42,8 +40,10 @@ 19.28 && echo "Success" \ 19.29 || echo "Failed" 19.30 19.31 - ! [ -e "$FBFILE" ] \ 19.32 -|| ! grep -q "event6@example.com" "$FBFILE" \ 19.33 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 19.34 +> out1f.tmp 19.35 + 19.36 + ! grep -q "event6@example.com" "out1f.tmp" \ 19.37 && echo "Success" \ 19.38 || echo "Failed" 19.39 19.40 @@ -61,9 +61,11 @@ 19.41 19.42 # Note that the invitation has only been prepared, not processed. 19.43 19.44 - ! [ -e "$FBFILE" ] \ 19.45 -|| ( ! grep -q "^20141126T150000Z${TAB}20141126T160000Z" "$FBFILE" \ 19.46 - && ! grep -q "^20141126T160000Z${TAB}20141126T170000Z" "$FBFILE" ) \ 19.47 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 19.48 +> out2f.tmp 19.49 + 19.50 + ! grep -q "^20141126T150000Z${TAB}20141126T160000Z" "out2f.tmp" \ 19.51 +&& ! grep -q "^20141126T160000Z${TAB}20141126T170000Z" "out2f.tmp" \ 19.52 && echo "Success" \ 19.53 || echo "Failed" 19.54 19.55 @@ -72,8 +74,10 @@ 19.56 && echo "Success" \ 19.57 || echo "Failed" 19.58 19.59 - ! [ -e "$FBOFFERFILE" ] \ 19.60 -|| ! grep -q "^20141126T160000Z${TAB}20141126T170000Z" "$FBOFFERFILE" \ 19.61 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_offers" \ 19.62 +> out2o.tmp 19.63 + 19.64 + ! grep -q "^20141126T160000Z${TAB}20141126T170000Z" "out2o.tmp" \ 19.65 && echo "Success" \ 19.66 || echo "Failed" 19.67 19.68 @@ -81,13 +85,18 @@ 19.69 19.70 "$OUTGOING_SCRIPT" $ARGS < out2r.tmp 2>> $ERROR 19.71 19.72 - ! [ -e "$FBFILE" ] \ 19.73 -|| ( ! grep -q "^20141126T150000Z${TAB}20141126T160000Z" "$FBFILE" \ 19.74 - && ! grep -q "^20141126T160000Z${TAB}20141126T170000Z" "$FBFILE" ) \ 19.75 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 19.76 +> out2f2.tmp 19.77 + 19.78 + ! grep -q "^20141126T150000Z${TAB}20141126T160000Z" "out2f2.tmp" \ 19.79 +&& ! grep -q "^20141126T160000Z${TAB}20141126T170000Z" "out2f2.tmp" \ 19.80 && echo "Success" \ 19.81 || echo "Failed" 19.82 19.83 - grep -q "^20141126T160000Z${TAB}20141126T170000Z" "$FBOFFERFILE" \ 19.84 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_offers" \ 19.85 +> out2o2.tmp 19.86 + 19.87 + grep -q "^20141126T160000Z${TAB}20141126T170000Z" "out2o2.tmp" \ 19.88 && echo "Success" \ 19.89 || echo "Failed" 19.90 19.91 @@ -98,21 +107,32 @@ 19.92 | "$SHOWMAIL" \ 19.93 > out3.tmp 19.94 19.95 - ! [ -e "$FBSENDEROTHERFILE" ] \ 19.96 -|| ( ! grep -q "^20141126T150000Z${TAB}20141126T160000Z" "$FBSENDEROTHERFILE" \ 19.97 - && ! grep -q "^20141126T160000Z${TAB}20141126T170000Z" "$FBSENDEROTHERFILE" ) \ 19.98 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy_other" "$USER" \ 19.99 +> out3f.tmp 19.100 + 19.101 + ! grep -q "^20141126T150000Z${TAB}20141126T160000Z" "out3f.tmp" \ 19.102 +&& ! grep -q "^20141126T160000Z${TAB}20141126T170000Z" "out3f.tmp" \ 19.103 && echo "Success" \ 19.104 || echo "Failed" 19.105 19.106 - grep -q 'DTSTART;TZID=Europe/Oslo.*:20141126T160000' "$STORE/$SENDER/objects/event6@example.com" \ 19.107 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "object" "event6@example.com" \ 19.108 +> out3O.tmp 19.109 + 19.110 + grep -q 'DTSTART;TZID=Europe/Oslo.*:20141126T160000' "out3O.tmp" \ 19.111 && echo "Success" \ 19.112 || echo "Failed" 19.113 19.114 - grep -q 'DTSTART;TZID=Europe/Oslo.*:20141126T170000' "$STORE/$SENDER/counters/objects/event6@example.com/$USER" \ 19.115 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "countered_object" "event6@example.com" "$USER" \ 19.116 +> out3C.tmp 19.117 + 19.118 + grep -q 'DTSTART;TZID=Europe/Oslo.*:20141126T170000' "out3C.tmp" \ 19.119 && echo "Success" \ 19.120 || echo "Failed" 19.121 19.122 - grep -q 'event6@example.com' "$FBSENDERREQUESTS" \ 19.123 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "requests" \ 19.124 +> out3R.tmp 19.125 + 19.126 + grep -q 'event6@example.com' "out3R.tmp" \ 19.127 && echo "Success" \ 19.128 || echo "Failed" 19.129 19.130 @@ -137,11 +157,17 @@ 19.131 19.132 "$OUTGOING_SCRIPT" $ARGS < out5.tmp 2>> $ERROR 19.133 19.134 - ! [ -e "$STORE/$SENDER/counters/objects/event6@example.com/$USER" ] \ 19.135 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "countered_object" "event6@example.com" "$USER" \ 19.136 +> out5C.tmp 19.137 + 19.138 + ! grep -q 'event6@example.com' "out5C.tmp" \ 19.139 && echo "Success" \ 19.140 || echo "Failed" 19.141 19.142 - ! grep -q 'event6@example.com' "$FBSENDERREQUESTS" \ 19.143 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "requests" \ 19.144 +> out5R.tmp 19.145 + 19.146 + ! grep -q 'event6@example.com' "out5R.tmp" \ 19.147 && echo "Success" \ 19.148 || echo "Failed" 19.149 19.150 @@ -149,13 +175,18 @@ 19.151 | "$SHOWMAIL" \ 19.152 > out6.tmp 19.153 19.154 - ! [ -e "$FBFILE" ] \ 19.155 -|| ( ! grep -q "^20141126T150000Z${TAB}20141126T160000Z" "$FBFILE" \ 19.156 - && ! grep -q "^20141126T160000Z${TAB}20141126T170000Z" "$FBFILE" ) \ 19.157 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 19.158 +> out6f.tmp 19.159 + 19.160 + ! grep -q "^20141126T150000Z${TAB}20141126T160000Z" "out6f.tmp" \ 19.161 +&& ! grep -q "^20141126T160000Z${TAB}20141126T170000Z" "out6f.tmp" \ 19.162 && echo "Success" \ 19.163 || echo "Failed" 19.164 19.165 - ! grep -q "^20141126T150000Z${TAB}20141126T160000Z" "$FBOFFERFILE" \ 19.166 -&& ! grep -q "^20141126T160000Z${TAB}20141126T170000Z" "$FBOFFERFILE" \ 19.167 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_offers" \ 19.168 +> out6o.tmp 19.169 + 19.170 + ! grep -q "^20141126T150000Z${TAB}20141126T160000Z" "out6o.tmp" \ 19.171 +&& ! grep -q "^20141126T160000Z${TAB}20141126T170000Z" "out6o.tmp" \ 19.172 && echo "Success" \ 19.173 || echo "Failed"
20.1 --- a/tests/test_person_invitation_recurring.sh Wed Mar 09 21:38:56 2016 +0100 20.2 +++ b/tests/test_person_invitation_recurring.sh Thu Mar 10 01:43:31 2016 +0100 20.3 @@ -4,9 +4,6 @@ 20.4 20.5 USER="mailto:vincent.vole@example.com" 20.6 SENDER="mailto:paul.boddie@example.com" 20.7 -FBFILE="$STORE/$USER/freebusy" 20.8 -FBOTHERFILE="$STORE/$USER/freebusy-other/$SENDER" 20.9 -FBSENDERFILE="$STORE/$SENDER/freebusy" 20.10 20.11 mkdir -p "$PREFS/$USER" 20.12 echo 'Europe/Oslo' > "$PREFS/$USER/TZID" 20.13 @@ -39,7 +36,10 @@ 20.14 20.15 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-person-recurring.txt" 2>> $ERROR 20.16 20.17 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBSENDERFILE" \ 20.18 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 20.19 +> out1f.tmp 20.20 + 20.21 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out1f.tmp" \ 20.22 && echo "Success" \ 20.23 || echo "Failed" 20.24 20.25 @@ -53,12 +53,17 @@ 20.26 && echo "Success" \ 20.27 || echo "Failed" 20.28 20.29 - ! [ -e "$FBFILE" ] \ 20.30 -|| ! grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ 20.31 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 20.32 +> out2f.tmp 20.33 + 20.34 + ! grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out2f.tmp" \ 20.35 && echo "Success" \ 20.36 || echo "Failed" 20.37 20.38 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBOTHERFILE" \ 20.39 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 20.40 +> out2o.tmp 20.41 + 20.42 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out2o.tmp" \ 20.43 && echo "Success" \ 20.44 || echo "Failed" 20.45 20.46 @@ -68,7 +73,10 @@ 20.47 | tee out3.tmp \ 20.48 | "$OUTGOING_SCRIPT" $ARGS 2>> $ERROR 20.49 20.50 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ 20.51 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 20.52 +> out3f.tmp 20.53 + 20.54 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out3f.tmp" \ 20.55 && echo "Success" \ 20.56 || echo "Failed" 20.57 20.58 @@ -76,8 +84,11 @@ 20.59 20.60 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-cancel-person-recurring-instance.txt" 2>> $ERROR 20.61 20.62 - [ `grep "event8@example.com" "$FBSENDERFILE" | wc -l` = '2' ] \ 20.63 -&& ! grep -q "^20141114T090000Z${TAB}20141114T100000Z" "$FBSENDERFILE" \ 20.64 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 20.65 +> out3s.tmp 20.66 + 20.67 + [ `grep "event8@example.com" "out3s.tmp" | wc -l` = '2' ] \ 20.68 +&& ! grep -q "^20141114T090000Z${TAB}20141114T100000Z" "out3s.tmp" \ 20.69 && echo "Success" \ 20.70 || echo "Failed" 20.71 20.72 @@ -91,13 +102,19 @@ 20.73 && echo "Success" \ 20.74 || echo "Failed" 20.75 20.76 - [ `grep "event8@example.com" "$FBFILE" | wc -l` = '2' ] \ 20.77 -&& ! grep -q "^20141114T090000Z${TAB}20141114T100000Z" "$FBFILE" \ 20.78 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 20.79 +> out4f.tmp 20.80 + 20.81 + [ `grep "event8@example.com" "out4f.tmp" | wc -l` = '2' ] \ 20.82 +&& ! grep -q "^20141114T090000Z${TAB}20141114T100000Z" "out4f.tmp" \ 20.83 && echo "Success" \ 20.84 || echo "Failed" 20.85 20.86 - [ `grep "event8@example.com" "$FBOTHERFILE" | wc -l` = '2' ] \ 20.87 -&& ! grep -q "^20141114T090000Z${TAB}20141114T100000Z" "$FBOTHERFILE" \ 20.88 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 20.89 +> out4o.tmp 20.90 + 20.91 + [ `grep "event8@example.com" "out4o.tmp" | wc -l` = '2' ] \ 20.92 +&& ! grep -q "^20141114T090000Z${TAB}20141114T100000Z" "out4o.tmp" \ 20.93 && echo "Success" \ 20.94 || echo "Failed" 20.95 20.96 @@ -105,8 +122,11 @@ 20.97 20.98 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-person-recurring-reschedule-instance.txt" 2>> $ERROR 20.99 20.100 - grep -q "^20141011T080000Z${TAB}20141011T090000Z" "$FBSENDERFILE" \ 20.101 -&& ! grep -q "^20141010T080000Z${TAB}20141010T090000Z" "$FBSENDERFILE" \ 20.102 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 20.103 +> out4s.tmp 20.104 + 20.105 + grep -q "^20141011T080000Z${TAB}20141011T090000Z" "out4s.tmp" \ 20.106 +&& ! grep -q "^20141010T080000Z${TAB}20141010T090000Z" "out4s.tmp" \ 20.107 && echo "Success" \ 20.108 || echo "Failed" 20.109 20.110 @@ -120,13 +140,19 @@ 20.111 && echo "Success" \ 20.112 || echo "Failed" 20.113 20.114 - ! grep -q "^20141011T080000Z${TAB}20141011T090000Z" "$FBFILE" \ 20.115 -&& grep -q "^20141010T080000Z${TAB}20141010T090000Z" "$FBFILE" \ 20.116 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 20.117 +> out5f.tmp 20.118 + 20.119 + ! grep -q "^20141011T080000Z${TAB}20141011T090000Z" "out5f.tmp" \ 20.120 +&& grep -q "^20141010T080000Z${TAB}20141010T090000Z" "out5f.tmp" \ 20.121 && echo "Success" \ 20.122 || echo "Failed" 20.123 20.124 - grep -q "^20141011T080000Z${TAB}20141011T090000Z" "$FBOTHERFILE" \ 20.125 -&& ! grep -q "^20141010T080000Z${TAB}20141010T090000Z" "$FBOTHERFILE" \ 20.126 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 20.127 +> out5o.tmp 20.128 + 20.129 + grep -q "^20141011T080000Z${TAB}20141011T090000Z" "out5o.tmp" \ 20.130 +&& ! grep -q "^20141010T080000Z${TAB}20141010T090000Z" "out5o.tmp" \ 20.131 && echo "Success" \ 20.132 || echo "Failed" 20.133 20.134 @@ -136,8 +162,11 @@ 20.135 | tee out6.tmp \ 20.136 | "$OUTGOING_SCRIPT" $ARGS 2>> $ERROR 20.137 20.138 - grep -q "^20141011T080000Z${TAB}20141011T090000Z" "$FBFILE" \ 20.139 -&& ! grep -q "^20141010T080000Z${TAB}20141010T090000Z" "$FBFILE" \ 20.140 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 20.141 +> out6f.tmp 20.142 + 20.143 + grep -q "^20141011T080000Z${TAB}20141011T090000Z" "out6f.tmp" \ 20.144 +&& ! grep -q "^20141010T080000Z${TAB}20141010T090000Z" "out6f.tmp" \ 20.145 && echo "Success" \ 20.146 || echo "Failed" 20.147 20.148 @@ -145,7 +174,10 @@ 20.149 20.150 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-cancel-person-recurring.txt" 2>> $ERROR 20.151 20.152 - ! grep -q "event8@example.com" "$FBSENDERFILE" \ 20.153 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 20.154 +> out6s.tmp 20.155 + 20.156 + ! grep -q "event8@example.com" "out6s.tmp" \ 20.157 && echo "Success" \ 20.158 || echo "Failed" 20.159 20.160 @@ -153,17 +185,23 @@ 20.161 20.162 "$PERSON_SCRIPT" $ARGS < "$TEMPLATES/event-cancel-person-recurring.txt" 2>> $ERROR \ 20.163 | "$SHOWMAIL" \ 20.164 -> out6.tmp 20.165 +> out7.tmp 20.166 20.167 - ! grep -q 'METHOD:REPLY' out6.tmp \ 20.168 + ! grep -q 'METHOD:REPLY' out7.tmp \ 20.169 && echo "Success" \ 20.170 || echo "Failed" 20.171 20.172 - ! grep -q "event8@example.com" "$FBFILE" \ 20.173 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 20.174 +> out7f.tmp 20.175 + 20.176 + ! grep -q "event8@example.com" "out7f.tmp" \ 20.177 && echo "Success" \ 20.178 || echo "Failed" 20.179 20.180 - ! grep -q "event8@example.com" "$FBOTHERFILE" \ 20.181 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 20.182 +> out7o.tmp 20.183 + 20.184 + ! grep -q "event8@example.com" "out7o.tmp" \ 20.185 && echo "Success" \ 20.186 || echo "Failed" 20.187 20.188 @@ -173,53 +211,74 @@ 20.189 20.190 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-person-recurring.txt" 2>> $ERROR 20.191 20.192 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBSENDERFILE" \ 20.193 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 20.194 +> out7s.tmp 20.195 + 20.196 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out7s.tmp" \ 20.197 && echo "Success" \ 20.198 || echo "Failed" 20.199 20.200 "$PERSON_SCRIPT" $ARGS < "$TEMPLATES/event-request-person-recurring.txt" 2>> $ERROR \ 20.201 | "$SHOWMAIL" \ 20.202 -> out7.tmp 20.203 +> out8.tmp 20.204 20.205 - ! grep -q 'METHOD:REPLY' out7.tmp \ 20.206 + ! grep -q 'METHOD:REPLY' out8.tmp \ 20.207 && echo "Success" \ 20.208 || echo "Failed" 20.209 20.210 - ! grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ 20.211 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 20.212 +> out8f.tmp 20.213 + 20.214 + ! grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out8f.tmp" \ 20.215 && echo "Success" \ 20.216 || echo "Failed" 20.217 20.218 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBOTHERFILE" \ 20.219 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 20.220 +> out8o.tmp 20.221 + 20.222 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out8o.tmp" \ 20.223 && echo "Success" \ 20.224 || echo "Failed" 20.225 20.226 "$ACCEPT_SCRIPT" $ACCEPT_ARGS "$USER" "event8@example.com" 2>> $ERROR \ 20.227 -| tee out8.tmp \ 20.228 +| tee out9.tmp \ 20.229 | "$OUTGOING_SCRIPT" $ARGS 2>> $ERROR 20.230 20.231 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ 20.232 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 20.233 +> out9f.tmp 20.234 + 20.235 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out9f.tmp" \ 20.236 && echo "Success" \ 20.237 || echo "Failed" 20.238 20.239 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-cancel-person-recurring.txt" 2>> $ERROR 20.240 20.241 - ! grep -q "event8@example.com" "$FBSENDERFILE" \ 20.242 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 20.243 +> out9s.tmp 20.244 + 20.245 + ! grep -q "event8@example.com" "out9s.tmp" \ 20.246 && echo "Success" \ 20.247 || echo "Failed" 20.248 20.249 "$PERSON_SCRIPT" $ARGS < "$TEMPLATES/event-cancel-person-recurring.txt" 2>> $ERROR \ 20.250 | "$SHOWMAIL" \ 20.251 -> out9.tmp 20.252 +> out10.tmp 20.253 20.254 - ! grep -q 'METHOD:REPLY' out9.tmp \ 20.255 + ! grep -q 'METHOD:REPLY' out10.tmp \ 20.256 && echo "Success" \ 20.257 || echo "Failed" 20.258 20.259 - ! grep -q "event8@example.com" "$FBFILE" \ 20.260 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 20.261 +> out10f.tmp 20.262 + 20.263 + ! grep -q "event8@example.com" "out10f.tmp" \ 20.264 && echo "Success" \ 20.265 || echo "Failed" 20.266 20.267 - ! grep -q "event8@example.com" "$FBOTHERFILE" \ 20.268 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 20.269 +> out10o.tmp 20.270 + 20.271 + ! grep -q "event8@example.com" "out10o.tmp" \ 20.272 && echo "Success" \ 20.273 || echo "Failed" 20.274 20.275 @@ -228,32 +287,44 @@ 20.276 20.277 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-person-recurring-day-floating.txt" 2>> $ERROR 20.278 20.279 - grep -q "^20141211T230000Z${TAB}20141212T230000Z" "$FBSENDERFILE" \ 20.280 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 20.281 +> out10s.tmp 20.282 + 20.283 + grep -q "^20141211T230000Z${TAB}20141212T230000Z" "out10s.tmp" \ 20.284 && echo "Success" \ 20.285 || echo "Failed" 20.286 20.287 "$PERSON_SCRIPT" $ARGS < "$TEMPLATES/event-request-person-recurring-day-floating.txt" 2>> $ERROR \ 20.288 | "$SHOWMAIL" \ 20.289 -> out10.tmp 20.290 +> out11.tmp 20.291 20.292 - ! grep -q 'METHOD:REPLY' out10.tmp \ 20.293 + ! grep -q 'METHOD:REPLY' out11.tmp \ 20.294 && echo "Success" \ 20.295 || echo "Failed" 20.296 20.297 - ! grep -q "^20141211T220000Z${TAB}20141212T220000Z" "$FBFILE" \ 20.298 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 20.299 +> out11f.tmp 20.300 + 20.301 + ! grep -q "^20141211T220000Z${TAB}20141212T220000Z" "out11f.tmp" \ 20.302 && echo "Success" \ 20.303 || echo "Failed" 20.304 20.305 # (The organiser is not attending.) 20.306 20.307 - ! grep -q "^20141211T220000Z${TAB}20141212T220000Z" "$FBOTHERFILE" \ 20.308 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 20.309 +> out11o.tmp 20.310 + 20.311 + ! grep -q "^20141211T220000Z${TAB}20141212T220000Z" "out11o.tmp" \ 20.312 && echo "Success" \ 20.313 || echo "Failed" 20.314 20.315 "$ACCEPT_SCRIPT" $ACCEPT_ARGS "$USER" "event12@example.com" 2>> $ERROR \ 20.316 -| tee out11.tmp \ 20.317 +| tee out12.tmp \ 20.318 | "$OUTGOING_SCRIPT" $ARGS 2>> $ERROR 20.319 20.320 - grep -q "^20141211T220000Z${TAB}20141212T220000Z" "$FBFILE" \ 20.321 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 20.322 +> out12f.tmp 20.323 + 20.324 + grep -q "^20141211T220000Z${TAB}20141212T220000Z" "out12f.tmp" \ 20.325 && echo "Success" \ 20.326 || echo "Failed"
21.1 --- a/tests/test_person_invitation_refresh.sh Wed Mar 09 21:38:56 2016 +0100 21.2 +++ b/tests/test_person_invitation_refresh.sh Thu Mar 10 01:43:31 2016 +0100 21.3 @@ -4,9 +4,6 @@ 21.4 21.5 USER="mailto:vincent.vole@example.com" 21.6 SENDER="mailto:paul.boddie@example.com" 21.7 -FBFILE="$STORE/$USER/freebusy" 21.8 -FBOTHERFILE="$STORE/$USER/freebusy-other/$SENDER" 21.9 -FBSENDERFILE="$STORE/$SENDER/freebusy" 21.10 21.11 mkdir -p "$PREFS/$USER" 21.12 echo 'Europe/Oslo' > "$PREFS/$USER/TZID" 21.13 @@ -21,7 +18,10 @@ 21.14 21.15 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-person-recurring.txt" 2>> $ERROR 21.16 21.17 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBSENDERFILE" \ 21.18 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 21.19 +> out1f.tmp 21.20 + 21.21 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out1f.tmp" \ 21.22 && echo "Success" \ 21.23 || echo "Failed" 21.24 21.25 @@ -45,12 +45,17 @@ 21.26 && echo "Success" \ 21.27 || echo "Failed" 21.28 21.29 - ! [ -e "$FBFILE" ] \ 21.30 -|| ! grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ 21.31 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 21.32 +> out3f.tmp 21.33 + 21.34 + ! grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out3f.tmp" \ 21.35 && echo "Success" \ 21.36 || echo "Failed" 21.37 21.38 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBOTHERFILE" \ 21.39 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 21.40 +> out3f.tmp 21.41 + 21.42 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out3f.tmp" \ 21.43 && echo "Success" \ 21.44 || echo "Failed" 21.45 21.46 @@ -60,7 +65,10 @@ 21.47 | tee out4.tmp \ 21.48 | "$OUTGOING_SCRIPT" $ARGS 2>> $ERROR 21.49 21.50 - grep -q "^20141212T090000Z${TAB}20141212T100000Z" "$FBFILE" \ 21.51 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 21.52 +> out4f.tmp 21.53 + 21.54 + grep -q "^20141212T090000Z${TAB}20141212T100000Z" "out4f.tmp" \ 21.55 && echo "Success" \ 21.56 || echo "Failed" 21.57 21.58 @@ -78,8 +86,11 @@ 21.59 21.60 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-request-person-recurring-reschedule-instance.txt" 2>> $ERROR 21.61 21.62 - grep -q "^20141011T080000Z${TAB}20141011T090000Z" "$FBSENDERFILE" \ 21.63 -&& ! grep -q "^20141010T080000Z${TAB}20141010T090000Z" "$FBSENDERFILE" \ 21.64 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 21.65 +> out5f.tmp 21.66 + 21.67 + grep -q "^20141011T080000Z${TAB}20141011T090000Z" "out5f.tmp" \ 21.68 +&& ! grep -q "^20141010T080000Z${TAB}20141010T090000Z" "out5f.tmp" \ 21.69 && echo "Success" \ 21.70 || echo "Failed" 21.71 21.72 @@ -102,8 +113,14 @@ 21.73 | "$SHOWMAIL" \ 21.74 > out6a.tmp 21.75 21.76 - [ -e "$STORE/$USER/objects/event8@example.com" ] \ 21.77 -&& [ -e "$STORE/$USER/recurrences/event8@example.com/20141010T080000Z" ] \ 21.78 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "object" "event8@example.com" \ 21.79 +> out6O.tmp 21.80 + 21.81 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "recurrence" "event8@example.com" "20141010T080000Z" \ 21.82 +> out6R.tmp 21.83 + 21.84 + grep -q 'event8@example.com' "out6O.tmp" \ 21.85 +&& grep -q 'event8@example.com' "out6R.tmp" \ 21.86 && echo "Success" \ 21.87 || echo "Failed" 21.88 21.89 @@ -112,14 +129,26 @@ 21.90 21.91 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-cancel-person-recurring-rescheduled-instance.txt" 2>> $ERROR 21.92 21.93 - [ -e "$STORE/$SENDER/objects/event8@example.com" ] \ 21.94 -&& ! [ -e "$STORE/$SENDER/recurrences/event8@example.com/20141010T080000Z" ] \ 21.95 -&& [ -e "$STORE/$SENDER/cancellations/recurrences/event8@example.com/20141010T080000Z" ] \ 21.96 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "object" "event8@example.com" \ 21.97 +> out6O2.tmp 21.98 + 21.99 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "recurrence" "event8@example.com" "20141010T080000Z" \ 21.100 +> out6R2.tmp 21.101 + 21.102 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "cancelled_recurrences" "event8@example.com" \ 21.103 +> out6C.tmp 21.104 + 21.105 + grep -q 'event8@example.com' "out6O2.tmp" \ 21.106 +&& ! grep -q 'event8@example.com' "out6R2.tmp" \ 21.107 +&& grep -q '20141010T080000Z' "out6C.tmp" \ 21.108 && echo "Success" \ 21.109 || echo "Failed" 21.110 21.111 - ! grep -q "^20141010T080000Z${TAB}20141010T090000Z" "$FBSENDERFILE" \ 21.112 -&& ! grep -q "^20141011T080000Z${TAB}20141011T090000Z" "$FBSENDERFILE" \ 21.113 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 21.114 +> out6f.tmp 21.115 + 21.116 + ! grep -q "^20141010T080000Z${TAB}20141010T090000Z" "out6f.tmp" \ 21.117 +&& ! grep -q "^20141011T080000Z${TAB}20141011T090000Z" "out6f.tmp" \ 21.118 && echo "Success" \ 21.119 || echo "Failed" 21.120 21.121 @@ -143,9 +172,18 @@ 21.122 | "$SHOWMAIL" \ 21.123 > out7a.tmp 21.124 21.125 - [ -e "$STORE/$USER/objects/event8@example.com" ] \ 21.126 -&& ! [ -e "$STORE/$USER/recurrences/event8@example.com/20141010T080000Z" ] \ 21.127 -&& [ -e "$STORE/$USER/cancellations/recurrences/event8@example.com/20141010T080000Z" ] \ 21.128 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "object" "event8@example.com" \ 21.129 +> out7O.tmp 21.130 + 21.131 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "recurrence" "event8@example.com" "20141010T080000Z" \ 21.132 +> out7R.tmp 21.133 + 21.134 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "cancelled_recurrences" "event8@example.com" \ 21.135 +> out7C.tmp 21.136 + 21.137 + grep -q 'event8@example.com' "out7O.tmp" \ 21.138 +&& ! grep -q 'event8@example.com' "out7R.tmp" \ 21.139 +&& grep -q '20141010T080000Z' "out7C.tmp" \ 21.140 && echo "Success" \ 21.141 || echo "Failed" 21.142 21.143 @@ -153,8 +191,11 @@ 21.144 21.145 "$OUTGOING_SCRIPT" $ARGS < "$TEMPLATES/event-add-person-recurring-rescheduled-instance.txt" 2>> $ERROR 21.146 21.147 - grep -q "^20141010T080000Z${TAB}20141010T090000Z" "$FBSENDERFILE" \ 21.148 -&& ! grep -q "^20141011T080000Z${TAB}20141011T090000Z" "$FBSENDERFILE" \ 21.149 + "$LIST_SCRIPT" $LIST_ARGS "$SENDER" "freebusy" \ 21.150 +> out7f.tmp 21.151 + 21.152 + grep -q "^20141010T080000Z${TAB}20141010T090000Z" "out7f.tmp" \ 21.153 +&& ! grep -q "^20141011T080000Z${TAB}20141011T090000Z" "out7f.tmp" \ 21.154 && echo "Success" \ 21.155 || echo "Failed" 21.156 21.157 @@ -162,17 +203,32 @@ 21.158 | "$SHOWMAIL" \ 21.159 > out8.tmp 21.160 21.161 - [ -e "$STORE/$USER/objects/event8@example.com" ] \ 21.162 -&& [ -e "$STORE/$USER/recurrences/event8@example.com/20141010T080000Z" ] \ 21.163 -&& ! [ -e "$STORE/$USER/cancellations/recurrences/event8@example.com/20141010T080000Z" ] \ 21.164 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "object" "event8@example.com" \ 21.165 +> out8O.tmp 21.166 + 21.167 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "recurrence" "event8@example.com" "20141010T080000Z" \ 21.168 +> out8R.tmp 21.169 + 21.170 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "cancelled_recurrences" "event8@example.com" \ 21.171 +> out8C.tmp 21.172 + 21.173 + grep -q 'event8@example.com' "out8O.tmp" \ 21.174 +&& grep -q 'event8@example.com' "out8R.tmp" \ 21.175 +&& ! grep -q '20141010T080000Z' "out8C.tmp" \ 21.176 && echo "Success" \ 21.177 || echo "Failed" 21.178 21.179 - ! grep -q "^20141010T080000Z${TAB}20141010T090000Z" "$FBFILE" \ 21.180 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 21.181 +> out8f.tmp 21.182 + 21.183 + ! grep -q "^20141010T080000Z${TAB}20141010T090000Z" "out8f.tmp" \ 21.184 && echo "Success" \ 21.185 || echo "Failed" 21.186 21.187 - grep -q "^20141010T080000Z${TAB}20141010T090000Z" "$FBOTHERFILE" \ 21.188 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy_other" "$SENDER" \ 21.189 +> out8f.tmp 21.190 + 21.191 + grep -q "^20141010T080000Z${TAB}20141010T090000Z" "out8f.tmp" \ 21.192 && echo "Success" \ 21.193 || echo "Failed" 21.194 21.195 @@ -182,7 +238,10 @@ 21.196 | tee out9.tmp \ 21.197 | "$OUTGOING_SCRIPT" $ARGS 2>> $ERROR 21.198 21.199 - grep -q "^20141010T080000Z${TAB}20141010T090000Z" "$FBFILE" \ 21.200 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "freebusy" \ 21.201 +> out9f.tmp 21.202 + 21.203 + grep -q "^20141010T080000Z${TAB}20141010T090000Z" "out9f.tmp" \ 21.204 && echo "Success" \ 21.205 || echo "Failed" 21.206 21.207 @@ -205,7 +264,13 @@ 21.208 | "$SHOWMAIL" \ 21.209 > out11.tmp 21.210 21.211 - [ -e "$STORE/$USER/objects/event8@example.com" ] \ 21.212 -&& [ -e "$STORE/$USER/recurrences/event8@example.com/20141010T080000Z" ] \ 21.213 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "object" "event8@example.com" \ 21.214 +> out11O.tmp 21.215 + 21.216 + "$LIST_SCRIPT" $LIST_ARGS "$USER" "recurrence" "event8@example.com" "20141010T080000Z" \ 21.217 +> out11R.tmp 21.218 + 21.219 + grep -q 'event8@example.com' "out11O.tmp" \ 21.220 +&& grep -q 'event8@example.com' "out11R.tmp" \ 21.221 && echo "Success" \ 21.222 || echo "Failed"
22.1 --- a/tools/install.sh Wed Mar 09 21:38:56 2016 +0100 22.2 +++ b/tools/install.sh Thu Mar 10 01:43:31 2016 +0100 22.3 @@ -28,6 +28,7 @@ 22.4 22.5 for DIR in "$INSTALL_DIR/imiptools" \ 22.6 "$INSTALL_DIR/imiptools/stores" \ 22.7 + "$INSTALL_DIR/imiptools/stores/database" \ 22.8 "$INSTALL_DIR/imiptools/handlers" \ 22.9 "$INSTALL_DIR/imiptools/handlers/scheduling" ; do 22.10 if [ ! -e "$DIR" ]; then 22.11 @@ -45,6 +46,7 @@ 22.12 22.13 cp imiptools/*.py "$INSTALL_DIR/imiptools/" 22.14 cp imiptools/stores/*.py "$INSTALL_DIR/imiptools/stores/" 22.15 +cp imiptools/stores/database/*.py "$INSTALL_DIR/imiptools/stores/database/" 22.16 cp imiptools/handlers/*.py "$INSTALL_DIR/imiptools/handlers/" 22.17 cp imiptools/handlers/scheduling/*.py "$INSTALL_DIR/imiptools/handlers/scheduling/" 22.18
23.1 --- a/tools/make_freebusy.py Wed Mar 09 21:38:56 2016 +0100 23.2 +++ b/tools/make_freebusy.py Thu Mar 10 01:43:31 2016 +0100 23.3 @@ -34,11 +34,12 @@ 23.4 sys.path.append(parent) 23.5 23.6 from codecs import getwriter 23.7 +from imiptools import config 23.8 from imiptools.client import Client 23.9 from imiptools.data import get_window_end, Object 23.10 from imiptools.dates import get_default_timezone, to_utc_datetime 23.11 from imiptools.period import FreeBusyCollection 23.12 -from imiptools.stores.file import FileStore, FilePublisher, FileJournal 23.13 +from imiptools.stores import get_store, get_publisher, get_journal 23.14 23.15 def make_freebusy(client, participant, store_and_publish, include_needs_action, 23.16 reset_updated_list, verbose): 23.17 @@ -148,6 +149,7 @@ 23.18 23.19 participants = [] 23.20 args = [] 23.21 + store_type = [] 23.22 store_dir = [] 23.23 publishing_dir = [] 23.24 journal_dir = [] 23.25 @@ -163,6 +165,8 @@ 23.26 if arg in ("-n", "-s", "-v", "-r"): 23.27 args.append(arg) 23.28 l = ignored 23.29 + elif arg == "-T": 23.30 + l = store_type 23.31 elif arg == "-S": 23.32 l = store_dir 23.33 elif arg == "-P": 23.34 @@ -188,10 +192,11 @@ 23.35 23.36 General options: 23.37 23.38 --j indicate the journal directory location 23.39 --p indicate the preferences directory location 23.40 --P indicate the publishing directory location 23.41 --S indicate the store directory location 23.42 +-j Indicates the journal directory location 23.43 +-p Indicates the preferences directory location 23.44 +-P Indicates the publishing directory location 23.45 +-S Indicates the store directory location 23.46 +-T Indicates the store type (the configured value if omitted) 23.47 """ % split(sys.argv[0])[1] 23.48 sys.exit(1) 23.49 23.50 @@ -205,16 +210,19 @@ 23.51 23.52 # Override defaults if indicated. 23.53 23.54 - store_dir = store_dir and store_dir[0] or None 23.55 - publishing_dir = publishing_dir and publishing_dir[0] or None 23.56 - journal_dir = journal_dir and journal_dir[0] or None 23.57 - preferences_dir = preferences_dir and preferences_dir[0] or None 23.58 + getvalue = lambda value, default=None: value and value[0] or default 23.59 + 23.60 + store_type = getvalue(store_type, config.STORE_TYPE) 23.61 + store_dir = getvalue(store_dir) 23.62 + publishing_dir = getvalue(publishing_dir) 23.63 + journal_dir = getvalue(journal_dir) 23.64 + preferences_dir = getvalue(preferences_dir) 23.65 23.66 # Obtain store-related objects. 23.67 23.68 - store = FileStore(store_dir) 23.69 - publisher = FilePublisher(publishing_dir) 23.70 - journal = FileJournal(journal_dir) 23.71 + store = get_store(store_type, store_dir) 23.72 + publisher = get_publisher(publishing_dir) 23.73 + journal = get_journal(store_type, journal_dir) 23.74 23.75 # Obtain a list of users for processing. 23.76
24.1 --- a/tools/update_quotas.py Wed Mar 09 21:38:56 2016 +0100 24.2 +++ b/tools/update_quotas.py Thu Mar 10 01:43:31 2016 +0100 24.3 @@ -32,9 +32,10 @@ 24.4 sys.path.append(parent) 24.5 24.6 from codecs import getwriter 24.7 +from imiptools import config 24.8 from imiptools.dates import get_datetime, get_default_timezone, get_time, \ 24.9 to_utc_datetime 24.10 -from imiptools.stores.file import FileJournal 24.11 +from imiptools.stores import get_journal 24.12 24.13 def remove_expired_entries(entries, expiry): 24.14 24.15 @@ -110,6 +111,7 @@ 24.16 24.17 quotas = [] 24.18 args = [] 24.19 + store_type = [] 24.20 journal_dir = [] 24.21 expiry = [] 24.22 ignored = [] 24.23 @@ -123,6 +125,8 @@ 24.24 if arg in ("-s", "-v"): 24.25 args.append(arg) 24.26 l = ignored 24.27 + elif arg == "-T": 24.28 + l = store_type 24.29 elif arg == "-j": 24.30 l = journal_dir 24.31 elif arg == "-e": 24.32 @@ -141,8 +145,9 @@ 24.33 24.34 General options: 24.35 24.36 --e indicate an expiry time for events (default is now) 24.37 --j indicate the journal directory location 24.38 +-e Indicates an expiry time for events (default is now) 24.39 +-j Indicates the journal directory location 24.40 +-T Indicates the store type (the configured value if omitted) 24.41 """ % split(sys.argv[0])[1] 24.42 sys.exit(1) 24.43 24.44 @@ -153,8 +158,11 @@ 24.45 24.46 # Override defaults if indicated. 24.47 24.48 - journal_dir = journal_dir and journal_dir[0] or None 24.49 - expiry = expiry and expiry[0] or None 24.50 + getvalue = lambda value, default=None: value and value[0] or default 24.51 + 24.52 + store_type = getvalue(store_type, config.STORE_TYPE) 24.53 + journal_dir = getvalue(journal_dir) 24.54 + expiry = getvalue(expiry) 24.55 24.56 if expiry: 24.57 expiry = to_utc_datetime(get_datetime(expiry), get_default_timezone()) 24.58 @@ -164,7 +172,7 @@ 24.59 24.60 # Obtain store-related objects. 24.61 24.62 - journal = FileJournal(journal_dir) 24.63 + journal = get_journal(store_type, journal_dir) 24.64 24.65 # Obtain a list of users for processing. 24.66