From 536ee812eed4657cc3ccf3ad3bdcb20079976309 Mon Sep 17 00:00:00 2001 From: saurabhdhingra Date: Sat, 18 Jan 2025 21:46:24 +0530 Subject: [PATCH 1/6] First Commit --- .gitignore | 3 +++ PythonTask.pdf | Bin 19882 -> 0 bytes database.py | 7 +++++-- main.py | 21 +++++++++++++++++++++ models.py | 10 +++++----- schemas.py | 17 ++++++++++++----- 6 files changed, 46 insertions(+), 12 deletions(-) create mode 100644 .gitignore delete mode 100644 PythonTask.pdf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7716d0a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +secrets.env +/env +/__pycache__ \ No newline at end of file diff --git a/PythonTask.pdf b/PythonTask.pdf deleted file mode 100644 index 7e6a76af9b450b9ab08d3d636f8be2faddf9554c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19882 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 Cf7l)X diff --git a/database.py b/database.py index accf2f5..8dd46b8 100644 --- a/database.py +++ b/database.py @@ -2,9 +2,12 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker -// Free to use remote db or create a local database. Modify the URl appropriately -SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db" +from dotenv import load_dotenv +import os +load_dotenv("secrets.env") + +SQLALCHEMY_DATABASE_URL = os.getenv("DB_CONNECTION_STRING") engine = create_engine(SQLALCHEMY_DATABASE_URL) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() diff --git a/main.py b/main.py index f83e868..272e933 100644 --- a/main.py +++ b/main.py @@ -34,3 +34,24 @@ def read_user(user_id: int, db: Session = Depends(get_db)): raise HTTPException(status_code=404, detail="User not found") return user +@app.put("/users/{user_id}", response_model=schemas.User) +async def update_user(user_id: int, user: schemas.UserUpdate, db: Session = Depends(get_db)): + db_user = db.query(models.User).filter(models.User.id == user_id).first() + if not db_user: + raise HTTPException(status_code=404, detail="User not found") + for key, value in user.dict(exclude_unset=True).items(): + setattr(db_user, key, value) + db.commit() + db.refresh(db_user) + return db_user + + +@app.delete("/users/{user_id}", response_model=dict) +async def delete_user(user_id: int, db: Session = Depends(get_db)): + db_user = db.query(models.User).filter(models.User.id == user_id).first() + if not db_user: + raise HTTPException(status_code=404, detail="User not found") + db.delete(db_user) + db.commit() + return {"message": "User deleted successfully"} + diff --git a/models.py b/models.py index 0e42748..8ae35a7 100644 --- a/models.py +++ b/models.py @@ -5,10 +5,10 @@ class User(Base): __tablename__ = "users" id = Column(Integer, primary_key=True, index=True) - name = Column(String, index=True) + name = Column(String(30), index=True) age = Column(Integer) - gender = Column(String) - email = Column(String, unique=True, index=True) - city = Column(String, index=True) - interests = Column(ARRAY(String)) + gender = Column(String(1)) + email = Column(String(40), unique=True, index=True) + city = Column(String(30), index=True) + interests = Column(String(20)) diff --git a/schemas.py b/schemas.py index 5872710..3be25b7 100644 --- a/schemas.py +++ b/schemas.py @@ -1,20 +1,27 @@ -from pydantic import BaseModel -from typing import List +from typing import List, Optional +from pydantic import BaseModel, EmailStr class UserBase(BaseModel): name: str age: int gender: str - email: str + email: EmailStr city: str - interests: List[str] + interests: str class UserCreate(UserBase): pass +class UserUpdate(BaseModel): + name: Optional[str] = None + age: Optional[int] = None + gender: Optional[str] = None + email: Optional[EmailStr] = None + city: Optional[str] = None + interests: Optional[str] = None + class User(UserBase): id: int class Config: orm_mode = True - From 48390b4713c42bbc885b70889b57740a55cde89c Mon Sep 17 00:00:00 2001 From: saurabhdhingra Date: Sat, 18 Jan 2025 21:50:26 +0530 Subject: [PATCH 2/6] Changes --- models.py | 2 +- schemas.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/models.py b/models.py index 8ae35a7..9ef9fe2 100644 --- a/models.py +++ b/models.py @@ -10,5 +10,5 @@ class User(Base): gender = Column(String(1)) email = Column(String(40), unique=True, index=True) city = Column(String(30), index=True) - interests = Column(String(20)) + interests = Column(ARRAY(String(20))) diff --git a/schemas.py b/schemas.py index 3be25b7..b78498a 100644 --- a/schemas.py +++ b/schemas.py @@ -7,7 +7,7 @@ class UserBase(BaseModel): gender: str email: EmailStr city: str - interests: str + interests: List[str] class UserCreate(UserBase): pass @@ -18,7 +18,7 @@ class UserUpdate(BaseModel): gender: Optional[str] = None email: Optional[EmailStr] = None city: Optional[str] = None - interests: Optional[str] = None + interests: Optional[List[str]] = None class User(UserBase): id: int From 5e0bbb663c67b25ae07d9c19ea6b91721bb05e14 Mon Sep 17 00:00:00 2001 From: saurabhdhingra Date: Sat, 18 Jan 2025 21:51:11 +0530 Subject: [PATCH 3/6] Update ReadME --- README.md | 56 +------------------------------------------------------ 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/README.md b/README.md index 7432a62..7f9c2a5 100644 --- a/README.md +++ b/README.md @@ -1,55 +1 @@ -# Marriage Matchmaking App - -## Brief Description -The Marriage Matchmaking App is a simple backend application designed to help users find potential matches based on their profile information. The app allows users to create, read, update, and delete profiles with details such as name, age, gender, email, city, and interests. - -## What is Provided? -This project provides a basic skeleton for a FastAPI-based backend application. -#### Github repo: **https://github.com/abhishek-UM/UrbanMatch-PythonTask/tree/master** - -The provided code includes: - -### Basic Project Structure: - -- **main.py** : The main application file with basic CRUD operations for user profiles. -- **models.py**: SQLAlchemy models defining the User schema. -- **database.py**: Database configuration and setup. -- **schemas.py**: Pydantic schemas for data validation and serialization. - -### Functionality: - -- Create User Endpoint: Create a new user profile. -- Read Users Endpoint: Retrieve a list of user profiles. -- Read User by ID Endpoint: Retrieve a user profile by ID. -- SQLite Database: The application uses SQLite as the database to store user profiles. - -## What is Required? -### Tasks: -1. Add User Update Endpoint: - - Implement an endpoint to update user details by ID in the main.py file. -2. Add User Deletion Endpoint: - - Implement an endpoint to delete a user profile by ID. -3. Find Matches for a User: - - Implement an endpoint to find potential matches for a user based on their profile information. -4. Add Email Validation: - - Add validation to ensure the email field in user profiles contains valid email addresses. - -## Instructions: -Implement the required endpoints and email validation: - -1. Add the necessary code for the update, delete, match and validation endpoints -2. Test Your Implementation: - 1. Verify that users can be updated and deleted correctly. - 2. Check that matches are correctly retrieved for a given user. - 3. Ensure email validation is working as expected. - -## Submit Your Work: -Provide the updated code files (main.py, models.py, database.py, and schemas.py). -Include a brief report explaining your approach and any assumptions made. - - -### Prerequisites -- Python 3.7+ -- FastAPI -- SQLAlchemy -- SQLite +# Marriage Matchmaking App Assignment - Saurabh Dhingra From 5864001797150a642c5f1cce06330d0d853c27da Mon Sep 17 00:00:00 2001 From: saurabhdhingra Date: Sat, 18 Jan 2025 22:00:40 +0530 Subject: [PATCH 4/6] Adding matches endpoint --- main.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index 272e933..49747cf 100644 --- a/main.py +++ b/main.py @@ -37,7 +37,7 @@ def read_user(user_id: int, db: Session = Depends(get_db)): @app.put("/users/{user_id}", response_model=schemas.User) async def update_user(user_id: int, user: schemas.UserUpdate, db: Session = Depends(get_db)): db_user = db.query(models.User).filter(models.User.id == user_id).first() - if not db_user: + if db_user is None: raise HTTPException(status_code=404, detail="User not found") for key, value in user.dict(exclude_unset=True).items(): setattr(db_user, key, value) @@ -45,6 +45,28 @@ async def update_user(user_id: int, user: schemas.UserUpdate, db: Session = Depe db.refresh(db_user) return db_user +@app.get("/users/{user_id}/matches", response_model=list[schemas.User]) +def find_potential_matches(user_id: int, db: Session = Depends(get_db)): + user = db.query(models.User).filter(models.User.id == user_id).first() + if user is None: + raise HTTPException(status_code=404, detail="User not found") + + opposite_gender = "m" if user.gender == "f" else "f" + + + matches = ( + db.query(models.User) + .filter( + models.User.gender == opposite_gender, + models.User.age >= user.age - 2, + models.User.age <= user.age + 2, + models.User.id != user_id + ) + .all() + ) + + return matches + @app.delete("/users/{user_id}", response_model=dict) async def delete_user(user_id: int, db: Session = Depends(get_db)): From f76f30ae695837f8c53982809a6a563b34dad101 Mon Sep 17 00:00:00 2001 From: saurabhdhingra Date: Sat, 18 Jan 2025 22:04:33 +0530 Subject: [PATCH 5/6] Changes to match-making endpoint --- main.py | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/main.py b/main.py index 49747cf..306000e 100644 --- a/main.py +++ b/main.py @@ -45,28 +45,39 @@ async def update_user(user_id: int, user: schemas.UserUpdate, db: Session = Depe db.refresh(db_user) return db_user +from typing import Optional + @app.get("/users/{user_id}/matches", response_model=list[schemas.User]) -def find_potential_matches(user_id: int, db: Session = Depends(get_db)): +def find_potential_matches( + user_id: int, + min_age: Optional[int] = None, + max_age: Optional[int] = None, + city: Optional[str] = None, + db: Session = Depends(get_db), +): user = db.query(models.User).filter(models.User.id == user_id).first() - if user is None: + if not user: raise HTTPException(status_code=404, detail="User not found") opposite_gender = "m" if user.gender == "f" else "f" + if min_age is None: + min_age = user.age - 2 + if max_age is None: + max_age = user.age + 2 + - matches = ( - db.query(models.User) - .filter( - models.User.gender == opposite_gender, - models.User.age >= user.age - 2, - models.User.age <= user.age + 2, - models.User.id != user_id - ) - .all() + query = db.query(models.User).filter( + models.User.gender == opposite_gender, + models.User.age >= min_age, + models.User.age <= max_age, ) - return matches + if city: + query = query.filter(models.User.city == city) + matches = query.all() + return matches @app.delete("/users/{user_id}", response_model=dict) async def delete_user(user_id: int, db: Session = Depends(get_db)): From f214ee4041ab0e6181ac0c2853ec1c84720def36 Mon Sep 17 00:00:00 2001 From: saurabhdhingra Date: Sun, 19 Jan 2025 10:42:50 +0530 Subject: [PATCH 6/6] Corrections --- PythonTask.pdf | Bin 0 -> 19882 bytes main.py | 25 ++++++++++++------------- schemas.py | 9 +++++++-- 3 files changed, 19 insertions(+), 15 deletions(-) create mode 100644 PythonTask.pdf diff --git a/PythonTask.pdf b/PythonTask.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7e6a76af9b450b9ab08d3d636f8be2faddf9554c GIT binary patch literal 19882 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 Cf7l)X literal 0 HcmV?d00001 diff --git a/main.py b/main.py index 306000e..76df9ea 100644 --- a/main.py +++ b/main.py @@ -48,23 +48,22 @@ async def update_user(user_id: int, user: schemas.UserUpdate, db: Session = Depe from typing import Optional @app.get("/users/{user_id}/matches", response_model=list[schemas.User]) -def find_potential_matches( - user_id: int, - min_age: Optional[int] = None, - max_age: Optional[int] = None, - city: Optional[str] = None, - db: Session = Depends(get_db), -): +def find_potential_matches(user_id: int, requirements: schemas.MatchRequirements, db: Session = Depends(get_db)): user = db.query(models.User).filter(models.User.id == user_id).first() - if not user: + if user is None: raise HTTPException(status_code=404, detail="User not found") opposite_gender = "m" if user.gender == "f" else "f" - if min_age is None: + if requirements.min_age is None: min_age = user.age - 2 - if max_age is None: + else: + min_age = int(requirements.min_age) + + if requirements.max_age is None: max_age = user.age + 2 + else: + max_age = int(requirements.max_age) query = db.query(models.User).filter( @@ -73,8 +72,8 @@ def find_potential_matches( models.User.age <= max_age, ) - if city: - query = query.filter(models.User.city == city) + if requirements.city: + query = query.filter(models.User.city == requirements.city) matches = query.all() return matches @@ -82,7 +81,7 @@ def find_potential_matches( @app.delete("/users/{user_id}", response_model=dict) async def delete_user(user_id: int, db: Session = Depends(get_db)): db_user = db.query(models.User).filter(models.User.id == user_id).first() - if not db_user: + if db_user is None: raise HTTPException(status_code=404, detail="User not found") db.delete(db_user) db.commit() diff --git a/schemas.py b/schemas.py index b78498a..3b7540a 100644 --- a/schemas.py +++ b/schemas.py @@ -7,7 +7,7 @@ class UserBase(BaseModel): gender: str email: EmailStr city: str - interests: List[str] + interests: str class UserCreate(UserBase): pass @@ -18,10 +18,15 @@ class UserUpdate(BaseModel): gender: Optional[str] = None email: Optional[EmailStr] = None city: Optional[str] = None - interests: Optional[List[str]] = None + interests: Optional[str] = None class User(UserBase): id: int class Config: orm_mode = True + +class MatchRequirements(BaseModel): + min_age: Optional[int] = None + max_age: Optional[int] = None + city: Optional[str] = None