예제 #1
0
def parse_fullcalendar_request(request, timezone):
    """ Parses start and end from the given fullcalendar request. It is
    expected that no timezone is passed (the default).

    See `<http://fullcalendar.io/docs/timezone/timezone/>`_

    :returns: A tuple of timezone-aware datetime objects or (None, None).

    """
    start = request.params.get('start')
    end = request.params.get('end')

    if start and end:
        if 'T' in start:
            start = parse_datetime(start)
            end = parse_datetime(end)
        else:
            start = datetime.combine(parse_date(start), time(0, 0))
            end = datetime.combine(parse_date(end), time(23, 59, 59, 999999))

        start = sedate.replace_timezone(start, timezone)
        end = sedate.replace_timezone(end, timezone)

        return start, end
    else:
        return None, None
예제 #2
0
    def add(self, title, start, end, timezone, autoclean=True, **optional):
        """ Add a new event.

        A unique, URL-friendly name is created automatically for this event
        using the title and optionally numbers for duplicate names.

        Every time a new event is added, old, stale events are deleted unless
        disabled with the ``autoclean`` option.

        Returns the created event or None if already automatically deleted.
        """
        event = Event(
            state='initiated',
            title=title,
            start=replace_timezone(start, timezone),
            end=replace_timezone(end, timezone),
            timezone=timezone,
            name=self._get_unique_name(title),
            **optional
        )

        self.session.add(event)
        self.session.flush()

        if autoclean:
            self.remove_stale_events()

        return event
예제 #3
0
    def filter_by_year(self, query):
        timezone = 'Europe/Zurich'

        start = sedate.replace_timezone(datetime(self.year, 1, 1), timezone)
        end = sedate.replace_timezone(datetime(self.year + 1, 1, 1), timezone)

        return query.filter(and_(
            start <= MissionReport.date, MissionReport.date < end
        ))
예제 #4
0
def test_get_date_range():
    assert sedate.get_date_range(
        sedate.replace_timezone(datetime(2015, 1, 1), 'Europe/Zurich'),
        datetime(2015, 1, 1, 12, 0).time(),
        datetime(2015, 1, 2, 11, 0).time(),
    ) == (
        sedate.replace_timezone(datetime(2015, 1, 1, 12, 0), 'Europe/Zurich'),
        sedate.replace_timezone(datetime(2015, 1, 2, 11, 0), 'Europe/Zurich'),
    )
예제 #5
0
    def update_model(self, model):
        """ Stores the form values on the page. """

        # clear the recurrence to avoid updating all occurrences too much
        model.recurrence = ''

        model.title = self.title.data
        model.content = {
            'description': self.description.data
        }
        model.location = self.location.data
        model.tags = self.tags.data
        model.timezone = 'Europe/Zurich'
        model.start = replace_timezone(
            datetime(
                self.start_date.data.year,
                self.start_date.data.month,
                self.start_date.data.day,
                self.start_time.data.hour,
                self.start_time.data.minute
            ),
            model.timezone
        )
        end_date = self.start_date.data
        if self.end_time.data <= self.start_time.data:
            end_date += timedelta(days=1)
        model.end = replace_timezone(
            datetime(
                end_date.year,
                end_date.month,
                end_date.day,
                self.end_time.data.hour,
                self.end_time.data.minute
            ),
            model.timezone
        )
        if self.weekly.data and self.end_date.data:
            until_date = to_timezone(
                replace_timezone(
                    datetime(
                        self.end_date.data.year,
                        self.end_date.data.month,
                        self.end_date.data.day,
                        self.end_time.data.hour,
                        self.end_time.data.minute
                    ), model.timezone
                ), 'UTC'
            )
            model.recurrence = (
                "RRULE:FREQ=WEEKLY;WKST=MO;BYDAY={0};UNTIL={1}".format(
                    ','.join(self.weekly.data),
                    until_date.strftime('%Y%m%dT%H%M%SZ')
                )
            )
        model.meta = model.meta or {}
        model.meta['submitter_email'] = self.email.data
예제 #6
0
def test_align_range_to_day():
    assert sedate.align_range_to_day(
        start=sedate.replace_timezone(datetime(2015, 1, 1, 10, 0),
                                      'Europe/Zurich'),
        end=sedate.replace_timezone(datetime(2015, 1, 1, 11, 0),
                                    'Europe/Zurich'),
        timezone='Europe/Zurich') == (sedate.replace_timezone(
            datetime(2015, 1, 1), 'Europe/Zurich'),
                                      sedate.replace_timezone(
                                          datetime(2015, 1, 1, 23, 59, 59,
                                                   999999), 'Europe/Zurich'))
