Пример #1
0
def test_human_readable_date(date, output):
    """Test that :func:`~app.models.Event.human_readable_date` properly
    formats event dates into human readable date strings.
    """
    event = Event(start_date=date, start_time=None,
                  end_date=date, end_time=None)
    assert event.human_readable_date() == output
Пример #2
0
def recurring_event(slug, index):
    """View a specific instance of a recurring event.

    **Route:** ``/events/<slug>/<index>``

    **Methods:** ``GET``

    :param str slug: The unique slug ID for the post.
    :param int index: The instance of the event to fetch.
    """
    if Event.objects(published=True, slug=slug).count() == 0:
        abort(404)  # Either invalid event ID or duplicate IDs.

    event = Event.objects(published=True, slug=slug)[0]

    if not event.is_recurring or not event.parent_series:
        return redirect(url_for('.event', slug=slug))

    if len(event.parent_series.events) <= index:
        abort(404)

    event = event.parent_series.events[index]
    return render_template('events/event.html',
                           event=event,
                           now=now,
                           upcoming_events=_upcoming_events_triple(event))
Пример #3
0
    def register_delete_rules(self):
        """Registers rules for how Mongoengine handles the deletion of objects
        that are being referenced by other objects.

        See the documentation for
        :func:`mongoengine.model.register_delete_rule` for more information.

        All delete rules for User fields must by DENY, because User objects
        should never be deleted.  Lists of reference fields should PULL, to
        remove deleted objects from the list, and all others should NULLIFY
        """
        from eventum.models import (Event, EventSeries, User, Post, BlogPost,
                                    Image)
        from mongoengine import NULLIFY, PULL, DENY

        Event.register_delete_rule(EventSeries, 'events', PULL)
        Image.register_delete_rule(BlogPost, 'images', PULL)
        Image.register_delete_rule(User, 'image', NULLIFY)
        Image.register_delete_rule(BlogPost, 'featured_image', NULLIFY)
        Image.register_delete_rule(Event, 'image', NULLIFY)
        EventSeries.register_delete_rule(Event, 'parent_series', NULLIFY)
        User.register_delete_rule(Event, 'creator', DENY)
        User.register_delete_rule(Image, 'creator', DENY)
        User.register_delete_rule(Post, 'author', DENY)
        User.register_delete_rule(Post, 'posted_by', DENY)
Пример #4
0
    def register_delete_rules(self):
        """Registers rules for how Mongoengine handles the deletion of objects
        that are being referenced by other objects.

        See the documentation for
        :func:`mongoengine.model.register_delete_rule` for more information.

        All delete rules for User fields must by DENY, because User objects
        should never be deleted.  Lists of reference fields should PULL, to
        remove deleted objects from the list, and all others should NULLIFY
        """
        from eventum.models import (Event, EventSeries, User, Post, BlogPost,
                                    Image)
        from mongoengine import NULLIFY, PULL, DENY

        Event.register_delete_rule(EventSeries, 'events', PULL)
        Image.register_delete_rule(BlogPost, 'images', PULL)
        Image.register_delete_rule(User, 'image', NULLIFY)
        Image.register_delete_rule(BlogPost, 'featured_image', NULLIFY)
        Image.register_delete_rule(Event, 'image', NULLIFY)
        EventSeries.register_delete_rule(Event, 'parent_series', NULLIFY)
        User.register_delete_rule(Event, 'creator', DENY)
        User.register_delete_rule(Image, 'creator', DENY)
        User.register_delete_rule(Post, 'author', DENY)
        User.register_delete_rule(Post, 'posted_by', DENY)
Пример #5
0
def event(slug):
    """View a specific non-recurring event, or the next upcoming instance of
    a recurring event.

    **Route:** ``/events/<slug>``

    **Methods:** ``GET``

    :param str slug: The unique slug ID for the post.
    """
    if Event.objects(published=True, slug=slug).count() == 0:
        abort(404)  # Either invalid event ID or duplicate IDs.

    event = Event.objects(published=True, slug=slug)[0]

    if event.is_recurring:
        upcoming_event_instances = (Event.objects(published=True,
                                                  start_date__gte=date.today(),
                                                  slug=slug)
                                         .order_by('start_date'))
        if upcoming_event_instances:
            event = upcoming_event_instances[0]
        else:
            event = event.parent_series.events[-1]

    return render_template('events/event.html',
                           event=event,
                           now=now,
                           upcoming_events=_upcoming_events_triple(event))
