def _get_default_settings(request: Request, order: Any) -> DefaultSettings: if isinstance(request.context, Group): is_home_page = False user_settings = (request.query(UserGroupSettings).filter( UserGroupSettings.user == request.user, UserGroupSettings.group == request.context, ).one_or_none()) else: is_home_page = True user_settings = None if user_settings and user_settings.default_order: default_order = user_settings.default_order elif request.user.home_default_order: default_order = request.user.home_default_order else: default_order = TopicSortOption.ACTIVITY # the default period depends on what the order is, so we need to see if # we're going to end up using the default order here as well if order is missing: order = default_order if user_settings and user_settings.default_period: user_default = user_settings.default_period default_period = ShortTimePeriod().deserialize(user_default) elif request.user.home_default_period: user_default = request.user.home_default_period default_period = ShortTimePeriod().deserialize(user_default) else: # Overall default periods, if the user doesn't have either a # group-specific or a home default set up: # * "all time" if sorting by new # * "all time" if sorting by activity and inside a group # * "3 days" if sorting by activity and on home page # * "1 day" otherwise (sorting by most votes or most comments) if order == TopicSortOption.NEW: default_period = None elif order == TopicSortOption.ACTIVITY and not is_home_page: default_period = None elif order == TopicSortOption.ACTIVITY: default_period = SimpleHoursPeriod(72) else: default_period = SimpleHoursPeriod(24) return DefaultSettings(order=default_order, period=default_period)
def _deserialize(self, value: str, attr: str, data: dict) -> Optional[SimpleHoursPeriod]: """Deserialize to a SimpleHoursPeriod object.""" if value == "all": return None try: return SimpleHoursPeriod.from_short_form(value) except ValueError: raise ValidationError("Invalid time period")
def get_search(request: Request, order: Optional[TopicSortOption], after: Optional[str], before: Optional[str], per_page: int, search: str, **kwargs: Any) -> dict: """Get a list of search results.""" # period needs special treatment so we can distinguish between missing and None period = kwargs.get("period", missing) group = None if isinstance(request.context, Group): group = request.context if not order: order = TopicSortOption.NEW if period is missing: period = None query = (request.query(Topic).join_all_relationships().search( search).apply_sort_option(order)) # if searching from inside a group, restrict to that group alone if group: query = query.inside_groups([group]) # restrict the time period, if not set to "all time" if period: query = query.inside_time_period(period) # apply before/after pagination restrictions if relevant if before: query = query.before_id36(before) if after: query = query.after_id36(after) topics = query.get_page(per_page) period_options = [SimpleHoursPeriod(hours) for hours in (1, 12, 24, 72)] # add the current period to the bottom of the dropdown if it's not one of the # "standard" ones if period and period not in period_options: period_options.append(period) return { "search": search, "topics": topics, "group": group, "order": order, "order_options": TopicSortOption, "period": period, "period_options": period_options, }
def _deserialize( self, value: str, attr: Optional[str], data: DataType, **kwargs: Any, ) -> Optional[SimpleHoursPeriod]: """Deserialize to a SimpleHoursPeriod object.""" if value == "all": return None try: return SimpleHoursPeriod.from_short_form(value) except ValueError as exc: raise ValidationError("Invalid time period") from exc
def get_search( request: Request, order: Any, period: Any, after: str, before: str, per_page: int, search: str, ) -> dict: """Get a list of search results.""" # pylint: disable=too-many-arguments if order is missing: order = TopicSortOption.NEW if period is missing: period = None query = (request.query(Topic).join_all_relationships().search( search).apply_sort_option(order)) # restrict the time period, if not set to "all time" if period: query = query.inside_time_period(period) # apply before/after pagination restrictions if relevant if before: query = query.before_id36(before) if after: query = query.after_id36(after) topics = query.get_page(per_page) period_options = [SimpleHoursPeriod(hours) for hours in (1, 12, 24, 72)] # add the current period to the bottom of the dropdown if it's not one of the # "standard" ones if period and period not in period_options: period_options.append(period) return { "search": search, "topics": topics, "order": order, "order_options": TopicSortOption, "period": period, "period_options": period_options, }
def _get_default_settings( request: Request, order: Optional[TopicSortOption] ) -> DefaultSettings: if isinstance(request.context, Group) and request.user: user_settings = ( request.query(UserGroupSettings) .filter( UserGroupSettings.user == request.user, UserGroupSettings.group == request.context, ) .one_or_none() ) else: user_settings = None if user_settings and user_settings.default_order: default_order = user_settings.default_order elif request.user and request.user.home_default_order: default_order = request.user.home_default_order else: default_order = TopicSortOption.ACTIVITY # the default period depends on what the order is, so we need to see if we're going # to end up using the default order here as well if not order: order = default_order if user_settings and user_settings.default_period: user_default = user_settings.default_period default_period = ShortTimePeriod().deserialize(user_default) elif request.user and request.user.home_default_period: user_default = request.user.home_default_period default_period = ShortTimePeriod().deserialize(user_default) else: # Overall default periods, if the user doesn't have either a group-specific or a # home default set up: # * "1 day" if sorting by most votes or most comments # * "all time" otherwise if order in (TopicSortOption.VOTES, TopicSortOption.COMMENTS): default_period = SimpleHoursPeriod(24) else: default_period = None return DefaultSettings(order=default_order, period=default_period)
def get_group_topics( # noqa request: Request, after: Optional[str], before: Optional[str], order: Optional[TopicSortOption], per_page: int, rank_start: Optional[int], tag: Optional[Ltree], unfiltered: bool, **kwargs: Any) -> dict: """Get a listing of topics in the group.""" # period needs special treatment so we can distinguish between missing and None period = kwargs.get("period", missing) is_home_page = request.matched_route.name == "home" if is_home_page: # on the home page, include topics from the user's subscribed groups # (or all groups, if logged-out) if request.user: groups = [sub.group for sub in request.user.subscriptions] else: groups = [ group for group in request.query(Group).all() if group.path != "test" ] subgroups = None else: # otherwise, just topics from the single group that we're looking at groups = [request.context] subgroups = (request.query(Group).filter( Group.path.descendant_of(request.context.path), Group.path != request.context.path, ).all()) default_settings = _get_default_settings(request, order) if not order: order = default_settings.order if period is missing: period = default_settings.period # set up the basic query for topics query = (request.query(Topic).join_all_relationships().inside_groups( groups, include_subgroups=not is_home_page).exclude_ignored(). apply_sort_option(order)) # restrict the time period, if not set to "all time" if period: query = query.inside_time_period(period) # restrict to a specific tag, if we're viewing a single one if tag: query = query.has_tag(str(tag)) # apply before/after pagination restrictions if relevant if before: query = query.before_id36(before) if after: query = query.after_id36(after) # apply topic tag filters unless they're disabled or viewing a single tag if request.user and request.user.filtered_topic_tags and not (tag or unfiltered): query = query.filter(~Topic.tags.descendant_of( # type: ignore any_(cast(request.user.filtered_topic_tags, TagList)))) topics = query.get_page(per_page) # don't show pinned topics on home page if request.matched_route.name == "home": pinned_topics = [] else: # get pinned topics pinned_query = (request.query(Topic).join_all_relationships( ).inside_groups(groups).is_pinned(True).apply_sort_option(order)) pinned_topics = pinned_query.all() period_options = [ SimpleHoursPeriod(hours) for hours in (1, 12, 24, 72, 168) ] # add the current period to the bottom of the dropdown if it's not one of the # "standard" ones if period and period not in period_options: period_options.append(period) if isinstance(request.context, Group): wiki_pages = (request.query(GroupWikiPage).filter( GroupWikiPage.group == request.context).order_by( GroupWikiPage.path).all()) # remove the index from the page list, we'll output it separately if any(page.path == "index" for page in wiki_pages): wiki_has_index = True wiki_pages = [page for page in wiki_pages if page.path != "index"] else: wiki_has_index = False else: wiki_pages = None wiki_has_index = False if isinstance(request.context, Group): # Get the most recent topic from each scheduled topic in this group # I'm not even going to attempt to write this query in pure SQLAlchemy topic_id_subquery = """ SELECT topic_id FROM (SELECT topic_id, schedule_id, row_number() OVER (PARTITION BY schedule_id ORDER BY created_time DESC) AS rownum FROM topics) AS t WHERE schedule_id IS NOT NULL AND rownum = 1 """ most_recent_scheduled_topics = ( request.query(Topic).join(TopicSchedule).filter( Topic.topic_id.in_(text(topic_id_subquery)), # type: ignore TopicSchedule.group == request.context, TopicSchedule.next_post_time != None, # noqa ).order_by(TopicSchedule.next_post_time).all()) else: most_recent_scheduled_topics = None if is_home_page: financial_data = get_financial_data(request.db_session) else: financial_data = None return { "group": request.context, "groups": groups, "topics": topics, "pinned_topics": pinned_topics, "order": order, "order_options": TopicSortOption, "period": period, "period_options": period_options, "is_default_period": period == default_settings.period, "is_default_view": (period == default_settings.period and order == default_settings.order), "rank_start": rank_start, "tag": tag, "unfiltered": unfiltered, "wiki_pages": wiki_pages, "wiki_has_index": wiki_has_index, "subgroups": subgroups, "most_recent_scheduled_topics": most_recent_scheduled_topics, "financial_data": financial_data, "current_time": utc_now(), }
def get_group_topics( request: Request, order: Any, # more specific would be better, but missing isn't typed period: Any, # more specific would be better, but missing isn't typed after: str, before: str, per_page: int, rank_start: Optional[int], tag: Optional[Ltree], unfiltered: bool, ) -> dict: """Get a listing of topics in the group.""" # pylint: disable=too-many-arguments, too-many-branches, too-many-locals if request.matched_route.name == "home": # on the home page, include topics from the user's subscribed groups # (or all groups, if logged-out) if request.user: groups = [sub.group for sub in request.user.subscriptions] else: groups = [ group for group in request.query(Group).all() if group.path != "test" ] else: # otherwise, just topics from the single group that we're looking at groups = [request.context] default_settings = _get_default_settings(request, order) if order is missing: order = default_settings.order if period is missing: period = default_settings.period # set up the basic query for topics query = (request.query(Topic).join_all_relationships().inside_groups( groups).apply_sort_option(order)) # restrict the time period, if not set to "all time" if period: query = query.inside_time_period(period) # restrict to a specific tag, if we're viewing a single one if tag: query = query.has_tag(tag) # apply before/after pagination restrictions if relevant if before: query = query.before_id36(before) if after: query = query.after_id36(after) # apply topic tag filters unless they're disabled or viewing a single tag if request.user and not (tag or unfiltered): # pylint: disable=protected-access query = query.filter(~Topic._tags.descendant_of( # type: ignore any_(cast(request.user._filtered_topic_tags, ArrayOfLtree)))) topics = query.get_page(per_page) period_options = [ SimpleHoursPeriod(hours) for hours in (1, 12, 24, 72, 168) ] # add the current period to the bottom of the dropdown if it's not one of the # "standard" ones if period and period not in period_options: period_options.append(period) if isinstance(request.context, Group): wiki_pages = (request.query(GroupWikiPage).filter( GroupWikiPage.group == request.context).order_by( GroupWikiPage.slug).all()) # remove the index from the page list, we'll output it separately if any(page.slug == "index" for page in wiki_pages): wiki_has_index = True wiki_pages = [page for page in wiki_pages if page.slug != "index"] else: wiki_has_index = False else: wiki_pages = None wiki_has_index = False return { "group": request.context, "groups": groups, "topics": topics, "order": order, "order_options": TopicSortOption, "period": period, "period_options": period_options, "is_default_period": period == default_settings.period, "is_default_view": (period == default_settings.period and order == default_settings.order), "rank_start": rank_start, "tag": tag, "unfiltered": unfiltered, "wiki_pages": wiki_pages, "wiki_has_index": wiki_has_index, }
def get_group_topics( # noqa request: Request, after: Optional[str], before: Optional[str], order: Optional[TopicSortOption], per_page: int, rank_start: Optional[int], tag: Optional[Ltree], unfiltered: bool, **kwargs: Any) -> dict: """Get a listing of topics in the group.""" # period needs special treatment so we can distinguish between missing and None period = kwargs.get("period", missing) is_home_page = request.matched_route.name in [ "home", "home_atom", "home_rss" ] is_atom = request.matched_route.name in ["home_atom", "group_topics_atom"] is_rss = request.matched_route.name in ["home_rss", "group_topics_rss"] if is_home_page: # on the home page, include topics from the user's subscribed groups # (or all groups, if logged-out) if request.user: groups = [sub.group for sub in request.user.subscriptions] else: groups = [ group for group in request.query(Group).all() if group.path != "test" ] subgroups = None else: # otherwise, just topics from the single group that we're looking at groups = [request.context] subgroups = (request.query(Group).filter( Group.path.descendant_of(request.context.path), Group.path != request.context.path, ).all()) default_settings = _get_default_settings(request, order) if not order: order = default_settings.order if period is missing: period = default_settings.period # force Newest sort order, and All Time period, for RSS feeds if is_atom or is_rss: order = TopicSortOption.NEW period = None # set up the basic query for topics query = (request.query(Topic).join_all_relationships().inside_groups( groups, include_subgroups=not is_home_page).exclude_ignored(). apply_sort_option(order)) # restrict the time period, if not set to "all time" if period: query = query.inside_time_period(period) # restrict to a specific tag, if we're viewing a single one if tag: query = query.has_tag(str(tag)) # apply before/after pagination restrictions if relevant if before: query = query.before_id36(before) if after: query = query.after_id36(after) # apply topic tag filters unless they're disabled if request.user and request.user.filtered_topic_tags and not unfiltered: filtered_topic_tags = request.user.filtered_topic_tags # if viewing single tag, don't filter that tag and its ancestors # for example, if viewing "ask.survey", don't filter "ask.survey" or "ask" if tag: filtered_topic_tags = [ ft for ft in filtered_topic_tags if not tag.descendant_of(ft.replace(" ", "_")) ] query = query.filter(~Topic.tags.descendant_of( # type: ignore any_(cast(filtered_topic_tags, TagList)))) topics = query.get_page(per_page) period_options = [ SimpleHoursPeriod(hours) for hours in (1, 12, 24, 72, 168) ] # add the current period to the bottom of the dropdown if it's not one of the # "standard" ones if period and period not in period_options: period_options.append(period) if isinstance(request.context, Group): wiki_pages = (request.query(GroupWikiPage).filter( GroupWikiPage.group == request.context).order_by( GroupWikiPage.path).all()) # remove the index from the page list, we'll output it separately if any(page.path == "index" for page in wiki_pages): wiki_has_index = True wiki_pages = [page for page in wiki_pages if page.path != "index"] else: wiki_has_index = False else: wiki_pages = None wiki_has_index = False if isinstance(request.context, Group): # Get the most recent topic from each scheduled topic in this group group_schedules = ( request.query(TopicSchedule).options( joinedload(TopicSchedule.latest_topic)).filter( TopicSchedule.group == request.context, TopicSchedule.next_post_time != None, # noqa ).order_by(TopicSchedule.next_post_time).all()) most_recent_scheduled_topics = [ schedule.latest_topic for schedule in group_schedules ] else: most_recent_scheduled_topics = [] if is_home_page: financial_data = get_financial_data(request.db_session) else: financial_data = None if is_atom: request.response.content_type = "application/atom+xml" if is_rss: request.response.content_type = "application/rss+xml" return { "group": request.context, "groups": groups, "topics": topics, "order": order, "order_options": TopicSortOption, "period": period, "period_options": period_options, "is_default_period": period == default_settings.period, "is_default_view": (period == default_settings.period and order == default_settings.order), "rank_start": rank_start, "tag": tag, "unfiltered": unfiltered, "wiki_pages": wiki_pages, "wiki_has_index": wiki_has_index, "subgroups": subgroups, "most_recent_scheduled_topics": most_recent_scheduled_topics, "financial_data": financial_data, "current_time": utc_now(), }
def get_group_topics( request: Request, order: Any, # more specific would be better, but missing isn't typed period: Any, # more specific would be better, but missing isn't typed after: str, before: str, per_page: int, rank_start: Optional[int], tag: Optional[Ltree], unfiltered: bool, ) -> dict: """Get a listing of topics in the group.""" # pylint: disable=too-many-arguments if request.matched_route.name == 'home': # on the home page, include topics from the user's subscribed groups groups = [sub.group for sub in request.user.subscriptions] else: # otherwise, just topics from the single group that we're looking at groups = [request.context] default_settings = _get_default_settings(request, order) if order is missing: order = default_settings.order if period is missing: period = default_settings.period # set up the basic query for topics query = (request.query(Topic).join_all_relationships().inside_groups( groups).apply_sort_option(order)) # restrict the time period, if not set to "all time" if period: query = query.inside_time_period(period) # restrict to a specific tag, if we're viewing a single one if tag: query = query.has_tag(tag) # apply before/after pagination restrictions if relevant if before: query = query.before_id36(before) if after: query = query.after_id36(after) # apply topic tag filters unless they're disabled or viewing a single tag if not (tag or unfiltered): # pylint: disable=protected-access query = query.filter(~Topic._tags.overlap( # type: ignore request.user._filtered_topic_tags)) topics = query.get_page(per_page) period_options = [SimpleHoursPeriod(hours) for hours in (1, 12, 24, 72)] # add the current period to the bottom of the dropdown if it's not one of # the "standard" ones if period and period not in period_options: period_options.append(period) return { 'group': request.context, 'topics': topics, 'order': order, 'order_options': TopicSortOption, 'period': period, 'period_options': period_options, 'is_default_period': period == default_settings.period, 'is_default_view': (period == default_settings.period and order == default_settings.order), 'rank_start': rank_start, 'tag': tag, 'unfiltered': unfiltered, }