Beispiel #1
0
def create_all_tables(db, verbose=False, add_initial_data=True):
    """Create all tables and required initial objects"""
    from indico.modules.categories import Category
    from indico.modules.designer import TemplateType
    from indico.modules.designer.models.templates import DesignerTemplate
    from indico.modules.oauth.models.applications import OAuthApplication, SystemAppType
    from indico.modules.users import User
    if verbose:
        print(cformat('%{green}Creating tables'))
    db.create_all()
    if add_initial_data:
        if verbose:
            print(cformat('%{green}Creating system user'))
        db.session.add(User(id=0, is_system=True, first_name='Indico', last_name='System'))
        if verbose:
            print(cformat('%{green}Creating root category'))
        cat = Category(id=0, title='Home', protection_mode=ProtectionMode.public)
        db.session.add(cat)
        db.session.flush()
        if verbose:
            print(cformat('%{green}Creating default ticket template for root category '))
        dt = DesignerTemplate(category_id=0, title='Default ticket', type=TemplateType.badge,
                              data=DEFAULT_TEMPLATE_DATA, is_system_template=True)
        cat.default_ticket_template = dt
        db.session.add(dt)
        if verbose:
            print(cformat('%{green}Creating system oauth apps'))
        for sat in SystemAppType:
            if sat != SystemAppType.none:
                db.session.add(OAuthApplication(system_app_type=sat, **sat.default_data))
        db.session.commit()
Beispiel #2
0
 def _process_args(self):
     if 'confId' in request.view_args:
         self.obj = Event.get_one(request.view_args['confId'], is_deleted=False)
         self.obj_type = 'event'
     elif 'category_id' in request.view_args:
         self.obj = Category.get_one(request.view_args['category_id'], is_deleted=False)
         self.obj_type = 'category' if not self.obj.is_root else None
     else:
         self.obj = Category.get_root()
         self.obj_type = None
Beispiel #3
0
 def _get_event_own_visibility_horizon(self, event):
     if self.visibility.data is None:  # unlimited
         return Category.get_root()
     elif self.visibility.data == 0:  # invisible
         return None
     else:
         return event.category.nth_parent(self.visibility.data - 1)
Beispiel #4
0
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()
Beispiel #5
0
 def _default_category(self):
     try:
         category_id = int(request.args['category_id'])
     except (ValueError, KeyError):
         return self.root_category if self.single_category else None
     else:
         return Category.get(category_id, is_deleted=False)
Beispiel #6
0
def _mappers_configured():
    event_alias = db.aliased(Event)

    # Event.category_chain -- the category ids of the event, starting
    # with the root category down to the event's immediate parent.
    cte = Category.get_tree_cte()
    query = select([cte.c.path]).where(cte.c.id == Event.category_id).correlate_except(cte)
    Event.category_chain = column_property(query, deferred=True)

    # Event.effective_protection_mode -- the effective protection mode
    # (public/protected) of the event, even if it's inheriting it from its
    # parent category
    query = (select([db.case({ProtectionMode.inheriting.value: Category.effective_protection_mode},
                             else_=Event.protection_mode, value=Event.protection_mode)])
             .where(Category.id == Event.category_id))
    Event.effective_protection_mode = column_property(query, deferred=True)

    # Event.series_pos -- the position of the event in its series
    subquery = (select([event_alias.id,
                        db.func.row_number().over(order_by=(event_alias.start_dt, event_alias.id)).label('pos')])
                .where((event_alias.series_id == Event.series_id) & ~event_alias.is_deleted)
                .correlate(Event)
                .alias())
    query = select([subquery.c.pos]).where(subquery.c.id == Event.id).correlate_except(subquery)
    Event.series_pos = column_property(query, group='series', deferred=True)

    # Event.series_count -- the number of events in the event's series
    query = (db.select([db.func.count(event_alias.id)])
             .where((event_alias.series_id == Event.series_id) & ~event_alias.is_deleted)
             .correlate_except(event_alias))
    Event.series_count = column_property(query, group='series', deferred=True)
Beispiel #7
0
 def is_visible_in(cls, category_id):
     """
     Create a filter that checks whether the event is visible in
     the specified category.
     """
     cte = Category.get_visible_categories_cte(category_id)
     return (db.exists(db.select([1]))
             .where(db.and_(cte.c.id == Event.category_id,
                            db.or_(Event.visibility.is_(None), Event.visibility > cte.c.level))))
Beispiel #8
0
 def process_formdata(self, valuelist):
     from indico.modules.categories import Category
     if valuelist:
         try:
             category_id = int(json.loads(valuelist[0])['id'])
         except KeyError:
             self.data = None
         else:
             self.data = Category.get(category_id, is_deleted=False)
Beispiel #9
0
def category_family(create_category, db):
    grandpa = Category.get_root()
    dad = create_category(1, title='Dad', parent=grandpa)
    son = create_category(2, title='Son', parent=dad)
    sibling = create_category(3, title='Sibling', parent=dad)

    db.session.add(son)
    db.session.flush()

    return grandpa, dad, son, sibling
