예제 #1
0
def mongo_to_ics(events, sub: db.Subscription = None):
    """
    creates the iCal based on the MongoDb database and events submitted
    """

    # initialize calendar object
    cal = Calendar()
    cal.add('PRODID', 'ABE')
    cal.add('VERSION', '2.0')
    for event in events:
        new_event = create_ics_event(
            event, sub=sub)  # create the base event fields in ics format

        recurrence = event['recurrence']
        if recurrence:
            new_event = create_ics_recurrence(
                new_event, recurrence)  # create the rrule field

        if event['sub_events']:
            for sub_event in event['sub_events']:
                full_sub_event = sub_event_to_full(mongo_to_dict(sub_event),
                                                   event)
                new_sub_event = create_ics_event(full_sub_event, True)
                cal.add_component(new_sub_event)
                new_event.add('EXDATE', sub_event['rec_id'])

        # vevent.add('attendee', 'MAILTO:[email protected]')

        cal.add_component(new_event)
    response = cal.to_ical()
    return response
예제 #2
0
    def get_events(self):
        query_dict = get_to_event_search(request)

        query_time_period = query_dict['end'] - query_dict['start']
        if query_time_period > timedelta(days=366):
            return "Too wide of date range in query. Max date range of 1 year allowed.", 404

        if not request_has_scope(request, 'read:all_events'):
            query_dict['visibility'] = 'public'

        query = event_query(query_dict)
        results = db.Event.objects(
            __raw__=query)  # {'start': new Date('2017-06-14')})
        logging.debug('found %s events for query', len(results))

        # date range for query
        start = query_dict['start']
        end = query_dict['end']

        events_list = []
        for event in results:
            if 'recurrence' in event:  # checks for recurrent events
                # expands a recurring event defintion into a json response with individual events
                events_list = recurring_to_full(event, events_list, start, end)
            else:  # appends the event information as a dictionary
                events_list.append(mongo_to_dict(event))
        return events_list
예제 #3
0
def recurring_to_full(event, events_list, start, end):
    """Expands recurring events in MongoDb to multiple placeholder objects
    event           mongoDB event

    events_list     list of events to be returned

    start, end      start and end indicating the query date range
    """
    if 'sub_events' in event:  # if there are sub_events in event
        for sub_event in event['sub_events']:
            if 'start' in sub_event:
                # if the sub_event fits into the date range and is not deleted
                if sub_event['start'] <= end and sub_event['start'] >= start \
                        and not sub_event['deleted']:
                    events_list.append(
                        sub_event_to_full(mongo_to_dict(sub_event), event))
    # generate a list of all datetimes a recurring event would occur
    rule_list = instance_creation(event, start, end)
    # for each instance create a full event definition based on its parent event
    for instance in rule_list:

        def convert_timezone(a):
            return a.replace(tzinfo=pytz.UTC) if isinstance(a, datetime) else a

        if convert_timezone(instance) >= convert_timezone(
                start) and convert_timezone(instance) < convert_timezone(end):
            events_list = placeholder_recurring_creation(
                instance, events_list, event)

    return (events_list)
예제 #4
0
def update_sub_event(received_data, parent_event, sub_event_id, ics=False):
    """edits a sub_event that has already been created

    sub_event_id        if the update is not coming from an ics feed:
                            - will be an objectid
                        if the update is coming from an ics feed:
                            - will be a rec_id (datetime object)
    """
    def convert_timezone(a):
        return a.replace(tzinfo=pytz.UTC) if isinstance(a, datetime) else a

    for sub_event in parent_event.sub_events:
        if not ics:  # if this update is not coming from an ics feed
            # if the sub_event to be updated's id matches the id of the received_data
            if sub_event['_id'] == sub_event_id:
                updated_sub_event_dict = create_new_sub_event_defintion(
                    mongo_to_dict(sub_event), received_data, parent_event)
                updated_sub_event = db.RecurringEventExc(
                    **updated_sub_event_dict)
                parent_event.update(pull__sub_events___id=sub_event_id)
                parent_event.update(
                    add_to_set__sub_events=updated_sub_event_dict)
                if not updated_sub_event_dict['forever']:
                    parent_event.recurrence_end = find_recurrence_end(
                        parent_event)
                parent_event.save()
                parent_event.reload()
                return (updated_sub_event)
        else:  # if this update is coming from an ics feed
            sub_event_compare = convert_timezone(sub_event["rec_id"])
            if sub_event_compare == sub_event_id:
                updated_sub_event_dict = create_new_sub_event_defintion(
                    mongo_to_dict(sub_event), received_data, parent_event)
                updated_sub_event = db.RecurringEventExc(
                    **updated_sub_event_dict)
                parent_event.update(pull__sub_events__rec_id=sub_event_id)
                parent_event.update(
                    add_to_set__sub_events=updated_sub_event_dict)
                if not updated_sub_event_dict['forever']:
                    parent_event.recurrence_end = find_recurrence_end(
                        parent_event)
                parent_event.save()
                parent_event.reload()
                return (updated_sub_event)