Пример #6
0
def recurring_event(slug, index):
    """View a specific instance of a recurring event.

    **Route:** ``/events/<slug>/<index>``

    **Methods:** ``GET``

    :param str slug: The unique slug ID for the post.
    :param int index: The instance of the event to fetch.
    """
    if Event.objects(published=True, slug=slug).count() == 0:
        abort(404)  # Either invalid event ID or duplicate IDs.

    event = Event.objects(published=True, slug=slug)[0]

    if not event.is_recurring or not event.parent_series:
        return redirect(url_for('.event', slug=slug))

    if len(event.parent_series.events) <= index:
        abort(404)

    event = event.parent_series.events[index]
    return render_template('events/event.html',
                           event=event,
                           now=now,
                           upcoming_events=_upcoming_events_triple(event))
Пример #7
0
    def create_single_event(cls, form, creator):
        """Creates a non-recurring Mongoengine and Google Calendar event from
        form data.

        :param form: The WTForms form.
        :type form: :class:`CreateEventForm` or a subclass.
        :param creator: The user that is currently logged in.
        :type creator: :class:`~app.models.User`

        :raises: :class:`GoogleCalendarAPIError` and it's subclasses

        :returns: Response from the Google Calendar API.
        :rtype: dict
        """

        # Generate the event and date data
        event_and_date_data = DataBuilder.event_and_date_data_from_form(
            form, creator=creator)
        event_and_date_data = cls._remove_none_fields(event_and_date_data)

        event = Event(**event_and_date_data)
        event.save()

        # Return the Google Calendar response
        return e.gcal_client().create_event(event)
Пример #8
0
def event(slug):
    """View a specific non-recurring event, or the next upcoming instance of
    a recurring event.

    **Route:** ``/events/<slug>``

    **Methods:** ``GET``

    :param str slug: The unique slug ID for the post.
    """
    if Event.objects(published=True, slug=slug).count() == 0:
        abort(404)  # Either invalid event ID or duplicate IDs.

    event = Event.objects(published=True, slug=slug)[0]

    if event.is_recurring:
        upcoming_event_instances = (Event.objects(published=True,
                                                  start_date__gte=date.today(),
                                                  slug=slug)
                                         .order_by('start_date'))
        if upcoming_event_instances:
            event = upcoming_event_instances[0]
        else:
            event = event.parent_series.events[-1]

    return render_template('events/event.html',
                           event=event,
                           now=now,
                           upcoming_events=_upcoming_events_triple(event))
Пример #9
0
    def create_single_event(cls, form, creator):
        """Creates a non-recurring Mongoengine and Google Calendar event from
        form data.

        :param form: The WTForms form.
        :type form: :class:`CreateEventForm` or a subclass.
        :param creator: The user that is currently logged in.
        :type creator: :class:`~app.models.User`

        :raises: :class:`GoogleCalendarAPIError` and it's subclasses

        :returns: Response from the Google Calendar API.
        :rtype: dict
        """

        # Generate the event and date data
        event_and_date_data = DataBuilder.event_and_date_data_from_form(
            form,
            creator=creator
        )
        event_and_date_data = cls._remove_none_fields(event_and_date_data)

        event = Event(**event_and_date_data)
        event.save()

        # Return the Google Calendar response
        return e.gcal_client().create_event(event)
Пример #10
0
def test_human_readable_time(start_time, end_time, output):
    """Test that :func:`~app.models.Event.human_readable_time` properly
    formats event times into human readable time strings.
    """
    any_date = dt.date(2015, 3, 31)
    event = Event(start_date=any_date, start_time=start_time,
                  end_date=any_date, end_time=end_time)
    assert event.human_readable_time() == output
Пример #11
0
def test_human_readable_atetime(sdate, stime, edate, etime, output):
    """Test that :func:`~app.models.Event.human_readable.datetime`
    properly formats event dates and times into human readable datetime
    strings.
    """

    event = Event(start_date=sdate, start_time=stime,
                  end_date=edate, end_time=etime)
    assert event.human_readable_datetime() == output
Пример #12
0
def test_event_starting_on_midnight():
    """Test that events starting on midnight are properly formatted."""
    event = Event(start_date=dt.date(2015, 4, 1),
                  start_time=dt.time(0),
                  end_date=dt.date(2015, 4, 1),
                  end_time=dt.time(5, 30))

    assert not event.is_multiday()
    assert event.human_readable_date() == "Wednesday, April 1"
    assert event.human_readable_time() == "12-5:30am"
