imip-agent

Annotated tests/test_handle.py

1336:5e4371f01764
2017-10-17 Paul Boddie Introduced convenience methods for ensuring URI values from object properties.
paul@585 1
#!/usr/bin/env python
paul@585 2
paul@585 3
"""
paul@585 4
A handler to help with testing.
paul@585 5
paul@1232 6
Copyright (C) 2014, 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
paul@585 7
paul@585 8
This program is free software; you can redistribute it and/or modify it under
paul@585 9
the terms of the GNU General Public License as published by the Free Software
paul@585 10
Foundation; either version 3 of the License, or (at your option) any later
paul@585 11
version.
paul@585 12
paul@585 13
This program is distributed in the hope that it will be useful, but WITHOUT
paul@585 14
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
paul@585 15
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
paul@585 16
details.
paul@585 17
paul@585 18
You should have received a copy of the GNU General Public License along with
paul@585 19
this program.  If not, see <http://www.gnu.org/licenses/>.
paul@585 20
"""
paul@585 21
paul@601 22
from imiptools.client import ClientForObject
paul@667 23
from imiptools.data import Object, get_address, parse_object
paul@800 24
from imiptools.dates import get_datetime, to_timezone
paul@585 25
from imiptools.mail import Messenger
paul@800 26
from imiptools.period import RecurringPeriod
paul@1088 27
from imiptools.stores import get_store, get_journal
paul@1123 28
from os.path import split
paul@585 29
import sys
paul@585 30
paul@601 31
class TestClient(ClientForObject):
paul@585 32
paul@585 33
    """
paul@585 34
    A content handler for use in testing, as opposed to operating within the
paul@585 35
    mail processing pipeline.
paul@585 36
    """
paul@585 37
paul@585 38
    # Action methods.
paul@585 39
paul@1123 40
    def handle_request(self, action, start=None, end=None, recurrenceid=None):
paul@585 41
paul@585 42
        """
paul@800 43
        Process the current request for the current user. Return whether the
paul@800 44
        given 'action' was taken.
paul@800 45
paul@800 46
        If 'start' and 'end' are specified, they will be used in any
paul@800 47
        counter-proposal.
paul@1123 48
paul@1123 49
        Where 'recurrenceid' is specified and refers to a new recurrence, the
paul@1123 50
        action will apply only to this new recurrence.
paul@585 51
        """
paul@585 52
paul@1123 53
        have_new_recurrence = self.obj.get_recurrenceid() != recurrenceid
paul@1123 54
paul@1123 55
        if have_new_recurrence:
paul@1123 56
            self.obj["RECURRENCE-ID"] = [(recurrenceid, {})]
paul@1124 57
            self.obj.remove_all(["RDATE", "RRULE"])
paul@1123 58
paul@585 59
        # Reply only on behalf of this user.
paul@585 60
paul@800 61
        if action in ("accept", "decline"):
paul@821 62
            attendee_attr = self.update_participation(action == "accept" and "ACCEPTED" or "DECLINED")
paul@800 63
            method = "REPLY"
paul@800 64
paul@800 65
        elif action == "counter":
paul@800 66
            attendee_attr = self.obj.get_value_map("ATTENDEE").get(self.user)
paul@1124 67
            method = "COUNTER"
paul@1124 68
paul@1124 69
        # Nothing else is supported.
paul@1124 70
paul@1124 71
        else:
paul@1124 72
            return None
paul@1124 73
paul@1124 74
        # For counter-proposals or new recurrences, set a new main period for
paul@1124 75
        # the event.
paul@1124 76
paul@1124 77
        if action == "counter" or have_new_recurrence:
paul@800 78
            period = self.obj.get_main_period(self.get_tzid())
paul@800 79
paul@800 80
            # Use the existing or configured time zone for the specified
paul@800 81
            # datetimes.
paul@800 82
paul@800 83
            start = to_timezone(get_datetime(start), period.tzid)
paul@800 84
            end = to_timezone(get_datetime(end), period.tzid)
paul@800 85
            period = RecurringPeriod(start, end, period.tzid, period.origin, period.get_start_attr(), period.get_end_attr())
paul@800 86
            self.obj.set_period(period)
paul@585 87
paul@1123 88
        # Where no attendees remain, no message is generated.
paul@1123 89
paul@585 90
        if not attendee_attr:
paul@585 91
            return None
