Skip to content

Commit 899a29d

Browse files
authored
Merge pull request #235 from cuappdev/yitbrek/users
Changes to how users are added and deleted
2 parents da2e14b + 8caf28f commit 899a29d

4 files changed

Lines changed: 98 additions & 45 deletions

File tree

requirements.txt

3.42 KB
Binary file not shown.

src/models/user.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class User(Base):
4848
foreign_keys="Friendship.friend_id",
4949
back_populates="friend")
5050

51+
workouts = relationship("Workout", cascade="all, delete-orphan", back_populates="user")
5152
def add_friend(self, friend):
5253
# Check if friendship already exists
5354
existing = Friendship.query.filter(

src/models/workout.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ class Workout(Base):
2121
workout_time = Column(DateTime(timezone=True), nullable=False, server_default=text("CURRENT_TIMESTAMP")) # should this be nullable?
2222
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
2323
facility_id = Column(Integer, ForeignKey("facility.id"), nullable=False)
24+
25+
user = relationship("User", back_populates='workouts')

src/schema.py

Lines changed: 95 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import binascii
2+
13
import graphene
24
import base64
35
import os
@@ -32,6 +34,8 @@
3234
import logging
3335
from zoneinfo import ZoneInfo
3436
from sqlalchemy import func, cast, Date
37+
import boto3
38+
from botocore.exceptions import ClientError
3539

3640
local_tz = ZoneInfo("America/New_York")
3741

@@ -833,81 +837,103 @@ class Arguments:
833837
def mutate(self, info, name, net_id, email, encoded_image=None):
834838
# Check if a user with the given NetID already exists
835839
existing_user = db_session.query(UserModel).filter(UserModel.net_id == net_id).first()
836-
final_photo_url = None
837840
if existing_user:
838841
raise GraphQLError("NetID already exists.")
839842

843+
final_photo_url = None
844+
840845
if encoded_image:
841-
upload_url = os.getenv("DIGITAL_OCEAN_URL")
842-
if not upload_url:
843-
raise GraphQLError("Upload URL not configured.")
844846

845-
headers = {"Content-Type": "application/json"}
847+
s3 = boto3.client(
848+
"s3",
849+
endpoint_url=os.getenv("DIGITAL_OCEAN_URL"),
850+
aws_access_key_id=os.getenv("DIGITAL_OCEAN_ACCESS"),
851+
aws_secret_access_key=os.getenv("DIGITAL_OCEAN_SECRET_ACCESS")
852+
)
846853

847-
image_bytes = base64.b64decode(encoded_image)
848-
files = {"image": ("profile.png", image_bytes, "image/png")}
849-
data = {"bucket": os.getenv("BUCKET_NAME")}
850854
try:
851-
response = requests.post(upload_url, files=files, data=data)
852-
response.raise_for_status()
853-
json_response = response.json()
854-
final_photo_url = json_response.get("data")
855-
if not final_photo_url:
856-
raise GraphQLError("No URL returned from upload service.")
857-
except requests.exceptions.RequestException as e:
858-
print(f"Request failed: {e}")
859-
raise GraphQLError(f"Failed to upload photo: {e}")
855+
image_data = base64.b64decode(encoded_image, validate=True)
856+
except (binascii.Error, ValueError) as err:
857+
raise GraphQLError("Invalid profile image encoding.")
860858

859+
try:
860+
bucket = "appdev-upload"
861+
path = f"uplift-dev/user-profile/{net_id}-profile.png"
862+
region = "nyc3"
863+
864+
s3.put_object(
865+
Bucket=bucket,
866+
Key=path,
867+
Body=image_data,
868+
ContentType="image/png",
869+
ACL="public-read"
870+
)
871+
872+
final_photo_url = f"https://{bucket}.{region}.digitaloceanspaces.com/{path}"
873+
except ClientError as e:
874+
print("Upload error:", e)
875+
raise GraphQLError("Error uploading user profile picture.")
876+
861877
new_user = UserModel(name=name, net_id=net_id, email=email, encoded_image=final_photo_url)
862878
db_session.add(new_user)
863879
db_session.commit()
864880

865881
return new_user
866882

867883

868-
class EditUser(graphene.Mutation):
884+
class EditUserById(graphene.Mutation):
869885
class Arguments:
886+
user_id = graphene.Int(required=True)
870887
name = graphene.String(required=False)
871-
net_id = graphene.String(required=True)
872888
email = graphene.String(required=False)
873889
encoded_image = graphene.String(required=False)
874890

875891
Output = User
876892

877-
def mutate(self, info, net_id, name=None, email=None, encoded_image=None):
878-
existing_user = db_session.query(UserModel).filter(UserModel.net_id == net_id).first()
893+
@jwt_required()
894+
def mutate(self, info, user_id, name=None, email=None, encoded_image=None):
895+
existing_user = db_session.query(UserModel).filter(UserModel.id == user_id).first()
896+
879897
if not existing_user:
880-
raise GraphQLError("User with given net id does not exist.")
881-
898+
raise GraphQLError("User with given id does not exist.")
899+
if get_jwt_identity() != user_id:
900+
raise GraphQLError("Unauthorized operation")
882901
if name is not None:
883902
existing_user.name = name
884903
if email is not None:
885904
existing_user.email = email
886905
if encoded_image is not None:
887-
upload_url = os.getenv("DIGITAL_OCEAN_URL") # Base URL for upload endpoint
888-
if not upload_url:
889-
raise GraphQLError("Upload URL not configured.")
890-
891-
payload = {
892-
"bucket": os.getenv("BUCKET_NAME", "DEV_BUCKET"),
893-
"image": encoded_image, # Base64-encoded image string
894-
}
895-
headers = {"Content-Type": "application/json"}
896-
897-
print(f"Uploading image with payload: {payload}")
906+
final_photo_url = None
907+
s3 = boto3.client(
908+
"s3",
909+
endpoint_url=os.getenv("DIGITAL_OCEAN_URL"),
910+
aws_access_key_id=os.getenv("DIGITAL_OCEAN_ACCESS"),
911+
aws_secret_access_key=os.getenv("DIGITAL_OCEAN_SECRET_ACCESS")
912+
)
913+
914+
try:
915+
image_data = base64.b64decode(encoded_image, validate=True)
916+
except (binascii.Error, ValueError) as err:
917+
raise GraphQLError("Invalid profile image encoding.")
898918

899919
try:
900-
response = requests.post(upload_url, json=payload, headers=headers)
901-
response.raise_for_status()
902-
json_response = response.json()
903-
print(f"Upload API response: {json_response}")
904-
final_photo_url = json_response.get("data")
905-
if not final_photo_url:
906-
raise GraphQLError("No URL returned from upload service.")
920+
bucket = "appdev-upload"
921+
path = f"uplift-dev/user-profile/{existing_user.net_id}-profile.png"
922+
region = "nyc3"
923+
924+
s3.put_object(
925+
Bucket=bucket,
926+
Key=path,
927+
Body=image_data,
928+
ContentType="image/png",
929+
ACL="public-read"
930+
)
931+
932+
final_photo_url = f"https://{bucket}.{region}.digitaloceanspaces.com/{path}"
907933
existing_user.encoded_image = final_photo_url
908-
except requests.exceptions.RequestException as e:
909-
print(f"Request failed: {e}")
910-
raise GraphQLError("Failed to upload photo.")
934+
except ClientError as e:
935+
print("Upload error:", e)
936+
raise GraphQLError("Error adding new user profile picture.")
911937

912938
db_session.commit()
913939
return existing_user
@@ -1063,6 +1089,7 @@ def mutate(self, info, user_id, workout_goal):
10631089

10641090
db_session.commit()
10651091
return user
1092+
10661093
class logWorkout(graphene.Mutation):
10671094
class Arguments:
10681095
workout_time = graphene.DateTime(required=True)
@@ -1157,11 +1184,34 @@ class Arguments:
11571184

11581185
Output = User
11591186

1187+
@jwt_required()
11601188
def mutate(self, info, user_id):
11611189
# Check if user exists
11621190
user = User.get_query(info).filter(UserModel.id == user_id).first()
1191+
11631192
if not user:
11641193
raise GraphQLError("User with given ID does not exist.")
1194+
1195+
if get_jwt_identity() != user_id:
1196+
raise GraphQLError("Unauthorized operation")
1197+
1198+
s3 = boto3.client(
1199+
"s3",
1200+
endpoint_url=os.getenv("DIGITAL_OCEAN_URL"),
1201+
aws_access_key_id=os.getenv("DIGITAL_OCEAN_ACCESS"),
1202+
aws_secret_access_key=os.getenv("DIGITAL_OCEAN_SECRET_ACCESS")
1203+
)
1204+
1205+
if user.encoded_image:
1206+
try:
1207+
s3.delete_object(
1208+
Bucket="appdev-upload",
1209+
Key=f"uplift-dev/user-profile/{user.net_id}-profile.png",
1210+
)
1211+
except ClientError as e:
1212+
print("Delete error:", e)
1213+
raise GraphQLError("Error deleting user profile picture")
1214+
11651215
db_session.delete(user)
11661216
db_session.commit()
11671217
return user
@@ -1440,7 +1490,7 @@ def mutate(self, info, user_id):
14401490
class Mutation(graphene.ObjectType):
14411491
create_giveaway = CreateGiveaway.Field(description="Creates a new giveaway.")
14421492
create_user = CreateUser.Field(description="Creates a new user.")
1443-
edit_user = EditUser.Field(description="Edit a new user.")
1493+
edit_user = EditUserById.Field(description="Edit a new user by id.")
14441494
enter_giveaway = EnterGiveaway.Field(description="Enters a user into a giveaway.")
14451495
set_workout_goals = SetWorkoutGoals.Field(description="Set a user's workout goals.")
14461496
log_workout = logWorkout.Field(description="Log a user's workout.")

0 commit comments

Comments
 (0)