Example #1
0
 def _process(self):
     self.user.settings.set('suggest_categories', True)
     tz = session.tzinfo
     hours, minutes = timedelta_split(tz.utcoffset(datetime.now()))[:2]
     categories = get_related_categories(self.user)
     categories_events = []
     if categories:
         category_ids = {c['categ'].id for c in categories.itervalues()}
         today = now_utc(False).astimezone(tz).date()
         query = (Event.query
                  .filter(~Event.is_deleted,
                          Event.category_chain_overlaps(category_ids),
                          Event.start_dt.astimezone(session.tzinfo) >= today)
                  .options(joinedload('category').load_only('id', 'title'),
                           joinedload('series'),
                           subqueryload('acl_entries'),
                           load_only('id', 'category_id', 'start_dt', 'end_dt', 'title', 'access_key',
                                     'protection_mode', 'series_id', 'series_pos', 'series_count'))
                  .order_by(Event.start_dt, Event.id))
         categories_events = get_n_matching(query, 10, lambda x: x.can_access(self.user))
     from_dt = now_utc(False) - relativedelta(weeks=1, hour=0, minute=0, second=0)
     linked_events = [(event, {'management': bool(roles & self.management_roles),
                               'reviewing': bool(roles & self.reviewer_roles),
                               'attendance': bool(roles & self.attendance_roles)})
                      for event, roles in get_linked_events(self.user, from_dt, 10).iteritems()]
     return WPUser.render_template('dashboard.html', 'dashboard',
                                   offset='{:+03d}:{:02d}'.format(hours, minutes), user=self.user,
                                   categories=categories,
                                   categories_events=categories_events,
                                   suggested_categories=get_suggested_categories(self.user),
                                   linked_events=linked_events)
Example #2
0
 def _calc_start_dt(self, event):
     local_now_date = now_utc().astimezone(event.tzinfo).date()
     local_now_naive = now_utc().astimezone(event.tzinfo).replace(tzinfo=None)
     if event.start_dt_local.date() >= local_now_date:
         # we have to add the timedelta to the naive datetime to avoid
         # dst changes between the old and new dates to change the time
         # of the event
         start_dt = event.start_dt_local.replace(tzinfo=None) + timedelta(days=7)
     else:
         start_dt = datetime.combine(local_now_date, event.start_dt_local.time())
     if start_dt < local_now_naive:
         # if the combination of 'today' with the original start time is
         # still in the past, then let's set it for tomorrow instead
         start_dt += timedelta(days=1)
     return event.tzinfo.localize(start_dt)
Example #3
0
 def get_latest(self, form, field):
     latest = self.latest(form, field) if callable(
         self.latest) else self.latest
     if latest == 'now':
         self.latest_now = True
         return now_utc().replace(second=59, microsecond=999)
     return as_utc(latest) if latest else latest
Example #4
0
def update_review(review, review_data, questions_data):
    paper = review.revision.paper
    event = paper.event
    changes = review.populate_from_dict(review_data)
    review.modified_dt = now_utc()
    log_fields = {}
    for question in event.cfp.get_questions_for_review_type(review.type):
        field_name = 'question_{}'.format(question.id)
        rating = question.get_review_rating(review, allow_create=True)
        old_value = rating.value
        rating.value = questions_data[field_name]
        if old_value != rating.value:
            field_type = question.field_type
            changes[field_name] = (question.field.get_friendly_value(old_value),
                                   question.field.get_friendly_value(rating.value))
            log_fields[field_name] = {
                'title': question.title,
                'type': field_type if field_type != 'rating' else 'number'
            }
    db.session.flush()
    notify_paper_review_submission(review)
    logger.info("Paper review %r modified", review)
    log_fields.update({
        'proposed_action': 'Action',
        'comment': 'Comment'
    })
    event.log(EventLogRealm.reviewing, EventLogKind.change, 'Papers',
              'Review for paper {} modified'.format(paper.verbose_title),
              session.user, data={'Changes': make_diff_log(changes, log_fields)})
Example #5
0
    def migrate_event_images(self):
        self.print_step('migrating event images')
        for event, picture in committing_iterator(self._iter_pictures()):
            local_file = picture._localFile
            content_type = mimetypes.guess_type(local_file.fileName)[0] or 'application/octet-stream'
            storage_backend, storage_path, size = self._get_local_file_info(local_file)

            if storage_path is None:
                self.print_warning(cformat('%{yellow}[{}]%{reset} -> %{red!}Not found in filesystem').format(
                    local_file.id), event_id=event.id)
                continue

            filename = secure_filename(convert_to_unicode(local_file.fileName), 'image')
            image = ImageFile(event_id=event.id,
                              filename=filename,
                              content_type=content_type,
                              created_dt=now_utc(),
                              size=size,
                              storage_backend=storage_backend,
                              storage_file_id=storage_path)

            db.session.add(image)
            db.session.flush()

            map_entry = LegacyImageMapping(event_id=event.id, legacy_image_id=local_file.id, image_id=image.id)

            db.session.add(map_entry)

            if not self.quiet:
                self.print_success(cformat('%{cyan}[{}]%{reset} -> %{blue!}{}').format(local_file.id, image),
                                   event_id=event.id)
Example #6
0
 def __init__(self, regform):
     super(OverviewStats, self).__init__(title=_("Overview"), subtitle="", type='overview')
     self.regform = regform
     self.registrations = regform.active_registrations
     self.countries, self.num_countries = self._get_countries()
     self.availability = self._get_availibility()
     self.days_left = max((self.regform.end_dt - now_utc()).days, 0) if self.regform.end_dt else 0
