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)
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)
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
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)})
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)
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
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')
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()
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)
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
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
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()
def getBookingType(booking): if booking.canBeStarted(): return "ongoing" elif booking.hasStartDate() and booking.getStartDate() > now_utc(): return "scheduled" else: return ""
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))
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
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
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
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')
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())
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()
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')
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()
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()
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))
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'))
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))
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)
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)
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
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)
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)
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()
def has_ended(self): return self.end_dt <= now_utc()
def has_started(cls): return (cls.start_dt != None) & (cls.start_dt <= now_utc()) # noqa
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()
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())
def has_ended(self): return self.end_dt is not None and self.end_dt <= now_utc()
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
def close(self): paper_reviewing_settings.set(self.event, 'end_dt', now_utc(False))
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())
def modification_ended(self): return self.modification_end_dt is not None and self.modification_end_dt <= now_utc()
def has_started(self): return self.start_dt is not None and self.start_dt <= now_utc()
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
def has_ended(cls): return (cls.end_dt != None) & (cls.end_dt <= now_utc()) # noqa
def open(self): if self.state != SurveyState.ready_to_open: raise IndicoError("Survey can't be opened") self.start_dt = now_utc()
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)
def is_overdue(self): return not self.is_sent and self.scheduled_dt <= now_utc()
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())
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()
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)
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)
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
def _checkParams(self): RHDisplayCategoryBase._checkParams(self) self.now = now_utc(exact=False).astimezone( self.category.display_tzinfo)
def register_login(self, ip): """Updates the last login information""" self.last_login_dt = now_utc() self.last_login_ip = ip
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()
def heartbeat(initial=False): celery_settings.set('last_ping', now_utc()) if initial: celery_settings.set('last_ping_version', indico.__version__) db.session.commit()