paul@585 92
paul@601 93
        # NOTE: This is a simpler form of the code in imipweb.client.
paul@585 94
paul@585 95
        organiser = get_address(self.obj.get_value("ORGANIZER"))
paul@585 96
paul@803 97
        self.update_sender(attendee_attr)
paul@585 98
        self.obj["ATTENDEE"] = [(self.user, attendee_attr)]
paul@585 99
        self.update_dtstamp()
paul@809 100
        self.update_sequence(False)
paul@585 101
paul@585 102
        message = self.messenger.make_outgoing_message(
paul@800 103
            [self.obj.to_part(method)],
paul@585 104
            [organiser],
paul@585 105
            outgoing_bcc=get_address(self.user)
paul@585 106
            )
paul@585 107
paul@585 108
        return message.as_string()
paul@585 109
paul@587 110
# A simple main program that attempts to handle a stored request, writing the
paul@585 111
# response message to standard output.
paul@585 112
paul@585 113
if __name__ == "__main__":
paul@1123 114
    progname = split(sys.argv[0])[-1]
paul@1123 115
paul@585 116
    try:
paul@1088 117
        action, store_type, store_dir, journal_dir, preferences_dir, user = sys.argv[1:7]
paul@1124 118
        if len(sys.argv) >= 10:
paul@1088 119
            start, end = sys.argv[7:9]
paul@1088 120
            i = 9
paul@800 121
        else:
paul@800 122
            start, end = None, None
paul@1088 123
            i = 7
paul@800 124
        uid, recurrenceid = (sys.argv[i:i+2] + [None] * 2)[:2]
paul@585 125
    except ValueError:
paul@800 126
        print >>sys.stderr, """\
paul@1123 127
Usage: %s <action> <store type> <store directory> <journal directory>
paul@1123 128
       <preferences directory> <user URI> [ <start> <end> ]
paul@1123 129
       <uid> <recurrence-id>
paul@1123 130
paul@1088 131
Need 'accept', 'counter' or 'decline', a store type, a store directory, a
paul@1124 132
journal directory, a preferences directory, user URI, any counter-proposal or
paul@1124 133
new recurrence datetimes (see below), plus the appropriate event UID and
paul@1124 134
RECURRENCE-ID (if a recurrence is involved).
paul@800 135
paul@800 136
The RECURRENCE-ID must be in exactly the form employed by the store, not a
paul@1123 137
different but equivalent representation, if the identifier is to refer to an
paul@1123 138
existing recurrence.
paul@800 139
paul@800 140
Alternatively, omit the UID and RECURRENCE-ID and provide event-only details on
paul@800 141
standard input to force the script to handle an event not already present in the
paul@800 142
store.
paul@800 143
paul@800 144
If 'counter' has been indicated, alternative start and end datetimes are also
paul@1124 145
required. If a specific recurrence is being separated from an event, such
paul@1124 146
datetimes are also required in order to set the main period of the recurrence.
paul@800 147
"""
paul@585 148
        sys.exit(1)
paul@585 149
paul@1088 150
    store = get_store(store_type, store_dir)
paul@1088 151
    journal = get_journal(store_type, journal_dir)
paul@667 152
paul@667 153
    if uid is not None:
paul@1232 154
        obj = store.get_event(user, uid, recurrenceid)
paul@585 155
paul@1123 156
        # Permit new recurrences by getting the parent object.
paul@1123 157
paul@1232 158
        if not obj:
paul@1232 159
            obj = store.get_event(user, uid)
paul@1123 160
paul@1232 161
        if not obj:
paul@667 162
            print >>sys.stderr, "No such event:", uid, recurrenceid
paul@667 163
            sys.exit(1)
paul@667 164
    else:
paul@1232 165
        obj = Object(parse_object(sys.stdin, "utf-8"))
paul@585 166
paul@1060 167
    handler = TestClient(obj, user, Messenger(), store, None, journal, preferences_dir)
paul@1123 168
    response = handler.handle_request(action, start, end, recurrenceid)
paul@585 169
paul@585 170
    if response:
paul@667 171
        if uid is not None:
paul@667 172
            store.dequeue_request(user, uid, recurrenceid)
paul@585 173
        print response
paul@585 174
    else:
paul@585 175
        sys.exit(1)
paul@585 176
paul@585 177
# vim: tabstop=4 expandtab shiftwidth=4