Example #7
0
 def _process(self):
     filename = '{}-category.atom'.format(secure_filename(self.category.title, str(self.category.id)))
     buf = serialize_category_atom(self.category,
                                   url_for(request.endpoint, self.category, _external=True),
                                   session.user,
                                   Event.end_dt >= now_utc())
     return send_file(filename, buf, 'application/atom+xml')
Example #8
0
def cleanup_categories(dbi, logger):
    config = Config.getInstance()

    logger.info("Checking whether any categories should be cleaned up")

    for categ_id, days in config.getCategoryCleanup().items():
        try:
            category = CategoryManager().getById(categ_id)
        except KeyError:
            logger.warning("Category '{0}' does not exist!".format(categ_id))
            continue

        now = now_utc()

        to_delete = [ev for ev in category.conferences if (now - ev._creationDS) > timedelta(days=days)]

        if to_delete:
            logger.info("Category '{0}': {1} events were created more than {2} days ago and will be deleted".format(
                categ_id, len(to_delete), days
            ))

            for i, event in enumerate(to_delete, 1):
                logger.info("Deleting {0}".format(repr(event)))
                event.delete()
                if i % 100 == 0:
                    dbi.commit()
            dbi.commit()
Example #9
0
    def _process(self):
        form = self._make_form()
        if form.validate_on_submit():
            submission = self._save_answers(form)
            if submission.is_anonymous:
                submission.user = None
            submission.submitted_dt = now_utc()
            submission.is_submitted = True
            submission.pending_answers = {}
            db.session.flush()
            save_submitted_survey_to_session(submission)
            self.survey.send_submission_notification(submission)
            flash(_('The survey has been submitted'), 'success')
            return redirect(url_for('.display_survey_list', self.event))

        surveys = Survey.query.with_parent(self.event).filter(Survey.is_visible).all()
        if not _can_redirect_to_single_survey(surveys):
            back_button_endpoint = '.display_survey_list'
        elif self.event.type_ != EventType.conference:
            back_button_endpoint = 'events.display'
        else:
            back_button_endpoint = None
        return self.view_class.render_template('display/survey_questionnaire.html', self.event,
                                               form=form, survey=self.survey,
                                               back_button_endpoint=back_button_endpoint,
                                               partial_completion=self.survey.partial_completion)
Example #10
0
def test_notification_rules(mocker, abstract_objects, create_email_template, dummy_user, dummy_event):
    send_email = mocker.patch('indico.modules.events.abstracts.notifications.send_email')

    event, abstract, track, contrib_type = abstract_objects
    event.abstract_email_templates.append(
        create_email_template(event, 0, 'merge', 'merged poster for track', [
            {'state': [AbstractState.merged.value], 'track': [track.id]}
        ], True))

    send_abstract_notifications(abstract)
    assert send_email.call_count == 0

    abstract.state = AbstractState.accepted
    abstract.judge = dummy_user
    abstract.judgment_dt = now_utc(False)
    abstract.accepted_track = track
    send_abstract_notifications(abstract)
    assert send_email.call_count == 0

    abstract.state = AbstractState.merged
    abstract.merged_into = Abstract(title='test', submitter=dummy_user, event=dummy_event)
    abstract.accepted_track = None
    abstract.submitted_for_tracks = {track}
    send_abstract_notifications(abstract)
    assert send_email.call_count == 1
Example #11
0
def test_notification_several_conditions(db, mocker, abstract_objects, create_email_template, create_dummy_track,
                                         create_dummy_contrib_type, dummy_user):
    event, abstract, track, contrib_type = abstract_objects
    event.abstract_email_templates = [
        create_email_template(event, 0, 'accept', 'accepted', [
            {'state': [AbstractState.accepted.value], 'track': [track.id], 'contribution_type': [contrib_type.id]},
            {'state': [AbstractState.accepted.value], 'contribution_type': []}
        ], True)
    ]

    send_email = mocker.patch('indico.modules.events.abstracts.notifications.send_email')
    abstract.state = AbstractState.accepted
    abstract.judge = dummy_user
    abstract.judgment_dt = now_utc(False)
    abstract.accepted_track = track
    send_abstract_notifications(abstract)
    assert send_email.call_count == 1

    send_email.reset_mock()
    abstract.accepted_contrib_type = contrib_type
    send_abstract_notifications(abstract)
    assert send_email.call_count == 1

    send_email.reset_mock()
    abstract.accepted_track = create_dummy_track(event)
    abstract.accepted_contrib_type = create_dummy_contrib_type(event, name='Presentation')
    db.session.flush()
    send_abstract_notifications(abstract)
    assert send_email.call_count == 0
Example #12
0
def category_cleanup():
    cfg = Config.getInstance()
    janitor_user = User.get_one(cfg.getJanitorUserId())

    logger.debug("Checking whether any categories should be cleaned up")
    for categ_id, days in cfg.getCategoryCleanup().iteritems():
        try:
            category = CategoryManager().getById(categ_id)
        except KeyError:
            logger.warning("Category {} does not exist!".format(categ_id))
            continue

        now = now_utc()
        to_delete = [ev for ev in category.conferences if (now - ev._creationDS) > timedelta(days=days)]
        if not to_delete:
            continue

        logger.info("Category {}: {} events were created more than {} days ago and will be deleted".format(
            categ_id, len(to_delete), days
        ))
        for i, event in enumerate(to_delete, 1):
            logger.info("Deleting {}".format(event))
            event.delete(user=janitor_user)
            if i % 100 == 0:
                db.session.commit()
                DBMgr.getInstance().commit()
        db.session.commit()
        DBMgr.getInstance().commit()
