mirror of
https://github.com/joaovitoriasilva/endurain.git
synced 2026-01-10 08:17:59 -05:00
Backend optimziation
Activity controller Gear controller
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -4,268 +4,339 @@ from . import sessionController
|
||||
from jose import JWTError
|
||||
from fastapi.responses import JSONResponse
|
||||
from db.db import (
|
||||
get_db_session,
|
||||
Follower,
|
||||
)
|
||||
from dependencies import get_db_session
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||
|
||||
|
||||
# Define an HTTP GET route to retrieve the number of users
|
||||
@router.get("/followers/user/{user_id}/targetUser/{target_user_id}")
|
||||
async def read_followers_user_specific_user(user_id: int, target_user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def read_followers_user_specific_user(
|
||||
user_id: int,
|
||||
target_user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Query the specific follower record
|
||||
follower = db_session.query(Follower).filter(
|
||||
(Follower.follower_id == user_id) & (Follower.following_id == target_user_id)
|
||||
).first()
|
||||
# Query the specific follower record
|
||||
follower = (
|
||||
db_session.query(Follower)
|
||||
.filter(
|
||||
(Follower.follower_id == user_id)
|
||||
& (Follower.following_id == target_user_id)
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
if follower:
|
||||
# User follows target_user_id or vice versa
|
||||
response_data = {
|
||||
"follower_id": user_id,
|
||||
"following_id": target_user_id,
|
||||
"is_accepted": follower.is_accepted
|
||||
}
|
||||
return JSONResponse(content=response_data, status_code=200)
|
||||
if follower:
|
||||
# User follows target_user_id or vice versa
|
||||
response_data = {
|
||||
"follower_id": user_id,
|
||||
"following_id": target_user_id,
|
||||
"is_accepted": follower.is_accepted,
|
||||
}
|
||||
return JSONResponse(content=response_data, status_code=200)
|
||||
|
||||
# Users are not following each other
|
||||
return JSONResponse(content={"detail": "Users are not following each other."}, status_code=404)
|
||||
# Users are not following each other
|
||||
return JSONResponse(
|
||||
content={"detail": "Users are not following each other."}, status_code=404
|
||||
)
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
|
||||
|
||||
@router.get("/followers/user/{user_id}/followers/count/all")
|
||||
async def get_user_follower_count_all(user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def get_user_follower_count_all(
|
||||
user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
follower_count = db_session.query(Follower).filter(
|
||||
Follower.follower_id == user_id
|
||||
).count()
|
||||
follower_count = (
|
||||
db_session.query(Follower).filter(Follower.follower_id == user_id).count()
|
||||
)
|
||||
|
||||
# Respond with the count
|
||||
return {"follower_count": follower_count}
|
||||
# Respond with the count
|
||||
return {"follower_count": follower_count}
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
|
||||
|
||||
@router.get("/followers/user/{user_id}/followers/count")
|
||||
async def get_user_follower_count(user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def get_user_follower_count(
|
||||
user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Query for the count of entries where user_id is equal to Follower.follower_id
|
||||
follower_count = db_session.query(Follower).filter(
|
||||
(Follower.follower_id == user_id) & (Follower.is_accepted == True)
|
||||
).count()
|
||||
# Query for the count of entries where user_id is equal to Follower.follower_id
|
||||
follower_count = (
|
||||
db_session.query(Follower)
|
||||
.filter((Follower.follower_id == user_id) & (Follower.is_accepted == True))
|
||||
.count()
|
||||
)
|
||||
|
||||
# Respond with the count
|
||||
return {"follower_count": follower_count}
|
||||
# Respond with the count
|
||||
return {"follower_count": follower_count}
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
|
||||
|
||||
@router.get("/followers/user/{user_id}/followers/all")
|
||||
async def get_user_follower_all(user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def get_user_follower_all(
|
||||
user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Query for the entries where both conditions are met
|
||||
followers = db_session.query(Follower).filter(
|
||||
Follower.following_id == user_id
|
||||
).all()
|
||||
# Query for the entries where both conditions are met
|
||||
followers = (
|
||||
db_session.query(Follower).filter(Follower.following_id == user_id).all()
|
||||
)
|
||||
|
||||
# Convert the query result to a list of dictionaries
|
||||
followers_list = [{"follower_id": follower.follower_id, "is_accepted": follower.is_accepted}
|
||||
for follower in followers]
|
||||
# Convert the query result to a list of dictionaries
|
||||
followers_list = [
|
||||
{"follower_id": follower.follower_id, "is_accepted": follower.is_accepted}
|
||||
for follower in followers
|
||||
]
|
||||
|
||||
# Respond with the list of followers
|
||||
return {"followers": followers_list}
|
||||
# Respond with the list of followers
|
||||
return {"followers": followers_list}
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
|
||||
|
||||
@router.get("/followers/user/{user_id}/following/count/all")
|
||||
async def get_user_follower_count_all(user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def get_user_following_count_all(
|
||||
user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
following_count = db_session.query(Follower).filter(
|
||||
Follower.following_id == user_id
|
||||
).count()
|
||||
following_count = (
|
||||
db_session.query(Follower).filter(Follower.following_id == user_id).count()
|
||||
)
|
||||
|
||||
# Respond with the count
|
||||
return {"following_count": following_count}
|
||||
# Respond with the count
|
||||
return {"following_count": following_count}
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
|
||||
|
||||
@router.get("/followers/user/{user_id}/following/count")
|
||||
async def get_user_follower_count(user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def get_user_following_count(
|
||||
user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Query for the count of entries where user_id is equal to Follower.follower_id
|
||||
following_count = db_session.query(Follower).filter(
|
||||
(Follower.following_id == user_id) & (Follower.is_accepted == True)
|
||||
).count()
|
||||
# Query for the count of entries where user_id is equal to Follower.follower_id
|
||||
following_count = (
|
||||
db_session.query(Follower)
|
||||
.filter((Follower.following_id == user_id) & (Follower.is_accepted == True))
|
||||
.count()
|
||||
)
|
||||
|
||||
# Respond with the count
|
||||
return {"following_count": following_count}
|
||||
# Respond with the count
|
||||
return {"following_count": following_count}
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
|
||||
|
||||
@router.get("/followers/user/{user_id}/following/all")
|
||||
async def get_user_following_all(user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def get_user_following_all(
|
||||
user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Query for the entries where both conditions are met
|
||||
followings = db_session.query(Follower).filter(
|
||||
Follower.follower_id == user_id
|
||||
).all()
|
||||
# Query for the entries where both conditions are met
|
||||
followings = (
|
||||
db_session.query(Follower).filter(Follower.follower_id == user_id).all()
|
||||
)
|
||||
|
||||
# Convert the query result to a list of dictionaries
|
||||
following_list = [{"following_id": following.following_id, "is_accepted": following.is_accepted}
|
||||
for following in followings]
|
||||
# Convert the query result to a list of dictionaries
|
||||
following_list = [
|
||||
{
|
||||
"following_id": following.following_id,
|
||||
"is_accepted": following.is_accepted,
|
||||
}
|
||||
for following in followings
|
||||
]
|
||||
|
||||
# Respond with the list of following
|
||||
return {"followings": following_list}
|
||||
# Respond with the list of following
|
||||
return {"followings": following_list}
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
|
||||
@router.put("/followers/accept/user/{user_id}/targetUser/{target_user_id}")
|
||||
async def accept_follow(user_id: int, target_user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def accept_follow(
|
||||
user_id: int,
|
||||
target_user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Check if the follow relationship exists and is not accepted yet
|
||||
follow_request = db_session.query(Follower).filter(
|
||||
(Follower.follower_id == target_user_id) & (Follower.following_id == user_id) &
|
||||
(Follower.is_accepted == False)
|
||||
).first()
|
||||
|
||||
if follow_request:
|
||||
# Accept the follow request by changing the "is_accepted" column to True
|
||||
follow_request.is_accepted = True
|
||||
db_session.commit()
|
||||
|
||||
# Return success response
|
||||
response_data = {
|
||||
"follower_id": target_user_id,
|
||||
"following_id": user_id,
|
||||
"is_accepted": True
|
||||
}
|
||||
return JSONResponse(content=response_data, status_code=200)
|
||||
else:
|
||||
# Follow request does not exist or has already been accepted
|
||||
raise HTTPException(status_code=400, detail="Invalid follow request.")
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
@router.post("/followers/create/user/{user_id}/targetUser/{target_user_id}")
|
||||
async def create_follow(user_id: int, target_user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Check if the follow relationship already exists
|
||||
existing_follow = db_session.query(Follower).filter(
|
||||
(Follower.follower_id == user_id) & (Follower.following_id == target_user_id)
|
||||
).first()
|
||||
|
||||
if existing_follow:
|
||||
# Follow relationship already exists
|
||||
raise HTTPException(status_code=400, detail="Follow relationship already exists.")
|
||||
|
||||
# Create a new follow relationship
|
||||
new_follow = Follower(
|
||||
follower_id=user_id,
|
||||
following_id=target_user_id,
|
||||
is_accepted=False
|
||||
# Check if the follow relationship exists and is not accepted yet
|
||||
follow_request = (
|
||||
db_session.query(Follower)
|
||||
.filter(
|
||||
(Follower.follower_id == target_user_id)
|
||||
& (Follower.following_id == user_id)
|
||||
& (Follower.is_accepted == False)
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
# Add the new follow relationship to the database
|
||||
db_session.add(new_follow)
|
||||
if follow_request:
|
||||
# Accept the follow request by changing the "is_accepted" column to True
|
||||
follow_request.is_accepted = True
|
||||
db_session.commit()
|
||||
|
||||
# Return success response
|
||||
response_data = {
|
||||
"follower_id": user_id,
|
||||
"following_id": target_user_id,
|
||||
"is_accepted": False
|
||||
"follower_id": target_user_id,
|
||||
"following_id": user_id,
|
||||
"is_accepted": True,
|
||||
}
|
||||
return JSONResponse(content=response_data, status_code=201)
|
||||
return JSONResponse(content=response_data, status_code=200)
|
||||
else:
|
||||
# Follow request does not exist or has already been accepted
|
||||
raise HTTPException(status_code=400, detail="Invalid follow request.")
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
@router.delete("/followers/delete/user/{user_id}/targetUser/{target_user_id}")
|
||||
async def delete_follow(user_id: int, target_user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
|
||||
|
||||
@router.post("/followers/create/user/{user_id}/targetUser/{target_user_id}")
|
||||
async def create_follow(
|
||||
user_id: int,
|
||||
target_user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Query and delete the specific follower record
|
||||
follower = db_session.query(Follower).filter(
|
||||
(Follower.follower_id == user_id) & (Follower.following_id == target_user_id)
|
||||
).first()
|
||||
# Check if the follow relationship already exists
|
||||
existing_follow = (
|
||||
db_session.query(Follower)
|
||||
.filter(
|
||||
(Follower.follower_id == user_id)
|
||||
& (Follower.following_id == target_user_id)
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
if follower:
|
||||
# Delete the follower record
|
||||
db_session.delete(follower)
|
||||
db_session.commit()
|
||||
if existing_follow:
|
||||
# Follow relationship already exists
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Follow relationship already exists."
|
||||
)
|
||||
|
||||
# Respond with a success message
|
||||
return JSONResponse(content={"detail": "Follower record deleted successfully."}, status_code=200)
|
||||
# Create a new follow relationship
|
||||
new_follow = Follower(
|
||||
follower_id=user_id, following_id=target_user_id, is_accepted=False
|
||||
)
|
||||
|
||||
# Follower record not found
|
||||
raise HTTPException(status_code=404, detail="Follower record not found.")
|
||||
# Add the new follow relationship to the database
|
||||
db_session.add(new_follow)
|
||||
db_session.commit()
|
||||
|
||||
# Return success response
|
||||
response_data = {
|
||||
"follower_id": user_id,
|
||||
"following_id": target_user_id,
|
||||
"is_accepted": False,
|
||||
}
|
||||
return JSONResponse(content=response_data, status_code=201)
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
|
||||
@router.delete("/followers/delete/user/{user_id}/targetUser/{target_user_id}")
|
||||
async def delete_follow(
|
||||
user_id: int,
|
||||
target_user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Query and delete the specific follower record
|
||||
follower = (
|
||||
db_session.query(Follower)
|
||||
.filter(
|
||||
(Follower.follower_id == user_id)
|
||||
& (Follower.following_id == target_user_id)
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
if follower:
|
||||
# Delete the follower record
|
||||
db_session.delete(follower)
|
||||
db_session.commit()
|
||||
|
||||
# Respond with a success message
|
||||
return JSONResponse(
|
||||
content={"detail": "Follower record deleted successfully."},
|
||||
status_code=200,
|
||||
)
|
||||
|
||||
# Follower record not found
|
||||
raise HTTPException(status_code=404, detail="Follower record not found.")
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
@@ -1,330 +1,581 @@
|
||||
import os
|
||||
"""
|
||||
API Router for managing user gear information.
|
||||
|
||||
This module defines FastAPI routes for performing CRUD operations on user gear records.
|
||||
It includes endpoints for retrieving, creating, updating, and deleting gear records.
|
||||
The routes handle user authentication, database interactions using SQLAlchemy,
|
||||
and provide JSON responses with appropriate metadata.
|
||||
|
||||
Endpoints:
|
||||
- GET /gear/all: Retrieve all user gear records.
|
||||
- GET /gear/all/{gear_type}: Retrieve user gear records filtered by gear type.
|
||||
- GET /gear/number: Retrieve the total number of user gear records.
|
||||
- GET /gear/all/pagenumber/{pageNumber}/numRecords/{numRecords}: Retrieve user gear records with pagination.
|
||||
- GET /gear/{nickname}/gearfromnickname: Retrieve user gear records by nickname.
|
||||
- GET /gear/{id}/gearfromid: Retrieve user gear records by ID.
|
||||
- POST /gear/create: Create a new user gear record.
|
||||
- PUT /gear/{gear_id}/edit: Edit an existing user gear record.
|
||||
- DELETE /gear/{gear_id}/delete: Delete an existing user gear record.
|
||||
|
||||
Dependencies:
|
||||
- OAuth2PasswordBearer: FastAPI security scheme for handling OAuth2 password bearer tokens.
|
||||
- get_db_session: Dependency function to get a database session.
|
||||
- create_error_response: Function to create a standardized error response.
|
||||
- get_current_user: Dependency function to get the current authenticated user.
|
||||
|
||||
Models:
|
||||
- GearBase: Base Pydantic model for gear attributes.
|
||||
- GearCreateRequest: Pydantic model for creating gear records.
|
||||
- GearEditRequest: Pydantic model for editing gear records.
|
||||
|
||||
Functions:
|
||||
- gear_record_to_dict: Convert Gear SQLAlchemy objects to dictionaries.
|
||||
|
||||
Logger:
|
||||
- Logger named "myLogger" for logging errors and exceptions.
|
||||
|
||||
"""
|
||||
import logging
|
||||
from fastapi import APIRouter, Depends, HTTPException, Response
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from typing import List, Optional
|
||||
from sqlalchemy import func
|
||||
from db.db import get_db_session, Gear
|
||||
from jose import jwt, JWTError
|
||||
from sqlalchemy.orm import Session
|
||||
from db.db import Gear
|
||||
from jose import JWTError
|
||||
from urllib.parse import unquote
|
||||
from pydantic import BaseModel
|
||||
from . import sessionController
|
||||
from dependencies import get_db_session, create_error_response, get_current_user
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
# Define the API router
|
||||
router = APIRouter()
|
||||
|
||||
# Define a loggger created on main.py
|
||||
logger = logging.getLogger("myLogger")
|
||||
|
||||
# Define the OAuth2 scheme for handling bearer tokens
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||
|
||||
|
||||
class GearBase(BaseModel):
|
||||
"""
|
||||
Base Pydantic model for representing gear attributes.
|
||||
|
||||
Attributes:
|
||||
- brand (str, optional): The brand of the gear.
|
||||
- model (str, optional): The model of the gear.
|
||||
- nickname (str): The nickname of the gear.
|
||||
- gear_type (int): The type of gear.
|
||||
- date (str): The creation date of the gear.
|
||||
"""
|
||||
|
||||
brand: Optional[str]
|
||||
model: Optional[str]
|
||||
nickname: str
|
||||
gear_type: int
|
||||
date: str
|
||||
|
||||
|
||||
class GearCreateRequest(GearBase):
|
||||
"""
|
||||
Pydantic model for creating gear records.
|
||||
|
||||
Inherits from GearBase, which defines the base attributes for gear.
|
||||
|
||||
This class extends the GearBase Pydantic model and is specifically tailored for
|
||||
creating new gear records.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class GearEditRequest(GearBase):
|
||||
"""
|
||||
Pydantic model for editing gear records.
|
||||
|
||||
Inherits from GearBase, which defines the base attributes for gear.
|
||||
|
||||
This class extends the GearBase Pydantic model and is designed for editing existing
|
||||
gear records. Includes an additional attribute 'is_active'
|
||||
to indicate whether the gear is active or not.
|
||||
|
||||
"""
|
||||
|
||||
is_active: int
|
||||
|
||||
|
||||
# Define a function to convert Gear SQLAlchemy objects to dictionaries
|
||||
def gear_record_to_dict(record: Gear) -> dict:
|
||||
"""
|
||||
Convert Gear SQLAlchemy objects to dictionaries.
|
||||
|
||||
Parameters:
|
||||
- record (Gear): The Gear SQLAlchemy object to convert.
|
||||
|
||||
Returns:
|
||||
- dict: A dictionary representation of the Gear object.
|
||||
|
||||
This function is used to convert an SQLAlchemy Gear object into a dictionary format for easier serialization and response handling.
|
||||
"""
|
||||
return {
|
||||
"id": record.id,
|
||||
"brand": record.brand,
|
||||
"model": record.model,
|
||||
"nickname": record.nickname,
|
||||
"gear_type": record.gear_type,
|
||||
"user_id": record.user_id,
|
||||
"created_at": record.created_at.strftime("%Y-%m-%dT%H:%M:%S"),
|
||||
"is_active": record.is_active,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/gear/all", response_model=List[dict])
|
||||
async def read_gear_all(token: str = Depends(oauth2_scheme)):
|
||||
async def read_gear_all(
|
||||
user_id: int = Depends(get_current_user),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
"""
|
||||
Retrieve all user gear records.
|
||||
|
||||
Parameters:
|
||||
- user_id (int): The ID of the authenticated user.
|
||||
- db_session (Session): SQLAlchemy database session.
|
||||
|
||||
Returns:
|
||||
- JSONResponse: JSON response containing metadata and user gear records.
|
||||
|
||||
Raises:
|
||||
- JWTError: If the user is not authenticated.
|
||||
- Exception: For other unexpected errors.
|
||||
"""
|
||||
try:
|
||||
sessionController.validate_token(token)
|
||||
with get_db_session() as db_session:
|
||||
payload = jwt.decode(
|
||||
token, os.environ.get("SECRET_KEY"), algorithms=[os.environ.get("ALGORITHM")]
|
||||
)
|
||||
user_id = payload.get("id")
|
||||
# Query the gear records using SQLAlchemy
|
||||
gear_records = (
|
||||
db_session.query(Gear)
|
||||
.filter(Gear.user_id == user_id)
|
||||
.order_by(Gear.nickname)
|
||||
.all()
|
||||
)
|
||||
|
||||
# Query the gear records using SQLAlchemy
|
||||
gear_records = (
|
||||
db_session.query(Gear)
|
||||
.filter(Gear.user_id == user_id)
|
||||
.order_by(Gear.nickname)
|
||||
.all()
|
||||
)
|
||||
# Use the gear_record_to_dict function to convert SQLAlchemy objects to dictionaries
|
||||
gear_records_dict = [gear_record_to_dict(record) for record in gear_records]
|
||||
|
||||
# Convert the SQLAlchemy objects to dictionaries
|
||||
results = [gear.__dict__ for gear in gear_records]
|
||||
# Include metadata in the response
|
||||
metadata = {"total_records": len(gear_records)}
|
||||
|
||||
# Return the queried values using JSONResponse
|
||||
return JSONResponse(
|
||||
content={"metadata": metadata, "gear_records": gear_records_dict}
|
||||
)
|
||||
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
except NameError as err:
|
||||
print(err)
|
||||
|
||||
return results
|
||||
# Return an error response if the user is not authenticated
|
||||
return create_error_response("UNAUTHORIZED", "Unauthorized", 401)
|
||||
except Exception as err:
|
||||
# Log the error and return an error response
|
||||
logger.error(f"Error in read_gear_all: {err}", exc_info=True)
|
||||
return create_error_response(
|
||||
"INTERNAL_SERVER_ERROR", "Internal Server Error", 500
|
||||
)
|
||||
|
||||
|
||||
@router.get("/gear/all/running", response_model=List[dict])
|
||||
async def read_gear_all_running(token: str = Depends(oauth2_scheme)):
|
||||
@router.get("/gear/all/{gear_type}", response_model=List[dict])
|
||||
async def read_gear_all_by_type(
|
||||
gear_type: int,
|
||||
user_id: int = Depends(get_current_user),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
"""
|
||||
Retrieve user gear records filtered by gear type.
|
||||
|
||||
Parameters:
|
||||
- gear_type (int): The type of gear to filter by.
|
||||
- user_id (int, optional): The ID of the authenticated user (default: extracted from token).
|
||||
- db_session (Session, optional): SQLAlchemy database session (default: obtained from dependency).
|
||||
|
||||
Returns:
|
||||
- JSONResponse: JSON response containing metadata and user gear records filtered by gear type.
|
||||
|
||||
Raises:
|
||||
- ValueError: If the gear type is invalid.
|
||||
- JWTError: If the user is not authenticated.
|
||||
- Exception: For other unexpected errors.
|
||||
|
||||
This function queries user gear records from the database based on the specified gear type.
|
||||
It filters records by both gear type and user ID, includes metadata in the response,
|
||||
and returns a JSONResponse with the filtered gear records.
|
||||
|
||||
"""
|
||||
try:
|
||||
sessionController.validate_token(token)
|
||||
with get_db_session() as db_session:
|
||||
payload = jwt.decode(
|
||||
token, os.environ.get("SECRET_KEY"), algorithms=[os.environ.get("ALGORITHM")]
|
||||
)
|
||||
user_id = payload.get("id")
|
||||
# Validate the gear type (example validation)
|
||||
if not (1 <= gear_type <= 3):
|
||||
# Return an error response if the gear type in invalid
|
||||
return create_error_response("UNPROCESSABLE COMTENT", "Invalid gear type. Must be between 1 and 3", 422)
|
||||
|
||||
# Query the gear records using SQLAlchemy
|
||||
gear_records = (
|
||||
db_session.query(Gear)
|
||||
.filter(Gear.gear_type == 2, Gear.user_id == user_id)
|
||||
.order_by(Gear.nickname)
|
||||
.all()
|
||||
)
|
||||
# Query the gear records using SQLAlchemy and filter by gear type and user ID
|
||||
gear_records = (
|
||||
db_session.query(Gear)
|
||||
.filter(Gear.gear_type == gear_type, Gear.user_id == user_id)
|
||||
.order_by(Gear.nickname)
|
||||
.all()
|
||||
)
|
||||
|
||||
# Convert the SQLAlchemy objects to dictionaries
|
||||
results = [gear.__dict__ for gear in gear_records]
|
||||
# Use the gear_record_to_dict function to convert SQLAlchemy objects to dictionaries
|
||||
gear_records_dict = [gear_record_to_dict(record) for record in gear_records]
|
||||
|
||||
# Include metadata in the response
|
||||
metadata = {
|
||||
"total_records": len(gear_records),
|
||||
"gear_type": gear_type,
|
||||
}
|
||||
|
||||
# Return the queried values using JSONResponse
|
||||
return JSONResponse(
|
||||
content={"metadata": metadata, "gear_records": gear_records_dict}
|
||||
)
|
||||
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
except NameError as err:
|
||||
print(err)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
@router.get("/gear/all/cycling", response_model=List[dict])
|
||||
async def read_gear_all_cycling(token: str = Depends(oauth2_scheme)):
|
||||
try:
|
||||
sessionController.validate_token(token)
|
||||
with get_db_session() as db_session:
|
||||
payload = jwt.decode(
|
||||
token, os.environ.get("SECRET_KEY"), algorithms=[os.environ.get("ALGORITHM")]
|
||||
)
|
||||
user_id = payload.get("id")
|
||||
|
||||
# Query the gear records using SQLAlchemy
|
||||
gear_records = (
|
||||
db_session.query(Gear)
|
||||
.filter(Gear.gear_type == 1, Gear.user_id == user_id)
|
||||
.order_by(Gear.nickname)
|
||||
.all()
|
||||
)
|
||||
|
||||
# Convert the SQLAlchemy objects to dictionaries
|
||||
results = [gear.__dict__ for gear in gear_records]
|
||||
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
except NameError as err:
|
||||
print(err)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
@router.get("/gear/all/swimming", response_model=List[dict])
|
||||
async def read_gear_all_swimming(token: str = Depends(oauth2_scheme)):
|
||||
try:
|
||||
sessionController.validate_token(token)
|
||||
with get_db_session() as db_session:
|
||||
payload = jwt.decode(
|
||||
token, os.environ.get("SECRET_KEY"), algorithms=[os.environ.get("ALGORITHM")]
|
||||
)
|
||||
user_id = payload.get("id")
|
||||
|
||||
# Query the gear records using SQLAlchemy
|
||||
gear_records = (
|
||||
db_session.query(Gear)
|
||||
.filter(Gear.gear_type == 3, Gear.user_id == user_id)
|
||||
.order_by(Gear.nickname)
|
||||
.all()
|
||||
)
|
||||
|
||||
# Convert the SQLAlchemy objects to dictionaries
|
||||
results = [gear.__dict__ for gear in gear_records]
|
||||
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
except NameError as err:
|
||||
print(err)
|
||||
|
||||
return results
|
||||
# Return an error response if the user is not authenticated
|
||||
return create_error_response("UNAUTHORIZED", "Unauthorized", 401)
|
||||
except Exception as err:
|
||||
# Log the error and return an error response
|
||||
logger.error(f"Error in read_gear_all_by_type: {err}", exc_info=True)
|
||||
return create_error_response(
|
||||
"INTERNAL_SERVER_ERROR", "Internal Server Error", 500
|
||||
)
|
||||
|
||||
|
||||
@router.get("/gear/number")
|
||||
async def read_gear_number(token: str = Depends(oauth2_scheme)):
|
||||
try:
|
||||
sessionController.validate_token(token)
|
||||
with get_db_session() as db_session:
|
||||
payload = jwt.decode(
|
||||
token, os.environ.get("SECRET_KEY"), algorithms=[os.environ.get("ALGORITHM")]
|
||||
)
|
||||
user_id = payload.get("id")
|
||||
async def read_gear_number(
|
||||
user_id: int = Depends(get_current_user),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
"""
|
||||
Retrieve the total number of user gear records.
|
||||
|
||||
# Query the number of gear records for the user using SQLAlchemy
|
||||
gear_count = (
|
||||
db_session.query(func.count(Gear.id))
|
||||
.filter(Gear.user_id == user_id)
|
||||
.scalar()
|
||||
)
|
||||
Parameters:
|
||||
- user_id (int, optional): The ID of the authenticated user (default: extracted from token).
|
||||
- db_session (Session, optional): SQLAlchemy database session (default: obtained from dependency).
|
||||
|
||||
Returns:
|
||||
- JSONResponse: JSON response containing metadata and the total number of user gear records.
|
||||
|
||||
Raises:
|
||||
- JWTError: If the user is not authenticated.
|
||||
- Exception: For other unexpected errors.
|
||||
|
||||
This function queries the total number of user gear records from the database,
|
||||
includes metadata in the response, and returns a JSONResponse with the total gear count.
|
||||
|
||||
"""
|
||||
try:
|
||||
# Query the number of gear records for the user using SQLAlchemy, filter by user ID and return the count
|
||||
gear_count = (
|
||||
db_session.query(func.count(Gear.id))
|
||||
.filter(Gear.user_id == user_id)
|
||||
.scalar()
|
||||
)
|
||||
|
||||
# Include metadata in the response
|
||||
metadata = {"total_records": 1}
|
||||
|
||||
# Return the queried values using JSONResponse
|
||||
return JSONResponse(content={"metadata": metadata, "gear_count": gear_count})
|
||||
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
except NameError as err:
|
||||
print(err)
|
||||
|
||||
return {0: gear_count}
|
||||
# Return an error response if the user is not authenticated
|
||||
return create_error_response("UNAUTHORIZED", "Unauthorized", 401)
|
||||
except Exception as err:
|
||||
# Log the error and return an error response
|
||||
logger.error(f"Error in read_gear_number: {err}", exc_info=True)
|
||||
return create_error_response(
|
||||
"INTERNAL_SERVER_ERROR", "Internal Server Error", 500
|
||||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/gear/all/pagenumber/{pageNumber}/numRecords/{numRecords}",
|
||||
response_model=List[dict],
|
||||
#tags=["Pagination"],
|
||||
)
|
||||
async def read_gear_all_pagination(
|
||||
pageNumber: int, numRecords: int, token: str = Depends(oauth2_scheme)
|
||||
pageNumber: int,
|
||||
numRecords: int,
|
||||
user_id: int = Depends(get_current_user),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
"""
|
||||
Retrieve user gear records with pagination.
|
||||
|
||||
Parameters:
|
||||
- pageNumber (int): The page number to retrieve.
|
||||
- numRecords (int): The number of records to display per page.
|
||||
- user_id (int, optional): The ID of the authenticated user (default: extracted from token).
|
||||
- db_session (Session, optional): SQLAlchemy database session (default: obtained from dependency).
|
||||
|
||||
Returns:
|
||||
- JSONResponse: JSON response containing metadata and user gear records for the specified page.
|
||||
|
||||
Raises:
|
||||
- JWTError: If the user is not authenticated.
|
||||
- Exception: For other unexpected errors.
|
||||
|
||||
This function queries user gear records from the database with pagination,
|
||||
includes metadata in the response, and returns a JSONResponse with the gear records for the specified page.
|
||||
|
||||
"""
|
||||
try:
|
||||
sessionController.validate_token(token)
|
||||
with get_db_session() as db_session:
|
||||
payload = jwt.decode(
|
||||
token, os.environ.get("SECRET_KEY"), algorithms=[os.environ.get("ALGORITHM")]
|
||||
)
|
||||
user_id = payload.get("id")
|
||||
# Use SQLAlchemy to query the gear records with pagination, filter by user ID, order by nickname ascending and return the records
|
||||
gear_records = (
|
||||
db_session.query(Gear)
|
||||
.filter(Gear.user_id == user_id)
|
||||
.order_by(Gear.nickname.asc())
|
||||
.offset((pageNumber - 1) * numRecords)
|
||||
.limit(numRecords)
|
||||
.all()
|
||||
)
|
||||
|
||||
# Use SQLAlchemy to query the gear records with pagination
|
||||
gear_records = (
|
||||
db_session.query(Gear)
|
||||
.filter(Gear.user_id == user_id)
|
||||
.order_by(Gear.nickname.asc())
|
||||
.offset((pageNumber - 1) * numRecords)
|
||||
.limit(numRecords)
|
||||
.all()
|
||||
)
|
||||
# Use the gear_record_to_dict function to convert SQLAlchemy objects to dictionaries
|
||||
gear_records_dict = [gear_record_to_dict(record) for record in gear_records]
|
||||
|
||||
# Convert the SQLAlchemy results to a list of dictionaries
|
||||
results = [record.__dict__ for record in gear_records]
|
||||
# Include metadata in the response
|
||||
metadata = {
|
||||
"total_records": len(gear_records),
|
||||
"page_number": pageNumber,
|
||||
"num_records": numRecords,
|
||||
}
|
||||
|
||||
# Return the queried values using JSONResponse
|
||||
return JSONResponse(
|
||||
content={"metadata": metadata, "gear_records": gear_records_dict}
|
||||
)
|
||||
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
except NameError as err:
|
||||
print(err)
|
||||
|
||||
return results
|
||||
# Return an error response if the user is not authenticated
|
||||
return create_error_response("UNAUTHORIZED", "Unauthorized", 401)
|
||||
except Exception as err:
|
||||
# Log the error and return an error response
|
||||
logger.error(f"Error in read_gear_all_pagination: {err}", exc_info=True)
|
||||
return create_error_response(
|
||||
"INTERNAL_SERVER_ERROR", "Internal Server Error", 500
|
||||
)
|
||||
|
||||
|
||||
@router.get("/gear/{nickname}/gearfromnickname", response_model=List[dict])
|
||||
async def read_gear_gearFromNickname(
|
||||
nickname: str, token: str = Depends(oauth2_scheme)
|
||||
nickname: str,
|
||||
user_id: int = Depends(get_current_user),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
"""
|
||||
Retrieve user gear records by nickname.
|
||||
|
||||
Parameters:
|
||||
- nickname (str): The nickname to search for in user gear records.
|
||||
- user_id (int, optional): The ID of the authenticated user (default: extracted from token).
|
||||
- db_session (Session, optional): SQLAlchemy database session (default: obtained from dependency).
|
||||
|
||||
Returns:
|
||||
- JSONResponse: JSON response containing metadata and user gear records matching the provided nickname.
|
||||
|
||||
Raises:
|
||||
- JWTError: If the user is not authenticated.
|
||||
- Exception: For other unexpected errors.
|
||||
|
||||
This function queries user gear records from the database by nickname,
|
||||
includes metadata in the response, and returns a JSONResponse with the matching gear records.
|
||||
|
||||
"""
|
||||
try:
|
||||
sessionController.validate_token(token)
|
||||
with get_db_session() as db_session:
|
||||
payload = jwt.decode(
|
||||
token, os.environ.get("SECRET_KEY"), algorithms=[os.environ.get("ALGORITHM")]
|
||||
# Define a search term
|
||||
partial_nickname = unquote(nickname).replace("+", " ")
|
||||
|
||||
# Use SQLAlchemy to query the gear records by nickname, filter by user ID and nickname, and return the records
|
||||
gear_records = (
|
||||
db_session.query(Gear)
|
||||
.filter(
|
||||
Gear.nickname.like(f"%{partial_nickname}%"), Gear.user_id == user_id
|
||||
)
|
||||
user_id = payload.get("id")
|
||||
.all()
|
||||
)
|
||||
|
||||
# Define a search term
|
||||
partial_nickname = unquote(nickname).replace("+", " ")
|
||||
# Use the gear_record_to_dict function to convert SQLAlchemy objects to dictionaries
|
||||
gear_records_dict = [gear_record_to_dict(record) for record in gear_records]
|
||||
|
||||
# Use SQLAlchemy to query the gear records by nickname
|
||||
gear_records = (
|
||||
db_session.query(Gear)
|
||||
.filter(
|
||||
Gear.nickname.like(f"%{partial_nickname}%"), Gear.user_id == user_id
|
||||
)
|
||||
.all()
|
||||
)
|
||||
# Include metadata in the response
|
||||
metadata = {
|
||||
"total_records": len(gear_records),
|
||||
"nickname": nickname,
|
||||
}
|
||||
|
||||
# Convert the SQLAlchemy results to a list of dictionaries
|
||||
results = [record.__dict__ for record in gear_records]
|
||||
# Return the queried values using JSONResponse
|
||||
return JSONResponse(
|
||||
content={"metadata": metadata, "gear_records": gear_records_dict}
|
||||
)
|
||||
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
except NameError as err:
|
||||
print(err)
|
||||
|
||||
return results
|
||||
# Return an error response if the user is not authenticated
|
||||
return create_error_response("UNAUTHORIZED", "Unauthorized", 401)
|
||||
except Exception as err:
|
||||
# Log the error and return an error response
|
||||
logger.error(f"Error in read_gear_gearFromNickname: {err}", exc_info=True)
|
||||
return create_error_response(
|
||||
"INTERNAL_SERVER_ERROR", "Internal Server Error", 500
|
||||
)
|
||||
|
||||
|
||||
# Get gear from id
|
||||
@router.get("/gear/{id}/gearfromid", response_model=List[dict])
|
||||
async def read_gear_gearFromId(id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def read_gear_gearFromId(
|
||||
id: int,
|
||||
user_id: int = Depends(get_current_user),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
"""
|
||||
Retrieve user gear records by ID.
|
||||
|
||||
Parameters:
|
||||
- id (int): The ID of the gear record to retrieve.
|
||||
- user_id (int, optional): The ID of the authenticated user (default: extracted from token).
|
||||
- db_session (Session, optional): SQLAlchemy database session (default: obtained from dependency).
|
||||
|
||||
Returns:
|
||||
- JSONResponse: JSON response containing metadata and user gear records matching the provided ID.
|
||||
|
||||
Raises:
|
||||
- JWTError: If the user is not authenticated.
|
||||
- Exception: For other unexpected errors.
|
||||
|
||||
This function queries user gear records from the database by ID,
|
||||
includes metadata in the response, and returns a JSONResponse with the matching gear records.
|
||||
|
||||
"""
|
||||
try:
|
||||
sessionController.validate_token(token)
|
||||
with get_db_session() as db_session:
|
||||
payload = jwt.decode(
|
||||
token, os.environ.get("SECRET_KEY"), algorithms=[os.environ.get("ALGORITHM")]
|
||||
)
|
||||
user_id = payload.get("id")
|
||||
# Use SQLAlchemy to query the gear record by ID and filter by user ID and gear ID
|
||||
gear_records = (
|
||||
db_session.query(Gear).filter(Gear.id == id, Gear.user_id == user_id).all()
|
||||
)
|
||||
|
||||
# Use SQLAlchemy to query the gear record by ID
|
||||
gear_record = (
|
||||
db_session.query(Gear)
|
||||
.filter(Gear.id == id, Gear.user_id == user_id)
|
||||
.first()
|
||||
)
|
||||
# Use the gear_record_to_dict function to convert SQLAlchemy objects to dictionaries
|
||||
gear_records_dict = [gear_record_to_dict(record) for record in gear_records]
|
||||
|
||||
# Convert the SQLAlchemy result to a list of dictionaries
|
||||
if gear_record:
|
||||
results = [gear_record.__dict__]
|
||||
else:
|
||||
results = []
|
||||
# Include metadata in the response
|
||||
metadata = {
|
||||
"total_records": len(gear_records),
|
||||
"id": id,
|
||||
}
|
||||
|
||||
# Return the queried values using JSONResponse
|
||||
return JSONResponse(
|
||||
content={"metadata": metadata, "gear_records": gear_records_dict}
|
||||
)
|
||||
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
except NameError as err:
|
||||
print(err)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
class CreateGearRequest(BaseModel):
|
||||
brand: Optional[str]
|
||||
model: Optional[str]
|
||||
nickname: str
|
||||
gear_type: int
|
||||
date: str
|
||||
# Return an error response if the user is not authenticated
|
||||
return create_error_response("UNAUTHORIZED", "Unauthorized", 401)
|
||||
except Exception as err:
|
||||
# Log the error and return an error response
|
||||
logger.error(f"Error in read_gear_gearFromId: {err}", exc_info=True)
|
||||
return create_error_response(
|
||||
"INTERNAL_SERVER_ERROR", "Internal Server Error", 500
|
||||
)
|
||||
|
||||
|
||||
@router.post("/gear/create")
|
||||
async def create_gear(gear: CreateGearRequest, token: str = Depends(oauth2_scheme)):
|
||||
async def create_gear(
|
||||
gear: GearCreateRequest,
|
||||
user_id: int = Depends(get_current_user),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
"""
|
||||
Create a new user gear record.
|
||||
|
||||
Parameters:
|
||||
- gear (GearCreateRequest): Pydantic model containing information for creating a new gear record.
|
||||
- user_id (int, optional): The ID of the authenticated user (default: extracted from token).
|
||||
- db_session (Session, optional): SQLAlchemy database session (default: obtained from dependency).
|
||||
|
||||
Returns:
|
||||
- JSONResponse: JSON response indicating the success of the gear creation.
|
||||
|
||||
Raises:
|
||||
- JWTError: If the user is not authenticated.
|
||||
- Exception: For other unexpected errors.
|
||||
|
||||
This function uses the provided GearCreateRequest model to create a new gear record in the database,
|
||||
associates it with the authenticated user, and returns a JSONResponse indicating the success of the creation.
|
||||
|
||||
"""
|
||||
try:
|
||||
sessionController.validate_token(token)
|
||||
|
||||
payload = jwt.decode(
|
||||
token, os.environ.get("SECRET_KEY"), algorithms=[os.environ.get("ALGORITHM")]
|
||||
# Use SQLAlchemy to create a new gear record
|
||||
gear_record = Gear(
|
||||
brand=unquote(gear.brand).replace("+", " "),
|
||||
model=unquote(gear.model).replace("+", " "),
|
||||
nickname=unquote(gear.nickname).replace("+", " "),
|
||||
gear_type=gear.gear_type,
|
||||
user_id=user_id,
|
||||
created_at=gear.date,
|
||||
is_active=True,
|
||||
)
|
||||
user_id = payload.get("id")
|
||||
|
||||
with get_db_session() as db_session:
|
||||
# Use SQLAlchemy to create a new gear record
|
||||
gear_record = Gear(
|
||||
brand=unquote(gear.brand).replace("+", " "),
|
||||
model=unquote(gear.model).replace("+", " "),
|
||||
nickname=unquote(gear.nickname).replace("+", " "),
|
||||
gear_type=gear.gear_type,
|
||||
user_id=user_id,
|
||||
created_at=gear.date,
|
||||
is_active=True,
|
||||
)
|
||||
# Add the gear record to the database using SQLAlchemy
|
||||
db_session.add(gear_record)
|
||||
db_session.commit()
|
||||
|
||||
# Add the gear record to the database using SQLAlchemy
|
||||
db_session.add(gear_record)
|
||||
db_session.commit()
|
||||
# Return a JSONResponse indicating the success of the gear creation
|
||||
return JSONResponse(
|
||||
content={"message": "Gear created successfully"}, status_code=201
|
||||
)
|
||||
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
except NameError as err:
|
||||
print(err)
|
||||
raise HTTPException(status_code=500, detail="Failed to create gear")
|
||||
|
||||
return {"message": "Gear added successfully"}
|
||||
|
||||
|
||||
class EditGearRequest(BaseModel):
|
||||
brand: Optional[str]
|
||||
model: Optional[str]
|
||||
nickname: str
|
||||
gear_type: int
|
||||
date: str
|
||||
is_active: int
|
||||
# Return an error response if the user is not authenticated
|
||||
return create_error_response("UNAUTHORIZED", "Unauthorized", 401)
|
||||
except Exception as err:
|
||||
# Log the error, rollback the transaction, and return an error response
|
||||
db_session.rollback()
|
||||
logger.error(f"Error in create_gear: {err}", exc_info=True)
|
||||
return create_error_response(
|
||||
"INTERNAL_SERVER_ERROR", "Internal Server Error", 500
|
||||
)
|
||||
|
||||
|
||||
@router.put("/gear/{gear_id}/edit")
|
||||
async def edit_gear(
|
||||
gear_id: int, gear: EditGearRequest, token: str = Depends(oauth2_scheme)
|
||||
gear_id: int,
|
||||
gear: GearEditRequest,
|
||||
user_id: int = Depends(get_current_user),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
"""
|
||||
Edit an existing user gear record.
|
||||
|
||||
Parameters:
|
||||
- gear_id (int): The ID of the gear record to edit.
|
||||
- gear (GearEditRequest): Pydantic model containing information for editing the gear record.
|
||||
- user_id (int, optional): The ID of the authenticated user (default: extracted from token).
|
||||
- db_session (Session, optional): SQLAlchemy database session (default: obtained from dependency).
|
||||
|
||||
Returns:
|
||||
- JSONResponse: JSON response indicating the success of the gear edit.
|
||||
|
||||
Raises:
|
||||
- JWTError: If the user is not authenticated.
|
||||
- Exception: For other unexpected errors.
|
||||
|
||||
This function uses the provided GearEditRequest model to edit an existing gear record in the database,
|
||||
verifies ownership, and returns a JSONResponse indicating the success of the edit.
|
||||
|
||||
"""
|
||||
try:
|
||||
sessionController.validate_token(token)
|
||||
|
||||
# Use SQLAlchemy to query and update the gear record
|
||||
with get_db_session() as db_session:
|
||||
gear_record = db_session.query(Gear).filter(Gear.id == gear_id).first()
|
||||
gear_record = db_session.query(Gear).filter(Gear.id == gear_id).first()
|
||||
|
||||
if gear_record:
|
||||
# Check if the gear record exists
|
||||
if gear_record:
|
||||
# Check if the gear record belongs to the user
|
||||
if gear_record.user_id == user_id:
|
||||
# Update the gear record
|
||||
if gear.brand is not None:
|
||||
gear_record.brand = unquote(gear.brand).replace("+", " ")
|
||||
if gear.model is not None:
|
||||
@@ -336,50 +587,98 @@ async def edit_gear(
|
||||
|
||||
# Commit the transaction
|
||||
db_session.commit()
|
||||
return {"message": "Gear edited successfully"}
|
||||
|
||||
# Return a JSONResponse indicating the success of the gear edit
|
||||
return JSONResponse(
|
||||
content={"message": "Gear edited successfully"}, status_code=200
|
||||
)
|
||||
else:
|
||||
raise HTTPException(status_code=404, detail="Gear not found")
|
||||
# Return an error response if the gear record does not belong to the user
|
||||
return JSONResponse(
|
||||
content={
|
||||
"message": f"Gear does not belong to user {user_id}. Will not edit"
|
||||
},
|
||||
status_code=404,
|
||||
)
|
||||
else:
|
||||
# Return an error response if the gear record is not found
|
||||
return JSONResponse(content={"message": "Gear not found"}, status_code=404)
|
||||
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
# Return an error response if the user is not authenticated
|
||||
return create_error_response("UNAUTHORIZED", "Unauthorized", 401)
|
||||
except Exception as err:
|
||||
print(err)
|
||||
raise HTTPException(status_code=500, detail="Failed to edit gear")
|
||||
|
||||
return {"message": "Gear edited successfully"}
|
||||
# Log the error, rollback the transaction, and return an error response
|
||||
db_session.rollback()
|
||||
logger.error(f"Error in edit_gear: {err}", exc_info=True)
|
||||
return create_error_response(
|
||||
"INTERNAL_SERVER_ERROR", "Internal Server Error", 500
|
||||
)
|
||||
|
||||
|
||||
@router.delete("/gear/{gear_id}/delete")
|
||||
async def delete_gear(
|
||||
gear_id: int, response: Response, token: str = Depends(oauth2_scheme)
|
||||
gear_id: int,
|
||||
user_id: int = Depends(get_current_user),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
"""
|
||||
Delete an existing user gear record.
|
||||
|
||||
Parameters:
|
||||
- gear_id (int): The ID of the gear record to delete.
|
||||
- user_id (int, optional): The ID of the authenticated user (default: extracted from token).
|
||||
- db_session (Session, optional): SQLAlchemy database session (default: obtained from dependency).
|
||||
|
||||
Returns:
|
||||
- JSONResponse: JSON response indicating the success of the gear deletion.
|
||||
|
||||
Raises:
|
||||
- JWTError: If the user is not authenticated.
|
||||
- Exception: For other unexpected errors.
|
||||
|
||||
This function deletes an existing gear record from the database,
|
||||
verifies ownership, and returns a JSONResponse indicating the success of the deletion.
|
||||
|
||||
"""
|
||||
try:
|
||||
sessionController.validate_token(token)
|
||||
|
||||
# Use SQLAlchemy to query and delete the gear record
|
||||
with get_db_session() as db_session:
|
||||
gear_record = db_session.query(Gear).filter(Gear.id == gear_id).first()
|
||||
|
||||
if gear_record:
|
||||
# Check for existing dependencies (uncomment if needed)
|
||||
# Example: Check if there are dependencies in another table
|
||||
# if db_session.query(OtherModel).filter(OtherModel.gear_id == gear_id).count() > 0:
|
||||
# response.status_code = 409
|
||||
# return {"detail": "Cannot delete gear due to existing dependencies"}
|
||||
gear_record = db_session.query(Gear).filter(Gear.id == gear_id).first()
|
||||
|
||||
# Check if the gear record exists
|
||||
if gear_record:
|
||||
# Check if the gear record belongs to the user
|
||||
if gear_record.user_id == user_id:
|
||||
# Delete the gear record
|
||||
db_session.delete(gear_record)
|
||||
|
||||
# Commit the transaction
|
||||
db_session.commit()
|
||||
return {"message": f"Gear {gear_id} has been deleted"}
|
||||
|
||||
# Return a JSONResponse indicating the success of the gear deletion
|
||||
return JSONResponse(
|
||||
content={"message": f"Gear {gear_id} has been deleted"},
|
||||
status_code=200,
|
||||
)
|
||||
else:
|
||||
raise HTTPException(status_code=404, detail="Gear not found")
|
||||
# Return an error response if the gear record does not belong to the user
|
||||
return JSONResponse(
|
||||
content={
|
||||
"message": f"Gear does not belong to user {user_id}. Will not delete"
|
||||
},
|
||||
status_code=404,
|
||||
)
|
||||
else:
|
||||
# Return an error response if the gear record is not found
|
||||
return JSONResponse(content={"message": "Gear not found"}, status_code=404)
|
||||
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
# Return an error response if the user is not authenticated
|
||||
return create_error_response("UNAUTHORIZED", "Unauthorized", 401)
|
||||
except Exception as err:
|
||||
print(err)
|
||||
raise HTTPException(status_code=500, detail="Failed to delete gear")
|
||||
|
||||
return {"message": f"Gear {gear_id} has been deleted"}
|
||||
# Log the error, rollback the transaction, and return an error response
|
||||
db_session.rollback()
|
||||
logger.error(f"Error in delete_gear: {err}", exc_info=True)
|
||||
return create_error_response(
|
||||
"INTERNAL_SERVER_ERROR", "Internal Server Error", 500
|
||||
)
|
||||
|
||||
@@ -4,14 +4,14 @@ from fastapi import APIRouter, Depends, HTTPException
|
||||
from datetime import datetime, timedelta
|
||||
from jose import jwt, JWTError
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from sqlalchemy.orm import Session
|
||||
from db.db import (
|
||||
get_db_session,
|
||||
User,
|
||||
AccessToken,
|
||||
) # Import your SQLAlchemy session management from db.db and models
|
||||
from controllers.userController import UserResponse
|
||||
from pydantic import BaseModel
|
||||
from opentelemetry import trace
|
||||
from dependencies import get_db_session
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -20,43 +20,78 @@ logger = logging.getLogger("myLogger")
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||
|
||||
|
||||
def get_user_id_from_token(token: str):
|
||||
try:
|
||||
payload = jwt.decode(
|
||||
token,
|
||||
os.environ.get("SECRET_KEY"),
|
||||
algorithms=[os.environ.get("ALGORITHM")],
|
||||
)
|
||||
return payload.get("id")
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
|
||||
def get_exp_from_token(token: str = Depends(oauth2_scheme)):
|
||||
try:
|
||||
payload = jwt.decode(
|
||||
token,
|
||||
os.environ.get("SECRET_KEY"),
|
||||
algorithms=[os.environ.get("ALGORITHM")],
|
||||
)
|
||||
return payload.get("exp")
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
def get_access_type_from_token(token: str = Depends(oauth2_scheme)):
|
||||
try:
|
||||
payload = jwt.decode(
|
||||
token,
|
||||
os.environ.get("SECRET_KEY"),
|
||||
algorithms=[os.environ.get("ALGORITHM")],
|
||||
)
|
||||
return payload.get("access_type")
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
|
||||
async def authenticate_user(
|
||||
username: str, password: str, neverExpires: bool, db_session=Depends(get_db_session)
|
||||
username: str,
|
||||
password: str,
|
||||
neverExpires: bool,
|
||||
db_session: Session,
|
||||
):
|
||||
try:
|
||||
with get_db_session() as db_session:
|
||||
# Use SQLAlchemy ORM to query the database
|
||||
user = (
|
||||
db_session.query(User)
|
||||
.filter(User.username == username, User.password == password)
|
||||
.first()
|
||||
)
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Incorrect username or password"
|
||||
)
|
||||
|
||||
# Check if there is an existing access token for the user
|
||||
access_token = (
|
||||
db_session.query(AccessToken)
|
||||
.filter(AccessToken.user_id == user.id)
|
||||
.first()
|
||||
)
|
||||
if access_token:
|
||||
return access_token.token
|
||||
|
||||
# If there is no existing access token, create a new one
|
||||
access_token_expires = timedelta(
|
||||
minutes=int(os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES"))
|
||||
)
|
||||
access_token = await create_access_token(
|
||||
data={"id": user.id, "access_type": user.access_type},
|
||||
never_expire=neverExpires,
|
||||
expires_delta=access_token_expires,
|
||||
db_session=db_session,
|
||||
# Use SQLAlchemy ORM to query the database
|
||||
user = (
|
||||
db_session.query(User)
|
||||
.filter(User.username == username, User.password == password)
|
||||
.first()
|
||||
)
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="Incorrect username or password"
|
||||
)
|
||||
|
||||
return access_token
|
||||
# Check if there is an existing access token for the user
|
||||
access_token = (
|
||||
db_session.query(AccessToken).filter(AccessToken.user_id == user.id).first()
|
||||
)
|
||||
if access_token:
|
||||
return access_token.token
|
||||
|
||||
# If there is no existing access token, create a new one
|
||||
access_token_expires = timedelta(
|
||||
minutes=int(os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES"))
|
||||
)
|
||||
access_token = await create_access_token(
|
||||
data={"id": user.id, "access_type": user.access_type},
|
||||
never_expire=neverExpires,
|
||||
db_session=db_session,
|
||||
expires_delta=access_token_expires,
|
||||
)
|
||||
|
||||
return access_token
|
||||
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
@@ -66,8 +101,8 @@ async def authenticate_user(
|
||||
async def create_access_token(
|
||||
data: dict,
|
||||
never_expire: bool,
|
||||
db_session: Session,
|
||||
expires_delta: timedelta = None,
|
||||
db_session=Depends(get_db_session),
|
||||
):
|
||||
to_encode = data.copy()
|
||||
if never_expire:
|
||||
@@ -89,135 +124,97 @@ async def create_access_token(
|
||||
created_at=datetime.utcnow(),
|
||||
expires_at=expire,
|
||||
)
|
||||
with get_db_session() as db_session:
|
||||
db_session.add(access_token)
|
||||
db_session.commit()
|
||||
|
||||
db_session.add(access_token)
|
||||
db_session.commit()
|
||||
|
||||
return encoded_jwt
|
||||
|
||||
|
||||
def remove_expired_tokens():
|
||||
# Get the tracer from the main module
|
||||
tracer = trace.get_tracer(__name__)
|
||||
|
||||
with tracer.start_as_current_span("remove_expired_tokens"):
|
||||
try:
|
||||
# Calculate the expiration time
|
||||
expiration_time = datetime.utcnow() - timedelta(
|
||||
minutes=int(os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES"))
|
||||
)
|
||||
|
||||
# Add tags related to the expiration check
|
||||
trace.get_current_span().set_attribute(
|
||||
"expiration_time", expiration_time.isoformat()
|
||||
)
|
||||
trace.get_current_span().set_attribute(
|
||||
"token_expire_minutes", os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES")
|
||||
)
|
||||
|
||||
# Delete expired access tokens using SQLAlchemy ORM
|
||||
with get_db_session() as db_session:
|
||||
rows_deleted = (
|
||||
db_session.query(AccessToken)
|
||||
.filter(AccessToken.created_at < expiration_time)
|
||||
.delete()
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
# Add tags related to the database operation
|
||||
trace.get_current_span().set_attribute("tokens_deleted", rows_deleted)
|
||||
trace.get_current_span().set_attribute("database_commit", "success")
|
||||
|
||||
logger.info(f"{rows_deleted} access tokens deleted from the database")
|
||||
# Log a success event
|
||||
trace.get_current_span().add_event(
|
||||
"SuccessEvent",
|
||||
{"message": f"{rows_deleted} access tokens deleted from the database"},
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
# Add tags related to the error
|
||||
trace.get_current_span().set_attribute("error_message", str(e))
|
||||
trace.get_current_span().set_attribute("database_commit", "failure")
|
||||
|
||||
trace.get_current_span().set_status(
|
||||
trace.status.Status(trace.StatusCode.ERROR, str(e))
|
||||
)
|
||||
|
||||
|
||||
def get_user_data(token: str):
|
||||
def remove_expired_tokens(db_session: Session):
|
||||
try:
|
||||
validate_token(token)
|
||||
payload = jwt.decode(
|
||||
token,
|
||||
os.environ.get("SECRET_KEY"),
|
||||
algorithms=[os.environ.get("ALGORITHM")],
|
||||
# Calculate the expiration time
|
||||
expiration_time = datetime.utcnow() - timedelta(
|
||||
minutes=int(os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES"))
|
||||
)
|
||||
user_id = payload.get("id")
|
||||
|
||||
# Delete expired access tokens using SQLAlchemy ORM
|
||||
rows_deleted = (
|
||||
db_session.query(AccessToken)
|
||||
.filter(AccessToken.created_at < expiration_time)
|
||||
.delete()
|
||||
)
|
||||
db_session.commit()
|
||||
|
||||
logger.info(f"{rows_deleted} access tokens deleted from the database")
|
||||
except Exception as err:
|
||||
logger.error(f"Error in remove_expired_tokens: {err}", exc_info=True)
|
||||
|
||||
|
||||
def get_user_data(db_session: Session, token: str = Depends(oauth2_scheme)):
|
||||
try:
|
||||
validate_token(db_session=db_session, token=token)
|
||||
|
||||
user_id = get_user_id_from_token(token)
|
||||
if user_id is None:
|
||||
raise HTTPException(
|
||||
status_code=401, detail="Invalid authentication credentials"
|
||||
)
|
||||
|
||||
with get_db_session() as db_session:
|
||||
# Retrieve the user details from the database using the user ID
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
# Retrieve the user details from the database using the user ID
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
|
||||
if user.strava_token is None:
|
||||
is_strava_linked = 0
|
||||
else:
|
||||
is_strava_linked = 1
|
||||
if user.strava_token is None:
|
||||
is_strava_linked = 0
|
||||
else:
|
||||
is_strava_linked = 1
|
||||
|
||||
# Map the user object to a dictionary that matches the UserResponse model
|
||||
user_data = {
|
||||
"id": user.id,
|
||||
"name": user.name,
|
||||
"username": user.username,
|
||||
"email": user.email,
|
||||
"city": user.city,
|
||||
"birthdate": user.birthdate,
|
||||
"preferred_language": user.preferred_language,
|
||||
"gender": user.gender,
|
||||
"access_type": user.access_type,
|
||||
"photo_path": user.photo_path,
|
||||
"photo_path_aux": user.photo_path_aux,
|
||||
"is_active": user.is_active,
|
||||
"is_strava_linked": is_strava_linked,
|
||||
}
|
||||
# Map the user object to a dictionary that matches the UserResponse model
|
||||
user_data = {
|
||||
"id": user.id,
|
||||
"name": user.name,
|
||||
"username": user.username,
|
||||
"email": user.email,
|
||||
"city": user.city,
|
||||
"birthdate": user.birthdate,
|
||||
"preferred_language": user.preferred_language,
|
||||
"gender": user.gender,
|
||||
"access_type": user.access_type,
|
||||
"photo_path": user.photo_path,
|
||||
"photo_path_aux": user.photo_path_aux,
|
||||
"is_active": user.is_active,
|
||||
"is_strava_linked": is_strava_linked,
|
||||
}
|
||||
|
||||
return user_data
|
||||
return user_data
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
|
||||
def validate_token(token: str):
|
||||
def validate_token(db_session: Session, token: str):
|
||||
try:
|
||||
decoded_token = jwt.decode(
|
||||
token,
|
||||
os.environ.get("SECRET_KEY"),
|
||||
algorithms=[os.environ.get("ALGORITHM")],
|
||||
)
|
||||
user_id = decoded_token.get("id")
|
||||
with get_db_session() as db_session:
|
||||
access_token = (
|
||||
db_session.query(AccessToken)
|
||||
.filter(AccessToken.user_id == user_id, AccessToken.token == token)
|
||||
.first()
|
||||
)
|
||||
user_id = get_user_id_from_token(token)
|
||||
|
||||
if access_token:
|
||||
expiration_datetime = datetime.fromtimestamp(decoded_token["exp"])
|
||||
current_time = datetime.utcnow()
|
||||
if current_time > expiration_datetime:
|
||||
raise JWTError("Token expired")
|
||||
else:
|
||||
return {"message": "Token is valid"}
|
||||
else:
|
||||
exp = get_exp_from_token(token)
|
||||
|
||||
access_token = (
|
||||
db_session.query(AccessToken)
|
||||
.filter(AccessToken.user_id == user_id, AccessToken.token == token)
|
||||
.first()
|
||||
)
|
||||
|
||||
if access_token:
|
||||
expiration_datetime = datetime.fromtimestamp(exp)
|
||||
current_time = datetime.utcnow()
|
||||
if current_time > expiration_datetime:
|
||||
raise JWTError("Token expired")
|
||||
else:
|
||||
return {"message": "Token is valid"}
|
||||
else:
|
||||
raise JWTError("Token expired")
|
||||
|
||||
# if 'exp' not in decoded_token:
|
||||
# return {"message": "Token is valid"}
|
||||
@@ -228,12 +225,7 @@ def validate_token(token: str):
|
||||
|
||||
def validate_admin_access(token: str):
|
||||
try:
|
||||
payload = jwt.decode(
|
||||
token,
|
||||
os.environ.get("SECRET_KEY"),
|
||||
algorithms=[os.environ.get("ALGORITHM")],
|
||||
)
|
||||
user_access_type = payload.get("access_type")
|
||||
user_access_type = get_access_type_from_token(token)
|
||||
if user_access_type != 2:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
except JWTError:
|
||||
@@ -247,9 +239,11 @@ class CreateTokenRequest(BaseModel):
|
||||
|
||||
|
||||
@router.post("/token")
|
||||
async def login_for_access_token(token: CreateTokenRequest):
|
||||
async def login_for_access_token(
|
||||
token: CreateTokenRequest, db_session: Session = Depends(get_db_session)
|
||||
):
|
||||
access_token = await authenticate_user(
|
||||
token.username, token.password, token.neverExpires
|
||||
token.username, token.password, token.neverExpires, db_session
|
||||
)
|
||||
if not access_token:
|
||||
raise HTTPException(status_code=400, detail="Unable to retrieve access token")
|
||||
@@ -257,33 +251,40 @@ async def login_for_access_token(token: CreateTokenRequest):
|
||||
|
||||
|
||||
@router.delete("/logout/{user_id}")
|
||||
async def logout(user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def logout(
|
||||
user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
with get_db_session() as db_session:
|
||||
access_token = (
|
||||
db_session.query(AccessToken)
|
||||
.filter(AccessToken.user_id == user_id, AccessToken.token == token)
|
||||
.first()
|
||||
)
|
||||
if access_token:
|
||||
db_session.delete(access_token)
|
||||
db_session.commit()
|
||||
return {"message": "Logged out successfully"}
|
||||
else:
|
||||
raise HTTPException(status_code=404, detail="Token not found")
|
||||
access_token = (
|
||||
db_session.query(AccessToken)
|
||||
.filter(AccessToken.user_id == user_id, AccessToken.token == token)
|
||||
.first()
|
||||
)
|
||||
if access_token:
|
||||
db_session.delete(access_token)
|
||||
db_session.commit()
|
||||
return {"message": "Logged out successfully"}
|
||||
else:
|
||||
raise HTTPException(status_code=404, detail="Token not found")
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
raise HTTPException(status_code=500, detail="Failed to invalidate access token")
|
||||
|
||||
|
||||
@router.get("/validate_token")
|
||||
async def check_validate_token(token: str = Depends(oauth2_scheme)):
|
||||
async def check_validate_token(
|
||||
token: str = Depends(oauth2_scheme), db_session: Session = Depends(get_db_session)
|
||||
):
|
||||
try:
|
||||
return validate_token(token)
|
||||
return validate_token(db_session, token)
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
|
||||
|
||||
@router.get("/users/me", response_model=UserResponse)
|
||||
async def read_users_me(token: str = Depends(oauth2_scheme)):
|
||||
return get_user_data(token)
|
||||
async def read_users_me(
|
||||
token: str = Depends(oauth2_scheme), db_session: Session = Depends(get_db_session)
|
||||
):
|
||||
return get_user_data(db_session, token)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from datetime import datetime, timedelta
|
||||
from db.db import get_db_session, User, Activity
|
||||
from db.db import User, Activity
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from fastapi.responses import RedirectResponse
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
@@ -10,7 +10,9 @@ from concurrent.futures import ThreadPoolExecutor
|
||||
from fastapi import BackgroundTasks
|
||||
from opentelemetry import trace
|
||||
from urllib.parse import urlencode
|
||||
from . import sessionController
|
||||
from . import sessionController
|
||||
from dependencies import get_db_session
|
||||
from sqlalchemy.orm import Session
|
||||
import logging
|
||||
import requests
|
||||
import os
|
||||
@@ -19,15 +21,17 @@ router = APIRouter()
|
||||
|
||||
logger = logging.getLogger("myLogger")
|
||||
|
||||
# Load the environment variables from config/.env
|
||||
#load_dotenv("config/.env")
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||
|
||||
|
||||
# Strava route to link user Strava account
|
||||
@router.get("/strava/strava-callback")
|
||||
async def strava_callback(state: str, code: str, background_tasks: BackgroundTasks):
|
||||
async def strava_callback(
|
||||
state: str,
|
||||
code: str,
|
||||
background_tasks: BackgroundTasks,
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
"""
|
||||
Callback endpoint for Strava OAuth2 authorization.
|
||||
|
||||
@@ -63,35 +67,35 @@ async def strava_callback(state: str, code: str, background_tasks: BackgroundTas
|
||||
|
||||
tokens = response.json()
|
||||
|
||||
with get_db_session() as db_session:
|
||||
# Query the activities records using SQLAlchemy
|
||||
db_user = db_session.query(User).filter(User.strava_state == state).first()
|
||||
# Query the activities records using SQLAlchemy
|
||||
db_user = db_session.query(User).filter(User.strava_state == state).first()
|
||||
|
||||
if db_user:
|
||||
db_user.strava_token = tokens["access_token"]
|
||||
db_user.strava_refresh_token = tokens["refresh_token"]
|
||||
db_user.strava_token_expires_at = datetime.fromtimestamp(
|
||||
tokens["expires_at"]
|
||||
)
|
||||
db_session.commit() # Commit the changes to the database
|
||||
if db_user:
|
||||
db_user.strava_token = tokens["access_token"]
|
||||
db_user.strava_refresh_token = tokens["refresh_token"]
|
||||
db_user.strava_token_expires_at = datetime.fromtimestamp(
|
||||
tokens["expires_at"]
|
||||
)
|
||||
db_session.commit() # Commit the changes to the database
|
||||
|
||||
# get_strava_activities((datetime.utcnow() - timedelta(days=90)).strftime("%Y-%m-%dT%H:%M:%SZ"))
|
||||
background_tasks.add_task(
|
||||
get_user_strava_activities,
|
||||
(
|
||||
datetime.utcnow()
|
||||
- timedelta(
|
||||
days=int(os.environ.get("STRAVA_DAYS_ACTIVITIES_ONLINK"))
|
||||
)
|
||||
).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
db_user.id,
|
||||
)
|
||||
# get_strava_activities((datetime.utcnow() - timedelta(days=90)).strftime("%Y-%m-%dT%H:%M:%SZ"))
|
||||
background_tasks.add_task(
|
||||
get_user_strava_activities,
|
||||
(
|
||||
datetime.utcnow()
|
||||
- timedelta(
|
||||
days=int(os.environ.get("STRAVA_DAYS_ACTIVITIES_ONLINK"))
|
||||
)
|
||||
).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
db_user.id,
|
||||
db_session,
|
||||
)
|
||||
|
||||
# Redirect to the main page or any other desired page after processing
|
||||
redirect_url = "https://gearguardian.jvslab.pt/settings/settings.php?profileSettings=1&stravaLinked=1" # Change this URL to your main page
|
||||
return RedirectResponse(url=redirect_url)
|
||||
else:
|
||||
raise HTTPException(status_code=404, detail="User not found.")
|
||||
# Redirect to the main page or any other desired page after processing
|
||||
redirect_url = "https://gearguardian.jvslab.pt/settings/settings.php?profileSettings=1&stravaLinked=1" # Change this URL to your main page
|
||||
return RedirectResponse(url=redirect_url)
|
||||
else:
|
||||
raise HTTPException(status_code=404, detail="User not found.")
|
||||
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
@@ -100,7 +104,7 @@ async def strava_callback(state: str, code: str, background_tasks: BackgroundTas
|
||||
|
||||
|
||||
# Strava logic to refresh user Strava account refresh account
|
||||
def refresh_strava_token():
|
||||
def refresh_strava_token(db_session: Session):
|
||||
"""
|
||||
Refresh Strava access tokens for all users.
|
||||
|
||||
@@ -124,71 +128,70 @@ def refresh_strava_token():
|
||||
token_url = "https://www.strava.com/oauth/token"
|
||||
|
||||
try:
|
||||
with get_db_session() as db_session:
|
||||
# Query all users from the database
|
||||
users = db_session.query(User).all()
|
||||
# Query all users from the database
|
||||
users = db_session.query(User).all()
|
||||
|
||||
for user in users:
|
||||
# expires_at = user.strava_token_expires_at
|
||||
if user.strava_token_expires_at is not None:
|
||||
refresh_time = user.strava_token_expires_at - timedelta(
|
||||
minutes=60
|
||||
)
|
||||
for user in users:
|
||||
# expires_at = user.strava_token_expires_at
|
||||
if user.strava_token_expires_at is not None:
|
||||
refresh_time = user.strava_token_expires_at - timedelta(minutes=60)
|
||||
|
||||
if datetime.utcnow() > refresh_time:
|
||||
# Parameters for the token refresh request
|
||||
payload = {
|
||||
"client_id": os.environ.get("STRAVA_CLIENT_ID"),
|
||||
"client_secret": os.environ.get("STRAVA_CLIENT_SECRET"),
|
||||
"refresh_token": user.strava_refresh_token,
|
||||
"grant_type": "refresh_token",
|
||||
}
|
||||
if datetime.utcnow() > refresh_time:
|
||||
# Parameters for the token refresh request
|
||||
payload = {
|
||||
"client_id": os.environ.get("STRAVA_CLIENT_ID"),
|
||||
"client_secret": os.environ.get("STRAVA_CLIENT_SECRET"),
|
||||
"refresh_token": user.strava_refresh_token,
|
||||
"grant_type": "refresh_token",
|
||||
}
|
||||
|
||||
try:
|
||||
# Make a POST request to refresh the Strava token
|
||||
response = requests.post(token_url, data=payload)
|
||||
response.raise_for_status() # Raise an error for bad responses
|
||||
try:
|
||||
# Make a POST request to refresh the Strava token
|
||||
response = requests.post(token_url, data=payload)
|
||||
response.raise_for_status() # Raise an error for bad responses
|
||||
|
||||
tokens = response.json()
|
||||
tokens = response.json()
|
||||
|
||||
# Update the user in the database
|
||||
db_user = (
|
||||
db_session.query(User)
|
||||
.filter(User.id == user.id)
|
||||
.first()
|
||||
# Update the user in the database
|
||||
db_user = (
|
||||
db_session.query(User)
|
||||
.filter(User.id == user.id)
|
||||
.first()
|
||||
)
|
||||
|
||||
if db_user:
|
||||
db_user.strava_token = tokens["access_token"]
|
||||
db_user.strava_refresh_token = tokens["refresh_token"]
|
||||
db_user.strava_token_expires_at = (
|
||||
datetime.fromtimestamp(tokens["expires_at"])
|
||||
)
|
||||
|
||||
if db_user:
|
||||
db_user.strava_token = tokens["access_token"]
|
||||
db_user.strava_refresh_token = tokens[
|
||||
"refresh_token"
|
||||
]
|
||||
db_user.strava_token_expires_at = (
|
||||
datetime.fromtimestamp(tokens["expires_at"])
|
||||
)
|
||||
db_session.commit() # Commit the changes to the database
|
||||
logger.info(
|
||||
f"Token refreshed successfully for user {user.id}."
|
||||
)
|
||||
else:
|
||||
logger.error("User not found in the database.")
|
||||
except requests.exceptions.RequestException as req_err:
|
||||
logger.error(
|
||||
f"Error refreshing token for user {user.id}: {req_err}"
|
||||
db_session.commit() # Commit the changes to the database
|
||||
logger.info(
|
||||
f"Token refreshed successfully for user {user.id}."
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
f"Token not refreshed for user {user.id}. Will not expire in less than 60min"
|
||||
else:
|
||||
logger.error("User not found in the database.")
|
||||
except requests.exceptions.RequestException as req_err:
|
||||
logger.error(
|
||||
f"Error refreshing token for user {user.id}: {req_err}"
|
||||
)
|
||||
else:
|
||||
logger.info(f"User {user.id} does not have strava linked")
|
||||
logger.info(
|
||||
f"Token not refreshed for user {user.id}. Will not expire in less than 60min"
|
||||
)
|
||||
else:
|
||||
logger.info(f"User {user.id} does not have strava linked")
|
||||
except NameError as db_err:
|
||||
logger.error(f"Database error: {db_err}")
|
||||
|
||||
|
||||
# Define an HTTP PUT route set strava unique state for link logic
|
||||
@router.put("/strava/set-user-unique-state/{state}")
|
||||
async def strava_set_user_unique_state(state: str, token: str = Depends(oauth2_scheme)):
|
||||
async def strava_set_user_unique_state(
|
||||
state: str,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
"""
|
||||
Set the Strava unique state for a user.
|
||||
|
||||
@@ -208,25 +211,21 @@ async def strava_set_user_unique_state(state: str, token: str = Depends(oauth2_s
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
|
||||
with get_db_session() as db_session:
|
||||
# From the token retrieve the user_id
|
||||
payload = jwt.decode(
|
||||
token, os.environ.get("SECRET_KEY"), algorithms=[os.environ.get("ALGORITHM")]
|
||||
)
|
||||
user_id = payload.get("id")
|
||||
# Get the user ID from the token
|
||||
user_id = sessionController.get_user_id_from_token(token)
|
||||
|
||||
# Query the database to find the user by their ID
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
# Query the database to find the user by their ID
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
|
||||
# Check if the user with the given ID exists
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
# Check if the user with the given ID exists
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
|
||||
# Set the user's photo paths to None to delete the photo
|
||||
user.strava_state = state
|
||||
# Set the user's photo paths to None to delete the photo
|
||||
user.strava_state = state
|
||||
|
||||
# Commit the changes to the database
|
||||
db_session.commit()
|
||||
# Commit the changes to the database
|
||||
db_session.commit()
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
@@ -243,7 +242,9 @@ async def strava_set_user_unique_state(state: str, token: str = Depends(oauth2_s
|
||||
|
||||
# Define an HTTP PUT route set strava unique state for link logic
|
||||
@router.put("/strava/unset-user-unique-state")
|
||||
async def strava_unset_user_unique_state(token: str = Depends(oauth2_scheme)):
|
||||
async def strava_unset_user_unique_state(
|
||||
token: str = Depends(oauth2_scheme), db_session: Session = Depends(get_db_session)
|
||||
):
|
||||
"""
|
||||
Unset the Strava unique state for a user.
|
||||
|
||||
@@ -262,25 +263,21 @@ async def strava_unset_user_unique_state(token: str = Depends(oauth2_scheme)):
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
|
||||
with get_db_session() as db_session:
|
||||
# From the token retrieve the user_id
|
||||
payload = jwt.decode(
|
||||
token, os.environ.get("SECRET_KEY"), algorithms=[os.environ.get("ALGORITHM")]
|
||||
)
|
||||
user_id = payload.get("id")
|
||||
# Get the user ID from the token
|
||||
user_id = sessionController.get_user_id_from_token(token)
|
||||
|
||||
# Query the database to find the user by their ID
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
# Query the database to find the user by their ID
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
|
||||
# Check if the user with the given ID exists
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
# Check if the user with the given ID exists
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
|
||||
# Set the user's photo paths to None to delete the photo
|
||||
user.strava_state = None
|
||||
# Set the user's photo paths to None to delete the photo
|
||||
user.strava_state = None
|
||||
|
||||
# Commit the changes to the database
|
||||
db_session.commit()
|
||||
# Commit the changes to the database
|
||||
db_session.commit()
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
@@ -295,7 +292,7 @@ async def strava_unset_user_unique_state(token: str = Depends(oauth2_scheme)):
|
||||
return {"message": f"Strava state for user {user_id} has been updated"}
|
||||
|
||||
|
||||
def get_strava_activities(start_date: datetime):
|
||||
def get_strava_activities(start_date: datetime, db_session: Session):
|
||||
"""
|
||||
Retrieve and process Strava activities for all users in the database.
|
||||
|
||||
@@ -314,128 +311,21 @@ def get_strava_activities(start_date: datetime):
|
||||
|
||||
with tracer.start_as_current_span("get_strava_activities"):
|
||||
try:
|
||||
with get_db_session() as db_session:
|
||||
# Query all users from the database
|
||||
users = db_session.query(User).all()
|
||||
# Query all users from the database
|
||||
users = db_session.query(User).all()
|
||||
|
||||
for user in users:
|
||||
if user.strava_token_expires_at is not None:
|
||||
# Log an informational event for tracing
|
||||
trace.get_current_span().add_event(
|
||||
"InfoEvent",
|
||||
{
|
||||
"message": f"User {user.id}: Started periodic activities processing"
|
||||
},
|
||||
)
|
||||
|
||||
# Create a Strava client with the user's access token
|
||||
stravaClient = Client(access_token=user.strava_token)
|
||||
|
||||
# Fetch Strava activities after the specified start date
|
||||
strava_activities = list(
|
||||
stravaClient.get_activities(after=start_date)
|
||||
)
|
||||
|
||||
if strava_activities:
|
||||
# Initialize an empty list for results
|
||||
all_results = []
|
||||
|
||||
# Use ThreadPoolExecutor for parallel processing of activities
|
||||
with ThreadPoolExecutor() as executor:
|
||||
results = list(
|
||||
executor.map(
|
||||
lambda activity: process_activity(
|
||||
activity, user.id, stravaClient
|
||||
),
|
||||
strava_activities,
|
||||
)
|
||||
)
|
||||
|
||||
# Append non-empty and non-None results to the overall results list
|
||||
all_results.extend(results)
|
||||
|
||||
# Flatten the list of results
|
||||
activities_to_insert = [
|
||||
activity
|
||||
for sublist in all_results
|
||||
for activity in sublist
|
||||
]
|
||||
|
||||
# Bulk insert all activities into the database
|
||||
with get_db_session() as db_session:
|
||||
db_session.bulk_save_objects(activities_to_insert)
|
||||
db_session.commit()
|
||||
|
||||
# Log an informational event for tracing
|
||||
trace.get_current_span().add_event(
|
||||
"InfoEvent",
|
||||
{
|
||||
"message": f"User {user.id}: {len(strava_activities)} periodic activities processed"
|
||||
},
|
||||
)
|
||||
|
||||
else:
|
||||
# Log an informational event if no activities were found
|
||||
trace.get_current_span().add_event(
|
||||
"InfoEvent",
|
||||
{
|
||||
"message": f"User {user.id}: No new activities found after {start_date}"
|
||||
},
|
||||
)
|
||||
|
||||
else:
|
||||
# Log an informational event if the user does not have Strava linked
|
||||
logger.info(f"User {user.id} does not have Strava linked")
|
||||
trace.get_current_span().add_event(
|
||||
"InfoEvent",
|
||||
{"message": f"User {user.id} does not have Strava linked"},
|
||||
)
|
||||
except NameError as db_err:
|
||||
# Log an error event if a NameError occurs (e.g., undefined function or variable)
|
||||
logger.error(f"Database error: {db_err}")
|
||||
trace.get_current_span().add_event(
|
||||
"ErrorEvent",
|
||||
{"message": f"Database error: {db_err}"},
|
||||
)
|
||||
|
||||
|
||||
def get_user_strava_activities(start_date: datetime, user_id: int):
|
||||
"""
|
||||
Retrieve Strava activities for a user, process them, and store in the database.
|
||||
|
||||
This function fetches Strava activities for a specified user after a given start date.
|
||||
It processes the activities using parallel execution, creates corresponding database
|
||||
records, and bulk inserts them into the database.
|
||||
|
||||
Parameters:
|
||||
- start_date (datetime): The start date for retrieving Strava activities.
|
||||
- user_id (int): The ID of the user for whom activities are to be processed.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# Get the tracer from the main module
|
||||
tracer = trace.get_tracer(__name__)
|
||||
|
||||
with tracer.start_as_current_span("get_user_strava_activities"):
|
||||
with get_db_session() as db_session:
|
||||
# Query user from the database
|
||||
db_user = db_session.query(User).get(user_id)
|
||||
|
||||
# Check if db returned an user object and variable is set
|
||||
if db_user:
|
||||
if db_user.strava_token_expires_at is not None:
|
||||
for user in users:
|
||||
if user.strava_token_expires_at is not None:
|
||||
# Log an informational event for tracing
|
||||
trace.get_current_span().add_event(
|
||||
"InfoEvent",
|
||||
{
|
||||
"message": f"User {db_user.id}: Started initial activities processing"
|
||||
"message": f"User {user.id}: Started periodic activities processing"
|
||||
},
|
||||
)
|
||||
|
||||
# Create a Strava client with the user's access token
|
||||
stravaClient = Client(access_token=db_user.strava_token)
|
||||
stravaClient = Client(access_token=user.strava_token)
|
||||
|
||||
# Fetch Strava activities after the specified start date
|
||||
strava_activities = list(
|
||||
@@ -451,7 +341,7 @@ def get_user_strava_activities(start_date: datetime, user_id: int):
|
||||
results = list(
|
||||
executor.map(
|
||||
lambda activity: process_activity(
|
||||
activity, db_user.id, stravaClient
|
||||
activity, user.id, stravaClient, db_session
|
||||
),
|
||||
strava_activities,
|
||||
)
|
||||
@@ -474,7 +364,7 @@ def get_user_strava_activities(start_date: datetime, user_id: int):
|
||||
trace.get_current_span().add_event(
|
||||
"InfoEvent",
|
||||
{
|
||||
"message": f"User {db_user.id}: {len(strava_activities)} initial activities processed"
|
||||
"message": f"User {user.id}: {len(strava_activities)} periodic activities processed"
|
||||
},
|
||||
)
|
||||
|
||||
@@ -483,28 +373,129 @@ def get_user_strava_activities(start_date: datetime, user_id: int):
|
||||
trace.get_current_span().add_event(
|
||||
"InfoEvent",
|
||||
{
|
||||
"message": f"User {db_user.id}: No new activities found after {start_date}"
|
||||
"message": f"User {user.id}: No new activities found after {start_date}"
|
||||
},
|
||||
)
|
||||
|
||||
else:
|
||||
# Log an informational event if the user does not have Strava linked
|
||||
logger.info(f"User {db_user.id} does not have Strava linked")
|
||||
logger.info(f"User {user.id} does not have Strava linked")
|
||||
trace.get_current_span().add_event(
|
||||
"InfoEvent",
|
||||
{"message": f"User {db_user.id} does not have Strava linked"},
|
||||
{"message": f"User {user.id} does not have Strava linked"},
|
||||
)
|
||||
except NameError as db_err:
|
||||
# Log an error event if a NameError occurs (e.g., undefined function or variable)
|
||||
logger.error(f"Database error: {db_err}")
|
||||
trace.get_current_span().add_event(
|
||||
"ErrorEvent",
|
||||
{"message": f"Database error: {db_err}"},
|
||||
)
|
||||
|
||||
|
||||
def get_user_strava_activities(start_date: datetime, user_id: int, db_session: Session):
|
||||
"""
|
||||
Retrieve Strava activities for a user, process them, and store in the database.
|
||||
|
||||
This function fetches Strava activities for a specified user after a given start date.
|
||||
It processes the activities using parallel execution, creates corresponding database
|
||||
records, and bulk inserts them into the database.
|
||||
|
||||
Parameters:
|
||||
- start_date (datetime): The start date for retrieving Strava activities.
|
||||
- user_id (int): The ID of the user for whom activities are to be processed.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
# Get the tracer from the main module
|
||||
tracer = trace.get_tracer(__name__)
|
||||
|
||||
with tracer.start_as_current_span("get_user_strava_activities"):
|
||||
# Query user from the database
|
||||
db_user = db_session.query(User).get(user_id)
|
||||
|
||||
# Check if db returned an user object and variable is set
|
||||
if db_user:
|
||||
if db_user.strava_token_expires_at is not None:
|
||||
# Log an informational event for tracing
|
||||
trace.get_current_span().add_event(
|
||||
"InfoEvent",
|
||||
{
|
||||
"message": f"User {db_user.id}: Started initial activities processing"
|
||||
},
|
||||
)
|
||||
|
||||
# Create a Strava client with the user's access token
|
||||
stravaClient = Client(access_token=db_user.strava_token)
|
||||
|
||||
# Fetch Strava activities after the specified start date
|
||||
strava_activities = list(stravaClient.get_activities(after=start_date))
|
||||
|
||||
if strava_activities:
|
||||
# Initialize an empty list for results
|
||||
all_results = []
|
||||
|
||||
# Use ThreadPoolExecutor for parallel processing of activities
|
||||
with ThreadPoolExecutor() as executor:
|
||||
results = list(
|
||||
executor.map(
|
||||
lambda activity: process_activity(
|
||||
activity, db_user.id, stravaClient, db_session
|
||||
),
|
||||
strava_activities,
|
||||
)
|
||||
)
|
||||
|
||||
# Append non-empty and non-None results to the overall results list
|
||||
all_results.extend(results)
|
||||
|
||||
# Flatten the list of results
|
||||
activities_to_insert = [
|
||||
activity for sublist in all_results for activity in sublist
|
||||
]
|
||||
|
||||
# Bulk insert all activities into the database
|
||||
with get_db_session() as db_session:
|
||||
db_session.bulk_save_objects(activities_to_insert)
|
||||
db_session.commit()
|
||||
|
||||
# Log an informational event for tracing
|
||||
trace.get_current_span().add_event(
|
||||
"InfoEvent",
|
||||
{
|
||||
"message": f"User {db_user.id}: {len(strava_activities)} initial activities processed"
|
||||
},
|
||||
)
|
||||
|
||||
else:
|
||||
# Log an informational event if no activities were found
|
||||
trace.get_current_span().add_event(
|
||||
"InfoEvent",
|
||||
{
|
||||
"message": f"User {db_user.id}: No new activities found after {start_date}"
|
||||
},
|
||||
)
|
||||
|
||||
else:
|
||||
# Log an informational event if the user is not found
|
||||
logger.info(f"User with ID {user_id} not found.")
|
||||
# Log an informational event if the user does not have Strava linked
|
||||
logger.info(f"User {db_user.id} does not have Strava linked")
|
||||
trace.get_current_span().add_event(
|
||||
"InfoEvent",
|
||||
{"message": f"User with ID {user_id} not found"},
|
||||
{"message": f"User {db_user.id} does not have Strava linked"},
|
||||
)
|
||||
|
||||
else:
|
||||
# Log an informational event if the user is not found
|
||||
logger.info(f"User with ID {user_id} not found.")
|
||||
trace.get_current_span().add_event(
|
||||
"InfoEvent",
|
||||
{"message": f"User with ID {user_id} not found"},
|
||||
)
|
||||
|
||||
def process_activity(activity, user_id, stravaClient):
|
||||
|
||||
def process_activity(activity, user_id, stravaClient, db_session: Session):
|
||||
"""
|
||||
Process a Strava activity and create a corresponding database record.
|
||||
|
||||
@@ -527,17 +518,16 @@ def process_activity(activity, user_id, stravaClient):
|
||||
with tracer.start_as_current_span("process_activity"):
|
||||
activities_to_insert = []
|
||||
|
||||
with get_db_session() as db_session:
|
||||
# Check if the activity already exists in the database
|
||||
activity_record = (
|
||||
db_session.query(Activity)
|
||||
.filter(Activity.strava_activity_id == activity.id)
|
||||
.first()
|
||||
)
|
||||
# Check if the activity already exists in the database
|
||||
activity_record = (
|
||||
db_session.query(Activity)
|
||||
.filter(Activity.strava_activity_id == activity.id)
|
||||
.first()
|
||||
)
|
||||
|
||||
if activity_record:
|
||||
# Skip existing activities
|
||||
return activities_to_insert
|
||||
if activity_record:
|
||||
# Skip existing activities
|
||||
return activities_to_insert
|
||||
|
||||
# Parse start and end dates
|
||||
start_date_parsed = activity.start_date
|
||||
|
||||
@@ -5,13 +5,14 @@ from typing import List, Optional
|
||||
from jose import JWTError
|
||||
import logging
|
||||
from datetime import date
|
||||
from . import sessionController
|
||||
from . import sessionController
|
||||
from sqlalchemy.orm import Session
|
||||
from db.db import (
|
||||
get_db_session,
|
||||
User,
|
||||
Gear,
|
||||
)
|
||||
from urllib.parse import unquote
|
||||
from dependencies import get_db_session
|
||||
|
||||
# Create an instance of an APIRouter
|
||||
router = APIRouter()
|
||||
@@ -40,21 +41,22 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||
|
||||
# Define an HTTP GET route to retrieve all users
|
||||
@router.get("/users/all", response_model=list[dict])
|
||||
async def read_users_all(token: str = Depends(oauth2_scheme)):
|
||||
async def read_users_all(
|
||||
token: str = Depends(oauth2_scheme), db_session: Session = Depends(get_db_session)
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Validate that the user has admin access
|
||||
sessionController.validate_admin_access(token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Query all users from the database
|
||||
users = db_session.query(User).all()
|
||||
# Query all users from the database
|
||||
users = db_session.query(User).all()
|
||||
|
||||
# Convert the SQLAlchemy User objects to dictionaries
|
||||
results = [user.__dict__ for user in users]
|
||||
# Convert the SQLAlchemy User objects to dictionaries
|
||||
results = [user.__dict__ for user in users]
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
@@ -65,18 +67,18 @@ async def read_users_all(token: str = Depends(oauth2_scheme)):
|
||||
|
||||
# Define an HTTP GET route to retrieve the number of users
|
||||
@router.get("/users/number")
|
||||
async def read_users_number(token: str = Depends(oauth2_scheme)):
|
||||
async def read_users_number(
|
||||
token: str = Depends(oauth2_scheme), db_session: Session = Depends(get_db_session)
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Validate that the user has admin access
|
||||
sessionController.validate_admin_access(token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Count the number of users in the database
|
||||
user_count = db_session.query(User).count()
|
||||
# Count the number of users in the database
|
||||
user_count = db_session.query(User).count()
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
@@ -91,28 +93,29 @@ async def read_users_number(token: str = Depends(oauth2_scheme)):
|
||||
response_model=List[dict],
|
||||
)
|
||||
async def read_users_all_pagination(
|
||||
pageNumber: int, numRecords: int, token: str = Depends(oauth2_scheme)
|
||||
pageNumber: int,
|
||||
numRecords: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Validate that the user has admin access
|
||||
sessionController.validate_admin_access(token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Use SQLAlchemy to query the user records with pagination
|
||||
user_records = (
|
||||
db_session.query(User)
|
||||
.order_by(User.name.asc())
|
||||
.offset((pageNumber - 1) * numRecords)
|
||||
.limit(numRecords)
|
||||
.all()
|
||||
)
|
||||
# Use SQLAlchemy to query the user records with pagination
|
||||
user_records = (
|
||||
db_session.query(User)
|
||||
.order_by(User.name.asc())
|
||||
.offset((pageNumber - 1) * numRecords)
|
||||
.limit(numRecords)
|
||||
.all()
|
||||
)
|
||||
|
||||
# Convert the SQLAlchemy results to a list of dictionaries
|
||||
results = [record.__dict__ for record in user_records]
|
||||
# Convert the SQLAlchemy results to a list of dictionaries
|
||||
results = [record.__dict__ for record in user_records]
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
@@ -128,11 +131,13 @@ async def read_users_all_pagination(
|
||||
# Define an HTTP GET route to retrieve user records by username
|
||||
@router.get("/users/{username}/userfromusername", response_model=List[dict])
|
||||
async def read_users_userFromUsername(
|
||||
username: str, token: str = Depends(oauth2_scheme)
|
||||
username: str,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Validate that the user has admin access
|
||||
sessionController.validate_admin_access(token)
|
||||
@@ -140,17 +145,15 @@ async def read_users_userFromUsername(
|
||||
# Define a search term
|
||||
partial_username = unquote(username).replace("+", " ")
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Use SQLAlchemy to query the user records by username
|
||||
user_records = (
|
||||
db_session.query(User)
|
||||
.filter(User.username.like(f"%{partial_username}%"))
|
||||
.all()
|
||||
)
|
||||
# Use SQLAlchemy to query the user records by username
|
||||
user_records = (
|
||||
db_session.query(User)
|
||||
.filter(User.username.like(f"%{partial_username}%"))
|
||||
.all()
|
||||
)
|
||||
|
||||
# Convert the SQLAlchemy results to a list of dictionaries
|
||||
results = [record.__dict__ for record in user_records]
|
||||
# Convert the SQLAlchemy results to a list of dictionaries
|
||||
results = [record.__dict__ for record in user_records]
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
@@ -165,21 +168,23 @@ async def read_users_userFromUsername(
|
||||
|
||||
# Define an HTTP GET route to retrieve user records by user ID
|
||||
@router.get("/users/{user_id}/userfromid", response_model=List[dict])
|
||||
async def read_users_userFromId(user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def read_users_userFromId(
|
||||
user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Validate that the user has admin access
|
||||
sessionController.validate_admin_access(token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Use SQLAlchemy to query the user records by user ID
|
||||
user_records = db_session.query(User).filter(User.id == user_id).all()
|
||||
# Use SQLAlchemy to query the user records by user ID
|
||||
user_records = db_session.query(User).filter(User.id == user_id).all()
|
||||
|
||||
# Convert the SQLAlchemy results to a list of dictionaries
|
||||
results = [record.__dict__ for record in user_records]
|
||||
# Convert the SQLAlchemy results to a list of dictionaries
|
||||
results = [record.__dict__ for record in user_records]
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
@@ -195,23 +200,23 @@ async def read_users_userFromId(user_id: int, token: str = Depends(oauth2_scheme
|
||||
# Define an HTTP GET route to retrieve user ID by username
|
||||
@router.get("/users/{username}/useridfromusername")
|
||||
async def read_users_userIDFromUsername(
|
||||
username: str, token: str = Depends(oauth2_scheme)
|
||||
username: str,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Validate that the user has admin access
|
||||
sessionController.validate_admin_access(token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Use SQLAlchemy to query the user ID by username
|
||||
user_id = (
|
||||
db_session.query(User.id)
|
||||
.filter(User.username == unquote(username).replace("+", " "))
|
||||
.first()
|
||||
)
|
||||
# Use SQLAlchemy to query the user ID by username
|
||||
user_id = (
|
||||
db_session.query(User.id)
|
||||
.filter(User.username == unquote(username).replace("+", " "))
|
||||
.first()
|
||||
)
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
@@ -222,27 +227,29 @@ async def read_users_userIDFromUsername(
|
||||
|
||||
# Define an HTTP GET route to retrieve user photos by user ID
|
||||
@router.get("/users/{user_id}/userphotofromid")
|
||||
async def read_users_userPhotoFromID(user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def read_users_userPhotoFromID(
|
||||
user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Validate that the user has admin access
|
||||
sessionController.validate_admin_access(token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Use SQLAlchemy to query the user's photo path by user ID
|
||||
user = db_session.query(User.photo_path).filter(User.id == user_id).first()
|
||||
# Use SQLAlchemy to query the user's photo path by user ID
|
||||
user = db_session.query(User.photo_path).filter(User.id == user_id).first()
|
||||
|
||||
if user:
|
||||
# Extract the photo_path attribute from the user object
|
||||
photo_path = user.photo_path
|
||||
else:
|
||||
# Handle the case where the user was not found or doesn't have a photo path
|
||||
raise HTTPException(
|
||||
status_code=404, detail="User not found or no photo path available"
|
||||
)
|
||||
if user:
|
||||
# Extract the photo_path attribute from the user object
|
||||
photo_path = user.photo_path
|
||||
else:
|
||||
# Handle the case where the user was not found or doesn't have a photo path
|
||||
raise HTTPException(
|
||||
status_code=404, detail="User not found or no photo path available"
|
||||
)
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
@@ -255,31 +262,29 @@ async def read_users_userPhotoFromID(user_id: int, token: str = Depends(oauth2_s
|
||||
# Define an HTTP GET route to retrieve user photos aux by user ID
|
||||
@router.get("/users/{user_id}/userphotoauxfromid")
|
||||
async def read_users_userPhotoAuxFromID(
|
||||
user_id: int, token: str = Depends(oauth2_scheme)
|
||||
user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Validate that the user has admin access
|
||||
sessionController.validate_admin_access(token)
|
||||
|
||||
# Create a database session using the get_db_session context manager
|
||||
with get_db_session() as db_session:
|
||||
# Use SQLAlchemy to query the user's photo path by user ID
|
||||
user = (
|
||||
db_session.query(User.photo_path_aux).filter(User.id == user_id).first()
|
||||
)
|
||||
# Use SQLAlchemy to query the user's photo path by user ID
|
||||
user = db_session.query(User.photo_path_aux).filter(User.id == user_id).first()
|
||||
|
||||
if user:
|
||||
# Extract the photo_path_aux attribute from the user object
|
||||
photo_path_aux = user.photo_path_aux
|
||||
else:
|
||||
# Handle the case where the user was not found or doesn't have a photo path
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="User not found or no photo path aux available",
|
||||
)
|
||||
if user:
|
||||
# Extract the photo_path_aux attribute from the user object
|
||||
photo_path_aux = user.photo_path_aux
|
||||
else:
|
||||
# Handle the case where the user was not found or doesn't have a photo path
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="User not found or no photo path aux available",
|
||||
)
|
||||
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
@@ -306,10 +311,14 @@ class CreateUserRequest(BaseModel):
|
||||
|
||||
# Define an HTTP POST route to create a new user
|
||||
@router.post("/users/create")
|
||||
async def create_user(user: CreateUserRequest, token: str = Depends(oauth2_scheme)):
|
||||
async def create_user(
|
||||
user: CreateUserRequest,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Validate that the user has admin access
|
||||
sessionController.validate_admin_access(token)
|
||||
@@ -330,10 +339,9 @@ async def create_user(user: CreateUserRequest, token: str = Depends(oauth2_schem
|
||||
is_active=user.is_active,
|
||||
)
|
||||
|
||||
with get_db_session() as db_session:
|
||||
# Add the new user to the database
|
||||
db_session.add(new_user)
|
||||
db_session.commit()
|
||||
# Add the new user to the database
|
||||
db_session.add(new_user)
|
||||
db_session.commit()
|
||||
|
||||
return {"message": "User added successfully"}
|
||||
except NameError as err:
|
||||
@@ -361,49 +369,49 @@ class EditUserRequest(BaseModel):
|
||||
async def edit_user(
|
||||
user_id: int,
|
||||
user_attributtes: EditUserRequest,
|
||||
token: str = Depends(oauth2_scheme), # Add the Request dependency
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Validate that the user has admin access
|
||||
sessionController.validate_admin_access(token)
|
||||
|
||||
with get_db_session() as db_session:
|
||||
# Query the database to find the user by their ID
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
# Query the database to find the user by their ID
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
|
||||
# Check if the user with the given ID exists
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
# Check if the user with the given ID exists
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
|
||||
# Update user information if provided in the form data
|
||||
if user_attributtes.name is not None:
|
||||
user.name = user_attributtes.name
|
||||
if user_attributtes.username is not None:
|
||||
user.username = user_attributtes.username
|
||||
if user_attributtes.email is not None:
|
||||
user.email = user_attributtes.email
|
||||
if user_attributtes.preferred_language is not None:
|
||||
user.preferred_language = user_attributtes.preferred_language
|
||||
if user_attributtes.city is not None:
|
||||
user.city = user_attributtes.city
|
||||
if user_attributtes.birthdate is not None:
|
||||
user.birthdate = user_attributtes.birthdate
|
||||
if user_attributtes.gender is not None:
|
||||
user.gender = user_attributtes.gender
|
||||
if user_attributtes.access_type is not None:
|
||||
user.access_type = user_attributtes.access_type
|
||||
if user_attributtes.photo_path is not None:
|
||||
user.photo_path = user_attributtes.photo_path
|
||||
if user_attributtes.photo_path_aux is not None:
|
||||
user.photo_path_aux = user_attributtes.photo_path_aux
|
||||
if user_attributtes.is_active is not None:
|
||||
user.is_active = user_attributtes.is_active
|
||||
# Update user information if provided in the form data
|
||||
if user_attributtes.name is not None:
|
||||
user.name = user_attributtes.name
|
||||
if user_attributtes.username is not None:
|
||||
user.username = user_attributtes.username
|
||||
if user_attributtes.email is not None:
|
||||
user.email = user_attributtes.email
|
||||
if user_attributtes.preferred_language is not None:
|
||||
user.preferred_language = user_attributtes.preferred_language
|
||||
if user_attributtes.city is not None:
|
||||
user.city = user_attributtes.city
|
||||
if user_attributtes.birthdate is not None:
|
||||
user.birthdate = user_attributtes.birthdate
|
||||
if user_attributtes.gender is not None:
|
||||
user.gender = user_attributtes.gender
|
||||
if user_attributtes.access_type is not None:
|
||||
user.access_type = user_attributtes.access_type
|
||||
if user_attributtes.photo_path is not None:
|
||||
user.photo_path = user_attributtes.photo_path
|
||||
if user_attributtes.photo_path_aux is not None:
|
||||
user.photo_path_aux = user_attributtes.photo_path_aux
|
||||
if user_attributtes.is_active is not None:
|
||||
user.is_active = user_attributtes.is_active
|
||||
|
||||
# Commit the changes to the database
|
||||
db_session.commit()
|
||||
# Commit the changes to the database
|
||||
db_session.commit()
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
@@ -417,28 +425,31 @@ async def edit_user(
|
||||
|
||||
# Define an HTTP PUT route to delete a user's photo
|
||||
@router.put("/users/{user_id}/delete-photo")
|
||||
async def delete_user_photo(user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def delete_user_photo(
|
||||
user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Validate that the user has admin access
|
||||
sessionController.validate_admin_access(token)
|
||||
|
||||
with get_db_session() as db_session:
|
||||
# Query the database to find the user by their ID
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
# Query the database to find the user by their ID
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
|
||||
# Check if the user with the given ID exists
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
# Check if the user with the given ID exists
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
|
||||
# Set the user's photo paths to None to delete the photo
|
||||
user.photo_path = None
|
||||
user.photo_path_aux = None
|
||||
# Set the user's photo paths to None to delete the photo
|
||||
user.photo_path = None
|
||||
user.photo_path_aux = None
|
||||
|
||||
# Commit the changes to the database
|
||||
db_session.commit()
|
||||
# Commit the changes to the database
|
||||
db_session.commit()
|
||||
except JWTError:
|
||||
# Handle JWT (JSON Web Token) authentication error
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
@@ -453,31 +464,34 @@ async def delete_user_photo(user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
|
||||
# Define an HTTP DELETE route to delete a user
|
||||
@router.delete("/users/{user_id}/delete")
|
||||
async def delete_user(user_id: int, token: str = Depends(oauth2_scheme)):
|
||||
async def delete_user(
|
||||
user_id: int,
|
||||
token: str = Depends(oauth2_scheme),
|
||||
db_session: Session = Depends(get_db_session),
|
||||
):
|
||||
try:
|
||||
# Validate the user's access token using the oauth2_scheme
|
||||
sessionController.validate_token(token)
|
||||
sessionController.validate_token(db_session, token)
|
||||
|
||||
# Validate that the user has admin access
|
||||
sessionController.validate_admin_access(token)
|
||||
|
||||
with get_db_session() as db_session:
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
user = db_session.query(User).filter(User.id == user_id).first()
|
||||
|
||||
# Check if the user with the given ID exists
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
# Check if the user with the given ID exists
|
||||
if not user:
|
||||
raise HTTPException(status_code=404, detail="User not found")
|
||||
|
||||
# Check for existing dependencies if needed (e.g., related systems)
|
||||
count_gear = db_session.query(Gear).filter(Gear.user_id == user_id).count()
|
||||
if count_gear > 0:
|
||||
raise HTTPException(
|
||||
status_code=409,
|
||||
detail="Cannot delete user due to existing dependencies",
|
||||
)
|
||||
# Delete the user from the database
|
||||
db_session.delete(user)
|
||||
db_session.commit()
|
||||
# Check for existing dependencies if needed (e.g., related systems)
|
||||
count_gear = db_session.query(Gear).filter(Gear.user_id == user_id).count()
|
||||
if count_gear > 0:
|
||||
raise HTTPException(
|
||||
status_code=409,
|
||||
detail="Cannot delete user due to existing dependencies",
|
||||
)
|
||||
# Delete the user from the database
|
||||
db_session.delete(user)
|
||||
db_session.commit()
|
||||
except JWTError:
|
||||
raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
except Exception as err:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Module: my_database_logic
|
||||
Module: db.py
|
||||
|
||||
This module defines the SQLAlchemy data models and database logic for managing users, followers,
|
||||
access tokens, gear, and activities. It establishes the database connection, creates tables,
|
||||
@@ -60,7 +60,9 @@ db_url = URL.create(
|
||||
)
|
||||
|
||||
# Create the SQLAlchemy engine
|
||||
engine = create_engine(db_url, pool_size=10, max_overflow=20, pool_timeout=180)
|
||||
engine = create_engine(
|
||||
db_url, pool_size=10, max_overflow=20, pool_timeout=180, pool_recycle=3600
|
||||
)
|
||||
|
||||
# Create a session factory
|
||||
Session = sessionmaker(bind=engine)
|
||||
@@ -68,18 +70,41 @@ Session = sessionmaker(bind=engine)
|
||||
# Create a base class for declarative models
|
||||
Base = declarative_base()
|
||||
|
||||
|
||||
# Data model for followers table using SQLAlchemy's ORM
|
||||
class Follower(Base):
|
||||
__tablename__ = "followers"
|
||||
|
||||
follower_id = Column(Integer, ForeignKey('users.id'), primary_key=True, index=True, comment="ID of the follower user")
|
||||
following_id = Column(Integer, ForeignKey('users.id'), primary_key=True, index=True, comment="ID of the following user")
|
||||
is_accepted = Column(Boolean, nullable=False, default=False, comment="Whether the follow request is accepted or not")
|
||||
follower_id = Column(
|
||||
Integer,
|
||||
ForeignKey("users.id"),
|
||||
primary_key=True,
|
||||
index=True,
|
||||
comment="ID of the follower user",
|
||||
)
|
||||
following_id = Column(
|
||||
Integer,
|
||||
ForeignKey("users.id"),
|
||||
primary_key=True,
|
||||
index=True,
|
||||
comment="ID of the following user",
|
||||
)
|
||||
is_accepted = Column(
|
||||
Boolean,
|
||||
nullable=False,
|
||||
default=False,
|
||||
comment="Whether the follow request is accepted or not",
|
||||
)
|
||||
|
||||
# Define a relationship to the User model
|
||||
follower = relationship('User', foreign_keys=[follower_id], back_populates="followers")
|
||||
follower = relationship(
|
||||
"User", foreign_keys=[follower_id], back_populates="followers"
|
||||
)
|
||||
# Define a relationship to the User model
|
||||
following = relationship('User', foreign_keys=[following_id], back_populates="following")
|
||||
following = relationship(
|
||||
"User", foreign_keys=[following_id], back_populates="following"
|
||||
)
|
||||
|
||||
|
||||
# Data model for users table using SQLAlchemy's ORM
|
||||
class User(Base):
|
||||
@@ -87,7 +112,9 @@ class User(Base):
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(
|
||||
String(length=250), nullable=False, comment="User real name (May include spaces)"
|
||||
String(length=250),
|
||||
nullable=False,
|
||||
comment="User real name (May include spaces)",
|
||||
)
|
||||
username = Column(
|
||||
String(length=250),
|
||||
@@ -141,9 +168,19 @@ class User(Base):
|
||||
# user_settings = relationship("UserSettings", back_populates="user")
|
||||
|
||||
# Establish a one-to-many relationship between User and Followers
|
||||
followers = relationship("Follower", back_populates="following", cascade="all, delete-orphan", foreign_keys=[Follower.following_id])
|
||||
followers = relationship(
|
||||
"Follower",
|
||||
back_populates="following",
|
||||
cascade="all, delete-orphan",
|
||||
foreign_keys=[Follower.following_id],
|
||||
)
|
||||
# Establish a one-to-many relationship between User and Followers
|
||||
following = relationship("Follower", back_populates="follower", cascade="all, delete-orphan", foreign_keys=[Follower.follower_id])
|
||||
following = relationship(
|
||||
"Follower",
|
||||
back_populates="follower",
|
||||
cascade="all, delete-orphan",
|
||||
foreign_keys=[Follower.follower_id],
|
||||
)
|
||||
|
||||
|
||||
# Data model for access_tokens table using SQLAlchemy's ORM
|
||||
@@ -271,7 +308,12 @@ class Activity(Base):
|
||||
comment="Average speed seconds per meter (s/m)",
|
||||
)
|
||||
average_power = Column(Integer, nullable=False, comment="Average power (watts)")
|
||||
visibility = Column(Integer, nullable=False, default=0, comment="0 - public, 1 - followers, 2 - private")
|
||||
visibility = Column(
|
||||
Integer,
|
||||
nullable=False,
|
||||
default=0,
|
||||
comment="0 - public, 1 - followers, 2 - private",
|
||||
)
|
||||
gear_id = Column(
|
||||
Integer,
|
||||
ForeignKey("gear.id", ondelete="SET NULL"),
|
||||
@@ -287,6 +329,7 @@ class Activity(Base):
|
||||
# Define a relationship to the Gear model
|
||||
gear = relationship("Gear", back_populates="activities")
|
||||
|
||||
|
||||
def create_database_tables():
|
||||
# Create tables
|
||||
Base.metadata.create_all(bind=engine)
|
||||
@@ -295,7 +338,7 @@ def create_database_tables():
|
||||
with get_db_session() as session:
|
||||
try:
|
||||
# Check if the user already exists
|
||||
existing_user = session.query(User).filter_by(username="admin").one()
|
||||
session.query(User).filter_by(username="admin").one()
|
||||
print("Admin user already exists. Will skip user creation.")
|
||||
except NoResultFound:
|
||||
# Create a new SHA-256 hash object
|
||||
@@ -325,6 +368,7 @@ def create_database_tables():
|
||||
|
||||
print("Admin user created successfully.")
|
||||
|
||||
|
||||
@contextmanager
|
||||
def get_db_session():
|
||||
session = Session()
|
||||
|
||||
67
backend/dependencies.py
Normal file
67
backend/dependencies.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from sqlalchemy.orm import Session
|
||||
from db.db import Session as BaseSession
|
||||
from fastapi.responses import JSONResponse
|
||||
from controllers import sessionController
|
||||
from fastapi import Depends
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
|
||||
# Define the OAuth2 scheme for handling bearer tokens
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||
|
||||
|
||||
def get_db_session() -> Session:
|
||||
"""
|
||||
Get a SQLAlchemy database session.
|
||||
|
||||
Returns:
|
||||
- Session: SQLAlchemy database session.
|
||||
|
||||
Yields:
|
||||
- Session: SQLAlchemy database session to the calling function.
|
||||
|
||||
# Note: The session is automatically committed and closed by FastAPI at the end of the request.
|
||||
"""
|
||||
db_session = BaseSession()
|
||||
try:
|
||||
yield db_session
|
||||
finally:
|
||||
db_session.close()
|
||||
|
||||
|
||||
def get_current_user(
|
||||
token: str = Depends(oauth2_scheme), db_session: Session = Depends(get_db_session)
|
||||
):
|
||||
"""
|
||||
Get the ID of the current authenticated user.
|
||||
|
||||
Parameters:
|
||||
- token (str): The authentication token for the user.
|
||||
- db_session (Session): SQLAlchemy database session.
|
||||
|
||||
Returns:
|
||||
- int: The ID of the current authenticated user.
|
||||
|
||||
Raises:
|
||||
- JWTError: If the authentication token is invalid or expired.
|
||||
- Exception: For other unexpected errors.
|
||||
"""
|
||||
sessionController.validate_token(db_session, token)
|
||||
return sessionController.get_user_id_from_token(token)
|
||||
|
||||
|
||||
# Standardized error response function
|
||||
def create_error_response(code: str, message: str, status_code: int):
|
||||
"""
|
||||
Create a JSON error response.
|
||||
|
||||
Parameters:
|
||||
- code (str): Error code to be included in the response.
|
||||
- message (str): Error message to be included in the response.
|
||||
- status_code (int): HTTP status code for the response.
|
||||
|
||||
Returns:
|
||||
- JSONResponse: JSON response containing the specified error information.
|
||||
"""
|
||||
return JSONResponse(
|
||||
content={"error": {"code": code, "message": message}}, status_code=status_code
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
from fastapi import FastAPI
|
||||
from fastapi import FastAPI, Depends
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from controllers import (
|
||||
sessionController,
|
||||
@@ -23,7 +23,9 @@ from opentelemetry.sdk.trace import TracerProvider
|
||||
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
||||
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
|
||||
import os
|
||||
from db.db import create_database_tables, get_db_session
|
||||
from db.db import create_database_tables
|
||||
from dependencies import get_db_session
|
||||
|
||||
|
||||
# from dotenv import load_dotenv
|
||||
import logging
|
||||
@@ -60,13 +62,19 @@ logger.addHandler(file_handler)
|
||||
|
||||
# trace.set_tracer_provider(TracerProvider(resource=Resource.create().add_attribute("service.name", "backend_api")))
|
||||
|
||||
if(os.environ.get("JAEGER_ENABLED") == "true"):
|
||||
if os.environ.get("JAEGER_ENABLED") == "true":
|
||||
trace.set_tracer_provider(
|
||||
TracerProvider(resource=Resource.create({"service.name": "backend_api"}))
|
||||
)
|
||||
trace.get_tracer_provider().add_span_processor(
|
||||
BatchSpanProcessor(
|
||||
OTLPSpanExporter(endpoint=os.environ.get("JAEGER_PROTOCOL") + "://" + os.environ.get("JAEGER_HOST") + ":" + os.environ.get("JAGGER_PORT"))
|
||||
OTLPSpanExporter(
|
||||
endpoint=os.environ.get("JAEGER_PROTOCOL")
|
||||
+ "://"
|
||||
+ os.environ.get("JAEGER_HOST")
|
||||
+ ":"
|
||||
+ os.environ.get("JAGGER_PORT")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -86,12 +94,25 @@ app.include_router(stravaController.router)
|
||||
scheduler = BackgroundScheduler()
|
||||
scheduler.start()
|
||||
|
||||
# Remove the leading space
|
||||
scheduler.add_job(sessionController.remove_expired_tokens, "interval", minutes=5)
|
||||
scheduler.add_job(stravaController.refresh_strava_token, "interval", minutes=30)
|
||||
# Job to remove expired tokens every 5 minutes
|
||||
scheduler.add_job(
|
||||
lambda: sessionController.remove_expired_tokens(db_session=get_db_session()),
|
||||
"interval",
|
||||
minutes=5,
|
||||
)
|
||||
|
||||
# Job to refresh the Strava token every 30 minutes
|
||||
scheduler.add_job(
|
||||
lambda: stravaController.refresh_strava_token(db_session=get_db_session()),
|
||||
"interval",
|
||||
minutes=30,
|
||||
)
|
||||
|
||||
# Job to get Strava activities every hour
|
||||
scheduler.add_job(
|
||||
lambda: stravaController.get_strava_activities(
|
||||
(datetime.utcnow() - timedelta(days=1)).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
(datetime.utcnow() - timedelta(days=1)).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
db_session=get_db_session(),
|
||||
),
|
||||
"interval",
|
||||
minutes=60,
|
||||
@@ -101,8 +122,7 @@ scheduler.add_job(
|
||||
@app.on_event("startup")
|
||||
async def startup_event():
|
||||
# Create the database and tables if they don't exist
|
||||
with get_db_session() as session:
|
||||
create_database_tables()
|
||||
create_database_tables()
|
||||
|
||||
|
||||
# Add the background scheduler to the app's shutdown event
|
||||
|
||||
@@ -102,13 +102,13 @@ if ($activity[0]["gear_id"] != null) {
|
||||
}
|
||||
|
||||
if ($activity[0]["activity_type"] == 1 || $activity[0]["activity_type"] == 2 || $activity[0]["activity_type"] == 3) {
|
||||
$activityGearOptions = getGearForRunning();
|
||||
$activityGearOptions = getGearFromType(2);
|
||||
} else {
|
||||
if ($activity[0]["activity_type"] == 4 || $activity[0]["activity_type"] == 5 || $activity[0]["activity_type"] == 6 || $activity[0]["activity_type"] == 7 || $activity[0]["activity_type"] == 8) {
|
||||
$activityGearOptions = getGearForCycling();
|
||||
$activityGearOptions = getGearFromType(1);
|
||||
} else {
|
||||
if ($activity[0]["activity_type"] == 9) {
|
||||
$activityGearOptions = getGearForSwimming();
|
||||
$activityGearOptions = getGearFromType(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ function getActivities()
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
return json_decode($response[0], true)["activity_records"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -25,7 +25,7 @@ function getUserActivities()
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
return json_decode($response[0], true)["activity_records"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ function getUserActivitiesWeek($userID, $week)
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
return json_decode($response[0], true)["activity_records"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -85,7 +85,7 @@ function getUserActivitiesThisMonthNumber($userID)
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
return json_decode($response[0], true)["activity_count"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -100,7 +100,7 @@ function getGearActivities($gearID)
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
return json_decode($response[0], true)["activity_records"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -131,7 +131,7 @@ function getUserActivitiesPagination($pageNumber, $numRecords)
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
return json_decode($response[0], true)["activity_records"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -146,7 +146,7 @@ function getFollowedUserActivitiesPagination($pageNumber, $numRecords)
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
return json_decode($response[0], true)["activity_records"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -161,8 +161,7 @@ function numActivities()
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
$data = json_decode($response[0], true);
|
||||
return $data[0];
|
||||
return json_decode($response[0], true)["activity_count"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -177,8 +176,7 @@ function numUserActivities()
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
$data = json_decode($response[0], true);
|
||||
return $data[0];
|
||||
return json_decode($response[0], true)["activity_count"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -193,8 +191,7 @@ function numFollowedUserActivities()
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
$data = json_decode($response[0], true);
|
||||
return $data[0];
|
||||
return json_decode($response[0], true)["activity_count"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -209,7 +206,7 @@ function getActivityFromId($id)
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
return json_decode($response[0], true)["activity_records"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -236,24 +233,24 @@ function newActivity($distance, $name, $type, $starttime, $endtime, $town, $coun
|
||||
$response = callAPIRoute("/activities/create", 0, 4, json_encode(array(
|
||||
'distance' => $distance,
|
||||
'name' => $name,
|
||||
'type' => $type,
|
||||
'starttime' => $starttime,
|
||||
'endtime' => $endtime,
|
||||
'activity_type' => $type,
|
||||
'start_time' => $starttime,
|
||||
'end_time' => $endtime,
|
||||
'city' => $city,
|
||||
'town' => $town,
|
||||
'country' => $country,
|
||||
'waypoints' => $waypoints,
|
||||
'elevationGain' => $elevationGain,
|
||||
'elevationLoss' => $elevationLoss,
|
||||
'elevation_gain' => $elevationGain,
|
||||
'elevation_loss' => $elevationLoss,
|
||||
'pace' => $pace,
|
||||
'averageSpeed' => $averageSpeed,
|
||||
'averagePower' => $averagePower,
|
||||
'strava_id' => $strava_id,
|
||||
'average_speed' => $averageSpeed,
|
||||
'average_power' => $averagePower,
|
||||
'strava_activity_id' => $strava_id,
|
||||
)));
|
||||
if ($response[0] === false) {
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
if ($response[1] === 201) {
|
||||
return 0;
|
||||
// $data = json_decode($response[0], true);
|
||||
// if (isset($data['id'])) {
|
||||
|
||||
@@ -10,52 +10,22 @@ function getGear()
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
return json_decode($response[0], true)["gear_records"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get all gear for running*/
|
||||
function getGearForRunning()
|
||||
/* Get all gear from type*/
|
||||
function getGearFromType($gear_type)
|
||||
{
|
||||
$response = callAPIRoute("/gear/all/running", 1, 0, NULL);
|
||||
$response = callAPIRoute("/gear/all/$gear_type", 1, 0, NULL);
|
||||
if ($response[0] === false) {
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get all gear for running*/
|
||||
function getGearForCycling()
|
||||
{
|
||||
$response = callAPIRoute("/gear/all/cycling", 1, 0, NULL);
|
||||
if ($response[0] === false) {
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get all gear for running*/
|
||||
function getGearForSwimming()
|
||||
{
|
||||
$response = callAPIRoute("/gear/all/swimming", 1, 0, NULL);
|
||||
if ($response[0] === false) {
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
return json_decode($response[0], true)["gear_records"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -70,7 +40,7 @@ function getGearPagination($pageNumber, $numRecords)
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
return json_decode($response[0], true)["gear_records"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -85,8 +55,7 @@ function numGears()
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
$data = json_decode($response[0], true);
|
||||
return $data[0];
|
||||
return json_decode($response[0], true)["gear_count"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -101,7 +70,7 @@ function getGearFromNickname($nickname)
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
return json_decode($response[0], true)["gear_records"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -116,7 +85,7 @@ function getGearFromId($id)
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
return json_decode($response[0], true);
|
||||
return json_decode($response[0], true)["gear_records"];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
@@ -126,7 +95,7 @@ function getGearFromId($id)
|
||||
/* Creates a new gear */
|
||||
function newGear($brand, $model, $nickname, $gear_type, $date)
|
||||
{
|
||||
if (getGearFromNickname($nickname) != NULL) {
|
||||
if (getGearFromNickname($nickname)["gear_records"] != NULL) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
@@ -140,7 +109,7 @@ function newGear($brand, $model, $nickname, $gear_type, $date)
|
||||
if ($response[0] === false) {
|
||||
return -1;
|
||||
} else {
|
||||
if ($response[1] === 200) {
|
||||
if ($response[1] === 201) {
|
||||
return 0;
|
||||
} else {
|
||||
return -2;
|
||||
|
||||
@@ -185,7 +185,7 @@ $userFollowingAll = getUserFollowingAll($_GET["userID"]);
|
||||
<?php echo $translationsUsersUser['user_stats_numberActivitiesMonth']; ?>
|
||||
</span>
|
||||
<h1>
|
||||
<?php echo $numUserActivitiesThisMonth["activity_count"]; ?>
|
||||
<?php echo $numUserActivitiesThisMonth; ?>
|
||||
</h1>
|
||||
<!--<hr class="mb-2 mt-2">-->
|
||||
<div class="row align-items-center">
|
||||
|
||||
Reference in New Issue
Block a user