예제 #7
0
파일: page.py 프로젝트: i18nHub/onegov.town
def view_news(self, request):

    layout = NewsLayout(self, request)
    years = self.years

    try:
        year = int(request.params["year"])
    except (ValueError, KeyError):
        year = years and years[0] or None

    query = self.news_query

    if year:
        start = replace_timezone(datetime(year, 1, 1), "UTC")
        query = query.filter(Page.created >= start)
        query = query.filter(Page.created < start.replace(year=year + 1))

    if request.is_logged_in:
        layout.editbar_links = list(self.get_editbar_links(request))
        children = query.all()
    else:
        children = request.exclude_invisible(query.all())

    return {
        "layout": layout,
        "title": self.title,
        "name": self.trait_messages[self.trait]["name"],
        "page": self,
        "children": children,
        "years": years,
        "current_year": year,
    }
예제 #8
0
def has_permission_scan_job(app, identity, model, permission):
    # Editors and members of groups may view and edit scan jobs within
    # the same group
    if identity.role in ('editor', 'member'):
        if identity.groupid:

            if permission in {ViewModel, EditModel}:
                if same_group(model, identity):
                    return True

            if permission is DeleteModel and identity.role == 'editor':
                if same_group(model, identity):
                    dt = model.dispatch_date

                    # editors of the same group may delete scan jobs up until
                    # 17:00 on the day before the dispatch
                    horizon = datetime(dt.year, dt.month, dt.day, 17)
                    horizon -= timedelta(days=1)
                    horizon = sedate.replace_timezone(horizon, 'Europe/Zurich')

                    now = sedate.utcnow()

                    return now <= horizon

    return permission in getattr(app.settings.roles, identity.role)
예제 #9
0
def test_standardize_aware_date():
    aware_date = sedate.replace_timezone(datetime(2014, 10, 1, 13, 30),
                                         'Europe/Zurich')

    normalized = sedate.standardize_date(aware_date, 'Europe/Zurich')

    assert normalized.tzname() == 'UTC'
    assert normalized.replace(tzinfo=None) == datetime(2014, 10, 1, 11, 30)
예제 #10
0
    def set_start(self, start):
        if not start.tzinfo:
            assert self.timezone
            start = sedate.replace_timezone(start, self.timezone)

        if self.raster is not None:
            self._start = rasterize_start(start, self.raster)
        else:
            self._start = rasterize_start(start, MIN_RASTER)
예제 #11
0
    def set_end(self, end):
        if not end.tzinfo:
            assert self.timezone
            end = sedate.replace_timezone(end, self.timezone)

        if self.raster is not None:
            self._end = rasterize_end(end, self.raster)
        else:
            self._end = rasterize_end(end, MIN_RASTER)
예제 #12
0
def test_align_date_to_day_up():
    unaligned = sedate.standardize_date(datetime(2012, 1, 24, 10), 'UTC')
    aligned = sedate.align_date_to_day(unaligned, 'Europe/Zurich', 'up')

    assert aligned.tzname() == 'UTC'
    assert aligned == sedate.standardize_date(
        datetime(2012, 1, 24, 23, 59, 59, 999999), 'Europe/Zurich')

    already_aligned = sedate.replace_timezone(
        datetime(2012, 1, 1, 23, 59, 59, 999999), 'Europe/Zurich')

    assert already_aligned == sedate.align_date_to_day(already_aligned,
                                                       'Europe/Zurich', 'up')
예제 #13
0
def test_is_whole_day():
    assert sedate.is_whole_day(
        sedate.replace_timezone(
            datetime(2015, 6, 30), 'Europe/Zurich'),
        sedate.replace_timezone(
            datetime(2015, 7, 1), 'Europe/Zurich'),
        'Europe/Zurich'
    )

    assert sedate.is_whole_day(
        sedate.replace_timezone(
            datetime(2015, 6, 30), 'Europe/Zurich'),
        sedate.replace_timezone(
            datetime(2015, 6, 30, 23, 59, 59), 'Europe/Zurich'),
        'Europe/Zurich'
    )

    assert not sedate.is_whole_day(
        sedate.replace_timezone(
            datetime(2015, 6, 30), 'Europe/Zurich'),
        sedate.replace_timezone(
            datetime(2015, 6, 30, 1), 'Europe/Zurich'),
        'Europe/Zurich'
    )
    assert not sedate.is_whole_day(
        sedate.replace_timezone(
            datetime(2015, 6, 30), 'Europe/Zurich'),
        sedate.replace_timezone(
            datetime(2015, 6, 30, 23, 59, 58), 'Europe/Zurich'),
        'Europe/Zurich'
    )
    assert not sedate.is_whole_day(
        sedate.replace_timezone(
            datetime(2015, 6, 30, 0, 0, 0, 999), 'Europe/Zurich'),
        sedate.replace_timezone(
            datetime(2015, 6, 30, 23, 59, 59), 'Europe/Zurich'),
        'Europe/Zurich'
    )