Example #13
0
 def getBookingType(booking):
     if booking.canBeStarted():
         return "ongoing"
     elif booking.hasStartDate() and booking.getStartDate() > now_utc():
         return "scheduled"
     else:
         return ""
Example #14
0
 def _process(self):
     self.regform.end_dt = now_utc()
     if not self.regform.has_started:
         self.regform.start_dt = self.regform.end_dt
     flash(_("Registrations for {} are now closed").format(self.regform.title), 'success')
     logger.info("Registrations for %s closed by %s", self.regform, session.user)
     return redirect(url_for('.manage_regform', self.regform))
Example #15
0
 def register_used(self, ip, uri, authenticated):
     """Updates the last used information"""
     self.last_used_dt = now_utc()
     self.last_used_ip = ip
     self.last_used_uri = uri
     self.last_used_auth = authenticated
     self.use_count = APIKey.use_count + 1
Example #16
0
 def get_earliest(self, form, field):
     earliest = self.earliest(form, field) if callable(
         self.earliest) else self.earliest
     if earliest == 'now':
         self.earliest_now = True
         return now_utc().replace(second=0, microsecond=0)
     return as_utc(earliest) if earliest else earliest
Example #17
0
def get_upcoming_events():
    """Get the global list of upcoming events"""
    from indico.modules.events import Event
    data = upcoming_events_settings.get_all()
    if not data['max_entries'] or not data['entries']:
        return
    tz = timezone(config.DEFAULT_TIMEZONE)
    now = now_utc(False).astimezone(tz)
    base_query = (Event.query
                  .filter(Event.effective_protection_mode == ProtectionMode.public,
                          ~Event.is_deleted,
                          Event.end_dt.astimezone(tz) > now)
                  .options(load_only('id', 'title', 'start_dt', 'end_dt')))
    queries = []
    cols = {'category': Event.category_id,
            'event': Event.id}
    for entry in data['entries']:
        delta = timedelta(days=entry['days'])
        query = (base_query
                 .filter(cols[entry['type']] == entry['id'])
                 .filter(db.cast(Event.start_dt.astimezone(tz), db.Date) > (now - delta).date())
                 .with_entities(Event, db.literal(entry['weight']).label('weight')))
        queries.append(query)

    query = (queries[0].union(*queries[1:])
             .order_by(db.desc('weight'), Event.start_dt, Event.title)
             .limit(data['max_entries']))
    for row in query:
        event = row[0]
        # we cache the result of the function and is_deleted is used in the repr
        # and having a broken repr on the cached objects would be ugly
        set_committed_value(event, 'is_deleted', False)
        yield event
Example #18
0
def update_email_log_state(log_entry, failed=False):
    if failed:
        log_entry.data['state'] = 'failed'
    else:
        log_entry.data['state'] = 'sent'
        log_entry.data['sent_dt'] = now_utc(False).isoformat()
    flag_modified(log_entry, 'data')
Example #19
0
def serialize_category_ical(category, user, event_filter):
    """Export the events in a category to iCal

    :param category: The category to export
    :param user: The user who needs to be able to access the events
    :param event_filter: A SQLalchemy criterion to restrict which
                         events will be returned.  Usually something
                         involving the start/end date of the event.
    """
    own_room_strategy = joinedload('own_room')
    own_room_strategy.load_only('building', 'floor', 'number', 'name')
    own_room_strategy.lazyload('owner')
    own_venue_strategy = joinedload('own_venue').load_only('name')
    query = (Event.query
             .filter(Event.category_chain.contains([int(category.getId())]),
                     ~Event.is_deleted,
                     event_filter)
             .options(load_only('id', 'start_dt', 'end_dt', 'title', 'description', 'own_venue_name',
                                'own_room_name', 'protection_mode'),
                      subqueryload('acl_entries'),
                      joinedload('person_links'),
                      own_room_strategy,
                      own_venue_strategy)
             .order_by(Event.start_dt))
    events = [e for e in query if e.can_access(user)]
    cal = ical.Calendar()
    cal.add('version', '2.0')
    cal.add('prodid', '-//CERN//INDICO//EN')

    now = now_utc(False)
    for event in events:
        url = url_for('event.conferenceDisplay', confId=event.id, _external=True)
        location = ('{} ({})'.format(event.room_name, event.venue_name)
                    if event.venue_name and event.room_name
                    else (event.venue_name or event.room_name))
        cal_event = ical.Event()
        cal_event.add('uid', u'indico-event-{}@cern.ch'.format(event.id))
        cal_event.add('dtstamp', now)
        cal_event.add('dtstart', event.start_dt)
        cal_event.add('dtend', event.end_dt)
        cal_event.add('url', url)
        cal_event.add('summary', event.title)
        cal_event.add('location', location)
        description = []
        if event.person_links:
            speakers = [u'{} ({})'.format(x.full_name, x.affiliation) if x.affiliation else x.full_name
                        for x in event.person_links]
            description.append(u'Speakers: {}'.format(u', '.join(speakers)))

        if event.description:
            desc_text = unicode(event.description) or u'<p/>'  # get rid of RichMarkup
            try:
                description.append(unicode(html.fromstring(desc_text).text_content()))
            except ParserError:
                # this happens e.g. if desc_text contains only a html comment
                pass
        description.append(url)
        cal_event.add('description', u'\n'.join(description))
        cal.add_component(cal_event)
    return BytesIO(cal.to_ical())
