Skip to content

Commit

Permalink
Merge pull request #67 from hotosm/update-profile
Browse files Browse the repository at this point in the history
Update User Profile
  • Loading branch information
nrjadkry authored Jul 10, 2024
2 parents caaeea0 + 779910a commit a632da2
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 23 deletions.
8 changes: 3 additions & 5 deletions src/backend/app/db/db_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,12 @@ class DbUser(Base):
__tablename__ = "users"

id = cast(str, Column(String, primary_key=True))
username = cast(str, Column(String, nullable=False, unique=True))
email_address = cast(str, Column(String, nullable=False, unique=True))
password = cast(str, Column(String))
name = cast(str, Column(String))
is_active = cast(bool, Column(Boolean, default=False))
is_superuser = cast(bool, Column(Boolean, default=False))
profile_img = cast(str, Column(String, nullable=True))
name = cast(str, Column(String))
email_address = cast(str, Column(String, nullable=False, unique=True))
role = cast(UserRole, Column(Enum(UserRole), default=UserRole.DRONE_PILOT))
date_registered = cast(datetime, Column(DateTime, default=timestamp))


Expand Down Expand Up @@ -73,7 +71,6 @@ class DbTask(Base):
)
project_task_index = cast(int, Column(Integer))
outline = cast(WKBElement, Column(Geometry("POLYGON", srid=4326)))
task_status = cast(TaskStatus, Column(Enum(TaskStatus), default=TaskStatus.READY))


class DbProject(Base):
Expand Down Expand Up @@ -269,6 +266,7 @@ class GroundControlPoint(Base):
class DbUserProfile(Base):
__tablename__ = "user_profile"
user_id = cast(str, Column(String, ForeignKey("users.id"), primary_key=True))
role = cast(UserRole, Column(Enum(UserRole), default=UserRole.DRONE_PILOT))
phone_number = cast(str, Column(String))
country = cast(str, Column(String))
city = cast(str, Column(String))
Expand Down
67 changes: 67 additions & 0 deletions src/backend/app/migrations/versions/3293e9c98b2a_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""
Revision ID: 3293e9c98b2a
Revises: 06668eb5d14a
Create Date: 2024-07-10 04:52:41.412683
"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision: str = "3293e9c98b2a"
down_revision: Union[str, None] = "06668eb5d14a"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("tasks", "task_status")
op.add_column(
"user_profile",
sa.Column(
"role",
sa.Enum("PROJECT_CREATOR", "DRONE_PILOT", name="userrole"),
nullable=True,
),
)
op.drop_column("users", "role")
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column(
"users",
sa.Column(
"role",
postgresql.ENUM("PROJECT_CREATOR", "DRONE_PILOT", "BOTH", name="userrole"),
autoincrement=False,
nullable=True,
),
)
op.drop_column("user_profile", "role")
op.add_column(
"tasks",
sa.Column(
"task_status",
postgresql.ENUM(
"READY",
"LOCKED_FOR_MAPPING",
"MAPPED",
"LOCKED_FOR_VALIDATION",
"VALIDATED",
"INVALIDATED",
"BAD",
"SPLIT",
name="taskstatus",
),
autoincrement=False,
nullable=True,
),
)
# ### end Alembic commands ###
35 changes: 35 additions & 0 deletions src/backend/app/migrations/versions/88ae62ec8876_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
Revision ID: 88ae62ec8876
Revises: 3293e9c98b2a
Create Date: 2024-07-10 05:21:58.749137
"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = "88ae62ec8876"
down_revision: Union[str, None] = "3293e9c98b2a"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint("users_username_key", "users", type_="unique")
op.drop_column("users", "username")
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column(
"users",
sa.Column("username", sa.VARCHAR(), autoincrement=False, nullable=False),
)
op.create_unique_constraint("users_username_key", "users", ["username"])
# ### end Alembic commands ###
1 change: 0 additions & 1 deletion src/backend/app/models/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ class DroneType(IntEnum):
class UserRole(IntEnum, Enum):
PROJECT_CREATOR = 1
DRONE_PILOT = 2
BOTH = 3


