model.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import datetime
  2. from passlib.apps import custom_app_context as pwd
  3. import peewee
  4. import typing
  5. import lc.config as c
  6. import lc.request as r
  7. class Model(peewee.Model):
  8. class Meta:
  9. database = c.DB
  10. # TODO: figure out authorization for users (oauth? passwd?)
  11. class User(Model):
  12. """
  13. A user! you know tf this is about
  14. """
  15. name = peewee.TextField()
  16. passhash = peewee.TextField()
  17. @staticmethod
  18. def from_request(user: r.User) -> "User":
  19. passhash = pwd.hash(user.password)
  20. return User.create(
  21. name=user.name,
  22. passhash=passhash,
  23. )
  24. def authenticate(self, password: str) -> bool:
  25. return pwd.verify(password, self.passhash)
  26. @staticmethod
  27. def by_slug(slug: str) -> "User":
  28. return User.get(name=slug)
  29. def base_url(self) -> str:
  30. return f"/u/{self.name}"
  31. def get_links(self, page: int) -> typing.List["Link"]:
  32. return Link.select().where(Link.user == self).paginate(page, c.PER_PAGE)
  33. def get_tag(self, tag_name: str) -> "Tag":
  34. return Tag.get((Tag.user == self) & (Tag.name == tag_name))
  35. class Link(Model):
  36. """
  37. A link as stored in the database
  38. """
  39. url = peewee.TextField()
  40. name = peewee.TextField()
  41. description = peewee.TextField()
  42. # TODO: do we need to track modified time?
  43. created = peewee.DateTimeField()
  44. # is the field entirely private?
  45. private = peewee.BooleanField()
  46. # owned by
  47. user = peewee.ForeignKeyField(User, backref="links")
  48. def link_url(self) -> str:
  49. return f"/u/{self.user.name}/l/{self.id}"
  50. @staticmethod
  51. def from_request(user: User, link: r.Link) -> "Link":
  52. l = Link.create(
  53. url=link.url,
  54. name=link.name,
  55. description=link.description,
  56. private=link.private,
  57. created=datetime.datetime.now(),
  58. user=user,
  59. )
  60. for tag_name in link.tags:
  61. t = Tag.get_or_create_tag(user, tag_name)
  62. HasTag.create(
  63. link=l, tag=t,
  64. )
  65. return l
  66. class Tag(Model):
  67. """
  68. A tag. This just indicates that a user has used this tag at some point.
  69. """
  70. name = peewee.TextField()
  71. parent = peewee.ForeignKeyField("self", null=True, backref="children")
  72. user = peewee.ForeignKeyField(User, backref="tags")
  73. def url(self) -> str:
  74. return f"/u/{self.user.name}/t/{self.name}"
  75. def get_links(self, page: int) -> typing.List[Link]:
  76. return [
  77. ht.link
  78. for ht in HasTag.select()
  79. .where((HasTag.tag == self))
  80. .paginate(page, c.PER_PAGE)
  81. ]
  82. @staticmethod
  83. def get_or_create_tag(user: User, tag_name: str):
  84. if (t := Tag.get_or_none(name=tag_name, user=user)) :
  85. return t
  86. parent = None
  87. if "/" in tag_name:
  88. parent_name = tag_name[: tag_name.rindex("/")]
  89. parent = Tag.get_or_create_tag(user, parent_name)
  90. return Tag.create(name=tag_name, parent=parent, user=user)
  91. class HasTag(Model):
  92. """
  93. Establishes that a link is tagged with a given tag.
  94. """
  95. link = peewee.ForeignKeyField(Link, backref="tags")
  96. tag = peewee.ForeignKeyField(Tag, backref="models")
  97. MODELS = [
  98. User,
  99. Link,
  100. Tag,
  101. HasTag,
  102. ]
  103. def create_tables():
  104. c.DB.create_tables(MODELS, safe=True)