Explorar el Código

Working on user and database basics.

Cixo Develop hace 8 meses
padre
commit
0a20fbd1be
Se han modificado 4 ficheros con 290 adiciones y 5 borrados
  1. 2 1
      assets/__init__.py
  2. 39 0
      assets/apikey.py
  3. 86 4
      assets/user.py
  4. 163 0
      assets/user_loader.py

+ 2 - 1
assets/__init__.py

@@ -1,4 +1,5 @@
 from .password import password
 from .user import user
 from .user import user_builder
-from .database import database
+from .database import database
+from .apikey import apikey

+ 39 - 0
assets/apikey.py

@@ -0,0 +1,39 @@
+import os
+
+class apikey:
+    """
+    This create new random API key.
+    """
+
+    def __new__(cls, lenght: int = 128) -> str:
+        """
+        This create new random API key.
+
+        lenght: int - Lenght os the api key (default: 128)
+        return: str - API key
+        """
+
+        byte = cls.__get_random(lenght)
+        string = cls.__to_hex(byte)
+
+        return string
+
+    def __to_hex(byte: bytes) -> str:
+        """
+        This convert random bytes to string.
+        
+        byte: bytes - Bytes array to convert
+        return: str - Result as string
+        """
+
+        return byte.hex()
+
+    def __get_random(lenght: int) -> bytes:
+        """
+        Get random count of hex chars from os.
+
+        lenght: int - Lenght of the bytes
+        return: bytes - Random bytes from os
+        """
+
+        return os.urandom(lenght)

+ 86 - 4
assets/user.py

@@ -1,10 +1,92 @@
 import sqlmodel
 
+from .apikey import apikey
+from .password import password
+
 class user(sqlmodel.SQLModel, table = True):
+    """
+    This represents user in database. All users has own unique nick and api
+    key. Nick and password is used to login, api key is long, random and
+    used to access database via API.
+    """
+
     id: int | None = sqlmodel.Field(default = None, primary_key = True)
-    nick: str = sqlmodel.Field(index = True)
-    password: str = sqlmodel.Field(index = True)
-    apikey: str = sqlmodel.Field(index = True)
+    nick: str = sqlmodel.Field(index = True, unique=True)
+    password: str = sqlmodel.Field(index = False)
+    apikey: str = sqlmodel.Field(index = True, unique=True)
 
 class user_builder:
-    pass
+    def __init__(self) -> None:
+        """
+        Create new empty user builder.
+        """
+
+        self.clean()
+
+    def clean(self) -> None:
+        """
+        This clean builed. That mean, new empty user is creating.
+        """
+
+        self.__target = user(apikey = apikey())
+
+    @property
+    def ready(self) -> bool:
+        """
+        This check that user in builder is ready to get.
+
+        return: bool - True when user is ready, false if not
+        """
+
+        if self.__target.nick is None:
+            return False
+
+        if self.__target.password is None:
+            return False
+
+        return True
+
+    @property
+    def nick(self) -> str | None:
+        """
+        return: str | None - Current nick of the user in builder
+        """
+
+        return self.__target.nick
+
+    @property
+    def password(self) -> bool:
+        """
+        return: bool - True when password is set, false if not
+        """
+
+        return self.__target.password is not None
+
+    @nick.setter
+    def nick(self, target: str) -> None:
+        """
+        target: str - New nick for the user
+        """
+
+        self.__target.nick = target
+
+    @password.setter
+    def password(self, target: str) -> None:
+        """
+        target: str - New password to hash and set
+        """
+
+        self.__target.password = password(target).result
+
+    @property
+    def result(self) -> user:
+        """
+        This return user setup in the builder.
+
+        return: user - User from builder
+        """
+
+        if not self.ready:
+            raise TypeError("User in builder is not ready yet.")
+
+        return self.__target

+ 163 - 0
assets/user_loader.py

@@ -0,0 +1,163 @@
+import sqlmodel
+
+from .user import user
+from .user import user_builder
+from .password import password
+
+class user_loader(sqlmodel.Session):
+    def login(self, nick: str, secret: str) -> user | None:
+        """
+        This get new user by nick and password. If user does not exists,
+        then return None. It also return None when user password is not
+        correct.
+
+        nick: str - Nick of the user
+        secret: str - Password of the user
+        return: user | None - Logged user, or None when not exists
+        """
+
+        result = self.get_by_nick(nick)
+
+        if result is None:
+            return None
+
+        if not password(secret).validate(result.password):
+            return None
+
+        return result
+
+    def register(self, target: user) -> bool:
+        """
+        This function register new user. It also check that user with given
+        apikey or nick not exists. If user had been created, then return True.
+        When something went wront, return False.
+
+        target: user - User to register in database
+        return: bool - True when registered new user, False when failed
+        """
+
+        if target.id is not None:
+            return False
+
+        if target.apikey is None or target.nick is None:
+            return False
+
+        if target.password is None:
+            return False
+
+        if self.nick_in_use(target.nick):
+            return False
+
+        if self.apikey_in_use(target.apikey):
+            return False
+
+        self.add(target)
+        self.commit()
+        self.refresh(target)
+
+        return True
+
+    def unregister(self, target: user) -> bool:
+        """
+        This function remove user from database.
+
+        target: user - User to remove from database
+        return: bool - True when removed, Falsd when something failed
+        """
+
+        if not self.is_registered(target):
+            return False
+
+        self.delete(target)
+        self.commit()
+
+        return True
+
+    def save(self, target: user) -> bool:
+        """
+        This function save already registered user to database, after changes.
+
+        target: user - User to save
+        return: bool - True when saved successfull, False when failed
+        """
+
+        if not self.is_registered(user):
+            return False
+
+        self.add(target)
+        self.commit()
+        self.refresh(target)
+
+        return True
+
+    def nick_in_use(self, nick: str) -> bool:
+        """
+        This function check that nick is already in use.
+
+        nick: str - Nick to check
+        return: bool - True when nick in use, False if not
+        """
+
+        return self.get_by_nick(nick) is not None
+
+    def get_by_apikey(self, apikey: str) -> user | None:
+        """
+        This get user from database by apikey, or return None when not exists.
+
+        apikey: str - Apikey of the user to load
+        return: user | None - User with given apikey, or none when not exists
+        """
+
+        query = sqlmodel.select(user).where(user.apikey == apikey).limit(1)
+        result = self.exec(query)
+
+        return result.first()
+
+    def apikey_in_use(self, apikey: str) -> bool:
+        """
+        This function check that apikey is already in use.
+
+        apikey: str - Apikey to check
+        return: bool - True when apikey is in use or False when not
+        """
+
+        return self.get_by_apikey(apikey) is not None
+
+    def get_by_nick(self, nick: str) -> user | None:
+        """
+        This get user from database by nick.
+
+        nick: str - Nick of the user to load
+        return: user | None - Loaded user or None when not exists.
+        """
+
+        query = sqlmodel.select(user).where(user.nick == nick).limit(1)
+        result = self.exec(query)
+
+        return result.first()
+
+    def get_by_id(self, id: int) -> user | None:
+        """
+        This function select user from database by ID.
+
+        id: int - ID of the user to select
+        return: user | None - Selected user or None when not exists
+        """
+
+        query = sqlmodel.select(user).where(user.id == id).limit(1)
+        result = self.exec(query)
+
+        return result.first()
+
+    def is_registered(self, target: user) -> bool:
+        """
+        This function check that user is registered.
+
+        target: user - User to check
+        return: bool - True when user is registered, False when not
+        """
+
+        if target.id is None:
+            return False
+
+        return self.get_by_id(target.id) is not None