예제 #5
0
    def get_event_by_id(self, event_id, rec_id):
        # This doesn't check the scope for viewing non-public events. These
        # events are protected by the obscurity of their ids: the event id is as
        # well-protected as the rest of its data.
        logging.debug('Event requested: %s', event_id)
        result = db.Event.objects(id=event_id).first()

        if not result:  # if there are no events with the event_id given
            # search for sub_events with that id and save the parent event
            cur_parent_event = db.Event.objects(
                __raw__={
                    'sub_events._id': objectid.ObjectId(event_id)
                }).first()

            if cur_parent_event:  # if a sub_event was found
                # access the information of the sub_event
                cur_sub_event = access_sub_event(
                    mongo_to_dict(cur_parent_event),
                    objectid.ObjectId(event_id))
                # expand the sub_event to inherit from the parent event
                return sub_event_to_full(cur_sub_event, cur_parent_event)
            else:
                logging.debug("No sub_event found")
                abort(404)
        # if an event was found and there is a rec_id given, a sub_event needs to be returned
        elif rec_id:
            # the json response will be used to display the information of the sub_event before it is edited
            logging.debug('Sub_event requested: %s', rec_id)
            # return a json response with the parent event information filled in with
            # the start and end datetimes updated from the rec_id
            result = placeholder_recurring_creation(rec_id, [], result, True)
            if not result:
                return f"Subevent not found with identifier '{rec_id}'", 404
            return result

        if not result:
            return f"Event not found with identifier '{event_id}'", 404
        return mongo_to_dict(result)
예제 #6
0
def duplicate_query_check(sub_event_dict, parent_event):
    """checks whether a dictionary has the same field-value pair as a parent event
    used to check for duplicate information in sub_events and their parent events
    """
    parent_event_dict = mongo_to_dict(parent_event)
    fields_to_pop = []
    for field in sub_event_dict:
        if field in parent_event_dict:
            if sub_event_dict[field] == parent_event_dict[field]:
                fields_to_pop.append(field)
    for field in fields_to_pop:
        sub_event_dict.pop(field)

    return (sub_event_dict)
예제 #7
0
 def post(self):
     """
     Create new event with parameters passed in through args or form
     """
     received_data = request_to_dict(request)
     logging.debug("Received POST data: %s",
                   received_data)  # combines args and form
     new_event = db.Event(**received_data)
     if not request_has_scope(request, 'create:protected_events'):
         check_protected_labels(new_event.labels)
     if 'recurrence' in new_event:  # if this is a recurring event
         if not new_event.recurrence.forever:  # if it doesn't recur forever
             # find the end of the recurrence
             new_event.recurrence_end = find_recurrence_end(new_event)
     new_event.save()
     return mongo_to_dict(new_event), 201
예제 #8
0
def cal_to_event(cal):
    """ Creates an event from a calendar object """
    received_data, sender = ical_to_dict(cal)
    try:
        new_event = db.Event(**received_data)
        if new_event.labels == []:  # if no labels were given
            new_event.labels = ['unlabeled']
        if 'recurrence' in new_event:  # if this is a recurring event
            if not new_event.recurrence.forever:  # if it doesn't recurr forever
                # find the end of the recurrence
                new_event.recurrence_end = find_recurrence_end(new_event)
        new_event.save()
    except ValidationError as error:
        error_reply(sender, error)
        return {
            'error_type': 'validation',
            'validation_errors': [str(err) for err in error.errors],
            'error_message': error.message
        }, 400
    else:  # return success
        new_event_dict = mongo_to_dict(new_event)
        reply_email(sender, new_event_dict)
        return new_event_dict, 201
