Skip to content

Commit

Permalink
HAN-72: add user fields (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
feijooso authored Apr 4, 2024
2 parents 7251a41 + 6e84896 commit 4b8793e
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -157,5 +157,5 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/
.DS_Store
16 changes: 10 additions & 6 deletions app/docker/tablas.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ CREATE TABLE IF NOT EXISTS users_service.users (
name VARCHAR(255),
email VARCHAR(255) UNIQUE NOT NULL,
gender VARCHAR(20),
photo VARCHAR(255)
photo VARCHAR(255),
birthdate DATE,
location JSONB,
nickname VARCHAR(30),
biography VARCHAR(255)
);

INSERT INTO
users_service.users (name, email)
VALUES ('Agus', 'agus@fi.uba.ar'),
('Pach', 'pach@fi.uba.ar'),
('Sofi', 'sofi@fi.uba.ar'),
('Violeta', 'violeta@fi.uba.ar');
users_service.users (name, email, birthdate, location)
VALUES ('Agus', 'agus@fi.uba.ar', TO_DATE('1999-01-29', 'YYYY-MM-DD'), '{"lat": 20, "long": 100}'),
('Pach', 'pach@fi.uba.ar', TO_DATE('1999-08-06', 'YYYY-MM-DD'), '{"lat": 10, "long": 200}'),
('Sofi', 'sofi@fi.uba.ar', TO_DATE('1998-04-26', 'YYYY-MM-DD'), '{"lat": 1190, "long": 500}'),
('Violeta', 'violeta@fi.uba.ar', TO_DATE('1998-05-12', 'YYYY-MM-DD'), '{"lat": 330, "long": 2333}');
9 changes: 9 additions & 0 deletions app/exceptions/UserException.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ def __init__(self, id: int):
super().__init__(status_code=status_code, detail=detail)


class InvalidData(HTTPException):
def __init__(self):
status_code = status.HTTP_400_BAD_REQUEST
super().__init__(
status_code=status_code,
detail="Invalid user data was provided"
)


class InvalidURL(HTTPException):
def __init__(self, id: int):
status_code = status.HTTP_400_BAD_REQUEST
Expand Down
6 changes: 5 additions & 1 deletion app/models/users.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from sqlalchemy import Column, Integer, String
from sqlalchemy import Column, Integer, String, JSON, Date
from models.database import Base
from os import environ

Expand All @@ -13,3 +13,7 @@ class User(Base):
email = Column(String, nullable=False)
gender = Column(String, nullable=True)
photo = Column(String, nullable=True)
birthdate = Column(Date, nullable=True)
location = Column(JSON, nullable=True)
nickname = Column(String, nullable=True)
biography = Column(String, nullable=True)
13 changes: 13 additions & 0 deletions app/repository/Users.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import Optional
from models.database import Base
from models.users import User
from datetime import date


class UsersRepository:
Expand Down Expand Up @@ -48,6 +49,10 @@ def create_user(
name: Optional[str] = None,
gender: Optional[str] = None,
photo: Optional[str] = None,
nickname: Optional[str] = None,
biography: Optional[str] = None,
location: Optional[dict] = None,
birthdate: Optional[date] = None
) -> User:
user_data = {"email": email}

Expand All @@ -57,6 +62,14 @@ def create_user(
user_data["gender"] = gender
if photo is not None:
user_data["photo"] = photo
if location is not None:
user_data["location"] = location
if birthdate is not None:
user_data["birthdate"] = birthdate
if nickname is not None:
user_data["nickname"] = nickname
if biography is not None:
user_data["biography"] = biography

new_user = User(**user_data)
self.session.add(new_user)
Expand Down
20 changes: 18 additions & 2 deletions app/schemas/Schemas.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import date
from pydantic import BaseModel
from typing import Optional
from typing import Optional, Dict


class UserSchema(BaseModel):
Expand All @@ -8,10 +9,21 @@ class UserSchema(BaseModel):
email: str
gender: str
photo: str
birthdate: date
location: Dict
nickname: str
biography: str


class CreateUserSchema(BaseModel):
email: str
name: Optional[str] = None
gender: Optional[str] = None
photo: Optional[str] = None
birthdate: Optional[date] = None
location: Optional[Dict] = None
nickname: Optional[str] = None
biography: Optional[str] = None


class LoginRequest(BaseModel):
Expand All @@ -21,4 +33,8 @@ class LoginRequest(BaseModel):
class UpdateUserSchema(BaseModel):
name: Optional[str] = None
gender: Optional[str] = None
photo: str
photo: Optional[str] = None
birthdate: Optional[date] = None
location: Optional[Dict] = None
nickname: Optional[str] = None
biography: Optional[str] = None
42 changes: 24 additions & 18 deletions app/service/Users.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from exceptions.UserException import UserNotFound, InvalidURL
from exceptions.UserException import UserNotFound, InvalidData, InvalidURL
from exceptions.LoginException import AuthenticationError
from models.users import User
from repository.Users import UsersRepository
Expand All @@ -21,16 +21,30 @@ def get_all_users(self):
return self.user_repository.get_all_users()

def create_user(self, user_data: dict):
email = user_data.get("email")
return self.user_repository.create_user(email)
if not self._validate_location(user_data.get("location")):
raise InvalidData()
return self.user_repository.create_user(**user_data)

def update_user(self, user_id: int, update_data: dict):
# TODO: aca habria que chequear a partir del token, session o algo que
# es el propio usuario editando sus datos y no permitir
# que un usuario edite los de un tercero
self.get_user(user_id)
filtered_update_data = {k: v for k, v in update_data.items()
if v is not None}
if 'photo' in filtered_update_data:
photo_url = filtered_update_data['photo']
if not re.match(r'^https?://(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,6}'
r'(?:/[^/#?]+)+(?:\?.*)?$', photo_url):
raise InvalidURL("Invalid photo URL")
self.user_repository.edit_user(user_id, filtered_update_data)

def login(self, auth_code: str):
access_token = self._get_access_token(auth_code)
if access_token is None:
raise AuthenticationError("Authentication code is invalid")

user_info = self._get_user_info(access_token)
print(user_info)
user = self.user_repository.get_user_by_email(user_info["email"])

if user is None:
Expand Down Expand Up @@ -72,17 +86,9 @@ def _get_user_info(self, access_token):
user_data['photo'] = response.json().get("picture")
return user_data

def update_user(self, user_id: int, update_data: dict):
# TODO: aca habria que chequear a partir del token, session o algo que
# es el propio usuario editando sus datos y no permitir
# que un usuario edite los de un tercero
self.get_user(user_id)
filtered_update_data = {k: v for k, v in update_data.items()
if v is not None}
if 'photo' in filtered_update_data:
photo_url = filtered_update_data['photo']
if not re.match(r'^https?://(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,6}'
r'(?:/[^/#?]+)+\.(?:jpg|jpeg|png|gif)$',
photo_url):
raise InvalidURL("Invalid photo URL")
self.user_repository.edit_user(user_id, filtered_update_data)
def _validate_location(self, location):
if "lat" in location and "long" in location:
if -90 <= location["lat"] <= 90 and \
-180 <= location["long"] <= 180:
return True
return False

0 comments on commit 4b8793e

Please sign in to comment.