def acceptShare(self, request, inviteUID, summary): # Accept the share try: shareeView = yield self._newStoreHome.acceptShare( inviteUID, summary) except DirectoryRecordNotFoundError: # Missing sharer record => fail request raise HTTPError( ErrorResponse( responsecode.FORBIDDEN, (calendarserver_namespace, "invalid-share"), "Invite UID not valid", )) if shareeView is None: raise HTTPError( ErrorResponse( responsecode.FORBIDDEN, (calendarserver_namespace, "invalid-share"), "Invite UID not valid", )) # Return the URL of the shared collection sharedAsURL = joinURL(self.url(), shareeView.shareName()) returnValue( XMLResponse(code=responsecode.OK, element=customxml.SharedAs( element.HRef.fromString(sharedAsURL))))
def doPOSTExpand(self, request): """ Expand a timezone within specified start/end dates. """ tzid = request.args.get("tzid", ()) if len(tzid) != 1: raise HTTPError(ErrorResponse( responsecode.BAD_REQUEST, (calendarserver_namespace, "valid-timezone"), "Invalid tzid query parameter", )) tzid = tzid[0] try: tzdata = readTZ(tzid) except TimezoneException: raise HTTPError(ErrorResponse( responsecode.NOT_FOUND, (calendarserver_namespace, "timezone-available"), "Timezone not found", )) try: start = request.args.get("start", ()) if len(start) != 1: raise ValueError() start = DateTime.parseText(start[0]) except ValueError: raise HTTPError(ErrorResponse( responsecode.BAD_REQUEST, (calendarserver_namespace, "valid-start-date"), "Invalid start query parameter", )) try: end = request.args.get("end", ()) if len(end) != 1: raise ValueError() end = DateTime.parseText(end[0]) if end <= start: raise ValueError() except ValueError: raise HTTPError(ErrorResponse( responsecode.BAD_REQUEST, (calendarserver_namespace, "valid-end-date"), "Invalid end query parameter", )) # Now do the expansion (but use a cache to avoid re-calculating TZs) observances = self.cache.get((tzid, start, end), None) if observances is None: observances = tzexpand(tzdata, start, end) self.cache[(tzid, start, end)] = observances # Turn into XML result = customxml.TZData( *[customxml.Observance(customxml.Onset(onset), customxml.UTCOffset(utc_offset)) for onset, utc_offset in observances] ) return XMLResponse(responsecode.OK, result)
def http_GET(self, request): """ The server-info GET method. """ yield self.authorize(request, (davxml.Read(), )) returnValue(XMLResponse(responsecode.OK, config.ServerInfo))
def doPOSTList(self, request): """ Return a list of all timezones known to the server. """ tzids = listTZs() tzids.sort() result = customxml.TZIDs(*[customxml.TZID(tzid) for tzid in tzids]) return XMLResponse(responsecode.OK, result)
def directShare(self, request): """ Directly bind an accessible calendar/address book collection into the current principal's calendar/addressbook home. @param request: the request triggering this action @type request: L{IRequest} @return: the (asynchronous) HTTP result to respond to the direct-share request. @rtype: L{Deferred} firing L{txweb2.http.Response}, failing with L{HTTPError} """ # Need to have at least DAV:read to do this yield self.authorize(request, (element.Read(), )) # Find current principal authz_principal = self.currentPrincipal(request).children[0] if not isinstance(authz_principal, element.HRef): raise HTTPError( ErrorResponse( responsecode.FORBIDDEN, (calendarserver_namespace, "valid-principal"), "Current user principal not a DAV:href", )) principalURL = str(authz_principal) if not principalURL: raise HTTPError( ErrorResponse( responsecode.FORBIDDEN, (calendarserver_namespace, "valid-principal"), "Current user principal not specified", )) sharee = (yield request.locateResource(principalURL)) # Check enabled for service from twistedcaldav.directory.principal import DirectoryCalendarPrincipalResource if not isinstance(sharee, DirectoryCalendarPrincipalResource): raise HTTPError( ErrorResponse( responsecode.FORBIDDEN, (calendarserver_namespace, "invalid-principal"), "Current user principal is not a calendar/addressbook enabled principal", )) # Get the home collection if self.isCalendarCollection(): shareeHomeResource = yield sharee.calendarHome(request) elif self.isAddressBookCollection() or self.isGroup(): shareeHomeResource = yield sharee.addressBookHome(request) else: raise HTTPError( ErrorResponse( responsecode.FORBIDDEN, (calendarserver_namespace, "invalid-principal"), "No calendar/addressbook home for principal", )) # TODO: Make sure principal is not sharing back to themselves hostURL = (yield self.canonicalURL(request)) shareeHomeURL = shareeHomeResource.url() if hostURL.startswith(shareeHomeURL): raise HTTPError( ErrorResponse( responsecode.FORBIDDEN, (calendarserver_namespace, "invalid-share"), "Can't share your own calendar or addressbook", )) # Accept it shareeView = yield self._newStoreObject.directShareWithUser( sharee.principalUID()) # Return the URL of the shared calendar sharedAsURL = joinURL(shareeHomeResource.url(), shareeView.name()) returnValue( XMLResponse(code=responsecode.OK, element=customxml.SharedAs( element.HRef.fromString(sharedAsURL))))
def doCapabilities(self, request): """ Return a list of all timezones known to the server. """ # Determine min/max date-time for iSchedule now = DateTime.getNowUTC() minDateTime = DateTime(now.getYear(), 1, 1, 0, 0, 0, Timezone.UTCTimezone) minDateTime.offsetYear(-1) maxDateTime = DateTime(now.getYear(), 1, 1, 0, 0, 0, Timezone.UTCTimezone) maxDateTime.offsetYear(10) dataTypes = [] dataTypes.append( ischedulexml.CalendarDataType(**{ "content-type": "text/calendar", "version": "2.0", })) if config.EnableJSONData: dataTypes.append( ischedulexml.CalendarDataType( **{ "content-type": "application/calendar+json", "version": "2.0", })) componentTypes = [] from twistedcaldav.ical import allowedSchedulingComponents for name in allowedSchedulingComponents: if name == "VFREEBUSY": componentTypes.append( ischedulexml.Component(ischedulexml.Method(name="REQUEST"), name=name)) else: componentTypes.append( ischedulexml.Component(ischedulexml.Method(name="REQUEST"), ischedulexml.Method(name="CANCEL"), ischedulexml.Method(name="REPLY"), name=name)) result = ischedulexml.QueryResult( ischedulexml.Capabilities( ischedulexml.Version.fromString( config.Scheduling.iSchedule.SerialNumber), ischedulexml.Versions( ischedulexml.Version.fromString("1.0"), ), ischedulexml.SchedulingMessages(*componentTypes), ischedulexml.CalendarDataTypes(*dataTypes), ischedulexml.Attachments(ischedulexml.External(), ), ischedulexml.MaxContentLength.fromString( config.MaxResourceSize), ischedulexml.MinDateTime.fromString(minDateTime.getText()), ischedulexml.MaxDateTime.fromString(maxDateTime.getText()), ischedulexml.MaxInstances.fromString( config.MaxAllowedInstances), ischedulexml.MaxRecipients.fromString( config.MaxAttendeesPerInstance), ischedulexml.Administrator.fromString( request.unparseURL(params="", querystring="", fragment="")), ), ) response = XMLResponse(responsecode.OK, result) response.headers.addRawHeader( ISCHEDULE_CAPABILITIES, str(config.Scheduling.iSchedule.SerialNumber)) return response