Пример #13
0
def _get_events_for_template(past, future):
    """Returns the events to insert in the events template.  Returns four
    groups of dates:

    - ``past_events``: A list of dictionaries, where the dictionaries contain a
        list of events for a week, and a label for the week.
    - ``this_week``: A list of events happening this week.
    - ``next_week``: A list of events happening next week.
    - ``future_events``: A list of dictionaries similar to ``post_events``,
        but for events happening in the future.

    :returns: ``past_events``, ``this_week``, ``next_week``, ``future_events``
    """
    today = date.today()
    last_sunday = datetime.combine(
        today - timedelta(days=(today.isoweekday() % 7)),
        datetime.min.time()
    )
    next_sunday = last_sunday + timedelta(days=7)
    following_sunday = last_sunday + timedelta(days=14)

    this_week = (Event.objects(start_date__gte=last_sunday,
                               start_date__lt=next_sunday)
                 .order_by('start_date'))
    next_week = (Event.objects(start_date__gte=next_sunday,
                               start_date__lt=following_sunday)
                 .order_by('start_date'))
    past_events = []
    future_events = []

    for week_no in range(past):
        ending_sunday = last_sunday - timedelta(days=7 * week_no)
        starting_sunday = last_sunday - timedelta(days=7 * (week_no + 1))
        week_name = _format_for_display(starting_sunday)
        events = Event.objects(start_date__gte=starting_sunday,
                               start_date__lt=ending_sunday)
        past_events.insert(0, {
            'week_name': week_name,
            'events': events,
        })

    for week_no in range(future):
        starting_sunday = following_sunday + timedelta(days=7 * week_no)
        ending_sunday = following_sunday + timedelta(days=7 * (week_no + 1))
        week_name = _format_for_display(starting_sunday)
        events = Event.objects(start_date__gte=starting_sunday,
                               start_date__lt=ending_sunday)
        future_events.append({
            'week_name': week_name,
            'events': events,
        })

    return past_events, this_week, next_week, future_events
Пример #14
0
    def _make_event(cls, e_data, d_data):
        """Create a new :class:`Event` object and save it to Mongoengine.

        The event is created by unpacking non-None fields of ``e_data`` and
        ``d_data`` in the constructor for :class:`Event`.

        :param dict e_data: The event data for this event.
        :param dict d_data: The date data for this event.
        """
        params = cls._remove_none_fields(dict(e_data.items() + d_data.items()))
        event = Event(**params)
        event.save()
        return event
Пример #15
0
    def _make_event(cls, e_data, d_data):
        """Create a new :class:`Event` object and save it to Mongoengine.

        The event is created by unpacking non-None fields of ``e_data`` and
        ``d_data`` in the constructor for :class:`Event`.

        :param dict e_data: The event data for this event.
        :param dict d_data: The date data for this event.
        """
        params = cls._remove_none_fields(dict(e_data.items() + d_data.items()))
        event = Event(**params)
        event.save()
        return event
Пример #16
0
def test_event_ending_on_midnight():
    """Test that events ending on midnight are properly formatted."""
    start_date, start_time = dt.date(2015, 3, 31), dt.time(22)
    end_date, end_time = dt.date(2015, 4, 1), dt.time(0)

    event = Event(start_date=start_date,
                  start_time=start_time,
                  end_date=end_date,
                  end_time=end_time)

    assert not event.is_multiday()
    assert event.human_readable_date() == "Tuesday, March 31"
    assert event.human_readable_time() == "10pm-12am"
Пример #17
0
 def test_human_readable_date(self):
     """Test that :func:`~app.models.Event.human_readable_date` properly
     formats event dates into human readable date strings.
     """
     from eventum.models import Event
     for event_date, string in self.DATES:
         event = Event(start_date=event_date,
                       start_time=None,
                       end_date=event_date,
                       end_time=None,
                       **self.EVENT_KWARGS)
         msg = self.ERROR_MSG.format('human readable date',
                                     string,
                                     event.human_readable_date())
         self.assertEqual(event.human_readable_date(), string, msg=msg)
Пример #18
0
    def test_event_ending_on_midnight(self):
        """Test that events ending on midnight are properly formatted."""
        from eventum.models import Event
        start_date, start_time = date(2015, 03, 31), time(22)
        end_date, end_time = date(2015, 04, 01), time(0)

        event = Event(start_date=start_date,
                      start_time=start_time,
                      end_date=end_date,
                      end_time=end_time,
                      **self.EVENT_KWARGS)

        self.assertFalse(event.is_multiday())
        self.assertEqual(event.human_readable_date(), 'Tuesday, March 31')
        self.assertEqual(event.human_readable_time(), '10pm-12am')
Пример #19
0
    def test_event_starting_on_midnight(self):
        """Test that events starting on midnight are properly formatted."""
        from eventum.models import Event
        start_date, start_time = date(2015, 04, 01), time(00)
        end_date, end_time = date(2015, 04, 01), time(05, 30)

        event = Event(start_date=start_date,
                      start_time=start_time,
                      end_date=end_date,
                      end_time=end_time,
                      **self.EVENT_KWARGS)

        self.assertFalse(event.is_multiday())
        self.assertEqual(event.human_readable_date(), 'Wednesday, April 1')
        self.assertEqual(event.human_readable_time(), '12-5:30am')