Example #20
0
File: tasks.py Project: fph/indico
def category_cleanup():
    from indico.modules.events import Event
    cfg = Config.getInstance()
    janitor_user = User.get_one(cfg.getJanitorUserId())

    logger.debug("Checking whether any categories should be cleaned up")
    for categ_id, days in cfg.getCategoryCleanup().iteritems():
        try:
            category = Category.get(int(categ_id), is_deleted=False)
        except KeyError:
            logger.warning("Category %s does not exist!", categ_id)
            continue

        now = now_utc()
        to_delete = Event.query.with_parent(category).filter(Event.created_dt < (now - timedelta(days=days))).all()
        if not to_delete:
            continue

        logger.info("Category %s: %s events were created more than %s days ago and will be deleted", categ_id,
                    len(to_delete), days)
        for i, event in enumerate(to_delete, 1):
            logger.info("Deleting %s", event)
            event.as_legacy.delete(user=janitor_user)
            if i % 100 == 0:
                db.session.commit()
                DBMgr.getInstance().commit()
        db.session.commit()
        DBMgr.getInstance().commit()
Example #21
0
 def _process(self):
     from indico.modules.events import Event
     filename = '{}-category.atom'.format(secure_filename(self._target.getName(), str(self._target.id)))
     buf = serialize_category_atom(self._target,
                                   url_for(request.endpoint, self._target, _external=True),
                                   session.user,
                                   Event.end_dt >= now_utc())
     return send_file(filename, buf, 'application/atom+xml')
Example #22
0
 def scheduled_dt(self):
     if self.schedule_type.data == 'absolute':
         dt = datetime.combine(self.absolute_date.data, self.absolute_time.data)
         return get_timezone(self.timezone).localize(dt).astimezone(pytz.utc)
     elif self.schedule_type.data == 'relative':
         return self.event.getStartDate() - self.relative_delta.data
     elif self.schedule_type.data == 'now':
         return now_utc()
Example #23
0
def send_event_reminders():
    reminders = EventReminder.find_all(~EventReminder.is_sent, ~Event.is_deleted,
                                       EventReminder.scheduled_dt <= now_utc(),
                                       _join=EventReminder.event)
    for reminder in reminders:
        logger.info('Sending event reminder: %s', reminder)
        reminder.send()
    db.session.commit()
Example #24
0
 def _process(self):
     if self.regform.has_ended:
         self.regform.end_dt = None
     else:
         self.regform.start_dt = now_utc()
     logger.info("Registrations for %s opened by %s", self.regform, session.user)
     flash(_("Registrations for {} are now open").format(self.regform.title), 'success')
     return redirect(url_for('.manage_regform', self.regform))
Example #25
0
 def validate_schedule_type(self, field):
     # Be graceful and allow a reminder that's in the past but on the same day.
     # It will be sent immediately but that way we are a little bit more user-friendly
     if field.data == 'now':
         return
     scheduled_dt = self.scheduled_dt.data
     if scheduled_dt is not None and scheduled_dt.date() < now_utc().date():
         raise ValidationError(_('The specified date is in the past'))
Example #26
0
 def open(self):
     if self.has_ended:
         abstracts_settings.set_multi(self.event, {
             'end_dt': None,
             'modification_end_dt': None
         })
     else:
         abstracts_settings.set(self.event, 'start_dt', now_utc(False))
Example #27
0
 def serialize(self):
     metadata = {
         'timestamp': now_utc(),
         'indico_version': indico.__version__,
         'objects': list(self._serialize_objects(Event.__table__, Event.id == self.event.id)),
         'users': self.users
     }
     yaml_data = yaml.dump(metadata, indent=2)
     self._add_file('data.yaml', len(yaml_data), yaml_data)
Example #28
0
def _inject_announcement_header(**kwargs):
    if not session.user or not session.user.is_admin or config.DISABLE_CELERY_CHECK:
        return
    last_ping = celery_settings.get('last_ping')
    last_ping_version = celery_settings.get('last_ping_version')
    down = not last_ping or (now_utc() - last_ping) > timedelta(hours=1)
    mismatch = last_ping_version and last_ping_version != indico.__version__
    if down or mismatch:
        return render_template('celery/warning.html', down=down)