예제 #9
0
    def delete(self, event_id, rec_id=None):
        """
        Delete individual event

        event_id        the id of the event to be deleted

        rec_id          the rec_id of a sub_event to be deleted
        """
        # TODO: call check_protected_labels(result.labels)
        # if not request_has_scope(request, 'delete:protected_events')
        logging.debug('Event requested: %s', event_id)
        result = db.Event.objects(id=event_id).first()
        if not result:  # if no event is found with the id given
            # try finding a sub_event with that id
            cur_parent_event = db.Event.objects(
                __raw__={
                    'sub_events._id': objectid.ObjectId(event_id)
                }).first()
            if cur_parent_event:  # if found update the deleted field of the sub_event
                received_data = {'deleted': True}
                result = update_sub_event(received_data, cur_parent_event,
                                          objectid.ObjectId(event_id))
                logging.debug("Edited sub_event deleted")
            else:
                abort(404)
        elif rec_id:  # if this is a sub_event of a recurring event that has not been created yet
            sub_event_dummy = placeholder_recurring_creation(
                rec_id, [], result, True)
            sub_event_dummy['deleted'] = True
            # create a sub_event with the deleted field set to true
            create_sub_event(sub_event_dummy, result)
            logging.debug("Deleted sub_event for the first time")
        else:  # if a normal event is to be deleted
            received_data = request_to_dict(request)
            logging.debug("Received DELETE data: %s", received_data)
            result.delete()
            return mongo_to_dict(result)
예제 #10
0
    def put(self, event_id):
        """
        Modify individual event

        event_id        id of the event to modify
        """
        received_data = request_to_dict(request)
        logging.debug("Received PUT data: %s", received_data)
        result = db.Event.objects(id=event_id).first()
        if not result:  # if no event was found
            # try finding a sub_event with the id and save the parent event it is stored under
            cur_parent_event = db.Event.objects(
                __raw__={
                    'sub_events._id': objectid.ObjectId(event_id)
                }).first()
            if cur_parent_event:  # if a sub_event was found, updated it with the received_data
                result = update_sub_event(received_data, cur_parent_event,
                                          objectid.ObjectId(event_id))
            else:
                abort(404)
        else:  # if event was found
            if not request_has_scope(request, 'edit:protected_events'):
                check_protected_labels(result.labels)
                # TODO: also check the new labels
            # if the received data is a new sub_event
            if 'sid' in received_data and received_data['sid'] is not None:
                # create a new sub_event document
                if 'rec_id' in received_data and received_data[
                        'rec_id'] is not None:
                    received_data['rec_id'] = dateutil.parser.parse(
                        str(received_data['rec_id']))
                    result = create_sub_event(received_data, result)
            else:  # if this a normal event to be updated
                result.update(**received_data)
                result.reload()
        return mongo_to_dict(result)
예제 #11
0
def extract_ics(cal, ics_url, labels=None):
    """
    Extracts the ics components and stores them

    cal         the ics calendar

    ics_url     the ics feed url

    labels      labels to assign to the events
    """
    results = db.ICS.objects(url=ics_url).first()
    logging.debug("ics feeds: %s", mongo_to_dict(results))

    if results:  # if this feed has already been inputted
        for component in cal.walk():
            if component.name == "VEVENT":
                last_modified = component.get('LAST-MODIFIED').dt
                now = datetime.datetime.now(timezone.utc)
                difference = now - last_modified
                # if an event has been modified in the last two hours
                if difference.total_seconds() < 7200:
                    update_ics_to_mongo(component, results.labels)
    else:  # if this is the first time this ics feed has been input
        # save the ics url feed as an ICS object
        ics_object = db.ICS(**{'url': ics_url, 'labels': labels}).save()
        temporary_dict = []
        for component in cal.walk():
            if component.name == "VEVENT":
                # convert the event to a dictionary
                com_dict = ics_to_dict(component, labels, ics_object.id)

                if 'rec_id' in com_dict:  # if this is a sub_event
                    # search for another event with the same UID
                    normal_event = db.Event.objects(__raw__={
                        'UID': com_dict['UID']
                    }).first()
                    if normal_event is not None:  # if its parent event has already been created
                        create_sub_event(com_dict, normal_event)
                        logging.debug("sub event created in new instance")
                    else:  # if its parent event has not been created
                        # store the dict in a list to come back to later
                        temporary_dict.append(com_dict)
                        logging.debug(
                            "temporarily saved recurring event as dict")
                else:  # if this is a regular event
                    try:
                        new_event = db.Event(**com_dict).save()
                    except:  # FIXME: bare except # noqa: E722
                        logging.exception("com_dict: %s", com_dict)
                        continue
                    if not new_event.labels:  # if the event has no labels
                        new_event.labels = ['unlabeled']
                    if 'recurrence' in new_event:  # if the event has no recurrence_end
                        if not new_event.recurrence.forever:
                            new_event.recurrence_end = find_recurrence_end(
                                new_event)
                            logging.debug("made end_recurrence: %s",
                                          new_event.recurrence_end)
                    new_event.save()

        # cycle through all the events in the temporary list
        for sub_event_dict in temporary_dict:
            normal_event = db.Event.objects(__raw__={
                'UID': sub_event_dict['UID']
            }).first()
            create_sub_event(sub_event_dict, normal_event)
            logging.debug(
                "temporarily deferred sub_event now saved as mongodb object")