Initial commit

This commit is contained in:
2026-11-05 08:28:15 +00:00
commit 08582a4f70
65 changed files with 1886 additions and 0 deletions
@@ -0,0 +1,24 @@
from backend.code.modules.database.database import DatabaseModule
class AccountRepository():
def __init__(self, repo: DatabaseModule):
self.conn = repo.conn
self.cursor = repo.cursor
def SelectByUsername(self, username: str):
sql = '''
SELECT *
FROM user_accounts
WHERE username = ?
'''
self.cursor.execute(sql, [username])
return self.cursor.fetchone()
def InsertAccount(self, user_id: int, username: str, locked: bool = False, active: bool = True):
sql = '''
INSERT INTO user_accounts(user_id, username, locked, active)
VALUES(?, ?, ?, ?)
'''
self.cursor.execute(sql, [user_id, username, locked, active])
self.conn.commit()
return self.cursor.lastrowid
@@ -0,0 +1,20 @@
from fastapi import APIRouter
routes = APIRouter(prefix="/animals/{animalId}/alerts", tags=['Animal alert'])
@routes.get("")
def ListAnimalAlerts(animalId: str):
pass
@routes.post("")
def RegisterAnimalAlert(animalId: str, data):
pass
@routes.put("/{id}")
def EditAnimalAlert(animalId: str, id: str, data):
pass
@routes.delete("/{id}")
def DisableAnimalAlert(animalId: str, id: str):
pass
@@ -0,0 +1,19 @@
from fastapi import APIRouter
routes = APIRouter(prefix="/animals/{animalId}/comments", tags=['Animal comment'])
@routes.get("")
def ListAnimalComments(animalId: str):
pass
@routes.post("")
def RegisterAnimalComment(animalId: str, data):
pass
@routes.put("/{id}")
def EditAnimalComment(animalId: str, id: str, data):
pass
@routes.delete("/{id}")
def DisableAnimalComment(animalId: str, id: str):
pass
@@ -0,0 +1,28 @@
from fastapi import APIRouter, UploadFile, File, HTTPException
ALLOWED_IMAGES = {
"image/jpeg",
"image/png",
"image/webp",
}
routes = APIRouter(prefix="/animals/{animalId}/images", tags=['Animal image'])
@routes.get("")
def ListAnimalImages(animalId: str):
pass
@routes.post("")
def RegisterAnimalImage(animalId: str, file: UploadFile = File(...)):
if file.content_type not in ALLOWED_IMAGES:
raise HTTPException(status_code=400, detail="File must be an image")
return {"data": file.filename}
@routes.put("/{id}")
def EditAnimalImage(animalId: str, id: str, data):
pass
@routes.delete("/{id}")
def DisableAnimalImage(animalId: str, id: str):
pass
+19
View File
@@ -0,0 +1,19 @@
from fastapi import APIRouter, status
routes = APIRouter(prefix="/animals", tags=['Animal'])
@routes.get("", status_code = status.HTTP_200_OK)
def FilterAnimals(data):
pass
@routes.post("", status_code = status.HTTP_201_CREATED)
def RegisterAnimal(data):
pass
@routes.put("/{id}", status_code = status.HTTP_204_NO_CONTENT)
def EditAnimal(id: str, data):
pass
@routes.delete("/{id}", status_code = status.HTTP_204_NO_CONTENT)
def DisableAnimal(id: str):
pass
+27
View File
@@ -0,0 +1,27 @@
from abc import ABC, abstractmethod
class DatabaseModule(ABC):
@abstractmethod
def SelectById(self):
raise NotImplementedError("Select by id method not implemented")
@abstractmethod
def SelectByCode(self):
raise NotImplementedError("Select by code method not implemented")
@abstractmethod
def Filter(self, data):
raise NotImplementedError("Filter method not implemented")
@abstractmethod
def Register(self, data):
raise NotImplementedError("Register method not implemented")
@abstractmethod
def Edit(self, register, data):
raise NotImplementedError("Edit method not implemented")
@abstractmethod
def Disable(self, register):
raise NotImplementedError("Disable method not implemented")
@@ -0,0 +1,48 @@
import os
from backend.code.modules.database.database import DatabaseModule
import sqlite3
class DatabaseSqliteModule(DatabaseModule):
def __init__(self):
self.database = '/projects/database/settlements.db'
self.schema = '/projects/database/1_schema_sqlite.sql'
self.basic_data = '/projects/database/2_population_sqlite.sql'
self.Initialize()
def Initialize(self):
exists = os.path.isfile(self.database)
self.conn = sqlite3.connect(self.database, check_same_thread=False)
self.cursor = self.conn.cursor()
if exists is False:
self.GenerateSchema()
self.PopulateDatabase()
def GenerateSchema(self):
with open(self.schema, 'r', encoding='utf-8') as file:
sql = file.read()
self.cursor.executescript(sql)
self.conn.commit()
def PopulateDatabase(self):
with open(self.basic_data, 'r', encoding='utf-8') as file:
sql = file.read()
self.cursor.executescript(sql)
self.conn.commit()
def SelectById(self):
raise NotImplementedError("Select by id method not implemented")
def SelectByCode(self):
raise NotImplementedError("Select by code method not implemented")
def Filter(self, data):
raise NotImplementedError("Filter method not implemented")
def Register(self, data):
raise NotImplementedError("Register method not implemented")
def Edit(self, register, data):
raise NotImplementedError("Edit method not implemented")
def Disable(self, register):
raise NotImplementedError("Disable method not implemented")
@@ -0,0 +1,13 @@
from datetime import datetime
from fastapi import APIRouter, status, HTTPException
routes = APIRouter(prefix="", tags=['Miscellaneous'])
@routes.api_route('/', methods=['GET', 'POST', 'PUT', 'DELETE'], status_code=status.HTTP_400_BAD_REQUEST)
def RootPathLocked():
pass
@routes.get('/isalive', status_code=status.HTTP_200_OK)
def CheckServerRunning():
now = datatime.now().strftime('%Y-%m-%d %H:%M:%S')
return {'data': f'Last server update: {now}'}
+183
View File
@@ -0,0 +1,183 @@
import os
from datetime import datetime, timedelta
from backend.code.modules.database.database_sqlite import DatabaseSqliteModule
from backend.code.modules.sessions.repository import SessionRepository
from backend.code.services.token import TokenService
from backend.code.services.mailing import MailingService
from backend.code.enums.errors_enum import ErrorTypeEnum
from backend.code.models.responses.session_token import SessionTokenResponse
from backend.code.modules.users.repository import UserRepository
class SessionsController():
def __init__(self):
database = DatabaseSqliteModule()
self.repo = SessionRepository(database)
self.token_service = TokenService()
self.mailing_service = MailingService()
def Login(self, user: str, password: str, domain: str = None):
account = self.repo.SelectByUsername(user)
if account is None:
return
# Array to properties
account_id = account[0]
user_id = account[1]
_password = account[3]
attempts = account[4]
locked = account[5]
name = account[7]
surnames = account[8]
email = account[9]
# Validations
if locked:
return ErrorTypeEnum.USER_ACCOUNT_LOCKED
# Default user has no password
if _password is None:
return ErrorTypeEnum.USER_ACCOUNT_NO_PASSWORD
if password != _password:
attempts = attempts + 1
self._OnUpdateAttempts(account_id, attempts)
return ErrorTypeEnum.USER_ACCOUNT_WRONG_PASSWORD
# Reset when password is correct and registered some attempts
if attempts > 0:
self._OnUpdateAttempts(account_id, 0)
# Generate token
payload = {
'UserId': user_id,
'Name': name,
'Surnames': surnames,
'Email': email
}
token = self.token_service.GenerateToken(payload)
session = self.repo.RegisterSession(account_id, token)
return SessionTokenResponse(Token=token)
def ValidateToken(self, token: str):
exists = self.repo.SelectByToken(token)
if exists is None:
return ErrorTypeEnum.USER_SESSION_NOT_EXISTS
# Array to properties
account_id = exists[0]
user_id = exists[1]
# Get metadata token
payload = self.token_service.ValidateToken(token)
if payload == False:
return
# Check token integrity
if payload['UserId'] != user_id:
return
autorefresh = self._OnCheckTokenAutoRefresh(payload['exp'])
if autorefresh:
token = self._OnRefreshToken(account_id, token, payload)
return token
def Logout(self, token: str):
exists = self.repo.SelectByToken(token)
if exists is None:
return
disabled = self.repo.DisableToken(token)
if disabled is None:
return
return disabled == 1
def RecoverAccount(self, username: str, domain: str = None):
account = self.repo.SelectByUsername(username)
if account is None:
return
# Array to properties
AccountId = account[0]
Fullname = f'{account[7]} {account[8]}'
Email = account[9]
now = datetime.now()
# Generate token
payload = {'Account': AccountId}
token = self.token_service.GenerateToken(payload)
url = f'{os.getenv('DOMAIN_URL')}/restore/{token}'
registered = self.repo.InsertRecoverRequest(AccountId, token)
if registered is None:
return
# Prepare notification
template = '''
Hola {},
Has pedido restaurar tu contraseña de {}. Accede al siguiente enlace para establecer una nueva contraseña:
{}
Si no has realizado esta petición de restauración de la cuenta, envia un correo a: {}
'''
message = template.format(Fullname, '[APP_NAME]', url, os.getenv('SUPPORT_EMAIL'))
# Send notification
self.mailing_service.SendMessage(
Email,
'Petición restaurar cuenta [APP_NAME]',
message
)
def ValidateTokenRecoverAccount(self, token: str):
validated = self.token_service.ValidateToken(token)
if validated is False:
return
exists = self.repo.SelectRecoverRequest(validated['Account'], token)
if exists is None:
return
disabled = self.repo.DisableRecoverRequest(token)
if disabled == 0:
return
return True
# region Utilities
def _OnUpdateAttempts(self, account_id: int, attempts: int):
locked = False
limit = int(os.getenv('USER_LIMIT_ATTEMPTS'))
if attempts > limit:
attempts = limit
locked = True
return self.repo.RefreshAttempts(account_id, attempts, locked)
def _OnCheckTokenAutoRefresh(self, expiration: int):
limit_minutes_left = 10
now = datetime.now()
expires_at = datetime.fromtimestamp(expiration)
difference = ((expires_at - now).total_seconds()) / 60 # seconds to minutes
return difference <= limit_minutes_left
def _OnRefreshToken(self, account_id: int, token: str, payload: dict):
old_disabled = self.repo.DisableToken(token)
if old_disabled is None:
return
new_token = self.token_service.GenerateToken(payload)
new_registered = self.repo.RegisterSession(account_id, new_token)
if new_registered is None:
return
return new_token
# endregion
@@ -0,0 +1,89 @@
from backend.code.modules.database.database import DatabaseModule
class SessionRepository():
def __init__(self, repo: DatabaseModule):
self.conn = repo.conn
self.cursor = repo.cursor
def SelectByUsername(self, username: str):
sql = '''
SELECT a.*, u.name, u.surnames, u.email
FROM user_accounts a
JOIN users u ON u.id = a.user_id
WHERE a.username = ?
AND a.active
'''
self.cursor.execute(sql, [username])
return self.cursor.fetchone()
def SelectByToken(self, token: str):
sql = '''
SELECT uas.account_id, u.id
FROM user_account_sessions uas
JOIN user_accounts ua ON uas.account_id = ua.id
JOIN users u ON ua.user_id = u.id
WHERE token = ?
AND uas.active
'''
self.cursor.execute(sql, [token])
return self.cursor.fetchone()
def RefreshAttempts(self, account_id: int, attempts: int, locked: bool):
sql = '''
UPDATE user_accounts
SET attempts = ?, locked = ?
WHERE id = ?
'''
self.cursor.execute(sql, [attempts, locked, account_id])
self.conn.commit()
return self.cursor.rowcount
def RegisterSession(self, accountId: int, token: str):
sql = '''
INSERT INTO user_account_sessions(account_id, token)
VALUES (?, ?)
'''
self.cursor.execute(sql, [accountId, token])
self.conn.commit()
return self.cursor.rowcount
def DisableToken(self, token: str):
sql = '''
UPDATE user_account_sessions
SET active = false
WHERE token = ?
'''
self.cursor.execute(sql, [token])
self.conn.commit()
return self.cursor.rowcount
def InsertRecoverRequest(self, accountId: int, token: str):
sql = '''
INSERT INTO user_account_recover_requests(account_id, token)
VALUES(?, ?)
'''
self.cursor.execute(sql, [accountId, token])
self.conn.commit()
return self.cursor.rowcount
def SelectRecoverRequest(self, accountId: int, token: str):
sql = '''
SELECT *
FROM user_account_recover_requests
WHERE account_id = ?
AND token = ?
AND active
'''
self.cursor.execute(sql, [accountId, token])
return self.cursor.fetchone()
def DisableRecoverRequest(self, token: str):
sql = '''
UPDATE user_account_recover_requests
SET active = false
WHERE token = ?
AND active
'''
self.cursor.execute(sql, [token])
self.conn.commit()
self.cursor.rowcount
+45
View File
@@ -0,0 +1,45 @@
from fastapi import APIRouter, status, Depends, HTTPException, Header
from backend.code.middlewares.private_middleware import PrivateMiddleware
from backend.code.models.requests.account_login import AccountLoginRequest
from backend.code.models.requests.account_recover import AccountRecoverRequest
from backend.code.models.responses.session_token import SessionTokenResponse
from backend.code.modules.sessions.controller import SessionsController
routes = APIRouter(prefix="/account", tags=['Session'])
middleware = PrivateMiddleware()
controller = SessionsController()
@routes.post('/login', status_code = status.HTTP_200_OK, response_model = SessionTokenResponse)
def Login(data: AccountLoginRequest):
session = controller.Login(data.Username, data.Password, data.Domain)
if type(session) is not SessionTokenResponse:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)
return session
@routes.post('/token/validate', status_code = status.HTTP_200_OK, response_model = SessionTokenResponse)
def ValidateToken(token: str = Depends(middleware.HasToken)):
validation = controller.ValidateToken(token)
if type(validation) is not SessionTokenResponse:
raise HTTPException(status_code = status.HTTP_401_UNAUTHORIZED)
return validation
@routes.post('/logout', status_code = status.HTTP_204_NO_CONTENT)
def Logout(token: str = Depends(middleware.HasToken)):
closed = controller.Logout(token)
if closed is None:
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND)
@routes.post('/recover', status_code = status.HTTP_200_OK)
def RecoverAccount(data: AccountRecoverRequest):
recovered = controller.RecoverAccount(data.Username, data.Domain)
if recovered is None:
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND)
@routes.post("/recover/validate/{token}", status_code=status.HTTP_204_NO_CONTENT)
def ValidateTokenRecoverAccount(token: str):
account = controller.ValidateTokenRecoverAccount(token)
if account is None:
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND)
@@ -0,0 +1,91 @@
from backend.code.enums.errors_enum import ErrorTypeEnum
from backend.code.core.controller import Controller
from backend.code.enums.errors_enum import ErrorTypeEnum
from backend.code.modules.database.database_sqlite import DatabaseSqliteModule
from backend.code.modules.settlements.repository import SettlementRepository
from backend.code.models.responses.settlement_detail import SettlementDetailResponse
class SettlementController(Controller):
def __init__(self):
database = DatabaseSqliteModule()
self.repo = SettlementRepository(database)
def ListSettlements(self, params: str = None):
result = []
if params is not None:
params = self._OnProcessParams(params)
settlements = self.repo.FilterSettlements(params)
if len(settlements) == 0:
return result
for _settlement in settlements:
settlement = SettlementDetailResponse(
Id = _settlement[0],
Name = _settlement[1],
Address = _settlement[2],
LastDone = _settlement[4],
LastDoneBy = _settlement[5],
Active = _settlement[6]
)
result.append(settlement)
return result
def SelectSettlement(self, id: int):
settlement = self.repo.SelectSettlementById(id)
if settlement is None:
return
return SettlementDetailResponse(
Id = settlement[0],
Name = settlement[1],
Address = settlement[2],
LastDone = settlement[4],
LastDoneBy = settlement[5],
Active = settlement[6]
)
def RegisterSettlement(self, name: str, address: str, active: bool = True):
exists = self.repo.FilterSettlements({'name': name, 'address': address})
if len(exists) > 0:
return ErrorTypeEnum.SETTLEMENT_EXISTS
settlement_id = self.repo.InsertSettlement(name, address, active)
if settlement_id is None:
return
return SettlementDetailResponse(
Id = settlement_id,
Name = name,
Address = address,
LastDone = None,
LastDoneBy = None,
Active = active
)
def EditSettlement(self, id: int, name: str, address: str, active: bool = True):
exists = self.repo.SelectSettlementById(id)
if exists is None:
return ErrorTypeEnum.SETTLEMENT_ID_NOT_EXISTS
edited = self.repo.UpdateSettlement(id, name, address, active)
if edited == 0:
return
return True
def RegisterSettlementDone(self, id: int, doneAt: datetime, doneBy: int):
pass
def DeleteSettlement(self, id: int):
exists = self.repo.SelectSettlementById(id)
if exists is None:
return ErrorTypeEnum.SETTLEMENT_ID_NOT_EXISTS
deleted = self.repo.DeleteSettlement(id)
if deleted == 0:
return
return True
@@ -0,0 +1,87 @@
from backend.code.modules.database.database import DatabaseModule
from datetime import datetime
class SettlementRepository():
def __init__(self, repo: DatabaseModule):
self.conn = repo.conn
self.cursor = repo.cursor
def FilterSettlements(self, filters: dict = None):
params = list()
sql = '''
SELECT *
FROM settlements
WHERE 1=1
'''
if filters is not None:
if 'name' in filters:
sql = sql + ' AND name LIKE ?'
params.append(filters['name'])
if 'address' in filters:
sql = sql + ' AND address LIKE ?'
params.append(filters['address'])
if 'last_done_by' in filters:
sql = sql + ' AND last_done_by LIKE ?'
params.append(filters['last_done_by'])
if 'last_done' in filters:
sql = sql + ' AND last_done = ?'
params.append(filters['last_done'])
# print(sql)
self.cursor.execute(sql, params)
return self.cursor.fetchall()
def SelectSettlementById(self, id: int):
sql = '''
SELECT *
FROM settlements
WHERE id = ?
AND active
'''
self.cursor.execute(sql, [id])
return self.cursor.fetchone()
def InsertSettlement(self, name: str, address: str, active: bool = True):
sql = '''
INSERT INTO settlements(name, address, active)
VALUES(?, ?, ?)
'''
self.cursor.execute(sql, [name, address, active])
self.conn.commit()
return self.cursor.lastrowid
def UpdateSettlement(self, id: int, name: str, address: str, active: bool = True):
sql = '''
UPDATE settlements
set name = ?, address = ?, active = ?
WHERE id = ?
'''
self.cursor.execute(sql, [name, address, active, id])
self.conn.commit()
return self.cursor.rowcount
def RegisterSettlementDone(self, id: int, user_done: int, done_at: datetime = datetime.now()):
sql = '''
UPDATE settlements
SET last_done_by = ?, last_done = ?
WHERE id = ?
'''
self.cursor.execute(sql, [done_at, user_done, id])
self.conn.commit()
return self.cursor.rowcount
def DeleteSettlement(self, id: int):
sql = '''
UPDATE settlements
SET active = false
WHERE id = ?
'''
self.cursor.execute(sql, [id])
self.conn.commit()
return self.cursor.rowcount
@@ -0,0 +1,62 @@
from fastapi import APIRouter, Query, status, Depends, Response, HTTPException
from backend.code.modules.settlements.controller import SettlementController
from backend.code.models.responses.settlement_detail import SettlementDetailResponse
from backend.code.models.requests.settlement_register import SettlementRegisterRequest
from backend.code.models.requests.settlement_edit import SettlementEditRequest
from backend.code.models.requests.settlement_register_done import SettlementRegisterDoneRequest
routes = APIRouter(prefix="/settlements", tags=['Settlement'])
controller = SettlementController()
@routes.get("", status_code = status.HTTP_200_OK, response_model = list[SettlementDetailResponse])
def ListSettlements(params: str | None = Query(default = None, alias = 'query')):
settlements = controller.ListSettlements(params)
if settlements is None:
raise HTTPException(status_code = status.HTTP_400_BAD_REQUEST)
if len(settlements) == 0:
return Response(status_code = status.HTTP_204_NO_CONTENT)
return settlements
@routes.get("/{id}", status_code = status.HTTP_200_OK, response_model = SettlementDetailResponse)
def GetSettlement(id: int):
settlement = controller.SelectSettlement(id)
if settlement is None:
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND)
return settlement
@routes.post('', status_code = status.HTTP_201_CREATED, response_model = SettlementDetailResponse)
def RegisterSettlement(data: SettlementRegisterRequest):
created = controller.RegisterSettlement(data.Name, data.Address, data.Active)
if created is None:
raise HTTPException(status_code = status.HTTP_400_BAD_REQUEST)
if created == -9:
raise HTTPException(status_code = status.HTTP_409_CONFLICT, detail = 'Settlement name or address exists')
return created
@routes.put("/{id}", status_code = status.HTTP_204_NO_CONTENT)
def EditSettlement(id: str, data: SettlementEditRequest):
edited = controller.EditSettlement(id, data.Name, data.Address, data.Active)
if edited is None:
raise HTTPException(status_code = status.HTTP_400_BAD_REQUEST)
if deleted == -10:
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND)
@routes.post('/done', status_code = status.HTTP_200_OK)
def RegisterSettlementDone(data: SettlementRegisterDoneRequest):
registered = controller.
@routes.delete("/{id}", status_code = status.HTTP_204_NO_CONTENT)
def DisableSettlement(id: str):
deleted = controller.DeleteSettlement(id)
if deleted is None:
raise HTTPException(status_code = status.HTTP_400_BAD_REQUEST)
if deleted == -10:
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND)
+118
View File
@@ -0,0 +1,118 @@
from backend.code.enums.errors_enum import ErrorTypeEnum
from backend.code.modules.database.database_sqlite import DatabaseSqliteModule
from backend.code.modules.users.repository import UserRepository
from backend.code.modules.accounts.repository import AccountRepository
from backend.code.models.responses.user_detail import UserDetailResponse
class UserController():
def __init__(self):
database = DatabaseSqliteModule()
self.repo = UserRepository(database)
self.account_repo = AccountRepository(database)
def ListUsers(self, params: str = None):
result = []
# Process filters
if params is not None:
params = self._OnProcessParams(params)
users = self.repo.FilterUsers(params)
if len(users) == 0:
return result
for _user in users:
user = UserDetailResponse(
Id = _user[0],
Name = _user[1],
Surnames = _user[2],
Email = _user[3],
Username = _user[4],
Locked = _user[5],
Active = _user[6]
)
result.append(user)
return result
def SelectUser(self, id: int):
user = self.repo.SelectUserById(id)
if user is None:
return
return UserDetailResponse(
Id = user[0],
Name = user[1],
Surnames = user[2],
Email = user[3],
Username = user[4],
Locked = user[5],
Active = user[6]
)
def RegisterUser(self, name: str, surnames: str, email: str, username: str = None, locked: bool = False, active: bool = True):
create_account = (username is not None)
# Check not exists
user_exists = self.repo.FilterUsers({'email': email})
if len(user_exists) > 0:
return ErrorTypeEnum.USER_EMAIL_EXISTS
if create_account:
account_exists = self.account_repo.SelectByUsername(username)
if account_exists is not None:
return ErrorTypeEnum.USER_ACCOUNT_EXISTS
# Register
user_id = self.repo.InsertUser(name, surnames, email)
if user_id is None:
return
if create_account:
account_id = self.account_repo.InsertAccount(user_id, username, locked, active)
if account_id is None:
return
return UserDetailResponse(
Id = user_id,
Name = name,
Surnames = surnames,
Email = email,
Username = username,
Locked = locked,
Active = active
)
def EditUser(self, id: int, name: str, surnames: str, email: str):
exists = self.repo.SelectUserById(id)
if exists is None:
return ErrorTypeEnum.USER_ID_NOT_EXISTS
edited = self.repo.UpdateUser(id, name, surnames, email)
if edited == 0:
return
return True
def DeleteUser(self, id: int):
exists = self.repo.SelectUserById(id)
if exists is None:
return ErrorTypeEnum.USER_ID_NOT_EXISTS
deleted = self.repo.DeleteUser(id)
if deleted == 0:
return
return True
#region Utilities
def _OnProcessParams(self, params: str):
result = {}
params = params.strip()
params = params.split(',')
for param in params:
field,value=param.split('=')
result[field.lower()]=value
return result
#endregion
+76
View File
@@ -0,0 +1,76 @@
from backend.code.modules.database.database import DatabaseModule
class UserRepository():
def __init__(self, repo: DatabaseModule):
self.conn = repo.conn
self.cursor = repo.cursor
def FilterUsers(self, filters: dict = None):
params = list()
sql = '''
SELECT u.*, a.username, a.locked, a.active
FROM users u
LEFT JOIN user_accounts a ON a.user_id = u.id
WHERE 1=1
'''
if filters is not None:
if 'name' in filters:
sql = sql + " AND u.name LIKE ?"
params.append(filters['name'])
if 'surnames' in filters:
sql = sql + " AND u.surnames LIKE ?"
params.append(filters['surnames'])
if 'email' in filters:
sql = sql + " AND u.email LIKE ?"
params.append(filters['email'])
if 'username' in filters:
sql = sql + " AND a.username LIKE ?"
params.append(filters['username'])
# print(sql)
self.cursor.execute(sql, params)
return self.cursor.fetchall()
def SelectUserById(self, id: int):
sql = '''
SELECT u.*, a.username, a.locked, a.active
FROM users u
LEFT JOIN user_accounts a ON a.user_id = u.id
WHERE u.id = ?
'''
self.cursor.execute(sql, [id])
return self.cursor.fetchone()
def InsertUser(self, name: str, surnames: str, email: str):
sql = '''
INSERT INTO users(name, surnames, email)
VALUES(?, ?, ?)
'''
self.cursor.execute(sql, [name, surnames, email])
self.conn.commit()
return self.cursor.lastrowid
def UpdateUser(self, id: int, name: str, surnames: str, email: str):
sql = '''
UPDATE users
SET name = ?, surnames = ?, email = ?
WHERE id = ?
'''
self.cursor.execute(sql, [name, surnames, email, id])
self.conn.commit()
return self.cursor.rowcount
def DeleteUser(self, id: int):
sql = '''
DELETE FROM users
WHERE id = ?
'''
self.cursor.execute(sql, [id])
self.conn.commit()
return self.cursor.rowcount
+60
View File
@@ -0,0 +1,60 @@
from fastapi import Query, APIRouter, status, Depends, Response, HTTPException
from backend.code.modules.users.controller import UserController
from backend.code.models.requests.user_register import UserRegisterRequest
from backend.code.models.requests.user_edit import UserEditRequest
from backend.code.models.responses.user_detail import UserDetailResponse
from backend.code.models.responses.user_created import UserCreatedResponse
routes = APIRouter(prefix="/users", tags=["User"])
controller = UserController()
@routes.get('', status_code = status.HTTP_200_OK, response_model = list[UserDetailResponse])
def ListUsers(params: str | None = Query(default = None, alias = "query")):
users = controller.ListUsers(params)
if users is None:
raise HTTPException(status_code = status.HTTP_400_BAD_REQUEST)
if len(users) == 0:
return Response(status_code = status.HTTP_204_NO_CONTENT)
return users
@routes.get('/{id}', status_code = status.HTTP_200_OK, response_model = UserDetailResponse)
def GetUser(id: int):
user = controller.SelectUser(id)
if user is None:
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND)
return user
@routes.post('', status_code = status.HTTP_201_CREATED, response_model = UserCreatedResponse)
def RegisterUser(data: UserRegisterRequest):
created = controller.RegisterUser(data.Name, data.Surnames, data.Email, data.Username, data.Locked, data.Active)
if created is None:
raise HTTPException(status_code = status.HTTP_400_BAD_REQUEST)
if created == -1:
raise HTTPException(status_code = status.HTTP_409_CONFLICT, detail = 'Email exists')
elif created == -2:
raise HTTPException(status_code = status.HTTP_409_CONFLICT, detail = 'Username exists')
return created
@routes.put('/{id}', status_code = status.HTTP_204_NO_CONTENT)
def EditUser(id: int, data: UserEditRequest):
edited = controller.EditUser(id, data.Name, data.Surnames, data.Email)
if edited is None:
raise HTTPException(status_code = status.HTTP_400_BAD_REQUEST)
if deleted == -3:
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND)
@routes.delete('/{id}', status_code = status.HTTP_204_NO_CONTENT)
def DeleteUser(id: int):
deleted = controller.DeleteUser(id)
if deleted is None:
raise HTTPException(status_code = status.HTTP_400_BAD_REQUEST)
if deleted == -3:
raise HTTPException(status_code = status.HTTP_404_NOT_FOUND)