Beispiel #10
0
 def _process(self):
     query = (Category.query
              .filter(Category.title_matches(request.args['term']),
                      ~Category.is_deleted)
              .options(undefer('chain_titles'))
              .order_by(Category.title))
     results = [{
         'title': category.title,
         'path': category.chain_titles[1:-1],
         'url': unicode(category.url)
     } for category in query.limit(7)]
     return jsonify(success=True, results=results, count=query.count())
Beispiel #11
0
 def _process(self):
     db.session.delete(self.template)
     root = Category.get_root()
     if not root.default_ticket_template:
         # if we deleted the root category's default template, pick
         # a system template as the new default (this always exists)
         system_template = DesignerTemplate.find_first(DesignerTemplate.is_system_template,
                                                       DesignerTemplate.type == TemplateType.badge)
         root.default_ticket_template = system_template
     db.session.flush()
     flash(_('The template has been deleted'), 'success')
     return jsonify_data(html=_render_template_list(self.target, event=self.event_or_none))
Beispiel #12
0
    def category_chain_overlaps(cls, category_ids):
        """
        Create a filter that checks whether the event has any of the
        provided category ids in its parent chain.

        :param category_ids: A list of category ids or a single
                             category id
        """
        from indico.modules.categories import Category
        if not isinstance(category_ids, (list, tuple, set)):
            category_ids = [category_ids]
        cte = Category.get_tree_cte()
        return (cte.c.id == Event.category_id) & cte.c.path.overlap(category_ids)
Beispiel #13
0
def test_excluded_categories(mocker, monkeypatch, db, create_category):
    """Test if category exclusions work."""
    plugin = mocker.patch('indico_livesync.plugin.LiveSyncPlugin')
    plugin.settings.get.return_value = [{'id': 2}, {'id': 3}]

    categories = {}
    with db.session.no_autoflush:
        for cat_id in xrange(6):
            category = (create_category(cat_id, title=str(cat_id), protection_mode=0,
                                        parent=categories[CATEGORY_PARENTS[cat_id]])
                        if cat_id else Category.get_root())
            categories[cat_id] = category
            db.session.add(category)
            db.session.flush()

    db.session.flush()

    for cat in categories.viewvalues():
        db = mocker.patch('indico_livesync.models.queue.db')
        LiveSyncQueueEntry.create({ChangeType.created}, obj_ref(cat), excluded_categories=get_excluded_categories())
        assert db.session.add.called == (cat.id not in {2, 3, 4, 5})
Beispiel #14
0
def test_effective_protection_mode(db):
    def _cat(id_, protection_mode=ProtectionMode.inheriting, children=None):
        return Category(id=id_, title='cat-{}'.format(id_), protection_mode=protection_mode, children=children or [])
    root = Category.get_root()
    root.protection_mode = ProtectionMode.protected
    root.children = [
        _cat(1),
        _cat(2, ProtectionMode.public, children=[
            _cat(3, children=[
                _cat(4, ProtectionMode.inheriting),
                _cat(5, ProtectionMode.public),
                _cat(6, ProtectionMode.protected),
            ]),
            _cat(7, ProtectionMode.protected, children=[
                _cat(8, ProtectionMode.inheriting),
                _cat(9, ProtectionMode.public),
                _cat(10, ProtectionMode.protected),
            ]),
            _cat(11)
        ])
    ]
    db.session.add(root)
    db.session.flush()
    data = {c.id: c.effective_protection_mode for c in Category.query.options(undefer('effective_protection_mode'))}
    assert data == {
        0: ProtectionMode.protected,
        1: ProtectionMode.protected,
        2: ProtectionMode.public,
        3: ProtectionMode.public,
        4: ProtectionMode.public,
        5: ProtectionMode.public,
        6: ProtectionMode.protected,
        7: ProtectionMode.protected,
        8: ProtectionMode.protected,
        9: ProtectionMode.public,
        10: ProtectionMode.protected,
        11: ProtectionMode.public
    }
Beispiel #15
0
 def _checkParams(self):
     RHUserBase._checkParams(self)
     self.category = Category.get_one(request.view_args['category_id'])
Beispiel #16
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())
Beispiel #17
0
 def _create_category(id_=None, **kwargs):
     kwargs.setdefault('title', u'cat#{}'.format(id_) if id_ is not None else u'dummy')
     kwargs.setdefault('timezone', 'UTC')
     if 'parent' not in kwargs:
         kwargs['parent'] = Category.get_root()
     return Category(id=id_, acl_entries=set(), **kwargs)
Beispiel #18
0
 def _process_args(self):
     self.event_type = EventType[request.view_args['event_type']]
     self.root_category = Category.get_root()
     self.single_category = not self.root_category.children
Beispiel #19
0
 def _process_args(self):
     RHUserBase._process_args(self)
     self.category = Category.get_one(request.view_args['category_id'])
     self.suggestion = self.user.suggested_categories.filter_by(category=self.category).first()
Beispiel #20
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())