imip-agent

Annotated imip_store.py

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