Пример #20
0
def index():
    """View the ADI homepage.

    **Route:** ``/``

    **Methods:** ``GET``
    """
    # cast date.today() to a datetime
    today = datetime.combine(date.today(), datetime.min.time())

    # Ending on a future date, or today at a future time. The events should be
    # published, and should be chronological.
    # We limit to four events, one large event and one set of three events.
    events = (Event.objects(Q(end_date__gte=today))
                   .filter(published=True)
                   .order_by('start_date', 'start_time')
                   .limit(ONE_LARGE_AND_TRIPLE))

    # sort published posts chronologically back in time
    all_blog_posts = (BlogPost.objects(published=True)
                              .order_by('-date_published'))
    latest_blog_post = all_blog_posts[0] if all_blog_posts else None

    return render_template('index.html',
                           events=events,
                           blog_post=latest_blog_post)
Пример #21
0
def event_archive(index):
    """View old events.

    **Route:** ``/events/<index>``

    **Methods:** ``GET``

    :param int index: The page to fetch
    """
    if index <= 0:
        return redirect(url_for('.events'))

    # Get all events that occur on this page or on subsequent pages, and order
    # them chronologically back in time
    today = date.today()
    events = (Event.objects(published=True, end_date__lt=today)
                   .order_by('-start_date')
                   .skip(NUM_PAST_EVENTS_FOR_FRONTPAGE +
                         (index - 1) * NUM_EVENTS_PER_PAGE))

    # If there are no such events, redirect to the pevious page
    if not events:
        return redirect(url_for('.event_archive', index=index - 1))

    # There is always a previous page, but there is only a next page if there
    # are more events after this page
    previous_index = index - 1
    next_index = index + 1 if len(events) > NUM_EVENTS_PER_PAGE else None

    # Use .limit() to only show NUM_EVENTS_PER_PAGE events per page
    return render_template('events/archive.html',
                           events=events.limit(NUM_EVENTS_PER_PAGE),
                           previous_index=previous_index,
                           next_index=next_index)
Пример #22
0
    def unpublish_event(self, stale_event):
        """Unpublish an event, moving it to the private calendar.

        The first argument is called ``stale_event`` because it might have
        outdated fields.  The first thing we do is find a fresh event with it's
        id in mongo.

        :param stale_event: The event to publish
        :type event: :class:`Event`

        :raises: :class:`EventumError.GCalAPI.BadStatusLine`,
            :class:`EventumError.GCalAPI.NotFound`,
            :class:`EventumError.GCalAPI.Error`,
            :class:`EventumError.GCalAPI.MissingID`

        :returns: The Google Calendar API response.
        :rtype: dict
        """
        self.before_request()

        # Freshen up stale_event
        event = Event.objects().get(id=stale_event.id)

        if event.published:
            raise EventumError.GCalAPI.PublishFailed.PublishedTrue()

        return self.move_event(event,
                               from_id=self.public_calendar_id,
                               to_id=self.private_calendar_id)
Пример #23
0
    def unpublish_event(self, stale_event):
        """Unpublish an event, moving it to the private calendar.

        The first argument is called ``stale_event`` because it might have
        outdated fields.  The first thing we do is find a fresh event with it's
        id in mongo.

        :param stale_event: The event to publish
        :type event: :class:`Event`

        :raises: :class:`EventumError.GCalAPI.BadStatusLine`,
            :class:`EventumError.GCalAPI.NotFound`,
            :class:`EventumError.GCalAPI.Error`,
            :class:`EventumError.GCalAPI.MissingID`

        :returns: The Google Calendar API response.
        :rtype: dict
        """
        self.before_request()

        # Freshen up stale_event
        event = Event.objects().get(id=stale_event.id)

        if event.published:
            raise EventumError.GCalAPI.PublishFailed.PublishedTrue()

        return self.move_event(event, from_id=self.public_calendar_id,
                               to_id=self.private_calendar_id)
Пример #24
0
def index():
    """View the ADI homepage.

    **Route:** ``/``

    **Methods:** ``GET``
    """
    this_moment = datetime.now().time()
    # cast date.today() to a datetime
    today = datetime.combine(date.today(), datetime.min.time())

    # Ending on a future date, or today at a future time. The events should be
    # published, and should be chronological.
    # We limit to four events, one large event and one set of three events.
    events = (Event.objects(Q(end_date__gte=today))
                            # |
                            # Q(end_date=today, end_time__gt=this_moment)) #
                   .filter(published=True)
                   .order_by('start_date', 'start_time')
                   .limit(ONE_LARGE_AND_TRIPLE))

    # sort published posts chronologically back in time
    all_blog_posts = (BlogPost.objects(published=True)
                              .order_by('-date_published'))
    latest_blog_post = all_blog_posts[0] if all_blog_posts else None

    return render_template('index.html',
                           events=events,
                           blog_post=latest_blog_post)
