def test_lookup(self): """ Test that L{CalendarUser.hosted} returns the expected results. """ txn = self.transactionUnderTest() cu = yield calendarUserFromCalendarUserAddress("urn:x-uid:user01", txn) yield self.commit() self.assertTrue(isinstance(cu, LocalCalendarUser)) self.assertTrue(cu.hosted()) self.assertTrue(cu.validOriginator()) self.assertTrue(cu.validRecipient()) txn = self.transactionUnderTest() cu = yield calendarUserFromCalendarUserAddress("mailto:[email protected]", txn) yield self.commit() self.assertTrue(isinstance(cu, InvalidCalendarUser)) self.assertFalse(cu.hosted()) self.assertFalse(cu.validOriginator()) self.assertFalse(cu.validRecipient()) txn = self.transactionUnderTest() cu = yield calendarUserFromCalendarUserAddress("urn:x-uid:user03", txn) yield self.commit() self.assertTrue(isinstance(cu, LocalCalendarUser)) self.assertTrue(cu.hosted()) self.assertTrue(cu.validOriginator()) self.assertFalse(cu.validRecipient())
def test_lookup(self): """ Test that L{CalendarUser.hosted} returns the expected results. """ txn = self.transactionUnderTest() cu = yield calendarUserFromCalendarUserAddress("urn:x-uid:user01", txn) yield self.commit() self.assertTrue(isinstance(cu, LocalCalendarUser)) self.assertTrue(cu.hosted()) self.assertTrue(cu.validOriginator()) self.assertTrue(cu.validRecipient()) txn = self.transactionUnderTest() cu = yield calendarUserFromCalendarUserAddress( "mailto:[email protected]", txn) yield self.commit() self.assertTrue(isinstance(cu, InvalidCalendarUser)) self.assertFalse(cu.hosted()) self.assertFalse(cu.validOriginator()) self.assertFalse(cu.validRecipient()) txn = self.transactionUnderTest() cu = yield calendarUserFromCalendarUserAddress("urn:x-uid:user03", txn) yield self.commit() self.assertTrue(isinstance(cu, LocalCalendarUser)) self.assertTrue(cu.hosted()) self.assertTrue(cu.validOriginator()) self.assertFalse(cu.validRecipient())
def test_one_event_event_details(self): """ Test when the calendar is empty. """ data = """BEGIN:VCALENDAR VERSION:2.0 PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN BEGIN:VEVENT UID:1234-5678 DTSTAMP:20080601T000000Z DTSTART:%s DTEND:%s END:VEVENT END:VCALENDAR """ % (self.now_12H.getText(), self.now_13H.getText(),) yield self._createCalendarObject(data, "user01", "test.ics") calendar = (yield self.calendarUnderTest(home="user01", name="calendar_1")) fbinfo = FreebusyQuery.FBInfo([], [], []) timerange = Period(self.now, self.now_1D) event_details = [] organizer = recipient = yield calendarUserFromCalendarUserAddress("mailto:[email protected]", self.transactionUnderTest()) freebusy = FreebusyQuery(organizer=organizer, recipient=recipient, timerange=timerange, event_details=event_details) freebusy.same_calendar_user = True result = yield freebusy.generateFreeBusyInfo([calendar, ], fbinfo) self.assertEqual(result, 1) self.assertEqual(fbinfo.busy, [Period(self.now_12H, self.now_13H), ]) self.assertEqual(len(fbinfo.tentative), 0) self.assertEqual(len(fbinfo.unavailable), 0) self.assertEqual(len(event_details), 1) self.assertEqual(str(event_details[0]), str(tuple(Component.fromString(data).subcomponents())[0]))
def test_freebusy(self): """ Test that action=component works. """ yield self.createShare("user01", "puser01") calendar1 = yield self.calendarUnderTest(txn=self.theTransactionUnderTest(0), home="user01", name="calendar") yield calendar1.createCalendarObjectWithName("1.ics", Component.fromString(self.caldata1)) yield self.commitTransaction(0) fbstart = "{now:04d}0102T000000Z".format(**self.nowYear) fbend = "{now:04d}0103T000000Z".format(**self.nowYear) shared = yield self.calendarUnderTest(txn=self.theTransactionUnderTest(1), home="puser01", name="shared-calendar") fbinfo = FreebusyQuery.FBInfo([], [], []) timerange = Period(DateTime.parseText(fbstart), DateTime.parseText(fbend)) organizer = recipient = (yield calendarUserFromCalendarUserAddress("mailto:[email protected]", self.theTransactionUnderTest(1))) freebusy = FreebusyQuery(organizer=organizer, recipient=recipient, timerange=timerange) matchtotal = (yield freebusy.generateFreeBusyInfo([shared, ], fbinfo)) self.assertEqual(matchtotal, 1) self.assertEqual(fbinfo[0], [Period.parseText("{now:04d}0102T140000Z/PT1H".format(**self.nowYear)), ]) self.assertEqual(len(fbinfo[1]), 0) self.assertEqual(len(fbinfo[2]), 0) yield self.commitTransaction(1)
def checkAttendeeAsOriginator(self): """ Check the validity of the ATTENDEE value as this is the originator of the iTIP message. Only local attendees are allowed for message originating from this server. """ # Attendee's MUST be the request URI owner attendeeAddress = yield calendarUserFromCalendarUserAddress(self.attendee, self.txn) if attendeeAddress.hosted(): if self.doingPOST is not None and attendeeAddress.record.uid != self.originator_uid: log.error("ATTENDEE in calendar data does not match owner of Outbox: {a}", a=self.attendee) raise HTTPError( self.errorResponse( responsecode.FORBIDDEN, self.errorElements["attendee-denied"], "Outbox does not belong to attendee", ) ) else: log.error("Unknown ATTENDEE in calendar data: {a}", a=self.attendee) raise HTTPError( self.errorResponse( responsecode.FORBIDDEN, self.errorElements["attendee-denied"], "No principal for attendee" ) )
def checkOriginator(self): """ Check the validity of the Originator header. Extract the corresponding principal. """ # Verify that Originator is a valid calendar user originatorAddress = yield calendarUserFromCalendarUserAddress( self.originator, self.txn) if not originatorAddress.hosted(): # Local requests MUST have a principal. log.error( "Could not find principal for originator: {o}", o=self.originator, ) raise HTTPError( self.errorResponse( responsecode.FORBIDDEN, self.errorElements["originator-denied"], "No principal for originator", )) else: if not originatorAddress.validOriginator() or isinstance( originatorAddress, OtherServerCalendarUser): log.error( "Originator not enabled or hosted on this server: {o}", o=self.originator, ) raise HTTPError( self.errorResponse( responsecode.FORBIDDEN, self.errorElements["originator-denied"], "Originator cannot be scheduled", )) self.originator = originatorAddress
def checkOriginator(self): """ Check the validity of the Originator header. Extract the corresponding principal. """ # Verify that Originator is a valid calendar user originatorAddress = yield calendarUserFromCalendarUserAddress(self.originator, self.txn) if not originatorAddress.hosted(): # Local requests MUST have a principal. log.error("Could not find principal for originator: {o}", o=self.originator) raise HTTPError( self.errorResponse( responsecode.FORBIDDEN, self.errorElements["originator-denied"], "No principal for originator" ) ) else: if not originatorAddress.validOriginator() or isinstance(originatorAddress, OtherServerCalendarUser): log.error("Originator not enabled or hosted on this server: {o}", o=self.originator) raise HTTPError( self.errorResponse( responsecode.FORBIDDEN, self.errorElements["originator-denied"], "Originator cannot be scheduled", ) ) self.originator = originatorAddress
def checkAttendeeAsOriginator(self): """ Check the validity of the ATTENDEE value as this is the originator of the iTIP message. Only local attendees are allowed for message originating from this server. """ # Attendee's MUST be the request URI owner attendeeAddress = yield calendarUserFromCalendarUserAddress( self.attendee, self.txn) if attendeeAddress.hosted(): if self.doingPOST is not None and attendeeAddress.record.uid != self.originator_uid: log.error( "ATTENDEE in calendar data does not match owner of Outbox: {a}", a=self.attendee, ) raise HTTPError( self.errorResponse( responsecode.FORBIDDEN, self.errorElements["attendee-denied"], "Outbox does not belong to attendee", )) else: log.error( "Unknown ATTENDEE in calendar data: {a}", a=self.attendee, ) raise HTTPError( self.errorResponse( responsecode.FORBIDDEN, self.errorElements["attendee-denied"], "No principal for attendee", ))
def recv_freebusy(self, txn, request): """ Process a freebusy cross-pod request. Message arguments as per L{send_freebusy}. @param request: request arguments @type request: C{dict} """ # Operate on the L{CommonHomeChild} calresource, _ignore = yield self._getStoreObjectForRequest( txn, request) organizer = yield calendarUserFromCalendarUserAddress( request["organizer"], txn) if request["organizer"] else None recipient = yield calendarUserFromCalendarUserAddress( request["recipient"], txn) if request["recipient"] else None freebusy = FreebusyQuery( organizer=organizer, recipient=recipient, timerange=Period.parseText(request["timerange"]), excludeUID=request["excludeuid"], event_details=request["event_details"], ) fbinfo = FreebusyQuery.FBInfo([], [], []) matchtotal = yield freebusy.generateFreeBusyInfo( [ calresource, ], fbinfo, matchtotal=request["matchtotal"], ) # Convert L{Period} objects to text for JSON response returnValue({ "fbresults": [ [item.getText() for item in fbinfo.busy], [item.getText() for item in fbinfo.tentative], [item.getText() for item in fbinfo.unavailable], ], "matchtotal": matchtotal, })
def checkRecipients(self): """ Check the validity of the Recipient header values. These must all be local as there is no concept of server-to-server relaying. """ results = [] for recipient in self.recipients: # Get the calendar user object for this recipient recipientAddress = yield calendarUserFromCalendarUserAddress( recipient, self.txn) # If no calendar user we may have a remote recipient but we should check whether # the address is one that ought to be on our server and treat that as a missing # user. Also if server-to-server is not enabled then remote addresses are not allowed. if not recipientAddress.hosted(): localUser = ( yield addressmapping.mapper.isCalendarUserInMyDomain(recipient)) if localUser: log.error( "No record for calendar user address: {r}", r=recipient, ) else: log.error( "Unknown calendar user address: {r}", r=recipient, ) results.append(InvalidCalendarUser(recipient)) else: # Map recipient to their inbox and cache on calendar user object inbox = None if recipientAddress.validRecipient(): if isinstance(recipientAddress, LocalCalendarUser): recipient_home = yield self.txn.calendarHomeWithUID( recipientAddress.record.uid, create=True) if recipient_home: inbox = (yield recipient_home.calendarWithName("inbox")) else: inbox = "dummy" recipientAddress.inbox = inbox if inbox: results.append(recipientAddress) else: log.error( "No scheduling for calendar user: {r}", r=recipient, ) results.append(InvalidCalendarUser(recipient)) self.recipients = results
def checkOrganizer(self): """ Check the validity of the ORGANIZER value. ORGANIZER must be local. """ # Verify that the ORGANIZER's cu address maps to a valid user organizer = self.calendar.getOrganizer() if organizer: organizerAddress = yield calendarUserFromCalendarUserAddress(organizer, self.txn) if organizerAddress.hosted(): if organizerAddress.validOriginator(): # Only do this check for a freebusy request. A check for an invite needs # to be handled later when we know whether a new invite is being added # (which we reject) vs an update to an existing one (which we allow). if self.checkForFreeBusy() and not organizerAddress.record.enabledAsOrganizer(): log.error("ORGANIZER not allowed to be an Organizer: {cal}", cal=self.calendar) raise HTTPError( self.errorResponse( responsecode.FORBIDDEN, self.errorElements["organizer-denied"], "Organizer cannot schedule", ) ) self.organizer = organizerAddress else: log.error("No scheduling for ORGANIZER: {o}", o=organizer) raise HTTPError( self.errorResponse( responsecode.FORBIDDEN, self.errorElements["organizer-denied"], "Organizer cannot schedule" ) ) else: localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(organizer)) if localUser: log.error("No principal for ORGANIZER in calendar data: {cal}", cal=self.calendar) raise HTTPError( self.errorResponse( responsecode.FORBIDDEN, self.errorElements["organizer-denied"], "No principal for organizer" ) ) else: self.organizer = organizerAddress else: log.error("ORGANIZER missing in calendar data: {cal}", cal=self.calendar) raise HTTPError( self.errorResponse( responsecode.FORBIDDEN, self.errorElements["invalid-scheduling-message"], "Missing organizer" ) )
def recv_freebusy(self, txn, request): """ Process a freebusy cross-pod request. Message arguments as per L{send_freebusy}. @param request: request arguments @type request: C{dict} """ # Operate on the L{CommonHomeChild} calresource, _ignore = yield self._getStoreObjectForRequest(txn, request) organizer = yield calendarUserFromCalendarUserAddress(request["organizer"], txn) if request["organizer"] else None recipient = yield calendarUserFromCalendarUserAddress(request["recipient"], txn) if request["recipient"] else None freebusy = FreebusyQuery( organizer=organizer, recipient=recipient, timerange=Period.parseText(request["timerange"]), excludeUID=request["excludeuid"], event_details=request["event_details"], ) fbinfo = FreebusyQuery.FBInfo([], [], []) matchtotal = yield freebusy.generateFreeBusyInfo( [calresource, ], fbinfo, matchtotal=request["matchtotal"], ) # Convert L{Period} objects to text for JSON response returnValue({ "fbresults": [ [item.getText() for item in fbinfo.busy], [item.getText() for item in fbinfo.tentative], [item.getText() for item in fbinfo.unavailable], ], "matchtotal": matchtotal, })
def checkRecipients(self): """ Check the validity of the Recipient header values. These must all be local as there is no concept of server-to-server relaying. """ results = [] for recipient in self.recipients: # Get the calendar user object for this recipient recipientAddress = yield calendarUserFromCalendarUserAddress(recipient, self.txn) # If no calendar user we may have a remote recipient but we should check whether # the address is one that ought to be on our server and treat that as a missing # user. Also if server-to-server is not enabled then remote addresses are not allowed. if not recipientAddress.hosted(): localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(recipient)) if localUser: log.error( "No record for calendar user address: {r}", r=recipient, ) else: log.error( "Unknown calendar user address: {r}", r=recipient, ) results.append(InvalidCalendarUser(recipient)) else: # Map recipient to their inbox and cache on calendar user object inbox = None if recipientAddress.validRecipient(): if isinstance(recipientAddress, LocalCalendarUser): recipient_home = yield self.txn.calendarHomeWithUID(recipientAddress.record.uid, create=True) if recipient_home: inbox = (yield recipient_home.calendarWithName("inbox")) else: inbox = "dummy" recipientAddress.inbox = inbox if inbox: results.append(recipientAddress) else: log.error( "No scheduling for calendar user: {r}", r=recipient, ) results.append(InvalidCalendarUser(recipient)) self.recipients = results
def checkOrganizer(self): """ Check the validity of the ORGANIZER value. ORGANIZER must be local. """ # Verify that the ORGANIZER's cu address maps to a valid user organizer = self.calendar.getOrganizer() if organizer: organizerAddress = yield calendarUserFromCalendarUserAddress(organizer, self.txn) if organizerAddress.hosted(): if organizerAddress.validOriginator(): # Only do this check for a freebusy request. A check for an invite needs # to be handled later when we know whether a new invite is being added # (which we reject) vs an update to an existing one (which we allow). if self.checkForFreeBusy() and not organizerAddress.record.enabledAsOrganizer(): log.error("ORGANIZER not allowed to be an Organizer: {cal}", cal=self.calendar,) raise HTTPError(self.errorResponse( responsecode.FORBIDDEN, self.errorElements["organizer-denied"], "Organizer cannot schedule", )) self.organizer = organizerAddress else: log.error("No scheduling for ORGANIZER: {o}", o=organizer,) raise HTTPError(self.errorResponse( responsecode.FORBIDDEN, self.errorElements["organizer-denied"], "Organizer cannot schedule", )) else: localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(organizer)) if localUser: log.error("No principal for ORGANIZER in calendar data: {cal}", cal=self.calendar,) raise HTTPError(self.errorResponse( responsecode.FORBIDDEN, self.errorElements["organizer-denied"], "No principal for organizer", )) else: self.organizer = organizerAddress else: log.error("ORGANIZER missing in calendar data: {cal}", cal=self.calendar,) raise HTTPError(self.errorResponse( responsecode.FORBIDDEN, self.errorElements["invalid-scheduling-message"], "Missing organizer", ))
def test_no_events(self): """ Test when the calendar is empty. """ calendar = (yield self.calendarUnderTest(home="user01", name="calendar_1")) fbinfo = FreebusyQuery.FBInfo([], [], []) timerange = Period(self.now, self.now_1D) organizer = recipient = yield calendarUserFromCalendarUserAddress("mailto:[email protected]", self.transactionUnderTest()) freebusy = FreebusyQuery(organizer=organizer, recipient=recipient, timerange=timerange) result = (yield freebusy.generateFreeBusyInfo([calendar, ], fbinfo)) self.assertEqual(result, 0) self.assertEqual(len(fbinfo.busy), 0) self.assertEqual(len(fbinfo.tentative), 0) self.assertEqual(len(fbinfo.unavailable), 0)
def test_one_event_event_details(self): """ Test when the calendar is empty. """ data = """BEGIN:VCALENDAR VERSION:2.0 PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN BEGIN:VEVENT UID:1234-5678 DTSTAMP:20080601T000000Z DTSTART:%s DTEND:%s END:VEVENT END:VCALENDAR """ % ( self.now_12H.getText(), self.now_13H.getText(), ) yield self._createCalendarObject(data, "user01", "test.ics") calendar = (yield self.calendarUnderTest(home="user01", name="calendar_1")) fbinfo = FreebusyQuery.FBInfo([], [], []) timerange = Period(self.now, self.now_1D) event_details = [] organizer = recipient = yield calendarUserFromCalendarUserAddress( "mailto:[email protected]", self.transactionUnderTest()) freebusy = FreebusyQuery(organizer=organizer, recipient=recipient, timerange=timerange, event_details=event_details) freebusy.same_calendar_user = True result = yield freebusy.generateFreeBusyInfo([ calendar, ], fbinfo) self.assertEqual(result, 1) self.assertEqual(fbinfo.busy, [ Period(self.now_12H, self.now_13H), ]) self.assertEqual(len(fbinfo.tentative), 0) self.assertEqual(len(fbinfo.unavailable), 0) self.assertEqual(len(event_details), 1) self.assertEqual( str(event_details[0]), str(tuple(Component.fromString(data).subcomponents())[0]))
def test_no_events(self): """ Test when the calendar is empty. """ calendar = (yield self.calendarUnderTest(home="user01", name="calendar_1")) fbinfo = FreebusyQuery.FBInfo([], [], []) timerange = Period(self.now, self.now_1D) organizer = recipient = yield calendarUserFromCalendarUserAddress( "mailto:[email protected]", self.transactionUnderTest()) freebusy = FreebusyQuery(organizer=organizer, recipient=recipient, timerange=timerange) result = (yield freebusy.generateFreeBusyInfo([ calendar, ], fbinfo)) self.assertEqual(result, 0) self.assertEqual(len(fbinfo.busy), 0) self.assertEqual(len(fbinfo.tentative), 0) self.assertEqual(len(fbinfo.unavailable), 0)