Example #29
0
def _get_category_score(user, categ, attended_events, debug=False):
    if debug:
        print(repr(categ))
    # We care about events in the whole timespan where the user attended some events.
    # However, this might result in some missed events e.g. if the user was not working for
    # a year and then returned. So we throw away old blocks (or rather adjust the start time
    # to the start time of the newest block)
    first_event_date = attended_events[0].start_dt.replace(hour=0, minute=0)
    last_event_date = attended_events[-1].start_dt.replace(hour=0, minute=0) + timedelta(days=1)
    blocks = _get_blocks(_query_categ_events(categ, first_event_date, last_event_date), attended_events)
    for a, b in window(blocks):
        # More than 3 months between blocks? Ignore the old block!
        if b[0].start_dt - a[-1].start_dt > timedelta(weeks=12):
            first_event_date = b[0].start_dt.replace(hour=0, minute=0)

    # Favorite categories get a higher base score
    score = int(categ in user.favorite_categories)
    if debug:
        print('{0:+.3f} - initial'.format(score))
    # Attendance percentage goes to the score directly. If the attendance is high chances are good that the user
    # is either very interested in whatever goes on in the category or it's something he has to attend regularily.
    total = _query_categ_events(categ, first_event_date, last_event_date).count()
    if total:
        attended_block_event_count = sum(1 for e in attended_events if e.start_dt >= first_event_date)
        score += attended_block_event_count / total
    if debug:
        print('{0:+.3f} - attendance'.format(score))
    # If there are lots/few unattended events after the last attended one we also update the score with that
    total_after = _query_categ_events(categ, last_event_date + timedelta(days=1), None).count()
    if total_after < total * 0.05:
        score += 0.25
    elif total_after > total * 0.25:
        score -= 0.5
    if debug:
        print('{0:+.3f} - unattended new events'.format(score))
    # Lower the score based on how long ago the last attended event was if there are no future events
    # We start applying this modifier only if the event has been more than 40 days in the past to avoid
    # it from happening in case of monthly events that are not created early enough.
    days_since_last_event = (date.today() - last_event_date.date()).days
    if days_since_last_event > 40:
        score -= 0.025 * days_since_last_event
    if debug:
        print('{0:+.3f} - days since last event'.format(score))
    # For events in the future however we raise the score
    now_local = utc_to_server(now_utc())
    attending_future = (_query_categ_events(categ, now_local, last_event_date)
                        .filter(Event.id.in_(e.id for e in attended_events))
                        .all())
    if attending_future:
        score += 0.25 * len(attending_future)
        if debug:
            print('{0:+.3f} - future event count'.format(score))
        days_to_future_event = (attending_future[0].start_dt.date() - date.today()).days
        score += max(0.1, -(max(0, days_to_future_event - 2) / 4) ** (1 / 3) + 2.5)
        if debug:
            print('{0:+.3f} - days to next future event'.format(score))
    return score
Example #30
0
def test_reject(reason, on_behalf, expected_state):
    ip = '127.0.0.1'
    agreement = Agreement()
    agreement.reject(from_ip=ip, reason=reason, on_behalf=on_behalf)
    assert agreement.state == expected_state
    assert agreement.signed_from_ip == ip
    assert agreement.reason == reason
    assert agreement.signed_dt == now_utc()
    agreement.definition.handle_rejected.assert_called_with(agreement)
Example #31
0
 def close(self):
     now = now_utc(False)
     abstracts_settings.set(self.event, 'end_dt', now)
     if not self.has_started:
         abstracts_settings.set(self.event, 'start_dt', now)
Example #32
0
 def _set_checked_in_dt(target, value, *unused):
     if not value:
         target.checked_in_dt = None
     elif target.checked_in != value:
         target.checked_in_dt = now_utc()
Example #33
0
 def has_ended(self):
     return self.end_dt <= now_utc()
Example #34
0
 def has_started(cls):
     return (cls.start_dt != None) & (cls.start_dt <= now_utc())  # noqa
Example #35
0
 def close(self):
     if self.state not in (SurveyState.active_and_clean, SurveyState.active_and_answered, SurveyState.limit_reached):
         raise IndicoError("Survey can't be closed")
     self.end_dt = now_utc()
Example #36
0
    def _process(self):
        if not self.plugin.can_manage_vc_rooms(session.user, self.event):
            flash(
                _('You are not allowed to modify {} rooms for this event.').
                format(self.plugin.friendly_name), 'error')
            return redirect(url_for('.manage_vc_rooms', self.event))

        form = self.plugin.create_form(
            self.event,
            existing_vc_room=self.vc_room,
            existing_event_vc_room=self.event_vc_room)

        if form.validate_on_submit():

            self.plugin.update_data_vc_room(self.vc_room, form.data)

            event_vc_room = process_vc_room_association(
                self.plugin,
                self.event,
                self.vc_room,
                form,
                event_vc_room=self.event_vc_room,
                allow_same_room=True)
            if not event_vc_room:
                return redirect(url_for('.manage_vc_rooms', self.event))

            self.vc_room.modified_dt = now_utc()

            try:
                self.plugin.update_room(self.vc_room, self.event)
            except VCRoomNotFoundError as err:
                Logger.get('modules.vc').warning(
                    "VC room %r not found. Setting it as deleted.",
                    self.vc_room)
                self.vc_room.status = VCRoomStatus.deleted
                flash(err.message, 'error')
                return redirect(url_for('.manage_vc_rooms', self.event))
            except VCRoomError as err:
                if err.field is None:
                    raise
                field = getattr(form, err.field)
                field.errors.append(err.message)
                db.session.rollback()
            else:
                # TODO
                # notify_modified(self.vc_room, self.event, session.user)

                flash(
                    _("{plugin_name} room '{room.name}' updated").format(
                        plugin_name=self.plugin.friendly_name,
                        room=self.vc_room), 'success')
                return jsonify_data(flash=False)

        form_html = self.plugin.render_form(plugin=self.plugin,
                                            event=self.event,
                                            form=form,
                                            existing_vc_room=self.vc_room,
                                            skip_fields=form.skip_fields
                                            | {'name'})

        return jsonify(html=form_html, js=_pop_injected_js())
Example #37
0
 def has_ended(self):
     return self.end_dt is not None and self.end_dt <= now_utc()
Example #38
0
 def open(self):
     if self.has_ended:
         paper_reviewing_settings.set(self.event, 'end_dt', None)
     else:
         paper_reviewing_settings.set(self.event, 'start_dt', now_utc(False))