Пример #25
0
 def test_human_readable_time(self):
     """Test that :func:`~app.models.Event.human_readable_time` properly
     formats event times into human readable time strings.
     """
     from eventum.models import Event
     any_date = date(2015, 03, 31)
     for start_time, end_time, string in self.TIMES:
         event = Event(start_date=any_date,
                       start_time=start_time,
                       end_date=any_date,
                       end_time=end_time,
                       **self.EVENT_KWARGS)
         msg = self.ERROR_MSG.format('human readable time',
                                     string,
                                     event.human_readable_time())
         self.assertEqual(event.human_readable_time(), string, msg=msg)
Пример #26
0
def event_archive(index):
    """View old events.

    **Route:** ``/events/<index>``

    **Methods:** ``GET``

    :param int index: The page to fetch
    """
    if index <= 0:
        return redirect(url_for('.events'))

    # Get all events that occur on this page or on subsequent pages, and order
    # them chronologically back in time
    today = date.today()
    events = (Event.objects(published=True, end_date__lt=today)
                   .order_by('-start_date')
                   .skip(NUM_PAST_EVENTS_FOR_FRONTPAGE +
                         (index - 1) * NUM_EVENTS_PER_PAGE))

    # If there are no such events, redirect to the pevious page
    if not events:
        return redirect(url_for('.event_archive', index=index - 1))

    # There is always a previous page, but there is only a next page if there
    # are more events after this page
    previous_index = index - 1
    next_index = index + 1 if len(events) > NUM_EVENTS_PER_PAGE else None

    # Use .limit() to only show NUM_EVENTS_PER_PAGE events per page
    return render_template('events/archive.html',
                           events=events.limit(NUM_EVENTS_PER_PAGE),
                           previous_index=previous_index,
                           next_index=next_index)
Пример #27
0
def delete(event_id):
    """Delete an existing event.

    **Route:** ``/admin/events/delete/<event_id>``

    **Methods:** ``POST``

    :param str event_id: The ID of the event to delete.
    """
    object_id = ObjectId(event_id)
    form = DeleteEventForm(request.form)
    if Event.objects(id=object_id).count() == 1:
        event = Event.objects().with_id(object_id)
        try:
            EventsHelper.delete_event(event, form)
        except EventumError.GCalAPI as e:
            flash(e.message, ERROR_FLASH)
    else:
        flash('Invalid event id', ERROR_FLASH)
    return redirect(url_for('.index'))
Пример #28
0
def _upcoming_events_triple(event):
    """Returns a set of three upcoming events, excluding ``event``.

    :param event: The event to exclude
    :type event: :class:`~app.models.Event`
    :returns: The set of three events
    :rtype: Mongoengine.queryset
    """
    return (Event.objects(
        published=True, start_date__gte=date.today(),
        id__ne=event.id).order_by('start_date').limit(ONE_TRIPLE))
Пример #29
0
def set_published_status(event_id, status):
    """"""
    object_id = ObjectId(event_id)
    if Event.objects(id=object_id).count() == 1:
        event = Event.objects().with_id(object_id)
        if status != event.published:
            event.published = status
            # TODO Actually publish/unpublish the event here
            if event.published:
                event.date_published = datetime.now()
                flash('Event published', MESSAGE_FLASH)
            else:
                event.date_published = None
                flash('Event unpublished', MESSAGE_FLASH)
            event.save()
        else:
            flash("The event had not been published.  No changes made.",
                  MESSAGE_FLASH)
    else:
        flash('Invalid event id', ERROR_FLASH)
    return redirect(url_for('.index'))
Пример #30
0
def _upcoming_events_triple(event):
    """Returns a set of three upcoming events, excluding ``event``.

    :param event: The event to exclude
    :type event: :class:`~app.models.Event`
    :returns: The set of three events
    :rtype: Mongoengine.queryset
    """
    return (Event.objects(published=True,
                          start_date__gte=date.today(),
                          id__ne=event.id)
                 .order_by('start_date')
                 .limit(ONE_TRIPLE))
Пример #31
0
    def run(self):
        """Run the generation.  Uses the configurations passed to
        func:`__init__`.
        """

        # Setup: db connection, superuser, and printer.
        connect(config['MONGODB_SETTINGS']['DB'])
        try:
            superuser = User.objects().get(gplus_id='super')
        except DoesNotExist:
            print ('Failed to get superuser.  Try running:\n'
                   '\texport GOOGLE_AUTH_ENABLED=TRUE')
        printer = ProgressPrinter(self.quiet)

        # Images
        if self.should_gen_images:
            if self.wipe:
                self.warn('Image')
                print CLIColor.warning('Wiping Image database.')
                Image.drop_collection()
            create_images(12, superuser, printer)

        # Blog posts
        if self.should_gen_posts:
            if self.wipe:
                self.warn('BlogPost')
                print CLIColor.warning('Wiping BlogPost database.')
                BlogPost.drop_collection()
            create_posts(10, superuser, printer)

        # Events and event series
        if self.should_gen_events:
            if self.wipe:
                self.warn('Event and EventSeries')
                print CLIColor.warning('Wiping Event database.')
                Event.drop_collection()
                print CLIColor.warning('Wiping EventSeries database.')
                EventSeries.drop_collection()
            create_events(superuser, printer)