예제 #14
0
    def extract_date(mission):
        d = datetime.utcfromtimestamp(int(mission.date))
        d = sedate.replace_timezone(d, 'Europe/Zurich')

        time = mission.alert_time.replace('.', ':')
        time = time.replace(';', ':')
        time = time.replace('::', ':')

        if ':' in time:
            h, m = (int(v.strip('<>-')) for v in time.split(':'))
        else:
            h = int(time)
            m = 0

        d = d.replace(hour=h)
        d = d.replace(minute=m)

        return d
예제 #15
0
def view_get_occurrence(self, request):
    """ View a single occurrence of an event. """

    layout = OccurrenceLayout(self, request)
    today = replace_timezone(as_datetime(date.today()), self.timezone)
    occurrences = self.event.occurrence_dates(localize=True)
    occurrences = list(filter(lambda x: x >= today, occurrences))
    description = linkify(self.event.description).replace('\n', '<br>')
    session = request.app.session()
    ticket = TicketCollection(session).by_handler_id(self.event.id.hex)

    return {
        'description': description,
        'layout': layout,
        'occurrence': self,
        'occurrences': occurrences,
        'ticket': ticket,
        'title': self.title,
    }
예제 #16
0
파일: file.py 프로젝트: OneGov/onegov.file
 def signature_timestamp(self):
     if self.signed:
         return sedate.replace_timezone(
             isodate.parse_datetime(self.signature_metadata['timestamp']),
             'UTC'
         )
예제 #17
0
    def query(self, start=None, end=None, tags=None, outdated=False):
        """ Queries occurrences with the given parameters.

        Finds all occurrences with any of the given tags and within the given
        start and end date. Start and end date are assumed to be dates only and
        therefore without a timezone - we search for the given date in the
        timezone of the occurrence!.

        If no start date is given and ``outdated`` is not set, only current
        occurrences are returned.
        """

        query = self.session.query(Occurrence)

        if start is not None:
            assert type(start) is date
            start = as_datetime(start)

            expressions = []
            for timezone in self.used_timezones:
                localized_start = replace_timezone(start, timezone)
                localized_start = standardize_date(localized_start, timezone)
                expressions.append(
                    and_(
                        Occurrence.timezone == timezone,
                        Occurrence.start >= localized_start
                    )
                )

            query = query.filter(or_(*expressions))
        elif not outdated:
            start = as_datetime(date.today())

            expressions = []
            for timezone in self.used_timezones:
                localized_start = replace_timezone(start, timezone)
                localized_start = standardize_date(localized_start, timezone)
                expressions.append(
                    and_(
                        Occurrence.timezone == timezone,
                        Occurrence.start >= localized_start
                    )
                )

            query = query.filter(or_(*expressions))

        if end is not None:
            assert type(end) is date
            end = as_datetime(end)
            end = end + timedelta(days=1)

            expressions = []
            for timezone in self.used_timezones:
                localized_end = replace_timezone(end, timezone)
                localized_end = standardize_date(localized_end, timezone)
                expressions.append(
                    and_(
                        Occurrence.timezone == timezone,
                        Occurrence.end < localized_end
                    )
                )

            query = query.filter(or_(*expressions))

        if tags:
            query = query.filter(Occurrence._tags.has_any(array(tags)))

        query = query.order_by(Occurrence.start, Occurrence.title)

        return query
