imip-agent

imiptools/handlers/scheduling/access.py

1128:a0043845de02
2016-04-19 Paul Boddie Test changes in attendance for declined recurrences. freebusy-collections
     1 #!/usr/bin/env python     2      3 """     4 Access-control-related scheduling functionality.     5      6 Copyright (C) 2016 Paul Boddie <paul@boddie.org.uk>     7      8 This program is free software; you can redistribute it and/or modify it under     9 the terms of the GNU General Public License as published by the Free Software    10 Foundation; either version 3 of the License, or (at your option) any later    11 version.    12     13 This program is distributed in the hope that it will be useful, but WITHOUT    14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    15 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    16 details.    17     18 You should have received a copy of the GNU General Public License along with    19 this program.  If not, see <http://www.gnu.org/licenses/>.    20 """    21     22 from imiptools.data import get_address, get_addresses    23 from imiptools.text import parse_line    24 import codecs    25     26 def access_control_list(handler, args):    27     28     """    29     Attempt to schedule the current object of the given 'handler' using an    30     access control list provided in the given 'args', applying it to the    31     organiser.    32     """    33     34     # Obtain either a file from the user's preferences directory...    35     36     if not args:    37         acl = handler.get_preferences().get("acl")    38         lines = acl.strip().split("\n")    39     40     # Or obtain the contents of a specific file.    41     42     else:    43         try:    44             f = codecs.open(args[0], encoding="utf-8")    45         except IOError:    46             return None    47         try:    48             lines = f.readlines()    49         finally:    50             f.close()    51     52     # Use the current object's identities with the ACL rules.    53     54     organiser = get_address(handler.obj.get_value("ORGANIZER"))    55     attendees = get_addresses(handler.obj.get_values("ATTENDEE"))    56     57     response = None    58     59     for line in lines:    60         parts = parse_line(line.strip())    61     62         # Skip empty lines.    63     64         if not parts:    65             continue    66     67         # Accept either a single word with an action or a rule.    68         # NOTE: Should signal an error with the format.    69     70         if len(parts) == 1:    71             action = parts[0]    72         elif len(parts) >= 3:    73             action, role, identities = parts[0], parts[1], map(get_address, parts[2:])    74         else:    75             return None    76     77         if action.lower() == "accept":    78             result = "ACCEPTED"    79         elif action.lower() in ["decline", "reject"]:    80             result = "DECLINED"    81         else:    82             return None    83     84         # With only an action, prepare a default response in case none of    85         # the rules match.    86     87         if len(parts) == 1:    88             response = result    89             continue    90     91         # Where no default has been set, use an implicit default based on    92         # the action appearing in a rule.    93     94         elif not response:    95             response = result == "ACCEPTED" and "DECLINED" or "ACCEPTED"    96     97         # Interpret a rule, attempting to match identities to properties.    98     99         if role.lower() in ["organiser", "organizer"]:   100             match = organiser in identities   101         elif role.lower() in ["attendee", "attendees"]:   102             match = set(attendees).intersection(identities)   103         else:   104             return None   105    106         # Use the result of any match.   107    108         if match:   109             response = result   110    111     return response   112    113 def same_domain_only(handler, args):   114    115     """   116     Attempt to schedule the current object of the given 'handler' if the   117     organiser employs an address in the same domain as the resource.   118     """   119    120     organiser = get_address(handler.obj.get_value("ORGANIZER"))   121     user = get_address(handler.user)   122    123     organiser_domain = organiser.rsplit("@", 1)[-1]   124     user_domain = user.rsplit("@", 1)[-1]   125        126     return organiser_domain == user_domain and "ACCEPTED" or "DECLINED"   127    128 # Registry of scheduling functions.   129    130 scheduling_functions = {   131     "access_control_list" : access_control_list,   132     "same_domain_only" : same_domain_only,   133     }   134    135 # Registries of locking and unlocking functions.   136    137 locking_functions = {}   138 unlocking_functions = {}   139    140 # Registries of listener functions.   141    142 confirmation_functions = {}   143 retraction_functions = {}   144    145 # vim: tabstop=4 expandtab shiftwidth=4