diff --git a/README.md b/README.md index 5353dd5..921a526 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,52 @@ -# 2023.2-UnB-TV-Users -Repositório de Backend +# UnB-TV Users + +
+logo UNBTV
+ +## Sobre + +O projeto visa o desenvolvimento de uma aplicação Web e Mobile para a UnB-TV, com o objetivo de centralizar e disponibilizar de forma unificada todo o conteúdo oferecido pela UnB-TV, incluindo vídeos e transmissões ao vivo, sendo desenvolvida no segundo semestre de 2023 pelas disciplinas de EPS e MDS da Universidade de Brasília. + +## Ambientes + +[Documentação](https://github.com/fga-eps-mds/2023.2-UnB-TV-DOC) +[Users](https://github.com/fga-eps-mds/2023.2-UnB-TV-Users) +[Admin](https://github.com/fga-eps-mds/2023.2-UnB-TV-Admin) +[Video](https://github.com/fga-eps-mds/2023.2-UnB-TV-VideoService) +[Gateway](https://github.com/fga-eps-mds/2023.2-UnB-TV-API-Gateway) +[Frontend](https://github.com/fga-eps-mds/2023.2-UnB-TV-Frontend) + +## Acessando o repositório localmente + +### Requisitos + +- docker e docker compose + +Primeiro passo é instalar o docker e docker compose, para isso siga os passos de instalação do [docker](https://docs.docker.com/engine/install/) e [docker compose](https://docs.docker.com/compose/install/). + +Execute o servidor local: + +``` +docker compose up +``` + +Acessar o localhost em: http://localhost:8000 + +## Equipe + +| Foto | Nome | Github | Email | Matrícula | +| :-----------------------------------------------------------------------------------------------------------------------------: | :-------------------------------: | :----------------: | :----------------------------: | :-------: | +| Davi Marinho da Silva Campos | Davi Marinho da Silva Campos | @DaviMarinho | davii_marinho@hotmail.com | 190026600 | +| Diego Carlito Rodrigues de Souza | Diego Carlito Rodrigues de Souza | @Diego-Carlito | <221007690@aluno.unb.br> | 221007690 | +| Eric Akio Lages Nishimura | Eric Akio Lages Nishimura | @eric-kingu | <190105895@aluno.unb.br> | 190105895 | +| Gabriela Tiago de Araujo | Gabriela Tiago de Araujo | @GabrielaTiago | <190028475@aluno.unb.br> | 190028475 | +| Gabrielle Ribeiro Gomes | Gabrielle Ribeiro Gomes | @Gabrielle-Ribeiro | gabrielleribeiro2010@gmail.com | 170011020 | +| Geraldo Victor Alves Barbosa | Geraldo Victor Alves Barbosa | @geraldovictor | geraldovictor@outlook.com | 170011119 | +| Jennifer Costa Cansanção | Jennifer Costa Cansanção | @cansancaojennifer | <221007733@aluno.unb.br> | 221007733 | +| Jennifer Costa Cansanção | João Victor de Oliveira Matos | @joao15victor08 | joao15victor08@gmail.com | 170013987 | +| Lucas da Cunha Andrade | Lucas da Cunha Andrade | @nYCSTs | lucascandrade14@hotmail.com | 180105256 | +| Marcos Antonio Teles de Castilhos | Marcos Antonio Teles de Castilhos | @Marcosatc147 | <221008300@aluno.unb.br> | 221008300 | +| Raissa Andrade Silveira | Raissa Andrade Silveira | @RaisSabeAndrade | <221035077@aluno.unb.br> | 221035077 | +| Ricardo de Castro Loureiro | Ricardo de Castro Loureiro | @castroricardo1 | ricardoloureiro75@gmail.com | 200043111 | +| Ana Carolina Rodrigues Leite | Sávio Cunha de Carvalho | @savioc2 | saviocunha61@gmail.com | 180130889 | +| Vitória Aquere Matos | Vitória Aquere Matos | @vitoriaaquere | <190096616@aluno.unb.br> | 190096616 | diff --git a/sonar-project.properties b/sonar-project.properties index fe0902d..9e26314 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,13 +1,14 @@ sonar.projectKey=fga-eps-mds_2023.2-UnB-TV-Users sonar.organization=fga-eps-mds-1 -sonar.sources=src -sonar.tests=tests -# sonar.test.inclusions=tests/*.py -sonar.exclusions=__pycache__, tests -# sonar.testExecutionReportPaths -sonar.sourceEncoding=UTF-8 +sonar.host.url=https://sonarcloud.io +sonar.language=py +sonar.sources=src +sonar.exclusions=tests sonar.python.version=3.11.5 sonar.python.xunit.reportPath=junit.xml -sonar.python.coverage.reportPaths=coverage.xml \ No newline at end of file +sonar.python.coverage.reportPaths=coverage.xml +sonar.coverage.exclusions=tests/*.py + +sonar.sourceEncoding=UTF-8 \ No newline at end of file diff --git a/src/controller/authController.py b/src/controller/authController.py index 236fc87..1cc8d7f 100644 --- a/src/controller/authController.py +++ b/src/controller/authController.py @@ -15,6 +15,7 @@ prefix="/auth" ) + # Retorna conexões disponíveis @auth.get("/vinculo", response_model=authSchema.Connections) def get_connection(): connections = [member.value for member in enumeration.UserConnection] @@ -46,6 +47,7 @@ async def register(data: authSchema.UserCreate, db: Session = Depends(get_db)): return JSONResponse(status_code=201, content={ "status": "success" }) + # Recebe os dados de login @auth.post("/login", response_model=authSchema.Token) async def login(data: authSchema.UserLogin, db: Session = Depends(get_db)): user = userRepository.get_user_by_email(db, data.email) @@ -64,6 +66,7 @@ async def login(data: authSchema.UserLogin, db: Session = Depends(get_db)): return JSONResponse(status_code=200, content={ "access_token": access_token, "refresh_token": refresh_token, "token_type": "bearer" }) + # Recebe os dados do usuário provenientes de uma autenticação social @auth.post("/login/social") async def login_social(user: authSchema.UserSocial, db: Session = Depends(get_db)): existing_user = userRepository.get_user_by_email(db, user.email) @@ -86,7 +89,8 @@ async def login_social(user: authSchema.UserSocial, db: Session = Depends(get_db "is_new_user": is_new_user, "user_id": user_id }) - + + # trata da renovação de tokens de acesso @auth.post("/refresh", response_model=authSchema.RefreshTokenResponse) def refresh_token(token: dict = Depends(security.verify_token)): access_token=security.create_access_token(token) @@ -104,6 +108,7 @@ async def send_new_code(data: authSchema.SendNewCode, db: Session = Depends(get_ res = await send_mail.send_verification_code(email=data.email, code=user.activation_code) return JSONResponse(status_code=201, content={ "status": "success" }) + # Recebe dados de validação de conta @auth.patch('/activate-account') async def validate_account(data: authSchema.AccountValidation, db: Session = Depends(get_db)): user = userRepository.get_user_by_email(db, data.email) @@ -148,21 +153,26 @@ async def verify_reset_code(data: authSchema.ResetPasswordVerify, db: Session = return JSONResponse(status_code=200, content={ "status": "success" }) + # Atualizar senha de um usuário após uma solicitação de redefinição @auth.patch('/reset-password/change', response_model=userSchema.User) async def update_user_password(data: authSchema.ResetPasswordUpdate, db: Session = Depends(get_db)): user = userRepository.get_user_by_email(db, data.email) if not user: raise HTTPException(status_code=404, detail=errorMessages.USER_NOT_FOUND) + # Valida a senha informada if data.password and not security.validate_password(data.password): raise HTTPException(status_code=400, detail=errorMessages.INVALID_PASSWORD) + # Verifica se o usuario possui um reset code. Se não possuir, a solicitação é invalida e deve ser bloqueada if not user.password_reset_code: raise HTTPException(status_code=401, detail=errorMessages.INVALID_REQUEST) - + + # Verifica se o código corresponde if data.code != user.password_reset_code: raise HTTPException(status_code=400, detail=errorMessages.INVALID_RESET_PASSWORD_CODE) + # Faz procedimento de hash da senha e atualiza usuario hashed_password = security.get_password_hash(data.password) updated_user = userRepository.update_password(db, user, hashed_password) diff --git a/src/controller/userController.py b/src/controller/userController.py index 21756b9..da27673 100644 --- a/src/controller/userController.py +++ b/src/controller/userController.py @@ -71,6 +71,8 @@ async def delete_user(user_id: int, db: Session = Depends(get_db), token: dict = @user.patch("/role/{user_id}", response_model=userSchema.User) def update_role(user_id: int, db: Session = Depends(get_db), token: dict = Depends(security.verify_token)): + # Obtem email do usuario a partir de token. + # Verifica se o usuário é ADMIN user = userRepository.get_user_by_email(db, email=token['email']) if user.role != enumeration.UserRole.ADMIN.value: raise HTTPException(status_code=401, detail=errorMessages.NO_PERMISSION) @@ -81,6 +83,7 @@ def update_role(user_id: int, db: Session = Depends(get_db), token: dict = Depen if not user: raise HTTPException(status_code=404, detail=errorMessages.USER_NOT_FOUND) + # Obtem o valor da outra role e atribui a outra role para o usuario. Caso ele seja um USER => ADMIN, caso seja ADMIN => USER new_role = enumeration.UserRole.ADMIN.value if user.role == enumeration.UserRole.USER.value else enumeration.UserRole.USER.value user = userRepository.update_user_role(db, db_user=user, role=new_role) diff --git a/src/repository/userRepository.py b/src/repository/userRepository.py index b6313d9..7422d77 100644 --- a/src/repository/userRepository.py +++ b/src/repository/userRepository.py @@ -7,12 +7,25 @@ from domain import userSchema from model import userModel +# Obtem usuario a partir do seu ID def get_user(db: Session, user_id: int): return db.query(userModel.User).filter(userModel.User.id == user_id).first() +# Obtem usuario a partir do Email def get_user_by_email(db: Session, email: str): return db.query(userModel.User).filter(userModel.User.email == email).first() +''' +Obtem lista de usuarios. Possui filtragem: +Filtros: +name: filtrar por nome do usuario +email: filtrar por email do usuario +name_or_email: filtragem que aceita tanto nome quanto email (OR) +connection: filtragem pelo vinculo do usuario + +Também aceita offset e limit. Para offset pula a quantidade informada, +para o limit, controla a quantidade de usuarios retornada +''' def get_users(db: Session, users_filter: userSchema.UserListFilter): query = db.query(userModel.User) @@ -26,15 +39,20 @@ def get_users(db: Session, users_filter: userSchema.UserListFilter): if (users_filter.connection): query = query.filter(userModel.User.connection == users_filter.connection) + # Realiza o count para retornar para o front para realizar paginação total_count = query.count() + # Ordena a lista de usuarios por ordem alfabetica pelo nome query = query.order_by(userModel.User.name.asc()) + # Realiza a delimitação por offset if (users_filter.offset): query = query.offset(users_filter.offset) + # Realiza a limitação por quantidade retornada if (users_filter.limit): query = query.limit(users_filter.limit) + # Retorna todos os usuarios filtrados, dentro de eventuais limitações (offset ou limit) e o total (geral) return { "users": query.all(), "total": total_count } def create_user(db: Session, name, connection, email, password, activation_code): @@ -44,6 +62,7 @@ def create_user(db: Session, name, connection, email, password, activation_code) db.refresh(db_user) return db_user +# Cria um usuario por login social. Essa criação é especial pois o usuario criado por rede social não possui SENHA def create_user_social(db: Session, name, email): db_user = userModel.User( name=name,