예제 #18
0
def test_editor_delete_day_before(wtfs_app, wtfs_password):
    session = wtfs_app.session()

    def permits(user, model, permission):
        return permits_by_app(wtfs_app, user, model, permission)

    # Remove existing users and group
    session.query(User).delete()
    session.query(Municipality).delete()

    # Add two towns
    foo = uuid4()

    session.add(Municipality(
        id=foo,
        name='Foo',
        bfs_number=1,
    ))
    session.add(PickupDate(
        date=date.today(),
        municipality_id=foo,
    ))

    bar = uuid4()

    session.add(Municipality(
        id=bar,
        name='Bar',
        bfs_number=1,
    ))
    session.add(PickupDate(
        date=date.today(),
        municipality_id=bar,
    ))

    # add a single scan job to foo
    session.add(ScanJob(
        type='normal',
        municipality_id=foo,
        delivery_number=1,
        dispatch_date=date(2019, 1, 1))
    )

    # an admin with access to all of it
    session.add(User(
        username='******',
        password_hash=wtfs_password,
        role='admin'
    ))

    # an editor with access to foo
    session.add(User(
        username='******',
        password_hash=wtfs_password,
        role='editor',
        group_id=foo
    ))

    # a member with access to foo
    session.add(User(
        username='******',
        password_hash=wtfs_password,
        role='member',
        group_id=foo
    ))

    # an editor with access to bar
    session.add(User(
        username='******',
        password_hash=wtfs_password,
        role='editor',
        group_id=bar
    ))

    # a member with access to bar
    session.add(User(
        username='******',
        password_hash=wtfs_password,
        role='member',
        group_id=bar
    ))

    session.flush()

    def fetch_user(username):
        return session.query(User).filter_by(username=username).one()

    job = session.query(ScanJob).one()

    admin = fetch_user('*****@*****.**')
    foo_editor = fetch_user('*****@*****.**')
    foo_member = fetch_user('*****@*****.**')
    bar_editor = fetch_user('*****@*****.**')
    bar_member = fetch_user('*****@*****.**')

    dt = sedate.replace_timezone(datetime(2018, 12, 31), 'Europe/Zurich')

    with freeze_time(dt.replace(hour=17, minute=0)):
        assert permits(admin, job, DeleteModel)
        assert permits(foo_editor, job, DeleteModel)
        assert not permits(foo_member, job, DeleteModel)
        assert not permits(bar_editor, job, DeleteModel)
        assert not permits(bar_member, job, DeleteModel)

    with freeze_time(dt.replace(hour=17, minute=1)):
        assert permits(admin, job, DeleteModel)
        assert not permits(foo_editor, job, DeleteModel)
        assert not permits(foo_member, job, DeleteModel)
        assert not permits(bar_editor, job, DeleteModel)
        assert not permits(bar_member, job, DeleteModel)
예제 #19
0
파일: cli.py 프로젝트: OneGov/onegov.wtfs
    def parse_datetime(dt):
        d = datetime.utcfromtimestamp(int(dt))
        d = sedate.replace_timezone(d, 'UTC')
        d = sedate.to_timezone(d, 'Europe/Zurich')

        return d
예제 #20
0
def send_daily_ticket_statistics(request):

    today = replace_timezone(datetime.utcnow(), 'UTC')
    today = to_timezone(today, 'Europe/Zurich')

    if today.weekday() in (SAT, SUN):
        return

    args = {}

    # get the current ticket count
    collection = TicketCollection(request.app.session())
    count = collection.get_count()
    args['currently_open'] = count.open
    args['currently_pending'] = count.pending
    args['currently_closed'] = count.closed

    # get tickets created yesterday or on the weekend
    end = datetime(today.year, today.month, today.day, tzinfo=today.tzinfo)
    if today.weekday() == MON:
        start = end - timedelta(days=2)
    else:
        start = end - timedelta(days=1)

    query = collection.query()
    query = query.filter(Ticket.created >= start)
    query = query.filter(Ticket.created <= end)
    args['opened'] = query.count()

    query = collection.query()
    query = query.filter(Ticket.modified >= start)
    query = query.filter(Ticket.modified <= end)
    query = query.filter(Ticket.state == 'pending')
    args['pending'] = query.count()

    query = collection.query()
    query = query.filter(Ticket.modified >= start)
    query = query.filter(Ticket.modified <= end)
    query = query.filter(Ticket.state == 'closed')
    args['closed'] = query.count()

    # render the email
    args['title'] = request.translate(
        _("${town} OneGov Cloud Status", mapping={
            'town': request.app.town.name
        })
    )
    args['layout'] = DefaultMailLayout(object(), request)
    args['is_monday'] = today.weekday() == MON
    args['town'] = request.app.town.name
    content = render_template('mail_daily_ticket_statistics.pt', request, args)

    # send one e-mail per user
    users = UserCollection(request.app.session()).query()
    users = users.options(undefer('data'))
    users = users.all()

    for user in users:

        if user.data and not user.data.get('daily_ticket_statistics'):
            continue

        request.app.send_email(
            subject=args['title'],
            receivers=(user.username, ),
            content=content
        )
예제 #21
0
def tzdatetime(year, month, day, hour, minute, timezone):
    return replace_timezone(datetime(year, month, day, hour, minute), timezone)