Пример #32
0
def events():
    """View the latest events.

    **Route:** ``/events``

    **Methods:** ``GET``
    """
    today = date.today()
    weekday = (today.isoweekday() % 7) + 1  # Sun: 1, Mon: 2, ... , Sat: 7
    last_sunday = datetime.combine(today - timedelta(days=weekday + 7),
                                   datetime.min.time())
    next_sunday = datetime.combine(today + timedelta(days=7 - weekday),
                                   datetime.min.time())
    recent_and_upcoming = Event.objects(published=True).order_by('start_date',
                                                                 'start_time')

    # Sort recent events chronologically backwards in time
    recent_events = (recent_and_upcoming.filter(end_date__lt=today)
                                        .order_by('-start_date')
                                        .limit(NUM_PAST_EVENTS_FOR_FRONTPAGE))

    events_this_week = list(
        recent_and_upcoming.filter(end_date__gte=today,
                                   start_date__lt=next_sunday)
    )

    # One large event, and one set of three small events
    upcoming_events = (recent_and_upcoming.filter(start_date__gt=next_sunday)
                                          .limit(ONE_LARGE_AND_TRIPLE))

    more_past_events = bool(Event.objects(published=True,
                                          start_date__lte=last_sunday).count())

    return render_template('events/events.html',
                           recent_events=recent_events,
                           events_this_week=events_this_week,
                           upcoming_events=upcoming_events,
                           more_past_events=more_past_events)
Пример #33
0
def events():
    """View the latest events.

    **Route:** ``/events``

    **Methods:** ``GET``
    """
    today = date.today()
    weekday = (today.isoweekday() % 7) + 1  # Sun: 1, Mon: 2, ... , Sat: 7
    last_sunday = datetime.combine(today - timedelta(days=weekday + 7),
                                   datetime.min.time())
    next_sunday = datetime.combine(today + timedelta(days=7 - weekday),
                                   datetime.min.time())
    recent_and_upcoming = Event.objects(published=True).order_by('start_date',
                                                                 'start_time')

    # Sort recent events chronologically backwards in time
    recent_events = (recent_and_upcoming.filter(end_date__lt=today)
                                        .order_by('-start_date')
                                        .limit(NUM_PAST_EVENTS_FOR_FRONTPAGE))

    events_this_week = list(
        recent_and_upcoming.filter(end_date__gte=today,
                                   start_date__lt=next_sunday)
    )

    # One large event, and one set of three small events
    upcoming_events = (recent_and_upcoming.filter(start_date__gt=next_sunday)
                                          .limit(ONE_LARGE_AND_TRIPLE))

    more_past_events = bool(Event.objects(published=True,
                                          start_date__lte=last_sunday).count())

    return render_template('events/events.html',
                           recent_events=recent_events,
                           events_this_week=events_this_week,
                           upcoming_events=upcoming_events,
                           more_past_events=more_past_events)
Пример #34
0
    def __call__(self, form, field):
        """Called internally by :mod:`wtforms` on validation of the field.

        :param form: The parent form
        :type form: :class:`Form`
        :param field: The field to validate
        :type field: :class:`Field`

        :raises: :class:`wtforms.validators.ValidationError`
        """
        from eventum.models import Event, EventSeries

        if EventSeries.objects(slug=field.data).count():
            raise ValidationError(self.message)
        if Event.objects(slug=field.data).count():
            raise ValidationError(self.message)
Пример #35
0
    def __call__(self, form, field):
        """Called internally by :mod:`wtforms` on validation of the field.

        :param form: The parent form
        :type form: :class:`Form`
        :param field: The field to validate
        :type field: :class:`Field`

        :raises: :class:`wtforms.validators.ValidationError`
        """
        from eventum.models import Event, EventSeries

        if EventSeries.objects(slug=field.data).count():
            raise ValidationError(self.message)
        if Event.objects(slug=field.data).count():
            raise ValidationError(self.message)
