Browse Source

Add pagination

Getty Ritter 4 years ago
parent
commit
7dcfac0f6c
5 changed files with 78 additions and 12 deletions
  1. 5 5
      lc/app.py
  2. 36 5
      lc/model.py
  3. 9 0
      lc/static/main.css
  4. 2 2
      stubs/peewee.py
  5. 26 0
      templates/linklist.mustache

+ 5 - 5
lc/app.py

@@ -70,12 +70,12 @@ class CreateUser(Endpoint):
 class GetUser(Endpoint):
     def html(self, slug: str):
         u = m.User.by_slug(slug)
-        pg = int(flask.request.args.get("page", 0))
-        links = u.get_links(page=pg)
+        pg = int(flask.request.args.get("page", 1))
+        links, pages = u.get_links(page=pg)
         return render(
             "main",
             title=f"user {u.name}",
-            content=render("linklist", links=links),
+            content=render("linklist", links=links, pages=pages),
             user=self.user,
         )
 
@@ -117,10 +117,10 @@ class GetTaggedLinks(Endpoint):
         u = m.User.by_slug(user)
         pg = int(flask.request.args.get("page", 0))
         t = u.get_tag(tag)
-        links = t.get_links(page=pg)
+        links, pages = t.get_links(page=pg)
         return render(
             "main",
             title=f"tag {tag}",
-            content=render("linklist", links=links),
+            content=render("linklist", links=links, pages=pages),
             user=self.user,
         )

+ 36 - 5
lc/model.py

@@ -1,3 +1,4 @@
+from dataclasses import dataclass
 import datetime
 from passlib.apps import custom_app_context as pwd
 import peewee
@@ -17,6 +18,29 @@ class Model(peewee.Model):
         return playhouse.shortcuts.model_to_dict(self)
 
 
+@dataclass
+class Pagination:
+    current: int
+    last: int
+
+    def previous(self) -> dict:
+        if self.current > 1:
+            return {"page": self.current - 1}
+        return None
+
+    def next(self) -> dict:
+        if self.current < self.last:
+            return {"page": self.current + 1}
+        return None
+
+    @classmethod
+    def from_total(cls, current, total) -> "Pagination":
+        return cls(
+            current=current,
+            last=((total-1)//c.PER_PAGE)+1,
+        )
+
+
 # TODO: figure out authorization for users (oauth? passwd?)
 class User(Model):
     """
@@ -43,7 +67,7 @@ class User(Model):
         self.save()
 
     @staticmethod
-    def login(user: r.User) -> "User":
+    def login(user: r.User) -> typing.Tuple["User", str]:
         u = User.by_slug(user.name)
         if not u.authenticate(user.password):
             raise e.BadPassword(name=user.name)
@@ -59,8 +83,10 @@ class User(Model):
     def base_url(self) -> str:
         return f"/u/{self.name}"
 
-    def get_links(self, page: int) -> typing.List["Link"]:
-        return Link.select().where(Link.user == self).order_by(-Link.created).paginate(page, c.PER_PAGE)
+    def get_links(self, page: int) -> typing.Tuple[typing.List["Link"], Pagination]:
+        links = Link.select().where(Link.user == self).order_by(-Link.created).paginate(page, c.PER_PAGE)
+        pagination = Pagination.from_total(page, Link.select().count())
+        return links, pagination
 
     def get_link(self, link_id: int) -> "Link":
         return Link.get((Link.user == self) & (Link.id == link_id))
@@ -120,8 +146,8 @@ class Tag(Model):
     def url(self) -> str:
         return f"/u/{self.user.name}/t/{self.name}"
 
-    def get_links(self, page: int) -> typing.List[Link]:
-        return [
+    def get_links(self, page: int) -> typing.Tuple[typing.List[Link], Pagination]:
+        links = [
             ht.link
             for ht in HasTag.select()
             .join(Link)
@@ -129,6 +155,11 @@ class Tag(Model):
             .order_by(-Link.created)
             .paginate(page, c.PER_PAGE)
         ]
+        pagination = Pagination.from_total(
+            page,
+            HasTag.select().where((HasTag.tag == self)).count(),
+        )
+        return links, pagination
 
     @staticmethod
     def get_or_create_tag(user: User, tag_name: str):

+ 9 - 0
lc/static/main.css

@@ -146,3 +146,12 @@ form > div {
     text-transform: uppercase;
     letter-spacing: 0.2em;
 }
+
+.pagination {
+    border-top: solid black;
+    display: flex;
+    justify-content: space-around;
+    font-size: large;
+    padding: 0.2em 2em;
+    margin: 0em 1em;
+}

+ 2 - 2
stubs/peewee.py

@@ -30,7 +30,7 @@ class Model:
 
 # These all do things that MyPy chokes on, so we're going to treat
 # them like methods instead of naming classes
-def TextField(unique: bool = False) -> Any:
+def TextField(default: str = '', unique: bool = False) -> Any:
     pass
 
 
@@ -38,7 +38,7 @@ def DateTimeField(unique: bool = False) -> Any:
     pass
 
 
-def BooleanField(unique: bool = False) -> Any:
+def BooleanField(default: bool = False, unique: bool = False) -> Any:
     pass
 
 

+ 26 - 0
templates/linklist.mustache

@@ -3,3 +3,29 @@
     {{>link}}
   {{/links}}
 </div>
+{{#pages}}
+  <div class="pagination">
+    <div class="navbutton">
+      <a href="?page=0">first</a>
+    </div>
+    <div class="navbutton">
+      {{#previous}}
+        <a href="?page={{page}}">prev</a>
+      {{/previous}}
+      {{^previous}}
+        prev
+      {{/previous}}
+    </div>
+    <div class="navbutton">
+      {{#next}}
+        <a href="?page={{page}}">next</a>
+      {{/next}}
+      {{^next}}
+        next
+      {{/next}}
+    </div>
+    <div class="navbutton">
+      <a href="?page={{last}}">last</a>
+    </div>
+  </div>
+{{/pages}}