class State(int, Enum):
Expand Down
30 changes: 23 additions & 7 deletions src/backend/app/users/user_crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from app.users.user_schemas import AuthUser, ProfileUpdate
from databases import Database
from fastapi import HTTPException
from app.models.enums import UserRole

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

Expand Down Expand Up @@ -103,10 +102,10 @@ async def get_or_create_user(
try:
update_sql = """
INSERT INTO users (
id, username, email_address, profile_img, role
id, name, email_address, profile_img, is_active, is_superuser, date_registered
)
VALUES (
:user_id, :username, :email_address, :profile_img, :role
:user_id, :name, :email_address, :profile_img, False, False, now()
)
ON CONFLICT (id)
DO UPDATE SET profile_img = :profile_img;
Expand All @@ -116,10 +115,9 @@ async def get_or_create_user(
update_sql,
{
"user_id": str(user_data.id),
"username": user_data.email, # FIXME: remove this
"name": user_data.name,
"email_address": user_data.email,
"profile_img": user_data.img_url,
"role": UserRole.DRONE_PILOT.name,
},
)
return user_data
Expand Down Expand Up @@ -154,12 +152,13 @@ async def update_user_profile(

try:
profile_query = """
INSERT INTO user_profile (user_id, phone_number, country, city, organization_name, organization_address, job_title, notify_for_projects_within_km,
INSERT INTO user_profile (user_id, role, phone_number, country, city, organization_name, organization_address, job_title, notify_for_projects_within_km,
experience_years, drone_you_own, certified_drone_operator)
VALUES (:user_id, :phone_number, :country, :city, :organization_name, :organization_address, :job_title, :notify_for_projects_within_km ,
VALUES (:user_id, :role, :phone_number, :country, :city, :organization_name, :organization_address, :job_title, :notify_for_projects_within_km ,
:experience_years, :drone_you_own, :certified_drone_operator)
ON CONFLICT (user_id)
DO UPDATE SET
role = :role,
phone_number = :phone_number,
country = :country,
city = :city,
Expand All @@ -176,6 +175,7 @@ async def update_user_profile(
profile_query,
{
"user_id": user_id,
"role": profile_update.role,
"phone_number": profile_update.phone_number,
"country": profile_update.country,
"city": profile_update.city,
Expand All @@ -188,6 +188,22 @@ async def update_user_profile(
"certified_drone_operator": profile_update.certified_drone_operator,
},
)

# If password is provided, update the users table
if profile_update.password:
password_update_query = """
UPDATE users
SET password = :password
WHERE id = :user_id;
"""
await db.execute(
password_update_query,
{
"password": get_password_hash(profile_update.password),
"user_id": user_id,
},
)

return True
except Exception as e:
raise HTTPException(status_code=400, detail=str(e)) from e
24 changes: 14 additions & 10 deletions src/backend/app/users/user_schemas.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from pydantic import BaseModel, EmailStr, ValidationInfo, Field
from pydantic.functional_validators import field_validator
from typing import Optional
from app.models.enums import UserRole


class AuthUser(BaseModel):
"""The user model returned from Google OAuth2."""

id: str
email: EmailStr
name: str
img_url: Optional[str] = None


Expand Down Expand Up @@ -75,13 +77,15 @@ class UserCreate(UserBase):


class ProfileUpdate(BaseModel):
phone_number: Optional[str]
country: Optional[str]
city: Optional[str]
organization_name: Optional[str]
organization_address: Optional[str]
job_title: Optional[str]
notify_for_projects_within_km: Optional[int]
drone_you_own: Optional[str]
experience_years: Optional[int]
certified_drone_operator: Optional[bool]
phone_number: Optional[str] = None
country: Optional[str] = None
city: Optional[str] = None
organization_name: Optional[str] = None
organization_address: Optional[str] = None
job_title: Optional[str] = None
notify_for_projects_within_km: Optional[int] = None
drone_you_own: Optional[str] = None
experience_years: Optional[int] = None
certified_drone_operator: Optional[bool] = False
role: Optional[UserRole] = UserRole.DRONE_PILOT.name
password: Optional[str] = None

0 comments on commit a632da2

Please sign in to comment.