From 0820886c14f9ec2e73df4c296722bc34c68cfa5a Mon Sep 17 00:00:00 2001 From: Deimos Date: Wed, 9 Oct 2019 18:53:50 -0600 Subject: [PATCH] Display a "content type" for topics in listings This should be stored in the database so that we can take advantage of it for searching/filtering, but I want to test it on the live site first and get input about what other types of content get posted. It'll be simpler to leave it in code only for that, and I can add it to the database later. --- tildes/scss/modules/_topic.scss | 7 +++ tildes/tildes/enums.py | 21 +++++++++ tildes/tildes/models/topic/topic.py | 45 +++++++++++++++++++- tildes/tildes/templates/macros/topics.jinja2 | 4 +- 4 files changed, 74 insertions(+), 3 deletions(-) diff --git a/tildes/scss/modules/_topic.scss b/tildes/scss/modules/_topic.scss index 0956c66..a87e2f0 100644 --- a/tildes/scss/modules/_topic.scss +++ b/tildes/scss/modules/_topic.scss @@ -81,6 +81,13 @@ white-space: nowrap; } +// This puts a bullet in front of the topic-content-type only when there's something +// else in front of it (group name and/or tags) +.topic-content-type:not(:first-child)::before { + content: "•"; + margin-right: 0.4rem; +} + .topic-group { margin-right: 0.4rem; } diff --git a/tildes/tildes/enums.py b/tildes/tildes/enums.py index 9b53fe0..e9dcef2 100644 --- a/tildes/tildes/enums.py +++ b/tildes/tildes/enums.py @@ -115,6 +115,27 @@ class ScraperType(enum.Enum): YOUTUBE = enum.auto() +class TopicContentType(enum.Enum): + """Enum for the different types of content for topics.""" + + ARTICLE = enum.auto() + ASK = enum.auto() + IMAGE = enum.auto() + PDF = enum.auto() + TEXT = enum.auto() + TWEET = enum.auto() + VIDEO = enum.auto() + + @property + def display_name(self) -> str: + """Return the content type's name in a format more suitable for display.""" + + if self.name == "PDF": + return self.name + + return self.name.capitalize() + + class TopicSortOption(enum.Enum): """Enum for the different methods topics can be sorted by. diff --git a/tildes/tildes/models/topic/topic.py b/tildes/tildes/models/topic/topic.py index 1eeb933..ab19b97 100644 --- a/tildes/tildes/models/topic/topic.py +++ b/tildes/tildes/models/topic/topic.py @@ -5,7 +5,9 @@ from datetime import datetime, timedelta from itertools import chain +from pathlib import PurePosixPath from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, TYPE_CHECKING +from urllib.parse import urlparse from pyramid.security import Allow, Authenticated, Deny, DENY_ALL, Everyone from sqlalchemy import ( @@ -24,7 +26,7 @@ from sqlalchemy.orm import deferred, relationship from sqlalchemy.sql.expression import text from titlecase import titlecase -from tildes.enums import TopicType +from tildes.enums import TopicContentType, TopicType from tildes.lib.database import TagList from tildes.lib.datetime import utc_from_timestamp, utc_now from tildes.lib.id import id_to_id36 @@ -394,7 +396,46 @@ class Topic(DatabaseModel): @property def is_spoiler(self) -> bool: """Return whether the topic is marked as a spoiler.""" - return "spoiler" in self.tags + return self.has_tag("spoiler") + + def has_tag(self, check_tag: str) -> bool: + """Return whether the topic has a tag or any sub-tag of it.""" + if check_tag in self.tags: + return True + + if any(tag.startswith(f"{check_tag}.") for tag in self.tags): + return True + + return False + + @property + def content_type(self) -> TopicContentType: + """Return the content's type based on the topic's attributes.""" + if self.is_text_type: + if self.has_tag("ask"): + return TopicContentType.ASK + + return TopicContentType.TEXT + else: + parsed_url = urlparse(self.link) # type: ignore + url_path = PurePosixPath(parsed_url.path) + + if url_path.suffix.lower() == ".pdf": + return TopicContentType.PDF + elif url_path.suffix.lower() in (".gif", ".jpeg", ".jpg", ".png"): + return TopicContentType.IMAGE + + # individual sites should be handled in a more general manner; fine for now + if self.link_domain == "youtube.com" and parsed_url.path == "/watch": + return TopicContentType.VIDEO + + try: + if self.link_domain == "twitter.com" and url_path.parts[2] == "status": + return TopicContentType.TWEET + except IndexError: + pass + + return TopicContentType.ARTICLE def get_content_metadata(self, key: str) -> Any: """Get a piece of content metadata "safely". diff --git a/tildes/tildes/templates/macros/topics.jinja2 b/tildes/tildes/templates/macros/topics.jinja2 index b05b95d..90cc985 100644 --- a/tildes/tildes/templates/macros/topics.jinja2 +++ b/tildes/tildes/templates/macros/topics.jinja2 @@ -46,8 +46,10 @@ {% endif %} + {{ topic.content_type.display_name }} + {% if topic.content_metadata_for_display %} - {{ topic.content_metadata_for_display }} + : {{ topic.content_metadata_for_display }} {% endif %} {% if topic.unimportant_tags and request.user and request.user.show_tags_in_listings %}