def _migrate_category(self, old_cat, position): # unlimited visibility is 999 but we have a 994 for some reason.. since nobody # has 900 levels of nesting we can just go for that threshold instead visibility = None if old_cat._visibility > 900 else old_cat._visibility if visibility == 0: self.print_warning( "Raising visibility from 'invisible' to 'category-only'", event_id=old_cat.id) visibility = 1 emails = re.split( r'[\s;,]+', convert_to_unicode(getattr(old_cat, '_notifyCreationList', ''))) emails = {sanitize_email(email).lower() for email in emails} emails = sorted(email for email in emails if is_valid_mail(email, False)) default_themes = self._process_default_themes(old_cat) title = self._fix_title(convert_to_unicode(old_cat.name), old_cat.id) if is_legacy_id(old_cat.id): # if category has a legacy (non-numeric) ID, generate a new ID # and establish a mapping (for URL redirection) new_id = self.gen_categ_id() db.session.add( LegacyCategoryMapping(legacy_category_id=old_cat.id, category_id=new_id)) self.print_success('%[white!]{:6s}%[reset] -> %[cyan]{}'.format( old_cat.id, new_id)) else: new_id = int(old_cat.id) if hasattr(old_cat, '_timezone'): tz_name = old_cat._timezone else: tz_name = self.makac_info._timezone cat = Category(id=int(new_id), position=position, title=title, description=convert_to_unicode(old_cat.description), visibility=visibility, timezone=convert_to_unicode(tz_name), event_creation_notification_emails=emails, default_event_themes=default_themes, suggestions_disabled=getattr(old_cat, '_suggestions_disabled', False)) if not self.quiet: self.print_success(cat.title, event_id=cat.id) if old_cat._icon: self._process_icon(cat, old_cat._icon) self._process_protection(cat, old_cat) self.migrate_category_attachments(cat, old_cat) cat.children = [(self._migrate_category(old_subcat, i)) for i, old_subcat in enumerate( sorted(old_cat.subcategories.itervalues(), key=attrgetter('_order')), 1)] # add to user favorites for user in self.global_ns.user_favorite_categories[old_cat.id]: user.favorite_categories.add(cat) self.global_ns.legacy_category_ids[old_cat.id] = cat return cat
def _migrate_category(self, old_cat, position): # unlimited visibility is 999 but we have a 994 for some reason.. since nobody # has 900 levels of nesting we can just go for that threshold instead visibility = None if old_cat._visibility > 900 else old_cat._visibility if visibility == 0: self.print_warning("Raising visibility from 'invisible' to 'category-only'", event_id=old_cat.id) visibility = 1 emails = re.split(r'[\s;,]+', convert_to_unicode(getattr(old_cat, '_notifyCreationList', ''))) emails = {sanitize_email(email).lower() for email in emails} emails = sorted(email for email in emails if is_valid_mail(email, False)) default_themes = self._process_default_themes(old_cat) title = self._fix_title(convert_to_unicode(old_cat.name), old_cat.id) cat = Category(id=int(old_cat.id), position=position, title=title, description=convert_to_unicode(old_cat.description), visibility=visibility, timezone=convert_to_unicode(old_cat._timezone), event_creation_notification_emails=emails, default_event_themes=default_themes, suggestions_disabled=getattr(old_cat, '_suggestions_disabled', False)) if not self.quiet: self.print_success(cat.title, event_id=cat.id) if old_cat._icon: self._process_icon(cat, old_cat._icon) self._process_protection(cat, old_cat) cat.children = [(self._migrate_category(old_subcat, i)) for i, old_subcat in enumerate(sorted(old_cat.subcategories.itervalues(), key=attrgetter('_order')), 1)] return cat
def create_category(parent, data): category = Category(parent=parent) data.setdefault('default_event_themes', parent.default_event_themes) data.setdefault('timezone', parent.timezone) category.populate_from_dict(data) db.session.add(category) db.session.flush() signals.category.created.send(category) logger.info('Category %s created by %s', category, session.user) return category
def create_category(parent, data): category = Category(parent=parent) data.setdefault("default_event_themes", parent.default_event_themes) data.setdefault("timezone", parent.timezone) category.populate_from_dict(data) db.session.add(category) db.session.flush() signals.category.created.send(category) logger.info("Category %s created by %s", category, session.user) return category
def _process(self): q = request.args["q"].lower() query = Category.query.filter(Category.title_matches(q)).options( undefer("deep_children_count"), undefer("deep_events_count"), undefer("has_events"), joinedload("acl_entries"), ) if session.user: # Prefer favorite categories query = query.order_by( Category.favorite_of.any(favorite_category_table.c.user_id == session.user.id).desc() ) # Prefer exact matches and matches at the beginning, then order by category title and if # those are identical by the chain titles query = query.order_by( (db.func.lower(Category.title) == q).desc(), db.func.lower(Category.title).startswith(q).desc(), db.func.lower(Category.title), Category.chain_titles, ) total_count = query.count() query = query.limit(10) return jsonify_data( categories=[serialize_category(c, with_favorite=True, with_path=True) for c in query], total_count=total_count, flash=False, )
def _process(self): q = request.args['q'].lower() query = (Category.query.filter(Category.title_matches(q)).options( undefer('deep_children_count'), undefer('deep_events_count'), undefer('has_events'), undefer('has_children'), joinedload('acl_entries'))) if session.user: # Prefer favorite categories query = query.order_by( Category.favorite_of.any(favorite_category_table.c.user_id == session.user.id).desc()) # Prefer exact matches and matches at the beginning, then order by category title and if # those are identical by the chain titles query = (query.order_by( (db.func.lower(Category.title) == q).desc(), db.func.lower(Category.title).startswith(q).desc(), db.func.lower(Category.title), Category.chain_titles)) total_count = query.count() query = query.limit(10) return jsonify_data(categories=[ serialize_category(c, with_favorite=True, with_path=True) for c in query ], total_count=total_count, flash=False)
def get_all_templates(obj): """Get all templates usable by an event/category.""" category = (obj.category or Category.get_root()) if isinstance( obj, Event) else obj return set( DesignerTemplate.query.filter( DesignerTemplate.category_id.in_(categ['id'] for categ in category.chain)))
def _checkParams(self, params): RHManageEventBase._checkParams(self, params) self.target_category = Category.get_one(int( request.form['target_category_id']), is_deleted=False) if not self.target_category.can_create_events(session.user): raise Forbidden( _("You may only move events to categories where you are allowed to create events." ))
def _process_args(self): RHManageCategorySelectedEventsBase._process_args(self) self.target_category = Category.get_or_404(int( request.form['target_category_id']), is_deleted=False) if not self.target_category.can_create_events(session.user): raise Forbidden( _("You may only move events to categories where you are allowed to create events." ))
def get_default_ticket_on_category(category, only_inherited=False): if category is None: category = Category.get_root() if not only_inherited and category.default_ticket_template: return category.default_ticket_template parent_chain = category.parent_chain_query.options( joinedload('default_ticket_template')).all() return next((category.default_ticket_template for category in reversed(parent_chain) if category.default_ticket_template), None)
def _check_access(self): RHRegistrationsActionBase._check_access(self) # Check that template belongs to this event or a category that is a parent if self.template.owner == self.event: return valid_category_ids = self.event.category_chain or [ Category.get_root().id ] if self.template.owner.id not in valid_category_ids: raise Forbidden
def _process_args(self): RHManageCategoryBase._process_args(self) target_category_id = request.form.get('target_category_id') if target_category_id is None: self.target_category = None else: self.target_category = Category.get_one(int(target_category_id), is_deleted=False) if not self.target_category.can_manage(session.user): raise Forbidden(_("You are not allowed to manage the selected destination.")) if self.target_category.events: raise BadRequest(_("The destination already contains an event."))
def validate_entries(self, field): if field.errors: return for entry in field.data: if entry['days'] < 0: raise ValidationError(_("'Days' must be a positive integer")) if entry['type'] not in {'category', 'category_tree', 'event'}: raise ValidationError(_('Invalid type')) if entry['type'] in {'category', 'category_tree'} and not Category.get(entry['id'], is_deleted=False): raise ValidationError(_('Invalid category: {}').format(entry['id'])) if entry['type'] == 'event' and not Event.get(entry['id'], is_deleted=False): raise ValidationError(_('Invalid event: {}').format(entry['id']))
def validate_entries(self, field): if field.errors: return for entry in field.data: if entry['days'] < 0: raise ValidationError(_("'Days' must be a positive integer")) if entry['type'] not in {'category', 'event'}: raise ValidationError(_('Invalid type')) if entry['type'] == 'category' and not Category.get(entry['id'], is_deleted=False): raise ValidationError(_('Invalid category: {}').format(entry['id'])) if entry['type'] == 'event' and not Event.get(entry['id'], is_deleted=False): raise ValidationError(_('Invalid event: {}').format(entry['id']))
def _process_args(self): RHManageCategoryBase._process_args(self) target_category_id = request.form.get('target_category_id') if target_category_id is None: self.target_category = None else: self.target_category = Category.get_or_404(int(target_category_id), is_deleted=False) if not self.target_category.can_manage(session.user): raise Forbidden( _("You are not allowed to manage the selected destination." ))
def _migrate_category(self, old_cat, position): # unlimited visibility is 999 but we have a 994 for some reason.. since nobody # has 900 levels of nesting we can just go for that threshold instead visibility = None if old_cat._visibility > 900 else old_cat._visibility if visibility == 0: self.print_warning( "Raising visibility from 'invisible' to 'category-only'", event_id=old_cat.id) visibility = 1 emails = re.split( r'[\s;,]+', convert_to_unicode(getattr(old_cat, '_notifyCreationList', ''))) emails = {sanitize_email(email).lower() for email in emails} emails = sorted(email for email in emails if is_valid_mail(email, False)) default_themes = self._process_default_themes(old_cat) title = self._fix_title(convert_to_unicode(old_cat.name), old_cat.id) cat = Category(id=int(old_cat.id), position=position, title=title, description=convert_to_unicode(old_cat.description), visibility=visibility, timezone=convert_to_unicode(old_cat._timezone), event_creation_notification_emails=emails, default_event_themes=default_themes, suggestions_disabled=getattr(old_cat, '_suggestions_disabled', False)) if not self.quiet: self.print_success(cat.title, event_id=cat.id) if old_cat._icon: self._process_icon(cat, old_cat._icon) self._process_protection(cat, old_cat) cat.children = [(self._migrate_category(old_subcat, i)) for i, old_subcat in enumerate( sorted(old_cat.subcategories.itervalues(), key=attrgetter('_order')), 1)] return cat
def _checkParams(self): data = request.json self.object = None if 'categId' in data: self.object = Category.get_one(data['categId']) elif 'contribId' in data: self.object = Contribution.get_one(data['contribId']) elif 'sessionId' in data: self.object = Session.get_one(data['sessionId']) elif 'confId' in data: self.object = Event.get_one(data['confId']) if self.object is None: raise BadRequest
def _process_args(self): data = request.json self.object = None if 'categId' in data: self.object = Category.get_one(data['categId']) elif 'contribId' in data: self.object = Contribution.get_one(data['contribId']) elif 'sessionId' in data: self.object = Session.get_one(data['sessionId']) elif 'confId' in data: self.object = Event.get_one(data['confId']) if self.object is None: raise BadRequest
def _process_args(self): data = request.json self.object = None if 'categId' in data: self.object = Category.get_or_404(data['categId']) elif 'contribId' in data: self.object = Contribution.get_or_404(data['contribId']) elif 'sessionId' in data: self.object = Session.get_or_404(data['sessionId']) elif 'eventId' in data: self.object = Event.get_or_404(data['eventId']) if self.object is None: raise BadRequest
def obj_deref(ref): """Returns the object identified by `ref`""" from indico_livesync.models.queue import EntryType if ref['type'] == EntryType.category: return Category.get_one(ref['category_id']) elif ref['type'] == EntryType.event: return Event.get_one(ref['event_id']) elif ref['type'] == EntryType.session: return Session.get_one(ref['session_id']) elif ref['type'] == EntryType.contribution: return Contribution.get_one(ref['contrib_id']) elif ref['type'] == EntryType.subcontribution: return SubContribution.get_one(ref['subcontrib_id']) else: raise ValueError('Unexpected object type: {}'.format(ref['type']))
def _process_cascaded_category_contents(records): """ Travel from categories to subcontributions, flattening the whole event structure. Yields everything that it finds (except for elements whose protection has changed but are not inheriting their protection settings from anywhere). :param records: queue records to process """ category_prot_records = { rec.category_id for rec in records if rec.type == EntryType.category and rec.change == ChangeType.protection_changed } category_move_records = { rec.category_id for rec in records if rec.type == EntryType.category and rec.change == ChangeType.moved } changed_events = set() category_prot_records -= category_move_records # A move already implies sending the whole record # Protection changes are handled differently, as there may not be the need to re-generate the record if category_prot_records: for categ in Category.find(Category.id.in_(category_prot_records)): cte = categ.get_protection_parent_cte() # Update only children that inherit inheriting_categ_children = (Event.query.join( cte, db.and_((Event.category_id == cte.c.id), (cte.c.protection_parent == categ.id)))) inheriting_direct_children = Event.find( (Event.category_id == categ.id) & Event.is_inheriting) changed_events.update( itertools.chain(inheriting_direct_children, inheriting_categ_children)) # Add move operations and explicitly-passed event records if category_move_records: changed_events.update( Event.find(Event.category_chain_overlaps(category_move_records))) for elem in _process_cascaded_event_contents( records, additional_events=changed_events): yield elem
def _process_cascaded_category_contents(records): """ Travel from categories to subcontributions, flattening the whole event structure. Yields everything that it finds (except for elements whose protection has changed but are not inheriting their protection settings from anywhere). :param records: queue records to process """ category_prot_records = {rec.category_id for rec in records if rec.type == EntryType.category and rec.change == ChangeType.protection_changed} category_move_records = {rec.category_id for rec in records if rec.type == EntryType.category and rec.change == ChangeType.moved} changed_events = set() category_prot_records -= category_move_records # A move already implies sending the whole record # Protection changes are handled differently, as there may not be the need to re-generate the record if category_prot_records: for categ in Category.find(Category.id.in_(category_prot_records)): cte = categ.get_protection_parent_cte() # Update only children that inherit inheriting_categ_children = (Event.query .join(cte, db.and_((Event.category_id == cte.c.id), (cte.c.protection_parent == categ.id)))) inheriting_direct_children = Event.find((Event.category_id == categ.id) & Event.is_inheriting) changed_events.update(itertools.chain(inheriting_direct_children, inheriting_categ_children)) # Add move operations and explicitly-passed event records if category_move_records: changed_events.update(Event.find(Event.category_chain_overlaps(category_move_records))) for elem in _process_cascaded_event_contents(records, additional_events=changed_events): yield elem
def create_category(parent, data): category = Category(parent=parent) data.setdefault('default_event_themes', parent.default_event_themes) data.setdefault('timezone', parent.timezone) category.populate_from_dict(data) db.session.add(category) db.session.flush() signals.category.created.send(category) logger.info('Category %s created by %s', category, session.user) sep = ' \N{RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK} ' category.log(CategoryLogRealm.category, LogKind.positive, 'Category', 'Category created', session.user, data={'Location': sep.join(category.chain_titles[:-1])}) parent.log(CategoryLogRealm.category, LogKind.positive, 'Content', f'Subcategory created: "{category.title}"', session.user) return category
def _get_category(self, category_id): category = self._category_query.filter_by(id=category_id, is_deleted=False).one_or_none() if category is None and category_id == 0: category = Category.get_root() return category
def _checkParams(self, params): RHConferenceModifBase._checkParams(self, params) self.target_category = Category.get_one(int(request.form['target_category_id']), is_deleted=False) if not self.target_category.can_create_events(session.user): raise Forbidden(_("You may only move events to categories where you are allowed to create events."))
def has_data(self): return Category.has_rows()
def principal_from_identifier(identifier, allow_groups=False, allow_external_users=False, allow_event_roles=False, allow_category_roles=False, allow_registration_forms=False, allow_emails=False, allow_networks=False, event_id=None, category_id=None, soft_fail=False): from indico.modules.categories.models.categories import Category from indico.modules.categories.models.roles import CategoryRole from indico.modules.events.models.events import Event from indico.modules.events.models.roles import EventRole from indico.modules.events.registration.models.forms import RegistrationForm from indico.modules.groups import GroupProxy from indico.modules.networks.models.networks import IPNetworkGroup from indico.modules.users import User if allow_category_roles and category_id is None and event_id is None: raise ValueError('Cannot use category roles without a category/event context') if allow_event_roles and event_id is None: raise ValueError('Cannot use event roles without an event context') if allow_registration_forms and event_id is None: raise ValueError('Cannot use registration forms without an event context') try: type_, data = identifier.split(':', 1) except ValueError: raise ValueError('Invalid data') if type_ == 'User': try: user_id = int(data) except ValueError: raise ValueError('Invalid data') user = User.get(user_id, is_deleted=(None if soft_fail else False)) if user is None: raise ValueError(f'Invalid user: {user_id}') return user elif type_ == 'ExternalUser': if not allow_external_users: raise ValueError('External users are not allowed') cache = make_scoped_cache('external-user') external_user_data = cache.get(data) if not external_user_data: raise ValueError('Invalid data') user = User.query.filter(User.all_emails == external_user_data['email'], ~User.is_deleted).first() if user: return user # create a pending user. this user isn't sent to the DB unless it gets added # to the sqlalchemy session somehow (e.g. by adding it to an ACL). # like this processing form data does not result in something being stored in # the database, which is good! return User(first_name=external_user_data['first_name'], last_name=external_user_data['last_name'], email=external_user_data['email'], affiliation=external_user_data['affiliation'], address=external_user_data['address'], phone=external_user_data['phone'], is_pending=True) elif type_ == 'Group': if not allow_groups: raise ValueError('Groups are not allowed') try: provider, name = data.split(':', 1) except ValueError: raise ValueError('Invalid data') if not provider: # local group try: group_id = int(name) except ValueError: raise ValueError('Invalid data') group = GroupProxy(group_id) else: # multipass group group = GroupProxy(name, provider) if not soft_fail and group.group is None: raise ValueError(f'Invalid group: {data}') return group elif type_ == 'EventRole': if not allow_event_roles: raise ValueError('Event roles are not allowed') try: event_role_id = int(data) except ValueError: raise ValueError('Invalid data') event_role = EventRole.get(event_role_id) if event_role is None or event_role.event_id != event_id: raise ValueError(f'Invalid event role: {event_role_id}') return event_role elif type_ == 'CategoryRole': if not allow_category_roles: raise ValueError('Category roles are not allowed') category = None if category_id is not None: category = Category.get(category_id) if category is None: raise ValueError(f'Invalid category id: {category_id}') elif event_id is not None: event = Event.get(event_id) if event is None: raise ValueError(f'Invalid event id: {event_id}') category = event.category try: category_role_id = int(data) except ValueError: raise ValueError('Invalid data') if soft_fail: category_role = CategoryRole.get(category_role_id) else: category_role = CategoryRole.get_category_role_by_id(category, category_role_id) if category_role is None: raise ValueError(f'Invalid category role: {category_role_id}') return category_role elif type_ == 'RegistrationForm': if not allow_registration_forms: raise ValueError('Registration forms are not allowed') try: reg_form_id = int(data) except ValueError: raise ValueError('Invalid data') registration_form = RegistrationForm.get(reg_form_id, is_deleted=(None if soft_fail else False)) if registration_form is None or registration_form.event_id != event_id: raise ValueError(f'Invalid registration form: {reg_form_id}') return registration_form elif type_ == 'Email': if not allow_emails: raise ValueError('Emails are not allowed') return EmailPrincipal(data) elif type_ == 'IPNetworkGroup': if not allow_networks: raise ValueError('Network groups are not allowed') try: netgroup_id = int(data) except ValueError: raise ValueError('Invalid data') netgroup = IPNetworkGroup.get(netgroup_id) if netgroup is None or (netgroup.hidden and not soft_fail): raise ValueError(f'Invalid network group: {netgroup_id}') return netgroup else: raise ValueError('Invalid data')
def _process_args(self): try: id_ = int(request.args['id']) except ValueError: raise BadRequest('Invalid Category ID') self.category = Category.get_or_404(id_, is_deleted=False)
def _get_category(self, category_id): category = self._category_query.filter_by( id=category_id, is_deleted=False).one_or_none() if category is None and category_id == 0: category = Category.get_root() return category
def _process_args(self): RHManageCategorySelectedEventsBase._process_args(self) self.target_category = Category.get_one(int(request.form['target_category_id']), is_deleted=False) if not self.target_category.can_create_events(session.user): raise Forbidden(_("You may only move events to categories where you are allowed to create events."))
if not allow_event_roles: raise ValueError('Event roles are not allowed') try: event_role_id = int(data) except ValueError: raise ValueError('Invalid data') event_role = EventRole.get(event_role_id) if event_role is None or event_role.event_id != event_id: raise ValueError(f'Invalid event role: {event_role_id}') return event_role elif type_ == 'CategoryRole': if not allow_category_roles: raise ValueError('Category roles are not allowed') category = None if category_id is not None: category = Category.get(category_id) if category is None: raise ValueError(f'Invalid category id: {category_id}') elif event_id is not None: event = Event.get(event_id) if event is None: raise ValueError(f'Invalid event id: {event_id}') category = event.category try: category_role_id = int(data) except ValueError: raise ValueError('Invalid data') if soft_fail: category_role = CategoryRole.get(category_role_id) else: category_role = CategoryRole.get_category_role_by_id(
def _checkParams(self): try: id_ = int(request.args['id']) except ValueError: raise BadRequest('Invalid Category ID') self.category = Category.get_one(id_, is_deleted=False)