def _get_category_score(user, categ, attended_events, debug=False):
    if debug:
        print(repr(categ))
    # We care about events in the whole timespan where the user attended some events.
    # However, this might result in some missed events e.g. if the user was not working for
    # a year and then returned. So we throw away old blocks (or rather adjust the start time
    # to the start time of the newest block)
    first_event_date = attended_events[0].start_dt.replace(hour=0, minute=0)
    last_event_date = attended_events[-1].start_dt.replace(
        hour=0, minute=0) + timedelta(days=1)
    blocks = _get_blocks(
        _query_categ_events(categ, first_event_date, last_event_date),
        attended_events)
    for a, b in window(blocks):
        # More than 3 months between blocks? Ignore the old block!
        if b[0].start_dt - a[-1].start_dt > timedelta(weeks=12):
            first_event_date = b[0].start_dt.replace(hour=0, minute=0)

    # Favorite categories get a higher base score
    score = int(categ in user.favorite_categories)
    if debug:
        print(f'{score:+.3f} - initial')
    # Attendance percentage goes to the score directly. If the attendance is high chances are good that the user
    # is either very interested in whatever goes on in the category or it's something he has to attend regularily.
    total = _query_categ_events(categ, first_event_date,
                                last_event_date).count()
    if total:
        attended_block_event_count = sum(1 for e in attended_events
                                         if e.start_dt >= first_event_date)
        score += attended_block_event_count / total
    if debug:
        print(f'{score:+.3f} - attendance')
    # If there are lots/few unattended events after the last attended one we also update the score with that
    total_after = _query_categ_events(categ,
                                      last_event_date + timedelta(days=1),
                                      None).count()
    if total_after < total * 0.05:
        score += 0.25
    elif total_after > total * 0.25:
        score -= 0.5
    if debug:
        print(f'{score:+.3f} - unattended new events')
    # Lower the score based on how long ago the last attended event was if there are no future events
    # We start applying this modifier only if the event has been more than 40 days in the past to avoid
    # it from happening in case of monthly events that are not created early enough.
    days_since_last_event = (date.today() - last_event_date.date()).days
    if days_since_last_event > 40:
        score -= 0.025 * days_since_last_event
    if debug:
        print(f'{score:+.3f} - days since last event')
    # For events in the future however we raise the score
    now_local = utc_to_server(now_utc())
    attending_future = (_query_categ_events(
        categ, now_local,
        last_event_date).filter(Event.id.in_(e.id
                                             for e in attended_events)).all())
    if attending_future:
        score += 0.25 * len(attending_future)
        if debug:
            print(f'{score:+.3f} - future event count')
        days_to_future_event = (attending_future[0].start_dt.date() -
                                date.today()).days
        score += max(0.1,
                     -(max(0, days_to_future_event - 2) / 4)**(1 / 3) + 2.5)
        if debug:
            print(f'{score:+.3f} - days to next future event')
    return score
Example #40
0
 def close(self):
     paper_reviewing_settings.set(self.event, 'end_dt', now_utc(False))
Example #41
0
 def can_edit_abstracts(self, user):
     modification_end = self.modification_end_dt
     return self.can_submit_abstracts(user) or (modification_end is not None and modification_end > now_utc())
Example #42
0
 def modification_ended(self):
     return self.modification_end_dt is not None and self.modification_end_dt <= now_utc()
Example #43
0
 def has_started(self):
     return self.start_dt is not None and self.start_dt <= now_utc()
Example #44
0
 def _update_last_use(response):
     with db.tmp_session() as sess:
         # do not modify `token` directly, it's attached to a different session!
         sess.query(OAuthToken).filter_by(id=token_id).update({OAuthToken.last_used_dt: now_utc()})
         sess.commit()
     return response
Example #45
0
 def has_ended(cls):
     return (cls.end_dt != None) & (cls.end_dt <= now_utc())  # noqa
Example #46
0
 def open(self):
     if self.state != SurveyState.ready_to_open:
         raise IndicoError("Survey can't be opened")
     self.start_dt = now_utc()
Example #47
0
    dummy_person.user = dummy_user if person_with_user else None
    agreement = Agreement.create_from_data(event=dummy_event,
                                           type_=type_,
                                           person=dummy_person)
    assert agreement.event == dummy_event
    assert agreement.type == type_
    assert agreement.state == AgreementState.pending
    assert agreement.uuid
    assert agreement.identifier == dummy_person.identifier
    assert agreement.person_email == dummy_person.email
    assert agreement.person_name == dummy_person.name
    assert agreement.user == dummy_person.user
    assert agreement.data == dummy_person.data


@freeze_time(now_utc())
@pytest.mark.usefixtures('mock_agreement_definition')
@pytest.mark.parametrize(('reason', 'on_behalf', 'expected_state'), (
    (None, True, AgreementState.accepted_on_behalf),
    (None, False, AgreementState.accepted),
    ('reason', False, AgreementState.accepted),
))
def test_accept(reason, on_behalf, expected_state):
    ip = '127.0.0.1'
    agreement = Agreement()
    agreement.accept(from_ip=ip, reason=reason, on_behalf=on_behalf)
    assert agreement.state == expected_state
    assert agreement.signed_from_ip == ip
    assert agreement.reason == reason
    assert agreement.signed_dt == now_utc()
    agreement.definition.handle_accepted.assert_called_with(agreement)
Example #48
0
 def is_overdue(self):
     return not self.is_sent and self.scheduled_dt <= now_utc()
