#27 List tags for user

Merged
getty merged 4 commits from getty/gr/list-tags into getty/master 4 years ago
6 changed files with 51 additions and 7 deletions
  1. 7 3
      lc/app.py
  2. 18 0
      lc/model.py
  3. 10 0
      lc/static/main.css
  4. 1 0
      lc/view.py
  5. 4 0
      stubs/peewee.py
  6. 11 4
      templates/linklist.mustache

+ 7 - 3
lc/app.py

@@ -89,12 +89,14 @@ class GetUser(Endpoint):
     def html(self, slug: str):
         u = m.User.by_slug(slug)
         pg = int(flask.request.args.get("page", 1))
+        tags = u.get_tags()
         links, pages = u.get_links(as_user=self.user, page=pg)
+        linklist = v.LinkList(links=links, pages=pages, tags=tags)
         return render(
             "main",
             v.Page(
                 title=f"user {u.name}",
-                content=render("linklist", v.LinkList(links=links, pages=pages)),
+                content=render("linklist", linklist),
                 user=self.user,
             ),
         )
@@ -170,7 +172,7 @@ class GetLink(Endpoint):
             "main",
             v.Page(
                 title=f"link {l.name}",
-                content=render("linklist", v.LinkList([l.to_view(self.user)])),
+                content=render("linklist", v.LinkList([l.to_view(self.user)], [])),
                 user=self.user,
             ),
         )
@@ -198,11 +200,13 @@ class GetTaggedLinks(Endpoint):
         pg = int(flask.request.args.get("page", 0))
         t = u.get_tag(tag)
         links, pages = t.get_links(as_user=self.user, page=pg)
+        tags = u.get_related_tags(t)
+        linklist = v.LinkList(links=links, pages=pages, tags=tags)
         return render(
             "main",
             v.Page(
                 title=f"tag {tag}",
-                content=render("linklist", v.LinkList(links=links, pages=pages,)),
+                content=render("linklist", linklist),
                 user=self.user,
             ),
         )

+ 18 - 0
lc/model.py

@@ -148,6 +148,24 @@ class User(Model):
                 for t in l["tags"].split():
                     HasTag.get_or_create(link=ln, tag=tags[t])
 
+    def get_tags(self) -> List[v.Tag]:
+        return sorted(
+            (t.to_view() for t in self.tags),  # type: ignore
+            key=lambda t: t.name,
+        )
+
+    def get_related_tags(self, tag: "Tag") -> List[v.Tag]:
+        # SELECT * from has_tag t1, has_tag t2, link l WHERE t1.link_id == l.id AND t2.link_id == l.id AND t1.id != t2.id AND t1 = self
+        SelfTag = HasTag.alias()
+        query = (
+            HasTag.select(HasTag.tag)
+            .join(Link, on=(HasTag.link == Link.id))
+            .join(SelfTag, on=(SelfTag.link == Link.id))
+            .where((SelfTag.tag == tag) & (SelfTag.id != HasTag.id))
+            .group_by(HasTag.tag)
+        )
+        return sorted((t.tag.to_view() for t in query), key=lambda t: t.name,)
+
 
 class Link(Model):
     """

+ 10 - 0
lc/static/main.css

@@ -198,3 +198,13 @@ form > div {
 .error p {
     margin-left: 2em;
 }
+
+.columns {
+    display: grid;
+    grid-template-columns: 60% 40%;
+}
+
+.tags {
+    padding: 2em;
+    word-spacing: 1em;
+}

+ 1 - 0
lc/view.py

@@ -78,6 +78,7 @@ class Link(View):
 @dataclass
 class LinkList(View):
     links: List[Any]
+    tags: List[Tag]
     pages: Optional[Pagination] = None
 
 

+ 4 - 0
stubs/peewee.py

@@ -36,6 +36,10 @@ class Model:
     def delete_instance(self) -> Any:
         pass
 
+    @classmethod
+    def alias(cls: Type[T]) -> Type[T]:
+        pass
+
 
 # These all do things that MyPy chokes on, so we're going to treat
 # them like methods instead of naming classes

+ 11 - 4
templates/linklist.mustache

@@ -1,7 +1,14 @@
-<div class="linklist">
-  {{#links}}
-    {{>link}}
-  {{/links}}
+<div class="columns">
+  <div class="linklist">
+    {{#links}}
+      {{>link}}
+    {{/links}}
+  </div>
+  <div class="tags">
+    {{#tags}}
+      <a href="{{url}}">{{name}}</a>
+    {{/tags}}
+  </div>
 </div>
 {{#pages}}
   <div class="pagination">