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 _get_upcoming_event(self): query = (Event.query .filter(Event.is_visible_in(self.category.id), Event.start_dt > now_utc(), ~Event.is_deleted) .options(subqueryload('acl_entries')) .order_by(Event.start_dt, Event.id)) res = get_n_matching(query, 1, lambda event: event.can_access(session.user)) if res: return res[0]
def _get_upcoming_event(self): query = (Event.query .filter(Event.is_visible_in(self.category), Event.start_dt > now_utc(), ~Event.is_deleted) .options(subqueryload('acl_entries')) .order_by(Event.start_dt, Event.id)) res = get_n_matching(query, 1, lambda event: event.can_access(session.user)) if res: return res[0]
def get_events_in_categories(category_ids, user, limit=10): """Get all the user-accessible events in a given set of categories.""" tz = session.tzinfo 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)) return get_n_matching(query, limit, lambda x: x.can_access(user))
def _paginate(self, query, page, column, user, admin_override_enabled): reverse = False pagenav = {'prev': None, 'next': None} if not page: query = query.order_by(column.desc()) elif page > 0: # next page query = query.filter(column < page).order_by(column.desc()) # since we asked for a next page we know that a previous page exists pagenav['prev'] = -(page - 1) elif page < 0: # prev page query = query.filter(column > -page).order_by(column) # since we asked for a previous page we know that a next page exists pagenav['next'] = -(page - 1) reverse = True def _can_access(obj): return (obj.effective_protection_mode == ProtectionMode.public or obj.can_access(user, allow_admin=admin_override_enabled)) res = get_n_matching(query, self.RESULTS_PER_PAGE + 1, _can_access, prefetch_factor=20) if len(res) > self.RESULTS_PER_PAGE: # we queried 1 more so we can see if there are more results available del res[self.RESULTS_PER_PAGE:] if reverse: pagenav['prev'] = -res[-1].id else: pagenav['next'] = res[-1].id if reverse: res.reverse() return res, pagenav
def _paginate(self, query, page, column, user, admin_override_enabled): reverse = False pagenav = {'prev': None, 'next': None} if not page: query = query.order_by(column.desc()) elif page > 0: # next page query = query.filter(column < page).order_by(column.desc()) # since we asked for a next page we know that a previous page exists pagenav['prev'] = -(page - 1) elif page < 0: # prev page query = query.filter(column > -page).order_by(column) # since we asked for a previous page we know that a next page exists pagenav['next'] = -(page - 1) reverse = True preloaded_categories = set() def _preload_categories(objs): nonlocal preloaded_categories obj_types = {type(o) for o in objs} assert len(obj_types) == 1 obj_type = obj_types.pop() if obj_type == Event: chain_query = db.session.query(Event.category_chain).filter( Event.id.in_(o.id for o in objs)) elif obj_type == Category: chain_query = db.session.query(Category.chain_ids).filter( Category.id.in_(o.id for o in objs)) elif obj_type == Contribution: chain_query = (db.session.query(Event.category_chain).join( Contribution.event).filter( Contribution.id.in_(o.id for o in objs))) elif obj_type == Attachment: chain_query = (db.session.query(Event.category_chain).join( Attachment.folder).join(AttachmentFolder.event).filter( Attachment.id.in_(o.id for o in objs))) elif obj_type == EventNote: chain_query = (db.session.query(Event.category_chain).join( EventNote.event).filter( EventNote.id.in_(o.id for o in objs))) else: raise Exception(f'Unhandled object type: {obj_type}') category_ids = set( itertools.chain.from_iterable(id for id, in chain_query)) query = (Category.query.filter( Category.id.in_(category_ids)).options( load_only('id', 'parent_id', 'protection_mode'))) Category.preload_relationships( query, 'acl_entries', strategy=lambda rel: _apply_acl_entry_strategy( subqueryload(rel), CategoryPrincipal)) preloaded_categories |= set(query) def _can_access(obj, allow_effective_protection_mode=True): if isinstance(obj, (Category, Event, Session, Contribution)): # more efficient for events/categories/contribs since it avoids climbing up the chain protection_mode = (obj.effective_protection_mode if allow_effective_protection_mode else obj.protection_mode) elif isinstance(obj, Attachment): # attachments don't have it so we can only skip access checks if they # are public themselves protection_mode = obj.protection_mode elif isinstance(obj, EventNote): # notes inherit from their parent return _can_access(obj.object, allow_effective_protection_mode=False) elif isinstance(obj, SubContribution): # subcontributions inherit from their contribution return _can_access(obj.contribution, allow_effective_protection_mode=False) else: raise Exception(f'Unexpected object: {obj}') return (protection_mode == ProtectionMode.public or obj.can_access( user, allow_admin=admin_override_enabled)) res = get_n_matching(query, self.RESULTS_PER_PAGE + 1, _can_access, prefetch_factor=20, preload_bulk=_preload_categories) if len(res) > self.RESULTS_PER_PAGE: # we queried 1 more so we can see if there are more results available del res[self.RESULTS_PER_PAGE:] if reverse: pagenav['prev'] = -res[-1].id else: pagenav['next'] = res[-1].id if reverse: res.reverse() return res, pagenav