Example #49
0
def serialize_categories_ical(category_ids,
                              user,
                              event_filter=True,
                              event_filter_fn=None,
                              update_query=None):
    """Export the events in a category to iCal

    :param category_ids: Category IDs to export
    :param user: The user who needs to be able to access the events
    :param event_filter: A SQLalchemy criterion to restrict which
                         events will be returned.  Usually something
                         involving the start/end date of the event.
    :param event_filter_fn: A callable that determines which events to include (after querying)
    :param update_query: A callable that can update the query used to retrieve the events.
                         Must return the updated query object.
    """
    own_room_strategy = joinedload('own_room')
    own_room_strategy.load_only('building', 'floor', 'number', 'verbose_name')
    own_room_strategy.lazyload('owner')
    own_venue_strategy = joinedload('own_venue').load_only('name')
    query = (Event.query.filter(
        Event.category_chain_overlaps(category_ids), ~Event.is_deleted,
        event_filter).options(
            load_only('id', 'category_id', 'start_dt', 'end_dt', 'title',
                      'description', 'own_venue_name', 'own_room_name',
                      'protection_mode', 'access_key'),
            subqueryload('acl_entries'), joinedload('person_links'),
            own_room_strategy, own_venue_strategy).order_by(Event.start_dt))
    if update_query:
        query = update_query(query)
    it = iter(query)
    if event_filter_fn:
        it = ifilter(event_filter_fn, it)
    events = list(it)
    # make sure the parent categories are in sqlalchemy's identity cache.
    # this avoids query spam from `protection_parent` lookups
    _parent_categs = (Category._get_chain_query(
        Category.id.in_({e.category_id
                         for e in events})).options(
                             load_only('id', 'parent_id', 'protection_mode'),
                             joinedload('acl_entries')).all())
    cal = ical.Calendar()
    cal.add('version', '2.0')
    cal.add('prodid', '-//CERN//INDICO//EN')

    now = now_utc(False)
    for event in events:
        if not event.can_access(user):
            continue
        location = ('{} ({})'.format(event.room_name, event.venue_name)
                    if event.venue_name and event.room_name else
                    (event.venue_name or event.room_name))
        cal_event = ical.Event()
        cal_event.add(
            'uid',
            u'indico-event-{}@{}'.format(event.id,
                                         url_parse(config.BASE_URL).host))
        cal_event.add('dtstamp', now)
        cal_event.add('dtstart', event.start_dt)
        cal_event.add('dtend', event.end_dt)
        cal_event.add('url', event.external_url)
        cal_event.add('summary', event.title)
        cal_event.add('location', location)
        description = []
        if event.person_links:
            speakers = [
                u'{} ({})'.format(x.full_name, x.affiliation)
                if x.affiliation else x.full_name for x in event.person_links
            ]
            description.append(u'Speakers: {}'.format(u', '.join(speakers)))

        if event.description:
            desc_text = unicode(
                event.description) or u'<p/>'  # get rid of RichMarkup
            try:
                description.append(
                    unicode(html.fromstring(desc_text).text_content()))
            except ParserError:
                # this happens e.g. if desc_text contains only a html comment
                pass
        description.append(event.external_url)
        cal_event.add('description', u'\n'.join(description))
        cal.add_component(cal_event)
    return BytesIO(cal.to_ical())
Example #50
0
    def update_last_run(self):
        """Updates the last run timestamp.

        Don't forget to call this if you implement your own `run` method!
        """
        self.agent.last_run = now_utc()
Example #51
0
 def reject(self, from_ip, reason=None, on_behalf=False):
     self.state = AgreementState.rejected if not on_behalf else AgreementState.rejected_on_behalf
     self.signed_from_ip = from_ip
     self.reason = reason
     self.signed_dt = now_utc()
     self.definition.handle_rejected(self)
Example #52
0
def setup_jinja(app):
    app.jinja_env.policies['ext.i18n.trimmed'] = True
    # Useful (Python) builtins
    app.add_template_global(dict)
    # Global functions
    app.add_template_global(url_for)
    app.add_template_global(url_for_plugin)
    app.add_template_global(url_rule_to_js)
    app.add_template_global(IndicoConfig(exc=Exception), 'indico_config')
    app.add_template_global(call_template_hook, 'template_hook')
    app.add_template_global(is_single_line_field, '_is_single_line_field')
    app.add_template_global(render_field, '_render_field')
    app.add_template_global(iter_form_fields, '_iter_form_fields')
    app.add_template_global(format_currency)
    app.add_template_global(get_currency_name)
    app.add_template_global(url_for_index)
    app.add_template_global(url_for_login)
    app.add_template_global(url_for_logout)
    app.add_template_global(lambda: str(uuid.uuid4()), 'uuid')
    app.add_template_global(icon_from_mimetype)
    app.add_template_global(render_sidemenu)
    app.add_template_global(slugify)
    app.add_template_global(lambda: date_time_util.now_utc(False), 'now')
    app.add_template_global(render_session_bar)
    app.add_template_global(get_request_stats)
    app.add_template_global(_get_indico_version(), 'indico_version')
    # Global variables
    app.add_template_global(LocalProxy(get_current_locale), 'current_locale')
    app.add_template_global(LocalProxy(lambda: current_plugin.manifest if current_plugin else None), 'plugin_webpack')
    # Useful constants
    app.add_template_global('^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$', name='time_regex_hhmm')  # for input[type=time]
    # Filters (indico functions returning UTF8)
    app.add_template_filter(date_time_util.format_date)
    app.add_template_filter(date_time_util.format_time)
    app.add_template_filter(date_time_util.format_datetime)
    app.add_template_filter(date_time_util.format_human_date)
    app.add_template_filter(date_time_util.format_timedelta)
    app.add_template_filter(date_time_util.format_number)
    # Filters (new ones returning unicode)
    app.add_template_filter(date_time_util.format_human_timedelta)
    app.add_template_filter(date_time_util.format_pretty_date)
    app.add_template_filter(date_time_util.format_pretty_datetime)
    app.add_template_filter(lambda d: Markup(html_params(**d)), 'html_params')
    app.add_template_filter(underline)
    app.add_template_filter(markdown)
    app.add_template_filter(dedent)
    app.add_template_filter(html_to_plaintext)
    app.add_template_filter(natsort)
    app.add_template_filter(groupby)
    app.add_template_filter(plusdelta)
    app.add_template_filter(decodeprincipal)
    app.add_template_filter(any)
    app.add_template_filter(alpha_enum)
    app.add_template_filter(crc32)
    app.add_template_filter(bool)
    app.add_template_filter(lambda s: Markup(sanitize_html(s or '')), 'sanitize_html')
    app.add_template_filter(RichMarkup, 'rich_markup')
    # Tests
    app.add_template_test(instanceof)  # only use this test if you really have to!
    app.add_template_test(subclassof)  # only use this test if you really have to!
    # i18n
    app.jinja_env.add_extension('jinja2.ext.i18n')
    app.jinja_env.install_gettext_callables(gettext_context, ngettext_context, True)