Пример #36
0
    def __call__(self, form, field):
        """Called internally by :mod:`wtforms` on validation of the field.

        :param form: The parent form
        :type form: :class:`Form`
        :param field: The field to validate
        :type field: :class:`Field`

        :raises: :class:`wtforms.validators.ValidationError`
        """
        from eventum.models import Event, EventSeries

        # If we change the slug, make sure the new slug doesn't exist
        if self.original.slug != field.data:
            if EventSeries.objects(slug=field.data).count():
                raise ValidationError(self.message)
            if Event.objects(slug=field.data).count():
                raise ValidationError(self.message)
Пример #37
0
    def __call__(self, form, field):
        """Called internally by :mod:`wtforms` on validation of the field.

        :param form: The parent form
        :type form: :class:`Form`
        :param field: The field to validate
        :type field: :class:`Field`

        :raises: :class:`wtforms.validators.ValidationError`
        """
        from eventum.models import Event, EventSeries

        # If we change the slug, make sure the new slug doesn't exist
        if self.original.slug != field.data:
            if EventSeries.objects(slug=field.data).count():
                raise ValidationError(self.message)
            if Event.objects(slug=field.data).count():
                raise ValidationError(self.message)
Пример #38
0
def events_this_week():
    """
    Get a json object containing information about all the events for the
    current week (Sunday to Sunday).

    **Route:** ``/admin/api/events/this_week

    **Methods:** ``GET``
    """

    today = date.today()
    last_sunday = datetime.combine(
        today - timedelta(days=(today.isoweekday() % 7)), datetime.min.time())
    next_tuesday = last_sunday + timedelta(days=9)
    events = Event.objects(start_date__gte=last_sunday,
                           start_date__lt=next_tuesday).order_by('start_date')
    event_dicts = [event.to_jsonifiable() for event in events]

    return json_success(event_dicts)
Пример #39
0
def events_this_week():
    """
    Get a json object containing information about all the events for the
    current week (Sunday to Sunday).

    **Route:** ``/admin/api/events/this_week

    **Methods:** ``GET``
    """

    today = date.today()
    last_sunday = datetime.combine(
        today - timedelta(days=(today.isoweekday() % 7)),
        datetime.min.time())
    next_sunday = last_sunday + timedelta(days=7)
    events = Event.objects(start_date__gte=last_sunday,
                           start_date__lt=next_sunday).order_by('start_date')
    event_dicts = [event.to_jsonifiable() for event in events]

    return json_success(event_dicts)
Пример #40
0
def index():
    """The homepage of Eventum. Shows the latest blog posts and events.

    **Route:** ``/admin/home``

    **Methods:** ``GET``
    """
    today = date.today()
    last_sunday = datetime.combine(
        today - timedelta(days=(today.isoweekday() % 7)),
        datetime.min.time())
    next_sunday = last_sunday + timedelta(days=7)

    this_week = (Event.objects(start_date__gt=last_sunday,
                               start_date__lt=next_sunday)
                 .order_by('start_date'))
    posts = BlogPost.objects().order_by('published', '-date_published')[:5]

    return render_template('eventum_home.html',
                           this_week=this_week,
                           recent_posts=posts)
Пример #41
0
def index():
    """The homepage of Eventum. Shows the latest blog posts and events.

    **Route:** ``/admin/home``

    **Methods:** ``GET``
    """
    today = date.today()
    last_sunday = datetime.combine(
        today - timedelta(days=(today.isoweekday() % 7)),
        datetime.min.time())
    next_sunday = last_sunday + timedelta(days=7)

    this_week = (Event.objects(start_date__gt=last_sunday,
                               start_date__lt=next_sunday)
                 .order_by('start_date'))
    posts = BlogPost.objects().order_by('published', '-date_published')[:5]

    return render_template('eventum_home.html',
                           this_week=this_week,
                           recent_posts=posts)
Пример #42
0
def edit(event_id):
    """Edit an existing event.

    **Route:** ``/admin/events/edit/<event_id>``

    **Methods:** ``GET, POST``

    :param str event_id: The ID of the event to edit.
    """

    try:
        event = Event.objects().get(id=event_id)
    except (DoesNotExist, ValidationError):
        flash('Cannot find event with id "{}"'.format(event_id), ERROR_FLASH)
        return redirect(url_for('.index'))

    if request.method == "POST":
        form = EditEventForm(event, request.form)
    else:
        form = EventsHelper.create_form(event, request)

    if form.validate_on_submit():
        try:
            EventsHelper.update_event(event, form)
        except EventumError.GCalAPI as e:
            flash(e.message, ERROR_FLASH)

        return redirect(url_for('.index'))
    if form.errors:
        for error in form.errors:
            for message in form.errors[error]:
                flash(message, ERROR_FLASH)

    delete_form = DeleteEventForm()
    upload_form = UploadImageForm()
    images = Image.objects()

    return render_template('eventum_events/edit.html', form=form, event=event,
                           delete_form=delete_form, upload_form=upload_form,
                           images=images)
