mirror of https://gitlab.com/tildes/tildes.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
74 lines
2.3 KiB
74 lines
2.3 KiB
"""Contains the UserInviteCode class."""
|
|
|
|
from datetime import datetime
|
|
import random
|
|
import string
|
|
|
|
from sqlalchemy import CheckConstraint, Column, ForeignKey, Integer, Text, TIMESTAMP
|
|
from sqlalchemy.sql.expression import text
|
|
|
|
from tildes.models import DatabaseModel
|
|
from .user import User
|
|
|
|
|
|
class UserInviteCode(DatabaseModel):
|
|
"""Model for invite codes that allow new users to register."""
|
|
|
|
__tablename__ = "user_invite_codes"
|
|
|
|
# the character set to generate codes using
|
|
ALPHABET = string.ascii_uppercase + string.digits
|
|
|
|
LENGTH = 15
|
|
|
|
code: str = Column(
|
|
Text,
|
|
CheckConstraint(f"LENGTH(code) <= {LENGTH}", name="code_length"),
|
|
primary_key=True,
|
|
)
|
|
user_id: int = Column(
|
|
Integer, ForeignKey("users.user_id"), nullable=False, index=True
|
|
)
|
|
created_time: datetime = Column(
|
|
TIMESTAMP(timezone=True), nullable=False, server_default=text("NOW()")
|
|
)
|
|
invitee_id: int = Column(Integer, ForeignKey("users.user_id"))
|
|
|
|
def __str__(self) -> str:
|
|
"""Format the code into a more easily readable version."""
|
|
formatted = ""
|
|
|
|
for count, char in enumerate(self.code):
|
|
# add a dash every 5 chars
|
|
if count > 0 and count % 5 == 0:
|
|
formatted += "-"
|
|
|
|
formatted += char.upper()
|
|
|
|
return formatted
|
|
|
|
def __init__(self, user: User) -> None:
|
|
"""Create a new (random) invite code owned by the user.
|
|
|
|
Note that uniqueness is not confirmed here, so there is the potential to create
|
|
duplicate codes (which will fail to commit to the database).
|
|
"""
|
|
self.user_id = user.user_id
|
|
|
|
code_chars = random.choices(self.ALPHABET, k=self.LENGTH)
|
|
self.code = "".join(code_chars)
|
|
|
|
@classmethod
|
|
def prepare_code_for_lookup(cls, code: str) -> str:
|
|
"""Prepare/sanitize a code for lookup purposes."""
|
|
# codes are stored in uppercase
|
|
code = code.upper()
|
|
|
|
# remove any characters that aren't in the code alphabet (allows dashes, spaces,
|
|
# etc. to be used to make the codes more readable)
|
|
code = "".join(letter for letter in code if letter in cls.ALPHABET)
|
|
|
|
if len(code) > cls.LENGTH:
|
|
raise ValueError("Code is longer than the maximum length")
|
|
|
|
return code
|