1.1 --- a/imip_store.py Sun Feb 07 23:35:20 2016 +0100
1.2 +++ b/imip_store.py Mon Feb 08 00:14:53 2016 +0100
1.3 @@ -3,7 +3,7 @@
1.4 """
1.5 A simple filesystem-based store of calendar data.
1.6
1.7 -Copyright (C) 2014, 2015 Paul Boddie <paul@boddie.org.uk>
1.8 +Copyright (C) 2014, 2015, 2016 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This program is free software; you can redistribute it and/or modify it under
1.11 the terms of the GNU General Public License as published by the Free Software
1.12 @@ -20,7 +20,7 @@
1.13 """
1.14
1.15 from datetime import datetime
1.16 -from imiptools.config import STORE_DIR, PUBLISH_DIR
1.17 +from imiptools.config import STORE_DIR, PUBLISH_DIR, JOURNAL_DIR
1.18 from imiptools.data import make_calendar, parse_object, to_stream
1.19 from imiptools.dates import format_datetime, get_datetime, to_timezone
1.20 from imiptools.filesys import fix_permissions, FileBase
1.21 @@ -30,12 +30,9 @@
1.22 from time import sleep
1.23 import codecs
1.24
1.25 -class FileStore(FileBase):
1.26 +class FileStoreBase(FileBase):
1.27
1.28 - "A file store of tabular free/busy data and objects."
1.29 -
1.30 - def __init__(self, store_dir=None):
1.31 - FileBase.__init__(self, store_dir or STORE_DIR)
1.32 + "A file store supporting user-specific locking and tabular data."
1.33
1.34 def acquire_lock(self, user, timeout=None):
1.35 FileBase.acquire_lock(self, timeout, user)
1.36 @@ -137,6 +134,13 @@
1.37 finally:
1.38 self.release_lock(user)
1.39
1.40 +class FileStore(FileStoreBase):
1.41 +
1.42 + "A file store of tabular free/busy data and objects."
1.43 +
1.44 + def __init__(self, store_dir=None):
1.45 + FileBase.__init__(self, store_dir or STORE_DIR)
1.46 +
1.47 # Store object access.
1.48
1.49 def _get_object(self, user, filename):
1.50 @@ -937,4 +941,90 @@
1.51
1.52 return True
1.53
1.54 +class FileJournal(FileStoreBase):
1.55 +
1.56 + "A journal system to support quotas."
1.57 +
1.58 + def __init__(self, store_dir=None):
1.59 + FileBase.__init__(self, store_dir or JOURNAL_DIR)
1.60 +
1.61 + # Groups of users sharing quotas.
1.62 +
1.63 + def get_groups(self, quota):
1.64 +
1.65 + "Return the identity mappings for the given 'quota' as a dictionary."
1.66 +
1.67 + filename = self.get_object_in_store(quota, "groups")
1.68 + if not filename or not isfile(filename):
1.69 + return {}
1.70 +
1.71 + return dict(self._get_table_atomic(quota, filename))
1.72 +
1.73 + def get_limits(self, quota):
1.74 +
1.75 + """
1.76 + Return the limits for the 'quota' as a dictionary mapping identities or
1.77 + groups to durations.
1.78 + """
1.79 +
1.80 + filename = self.get_object_in_store(quota, "limits")
1.81 + if not filename or not isfile(filename):
1.82 + return None
1.83 +
1.84 + return dict(self._get_table_atomic(quota, filename))
1.85 +
1.86 + # Free/busy period access.
1.87 +
1.88 + def get_freebusy(self, quota, user, get_table=None):
1.89 +
1.90 + "Get free/busy details for the given 'quota' and 'user'."
1.91 +
1.92 + filename = self.get_object_in_store(quota, "freebusy", user)
1.93 + if not filename or not isfile(filename):
1.94 + return []
1.95 + else:
1.96 + return map(lambda t: FreeBusyPeriod(*t),
1.97 + (get_table or self._get_table_atomic)(quota, filename, [(4, None)]))
1.98 +
1.99 + def set_freebusy(self, quota, user, freebusy, set_table=None):
1.100 +
1.101 + "For the given 'quota' and 'user', set 'freebusy' details."
1.102 +
1.103 + filename = self.get_object_in_store(quota, "freebusy", user)
1.104 + if not filename:
1.105 + return False
1.106 +
1.107 + (set_table or self._set_table_atomic)(quota, filename,
1.108 + map(lambda fb: fb.as_tuple(strings_only=True), freebusy))
1.109 + return True
1.110 +
1.111 + # Journal entry methods.
1.112 +
1.113 + def get_entries(self, quota, group):
1.114 +
1.115 + """
1.116 + Return a list of journal entries for the given 'quota' for the indicated
1.117 + 'group'.
1.118 + """
1.119 +
1.120 + filename = self.get_object_in_store(quota, "journal", group)
1.121 + if not filename or not isfile(filename):
1.122 + return []
1.123 +
1.124 + return self._get_table_atomic(quota, filename, [(1, None)])
1.125 +
1.126 + def set_entries(self, quota, group, entries):
1.127 +
1.128 + """
1.129 + For the given 'quota' and indicated 'group', set the list of journal
1.130 + 'entries'.
1.131 + """
1.132 +
1.133 + filename = self.get_object_in_store(quota, "journal", group)
1.134 + if not filename:
1.135 + return False
1.136 +
1.137 + self._set_table_atomic(quota, filename, entries, [(1, "")])
1.138 + return True
1.139 +
1.140 # vim: tabstop=4 expandtab shiftwidth=4