Пример #43
0
    def update_event(self, stale_event, as_exception=False):
        """Updates the event in Google Calendar.

        The first argument is called ``stale_event`` because it might have
        outdated fields.  The first thing we do is find a fresh event with it's
        id in mongo.

        This method will fall back to creating a new event if we don't have
        reference to a ``gcal_id`` for the event, or if the update otherwise
        fails.

        :param stale_event: The event to update.
        :type stale_event: :class:`Event`
        :param bool as_exception: Whether or not this update should happen as
            an exception in a series.  Otherwise, series' will be updated in
            their entirety.

        :raises: :class:`EventumError.GCalAPI.BadStatusLine`,
            :class:`EventumError.GCalAPI.NotFound`,
            :class:`EventumError.GCalAPI.MissingID`

        :returns: The Google Calendar API response.
        :rtype: dict
        """
        self.before_request()

        # Freshen up stale_event
        event = Event.objects().get(id=stale_event.id)

        if not event.gcal_id:
            # If we don't have a reference if it's associate Google Calendar
            # ID, then create it fresh.  This raises still because it
            # *shouldn't* ever happen, but it does.
            self.create_event(stale_event)
            raise EventumError.GCalAPI.MissingID.UpdateFellBackToCreate()

        resource = None
        resource = GoogleCalendarResourceBuilder.event_resource(
            event, for_update=True)

        calendar_id = self._calendar_id_for_event(event)

        # If this update should be an exception to a series of events, then
        # we only want to update the instance id.  Otherwise, using the
        # ``event.gcal_id`` will update the entire series.
        event_id_for_update = event.gcal_id
        if as_exception:
            instance = self._instance_resource_for_event_in_series(event)
            instance.update(resource)
            resource = instance
            event_id_for_update = instance['id']

        current_app.logger.info('[GOOGLE_CALENDAR]: Update Event')
        request = self.service.events().update(calendarId=calendar_id,
                                               eventId=event_id_for_update,
                                               body=resource)

        # Send the request, falling back to update if it fails.
        try:
            updated_event = self._execute_request(request)
        except EventumError.GCalAPI.NotFound as e:
            self.create_event(event)
            raise EventumError.GCalAPI.NotFound.UpdateFellBackToCreate(e=e)

        # Update the Event with the latest info from the response.
        self._update_event_from_response(event, updated_event)

        # Return the Google Calendar response dict
        return updated_event
Пример #44
0
    def update_event(self, stale_event, as_exception=False):
        """Updates the event in Google Calendar.

        The first argument is called ``stale_event`` because it might have
        outdated fields.  The first thing we do is find a fresh event with it's
        id in mongo.

        This method will fall back to creating a new event if we don't have
        reference to a ``gcal_id`` for the event, or if the update otherwise
        fails.

        :param stale_event: The event to update.
        :type stale_event: :class:`Event`
        :param bool as_exception: Whether or not this update should happen as
            an exception in a series.  Otherwise, series' will be updated in
            their entirety.

        :raises: :class:`EventumError.GCalAPI.BadStatusLine`,
            :class:`EventumError.GCalAPI.NotFound`,
            :class:`EventumError.GCalAPI.MissingID`

        :returns: The Google Calendar API response.
        :rtype: dict
        """
        self.before_request()

        # Freshen up stale_event
        event = Event.objects().get(id=stale_event.id)

        if not event.gcal_id:
            # If we don't have a reference if it's associate Google Calendar
            # ID, then create it fresh.  This raises still because it
            # *shouldn't* ever happen, but it does.
            self.create_event(stale_event)
            raise EventumError.GCalAPI.MissingID.UpdateFellBackToCreate()

        resource = None
        resource = GoogleCalendarResourceBuilder.event_resource(
            event, for_update=True)

        calendar_id = self._calendar_id_for_event(event)

        # If this update should be an exception to a series of events, then
        # we only want to update the instance id.  Otherwise, using the
        # ``event.gcal_id`` will update the entire series.
        event_id_for_update = event.gcal_id
        if as_exception:
            instance = self._instance_resource_for_event_in_series(event)
            instance.update(resource)
            resource = instance
            event_id_for_update = instance['id']

        current_app.logger.info('[GOOGLE_CALENDAR]: Update Event')
        request = self.service.events().update(calendarId=calendar_id,
                                               eventId=event_id_for_update,
                                               body=resource)

        # Send the request, falling back to update if it fails.
        try:
            updated_event = self._execute_request(request)
        except EventumError.GCalAPI.NotFound as e:
            self.create_event(event)
            raise EventumError.GCalAPI.NotFound.UpdateFellBackToCreate(e=e)

        # Update the Event with the latest info from the response.
        self._update_event_from_response(event, updated_event)

        # Return the Google Calendar response dict
        return updated_event