Example #53
0
def setup_jinja(app):
    config = Config.getInstance()
    # Unicode hack
    app.jinja_env.add_extension(EnsureUnicodeExtension)
    app.add_template_filter(EnsureUnicodeExtension.ensure_unicode)
    # Useful (Python) builtins
    app.add_template_global(dict)
    # Global functions
    app.add_template_global(url_for)
    app.add_template_global(url_for_plugin)
    app.add_template_global(url_rule_to_js)
    app.add_template_global(IndicoConfigWrapper(config), 'indico_config')
    app.add_template_global(config.getSystemIconURL, 'system_icon')
    app.add_template_global(include_css_assets)
    app.add_template_global(include_js_assets)
    app.add_template_global(include_plugin_css_assets)
    app.add_template_global(include_plugin_js_assets)
    app.add_template_global(call_template_hook, 'template_hook')
    app.add_template_global(is_single_line_field, '_is_single_line_field')
    app.add_template_global(render_field, '_render_field')
    app.add_template_global(iter_form_fields, '_iter_form_fields')
    app.add_template_global(format_currency)
    app.add_template_global(get_currency_name)
    app.add_template_global(url_for_index)
    app.add_template_global(url_for_login)
    app.add_template_global(url_for_logout)
    app.add_template_global(lambda: unicode(uuid.uuid4()), 'uuid')
    app.add_template_global(icon_from_mimetype)
    app.add_template_global(render_sidemenu)
    app.add_template_global(slugify)
    app.add_template_global(lambda: date_time_util.now_utc(False), 'now')
    # Useful constants
    app.add_template_global('^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$', name='time_regex_hhmm')  # for input[type=time]
    # Filters (indico functions returning UTF8)
    app.add_template_filter(EnsureUnicodeExtension.wrap_func(date_time_util.format_date))
    app.add_template_filter(EnsureUnicodeExtension.wrap_func(date_time_util.format_time))
    app.add_template_filter(EnsureUnicodeExtension.wrap_func(date_time_util.format_datetime))
    app.add_template_filter(EnsureUnicodeExtension.wrap_func(date_time_util.format_human_date))
    app.add_template_filter(EnsureUnicodeExtension.wrap_func(date_time_util.format_timedelta))
    app.add_template_filter(EnsureUnicodeExtension.wrap_func(date_time_util.format_number))
    # Filters (new ones returning unicode)
    app.add_template_filter(date_time_util.format_human_timedelta)
    app.add_template_filter(date_time_util.format_pretty_date)
    app.add_template_filter(date_time_util.format_pretty_datetime)
    app.add_template_filter(lambda d: Markup(html_params(**d)), 'html_params')
    app.add_template_filter(underline)
    app.add_template_filter(markdown)
    app.add_template_filter(dedent)
    app.add_template_filter(natsort)
    app.add_template_filter(groupby)
    app.add_template_filter(any)
    app.add_template_filter(strip_tags)
    app.add_template_filter(alpha_enum)
    app.add_template_filter(crc32)
    app.add_template_filter(bool)
    # Tests
    app.add_template_test(instanceof)  # only use this test if you really have to!
    app.add_template_test(subclassof)  # only use this test if you really have to!
    # i18n
    app.jinja_env.add_extension('jinja2.ext.i18n')
    app.jinja_env.install_gettext_callables(gettext_context, ngettext_context, True)
    # webassets
    app.jinja_env.add_extension('webassets.ext.jinja2.AssetsExtension')
    app.jinja_env.assets_environment = core_env
Example #54
0
 def _checkParams(self):
     RHDisplayCategoryBase._checkParams(self)
     self.now = now_utc(exact=False).astimezone(
         self.category.display_tzinfo)
Example #55
0
 def register_login(self, ip):
     """Updates the last login information"""
     self.last_login_dt = now_utc()
     self.last_login_ip = ip
Example #56
0
def is_event_excluded(event):
    """Check if an event is excluded from the calendar"""
    from indico_outlook.plugin import OutlookPlugin
    return event.duration > OutlookPlugin.settings.get(
        'max_event_duration') or event.end_dt <= now_utc()
Example #57
0
def heartbeat(initial=False):
    celery_settings.set('last_ping', now_utc())
    if initial:
        celery_settings.set('last_ping_version', indico.__version__)
    db.session.commit()