base

   1import json
   2import bcrypt
   3from flask_pymongo import PyMongo
   4from flask import Flask, request, jsonify
   5from flask_pymongo import PyMongo
   6from pymongo import MongoClient
   7import mongomock
   8from datetime import datetime, timedelta, timezone
   9from flask_jwt_extended import create_access_token,get_jwt,get_jwt_identity, \
  10                               unset_jwt_cookies, jwt_required, JWTManager
  11from datetime import datetime, timedelta
  12from functools import reduce
  13from bson import json_util 
  14from pymongo import MongoClient
  15from flasgger import Swagger
  16
  17
  18
  19api = Flask(__name__)
  20api.secret_key = 'secret'
  21api.config["JWT_SECRET_KEY"] = "softwareEngineering"
  22api.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=1)
  23jwt = JWTManager(api)
  24mongo = None
  25
  26Swagger(api)  
  27
  28
  29def setup_mongo_client(app):
  30    global mongo
  31    if app.config['TESTING']:
  32        # Use mongomock for testing
  33        app.mongo_client = mongomock.MongoClient()
  34        mongo = app.mongo_client["test"]
  35    else:
  36        # Use a real MongoDB connection for production
  37        app.mongo_client = MongoClient('localhost', 27017)
  38        mongo = app.mongo_client["test"]
  39
  40# Call setup_mongo_client during normal (non-test) app initialization
  41setup_mongo_client(api)
  42
  43@api.route('/token', methods=["POST"]) # pragma: no cover
  44def create_token():
  45    """
  46    Create a new access token
  47
  48    ---
  49    tags:
  50      - Authentication
  51    parameters:
  52      - name: email
  53        in: formData
  54        type: string
  55        required: true
  56        description: User email
  57      - name: password
  58        in: formData
  59        type: string
  60        required: true
  61        description: User password
  62    responses:
  63      200:
  64        description: Login successful
  65      401:
  66        description: Invalid email or password
  67    """
  68    email = request.json.get("email", None)
  69    password = request.json.get("password", None)
  70    user = mongo.user.find_one({"email": email})
  71    if (user is not None and (user["password"] == password)):
  72        access_token = create_access_token(identity=email)
  73        return jsonify({"message": "Login successful", "access_token":access_token})
  74    else:
  75        print("Invalid email or password")
  76        return jsonify({"message": "Invalid email or password"}),401
  77    
  78@api.route("/google-login", methods=["POST"])
  79def google_login():
  80    email = request.json.get("email", None)
  81    firstName = request.json.get("first_name", None)
  82    lastName = request.json.get("last_name", None)
  83    user = mongo.user.find_one({"email": email})
  84    if (user is None):
  85        mongo.user.insert_one({"email": email, "first_name": firstName, "last_name": lastName})
  86    access_token = create_access_token(identity=email)
  87    return jsonify({"message": "Login successful", "access_token":access_token})
  88        
  89    
  90
  91@api.route("/register", methods=["POST"])
  92def register():
  93    """
  94    Register a new user
  95
  96    ---
  97    tags:
  98      - User Registration
  99    parameters:
 100      - name: email
 101        in: formData
 102        type: string
 103        required: true
 104        description: User email
 105      - name: password
 106        in: formData
 107        type: string
 108        required: true
 109        description: User password
 110      - name: firstName
 111        in: formData
 112        type: string
 113        required: true
 114        description: User's first name
 115      - name: lastName
 116        in: formData
 117        type: string
 118        required: true
 119        description: User's last name
 120    responses:
 121      200:
 122        description: Registration successful
 123      409:
 124        description: User already exists
 125      500:
 126        description: Registration failed
 127    """
 128
 129    email = request.json.get('email', None)
 130    password = request.json.get('password', None)
 131    first_name = request.json.get('firstName', None)
 132    last_name = request.json.get('lastName', None)
 133    new_document = {
 134    "email": email,
 135    "password": password,
 136    "first_name": first_name,
 137    "last_name": last_name,
 138    }
 139    query = {
 140        "email": email,
 141    }
 142    try:
 143        inserted = mongo.user.update_one(query, {"$set": new_document}, upsert=True)
 144        if (inserted.upserted_id):
 145            response = jsonify({"msg": "register successful"})
 146        else:   
 147            print("User already exists")
 148            response = jsonify({"msg": "User already exists"})
 149    except Exception as e:
 150        response = jsonify({"msg": "register failed"})
 151
 152    return response
 153
 154@api.route("/logout", methods=["POST"])
 155def logout():
 156    """
 157    Logout the user and clear their session
 158
 159    ---
 160    tags:
 161      - User Logout
 162    responses:
 163      200:
 164        description: Logout successful
 165    """
 166    response = jsonify({"msg": "logout successful"})
 167    unset_jwt_cookies(response)
 168    return response
 169
 170@api.route('/events', methods=['GET'])
 171def get_events():
 172    """
 173    Retrieve a list of events
 174
 175    This endpoint retrieves a list of events from the database.
 176
 177    ---
 178    tags:
 179      - Events
 180    responses:
 181      200:
 182        description: A list of events
 183        schema:
 184          type: array
 185          items:
 186            type: object
 187            properties:
 188              _id:
 189                type: string
 190              # Add more properties as needed
 191      404:
 192        description: No events found
 193    """
 194    events_collection = mongo.events
 195    events = list(events_collection.find({}))
 196    for event in events:
 197        event["_id"] = str(event["_id"]) # Convert ObjectId to string
 198    return jsonify(events)
 199
 200@api.route('/is-enrolled', methods=['POST'])
 201@jwt_required()
 202def is_enrolled():
 203    """
 204    Check if the user is enrolled in an event
 205
 206    This endpoint checks if the authenticated user is enrolled in a specific event.
 207
 208    ---
 209    tags:
 210      - Events
 211    parameters:
 212      - in: body
 213        name: data
 214        description: Data containing the eventTitle
 215        required: true
 216        schema:
 217          type: object
 218          properties:
 219            eventTitle:
 220              type: string
 221        example:
 222          eventTitle: "Event Name"
 223    security:
 224      - JWT: []
 225    responses:
 226      200:
 227        description: Indicates whether the user is enrolled
 228        schema:
 229          type: object
 230          properties:
 231            isEnrolled:
 232              type: boolean
 233      401:
 234        description: Unauthorized access
 235    """
 236
 237    data = request.json
 238    eventTitle = data['eventTitle']
 239    current_user = get_jwt_identity()
 240    enrollment = mongo.user.find_one({"email": current_user, "eventTitle": eventTitle})
 241
 242    if enrollment:
 243        return jsonify({"isEnrolled": True})
 244    else:
 245        return jsonify({"isEnrolled": False})
 246
 247
 248@api.route('/enroll', methods=['POST']) # pragma: no cover
 249@jwt_required()
 250def enroll_event(): # pragma: no cover
 251    """
 252    Enroll the user in an event
 253
 254    This endpoint allows an authenticated user to enroll in an event.
 255
 256    ---
 257    tags:
 258      - Events
 259    parameters:
 260      - in: body
 261        name: data
 262        description: Data containing the eventTitle
 263        required: true
 264        schema:
 265          type: object
 266          properties:
 267            eventTitle:
 268              type: string
 269        example:
 270          eventTitle: "Event Name"
 271    security:
 272      - JWT: []
 273    responses:
 274      200:
 275        description: User successfully enrolled in the event
 276        schema:
 277          type: object
 278          properties:
 279            status:
 280              type: string
 281              example: "Data saved successfully"
 282      500:
 283        description: An error occurred while enrolling the user
 284    """
 285    data = request.get_json()  # get data from POST request
 286    current_user = get_jwt_identity()
 287    try:
 288        # Insert data into MongoDB
 289        mongo.user.insert_one({
 290            "email": current_user,
 291            "eventTitle": data['eventTitle']
 292        })
 293        response = {"status": "Data saved successfully"}
 294    except Exception as e:
 295        response = {"status": "Error", "message": str(e)}
 296    
 297    return jsonify(response)
 298
 299@api.route('/unenroll', methods=['POST']) # pragma: no cover
 300@jwt_required()
 301def unenroll_event(): # pragma: no cover
 302    """
 303    Unenroll the user from an event
 304
 305    This endpoint allows an authenticated user to unenroll from an event.
 306
 307    ---
 308    tags:
 309      - Events
 310    parameters:
 311      - in: body
 312        name: data
 313        description: Data containing the eventTitle
 314        required: true
 315        schema:
 316          type: object
 317          properties:
 318            eventTitle:
 319              type: string
 320        example:
 321          eventTitle: "Event Name"
 322    security:
 323      - JWT: []
 324    responses:
 325      200:
 326        description: User successfully unenrolled from the event
 327        schema:
 328          type: object
 329          properties:
 330            status:
 331              type: string
 332              example: "Data saved successfully"
 333      500:
 334        description: An error occurred while unenrolling the user
 335    """
 336    data = request.get_json()  # get data from POST request
 337    current_user = get_jwt_identity()
 338    try:
 339        # Insert data into MongoDB
 340        mongo.user.delete_one({
 341            "email": current_user,
 342            "eventTitle": data['eventTitle']
 343        })
 344        response = {"status": "Data saved successfully"}
 345    except Exception as e:
 346        response = {"status": "Error", "message": str(e)}
 347    
 348    return jsonify(response)
 349
 350@api.route('/profile')
 351@jwt_required()
 352def my_profile(): # pragma: no cover
 353    """
 354    Retrieve user profile information
 355
 356    This endpoint allows an authenticated user to retrieve their profile information.
 357
 358    ---
 359    tags:
 360      - User
 361    security:
 362      - JWT: []
 363    responses:
 364      200:
 365        description: User profile information retrieved successfully
 366        schema:
 367          type: object
 368        example:
 369          {
 370            "_id": "12345",
 371            "email": "user@example.com",
 372            "first_name": "John",
 373            "last_name": "Doe",
 374            "age": 30,
 375            "weight": 70,
 376            "height": 175
 377          }
 378      401:
 379        description: Unauthorized. User must be logged in to access their profile.
 380      404:
 381        description: User profile not found.
 382      500:
 383        description: An error occurred while retrieving the user profile.
 384    """
 385    current_user = get_jwt_identity()
 386    profile = mongo.user.find_one({"email": current_user})
 387    return jsonify(json_util.dumps(profile))
 388
 389@api.route('/caloriesConsumed',methods=["POST"])
 390@jwt_required()
 391def addUserConsumedCalories(): # pragma: no cover
 392    """
 393    Add consumed calories for a user
 394
 395    This endpoint allows an authenticated user to add consumed calories for a specific date.
 396
 397    ---
 398    tags:
 399      - User
 400    security:
 401      - JWT: []
 402    parameters:
 403      - name: body
 404        in: body
 405        required: true
 406        schema:
 407          type: object
 408          properties:
 409            intakeDate:
 410              type: string
 411              format: date
 412              description: The date for which calories are being recorded (e.g., "2023-10-17").
 413            intakeFoodItem:
 414              type: string
 415              description: The name of the food item.
 416            intakeCalories:
 417              type: integer
 418              description: The number of calories consumed for the food item.
 419    responses:
 420      200:
 421        description: Calories consumed data saved successfully.
 422        schema:
 423          type: object
 424        example:
 425          {
 426            "status": "Data saved successfully"
 427          }
 428      401:
 429        description: Unauthorized. User must be logged in to add consumed calories.
 430      500:
 431        description: An error occurred while saving consumed calories data.
 432    """
 433    data = request.get_json()  # get data from POST request
 434    current_user = get_jwt_identity()
 435    try:
 436        # Insert data into MongoDB
 437        mongo.user.update_one({'email': current_user, "consumedDate": data['intakeDate']}, {"$push": {"foodConsumed": {"item":data["intakeFoodItem"],"calories":data["intakeCalories"]}}}, upsert=True)
 438        response = {"status": "Data saved successfully"}
 439        statusCode = 200
 440    except Exception as e:
 441        response = {"status": "Error", "message": str(e)}
 442        statusCode = 500
 443    return jsonify(response),statusCode
 444
 445@api.route('/profileUpdate',methods=["POST"])
 446@jwt_required()
 447def profileUpdate(): # pragma: no cover
 448    """
 449    Update user profile
 450
 451    This endpoint allows an authenticated user to update their profile information.
 452
 453    ---
 454    tags:
 455      - User
 456    security:
 457      - JWT: []
 458    parameters:
 459      - name: body
 460        in: body
 461        required: true
 462        schema:
 463          type: object
 464          properties:
 465            firstName:
 466              type: string
 467              description: The user's first name.
 468            lastName:
 469              type: string
 470              description: The user's last name.
 471            age:
 472              type: integer
 473              description: The user's age.
 474            weight:
 475              type: number
 476              description: The user's weight.
 477            height:
 478              type: number
 479              description: The user's height.
 480            sex:
 481              type: string
 482              description: The user's sex.
 483    responses:
 484      200:
 485        description: User profile updated successfully.
 486        schema:
 487          type: object
 488        example:
 489          {
 490            "msg": "Update successful"
 491          }
 492      401:
 493        description: Unauthorized. User must be logged in to update their profile.
 494      500:
 495        description: An error occurred while updating the user's profile.
 496    """
 497    current_user = get_jwt_identity()
 498    first_name = request.json.get('firstName', None)
 499    last_name = request.json.get('lastName', None)
 500    age = request.json.get('age', None)
 501    weight = request.json.get('weight', None)
 502    height = request.json.get('height', None)
 503    sex = request.json.get('sex', None)
 504    activityLevel = request.json.get('activityLevel', None)
 505    bmi = (0.453*float(weight))/((0.3048*float(height))**2)
 506    bmi = round(bmi,2)
 507    tdee = calculate_tdee(height, weight, age, sex, activityLevel)
 508    new_document = {
 509    "first_name": first_name,
 510    "last_name": last_name,
 511    "age": age,
 512    "weight": weight,
 513    "height": height,
 514    "sex": sex,
 515    "bmi": bmi,
 516    "target_calories": tdee,
 517    }
 518    query = {
 519        "email": current_user,
 520    }
 521    try:
 522        mongo.user.update_one(query, {"$set": new_document}, upsert=True)
 523        response = jsonify({"msg": "update successful"})
 524    except Exception as e:
 525        response = jsonify({"msg": "update failed"})
 526
 527    return response
 528
 529@api.route('/goalsUpdate',methods=["POST"])
 530@jwt_required()
 531def goalsUpdate(): # pragma: no cover
 532    """
 533    Update user goals
 534
 535    This endpoint allows an authenticated user to update their fitness goals, such as target weight, target calories, and target goal.
 536
 537    ---
 538    tags:
 539      - User
 540    security:
 541      - JWT: []
 542    parameters:
 543      - name: body
 544        in: body
 545        required: true
 546        schema:
 547          type: object
 548          properties:
 549            targetWeight:
 550              type: number
 551              description: The user's target weight goal.
 552            targetCalories:
 553              type: number
 554              description: The user's target daily calorie intake goal.
 555            activityLevel:
 556              type: string
 557              description: The user's activity level.
 558    responses:
 559      200:
 560        description: User goals updated successfully.
 561        schema:
 562          type: object
 563        example:
 564          {
 565            "msg": "Update successful"
 566          }
 567      401:
 568        description: Unauthorized. User must be logged in to update their goals.
 569      500:
 570        description: An error occurred while updating the user's goals.
 571    """
 572    current_user = get_jwt_identity()
 573    targetWeight = request.json.get('targetWeight', None)
 574    activityLevel = request.json.get('activityLevel', None)
 575
 576    new_document = {
 577        "target_weight": targetWeight,
 578        "activity_level": activityLevel
 579    }
 580    query = {
 581        "email": current_user,
 582    }
 583    try:
 584        profile = mongo.user.find_one(query)
 585        tdee = calculate_tdee(profile["height"], profile["weight"], profile["age"], profile["sex"], activityLevel)
 586        if tdee:  
 587          new_document["target_calories"] = tdee
 588        mongo.user.update_one(query, {"$set": new_document}, upsert=True)
 589        response = jsonify({"msg": "update successful"})
 590    except Exception as e:
 591        response = jsonify({"msg": "update failed"})
 592
 593    return response
 594
 595
 596@api.route('/caloriesBurned',methods=["POST"])
 597@jwt_required()
 598def addUserBurnedCalories(): # pragma: no cover
 599    """
 600    Add user's burned calories
 601
 602    This endpoint allows an authenticated user to add information about calories burned on a specific date.
 603
 604    ---
 605    tags:
 606      - User
 607    security:
 608      - JWT: []
 609    parameters:
 610      - name: body
 611        in: body
 612        required: true
 613        schema:
 614          type: object
 615          properties:
 616            burnoutDate:
 617              type: string
 618              format: date
 619              description: The date on which calories were burned.
 620            burntoutCalories:
 621              type: number
 622              description: The number of calories burned on the specified date.
 623    responses:
 624      200:
 625        description: Calories burned data saved successfully.
 626        schema:
 627          type: object
 628        example:
 629          {
 630            "status": "Data saved successfully"
 631          }
 632      401:
 633        description: Unauthorized. User must be logged in to add burned calories data.
 634      500:
 635        description: An error occurred while saving the burned calories data.
 636    """
 637    data = request.get_json()  # get data from POST request
 638    current_user = get_jwt_identity()
 639    try:
 640        # Insert data into MongoDB
 641        mongo.user.update_one({'email': current_user, "consumedDate": data['burnoutDate']}, {"$inc": {"burntCalories": int(data["burntoutCalories"])}}, upsert=True)
 642        response = {"status": "Data saved successfully"}
 643        statusCode = 200
 644    except Exception as e:
 645        response = {"status": "Error", "message": str(e)}
 646        statusCode = 500
 647    return jsonify(response),statusCode
 648
 649@api.route('/createFood', methods=["POST"])
 650def createFood():
 651    """
 652    Create a custom food
 653
 654    This endpoint allows an authenticated user to create their custom food item with the amount of calories it has.
 655
 656    ---
 657    tags:
 658      - User
 659    parameters:
 660      - name: body
 661        in: body
 662        required: true
 663        schema:
 664          type: object
 665          properties:
 666            foodName:
 667              type: string
 668              format: food item name
 669              description: The name of the food item being created.
 670            calories:
 671              type: number
 672              description: The number of calories in the created food item.
 673    responses:
 674      200:
 675        description: Food item created successfully
 676        schema:
 677          type: object
 678        example:
 679          {
 680            "status": "Data saved successfully"
 681          }
 682      401:
 683        description: Unauthorized. User must be logged in to create custom food.
 684      500:
 685        description: An error occurred while creating the custom food.
 686
 687    """
 688    data = request.get_json() # get data from POST request
 689    foodName = data['foodName']
 690    calories = data['calories']
 691    try:
 692        # Insert data into MongoDB
 693        mongo.food.insert_one({'food': foodName, "calories": calories})
 694        response = {"status": "Data saved successfully"}
 695        statusCode = 200
 696    except Exception as e:
 697        response = {"status": "Error", "message": str(e)}
 698        statusCode = 500
 699    return jsonify(response),statusCode
 700
 701@api.route('/createMeal', methods=["POST"])
 702@jwt_required()
 703def createMeal():
 704    """
 705    Create a custom meal
 706
 707    This endpoint allows an authenticated user to create their own meals with different food items as the ingredients.
 708
 709    ---
 710    tags:
 711      - User
 712    security:
 713      - JWT: []
 714    parameters:
 715      - name: body
 716        in: body
 717        required: true
 718        schema:
 719          type: object
 720          properties:
 721            mealName:
 722              type: string
 723              format: Meal name
 724              description: The name of the meal item being created.
 725            ingredients:
 726              type: list
 727              description: Is a list of the ingredients in the meal.
 728    responses:
 729      200:
 730        description: Meal created successfully
 731        schema:
 732          type: object
 733        example:
 734          {
 735            "status": "Data saved successfully"
 736          }
 737      401:
 738        description: Unauthorized. User must be logged in to create custom meal.
 739      500:
 740        description: An error occurred while creating the custom meal.
 741
 742    """
 743    data = request.get_json() # get data from POST request
 744    current_user = get_jwt_identity()
 745    mealName = data['mealName']
 746    ingredients = data['ingredients']
 747    calories = 0
 748    for item in ingredients:
 749        food_item = mongo.food.find_one({"food": item})
 750        calories += int(food_item["calories"])
 751    try:
 752        # Insert data into MongoDB
 753        mongo.food.insert_one({'food': mealName, "calories": calories})
 754        mongo.user.insert_one({
 755            "email": current_user,
 756            "meal_name": mealName,
 757            "ingredients": ingredients,
 758            "total_calories": calories
 759        })
 760        response = {"status": "Data saved successfully"}
 761        statusCode = 200
 762    except Exception as e:
 763        response = {"status": "Error", "message": str(e)}
 764        statusCode = 500
 765    return jsonify(response),statusCode
 766
 767@api.route('/weekHistory',methods=["POST"])
 768@jwt_required()
 769def getWeekHistory(): # pragma: no cover
 770    """
 771    Get user's weekly history
 772
 773    This endpoint allows an authenticated user to retrieve their food consumption and calories burned history for the past week.
 774
 775    ---
 776    tags:
 777      - User
 778    security:
 779      - JWT: []
 780    parameters:
 781      - name: body
 782        in: body
 783        required: true
 784        schema:
 785          type: object
 786          properties:
 787            todayDate:
 788              type: string
 789              format: date
 790              description: The date for the end of the week (today's date).
 791    responses:
 792      200:
 793        description: Successfully retrieved the user's weekly history.
 794        schema:
 795          type: array
 796          items:
 797            type: object
 798            properties:
 799              dayIndex:
 800                type: integer
 801                description: Integer from 0 to 6 representing the day index.
 802              date:
 803                type: string
 804                format: date
 805                description: The date for each day in the week.
 806              foodConsumed:
 807                type: array
 808                items:
 809                  type: object
 810                  properties:
 811                    item:
 812                      type: string
 813                      description: Food item name.
 814                    calories:
 815                      type: number
 816                      description: Calories consumed from the food item.
 817                description: A list of dictionaries containing food items and their consumed calories.
 818              caloriesConsumed:
 819                type: number
 820                description: The sum of all calories consumed for that day.
 821              exceededDailyLimit:
 822                type: boolean
 823                description: Indicates whether the calories consumed exceeded the daily limit.
 824              burntCalories:
 825                type: number
 826                description: Calories burned on that day.
 827        example:
 828          [
 829            {
 830              "dayIndex": 0,
 831              "date": "10/13/2023",
 832              "foodConsumed": [
 833                {
 834                  "item": "Chicken Salad",
 835                  "calories": 500
 836                },
 837                {
 838                  "item": "Onion Soup",
 839                  "calories": 300
 840                },
 841                {
 842                  "item": "Potato Salad",
 843                  "calories": 500
 844                },
 845                {
 846                  "item": "Cheese Burger",
 847                  "calories": 500
 848                }
 849              ],
 850              "caloriesConsumed": 1800,
 851              "exceededDailyLimit": false,
 852              "burntCalories": 1200
 853            },
 854            {
 855              "dayIndex": 1,
 856              "date": "10/12/2023",
 857              "foodConsumed": [...],
 858              "caloriesConsumed": ...,
 859              "exceededDailyLimit": ...,
 860              "burntCalories": ...
 861            },
 862            ...
 863          ]
 864      401:
 865        description: Unauthorized. User must be logged in to retrieve weekly history.
 866      500:
 867        description: An error occurred while retrieving the user's weekly history.
 868    """
 869    data = request.get_json()  # get data from POST request
 870    current_user = get_jwt_identity()
 871    todayDate = datetime.strptime(data["todayDate"],"%m/%d/%Y")
 872    dates = [(todayDate-timedelta(days=x)).strftime("%m/%d/%Y") for x in range(7)]
 873    calorieLimit = 1000
 874    result = []
 875    try:
 876        for index,dateToFind in enumerate(dates):
 877            # Every day's res item should like this
 878            # {
 879            #   dayIndex: 0,               #Interger from 0-6
 880            #   date: "10/13/2023",        #Date 0=today, 6=7th day ago from today
 881            #   foodConsumed: [            # A list of dicts, each dict contains a food item and its calories
 882            #     {
 883            #       item: "Chicken Salad",
 884            #       calories: 500,
 885            #     },
 886            #     {
 887            #       item: "Onion Soup",
 888            #       calories: 300,
 889            #     },
 890            #     {
 891            #       item: "Potato Salad",
 892            #       calories: 500,
 893            #     },
 894            #     {
 895            #       item: "Cheese Burger",
 896            #       calories: 500,
 897            #     },
 898            #   ],
 899            #   caloriesConsumed: 1800,    # the sum of all calories consumed from above list
 900            #   exceededDailyLimit: false, # true or false based on whether caloriesConsumed is > limit user set
 901            #   burntCalories: 1200,       # calories burnt out on that day
 902            # }
 903            res = {}
 904            data = mongo.user.find_one({'email': current_user, "consumedDate": dateToFind})
 905            res["dayIndex"] = index
 906            res["date"] = dateToFind
 907            if data:
 908                if "foodConsumed" in data:
 909                    res["foodConsumed"] = data["foodConsumed"]
 910                    res["caloriesConsumed"] = reduce(lambda a,b: a+b, [int(item["calories"]) for item in data["foodConsumed"]])
 911                    res["exceededDailyLimit"] = res["caloriesConsumed"]>calorieLimit
 912                if "burntCalories" in data:
 913                    res["burntCalories"] = data["burntCalories"]
 914            if "foodConsumed" not in res:
 915                res["foodConsumed"] = []
 916            if "caloriesConsumed" not in res:
 917                res["caloriesConsumed"] = 0
 918            if "burntCalories" not in res:
 919                res["burntCalories"] = 0
 920            if "exceededDailyLimit" not in res:
 921                res["exceededDailyLimit"] = False
 922            result.append(res)
 923        response = result
 924        statusCode = 200
 925    except Exception as e:
 926        response = {"status": "Error", "message": str(e)}
 927        statusCode = 500
 928    return jsonify(response),statusCode
 929
 930@api.route("/myMeals",methods=["GET"])
 931@jwt_required()
 932def getMyMeals():
 933    """
 934    Get My Meals
 935
 936    This endpoint allows an authenticated user to retrieve the custom meals that they have created.
 937
 938    ---
 939    tags:
 940      - User
 941      - Meals
 942    security:
 943      - JWT: []
 944    responses:
 945      200:
 946        description: Successfully retrieved the custom meals created by user
 947        schema:
 948          type: object
 949          properties:
 950            mealName:
 951              type: string
 952              description: Name of the custom meal
 953            ingredients:
 954              type: array
 955              description: List of ingredients in the meal
 956          example:
 957            {
 958            "mealName":"My meal",
 959            "ingredients":["Eggs","Toast"],
 960            }
 961      401:
 962        description: Unauthorized. User must be logged in to retrieve the food calorie mapping.
 963      500:
 964        description: An error occurred while retrieving the food calorie mapping.
 965    """
 966    current_user = get_jwt_identity()
 967    result = []
 968    try:
 969        data = mongo.user.find({"email": current_user,"meal_name":{"$exists": True}})
 970        for meal in data:
 971            cal_info = []
 972            for item in meal['ingredients']:
 973                food_item = mongo.food.find_one({'food':item})
 974                cal_info.append({str(item):food_item['calories']})
 975            res={}
 976            res['meal_name']=meal['meal_name']
 977            res['ingredients']=meal['ingredients']
 978            res['total_calories']=meal['total_calories']
 979            result.append(res)
 980        response = result
 981        statusCode = 200
 982    except Exception as e:
 983        response = {"status": "Error", "message": str(e)}
 984        statusCode = 500
 985    return jsonify(response),statusCode
 986        
 987
 988@api.route('/foodCalorieMapping',methods=["GET"])
 989@jwt_required()
 990def getFoodCalorieMapping(): 
 991    """
 992    Get food calorie mapping
 993
 994    This endpoint allows an authenticated user to retrieve a mapping of food items to their respective calorie values.
 995
 996    ---
 997    tags:
 998      - Food
 999    security:
1000      - JWT: []
1001    responses:
1002      200:
1003        description: Successfully retrieved the food calorie mapping.
1004        schema:
1005          type: object
1006          properties:
1007            foodItem:
1008              type: integer
1009              description: Food item name.
1010            calories:
1011              type: number
1012              description: Calories associated with the food item.
1013        example:
1014          {
1015            "Potato": 50,
1016            "Acai": 20,
1017            "Cheeseburger": 80,
1018            ...
1019          }
1020      401:
1021        description: Unauthorized. User must be logged in to retrieve the food calorie mapping.
1022      500:
1023        description: An error occurred while retrieving the food calorie mapping.
1024    """
1025    try:
1026        data = mongo.food.find()
1027        # Response should be in this format {foodItem: calories, foodItem: calories....} 
1028        # For Example { Potato: 50, Acai: 20, Cheeseburger: 80 }
1029        response = {item["food"]:item["calories"] for item in data}
1030        statusCode = 200
1031    except Exception as e:
1032        response = {"status": "Error", "message": str(e)}
1033        statusCode = 500
1034    return jsonify(response),statusCode
1035
1036@api.route('/usersEvents',methods=["GET"]) 
1037@jwt_required()
1038def getUserRegisteredEvents(): 
1039    """
1040    Get user's registered events
1041
1042    This endpoint allows an authenticated user to retrieve the events they are registered for.
1043
1044    ---
1045    tags:
1046      - Events
1047    security:
1048      - JWT: []
1049    responses:
1050      200:
1051        description: Successfully retrieved the user's registered events.
1052        schema:
1053          type: array
1054          items:
1055            type: object
1056            properties:
1057              eventName:
1058                type: string
1059                description: Name of the event.
1060              date:
1061                type: string
1062                format: date
1063                description: Date of the event.
1064            example:
1065              [
1066                {
1067                  "eventName": "Yoga",
1068                  "date": "2023-12-11"
1069                },
1070                {
1071                  "eventName": "Swimming",
1072                  "date": "2023-11-10"
1073                },
1074                ...
1075              ]
1076      401:
1077        description: Unauthorized. User must be logged in to retrieve their registered events.
1078      500:
1079        description: An error occurred while retrieving the user's registered events.
1080    """
1081    try:
1082        # current_user = get_jwt_identity()
1083        current_user = get_jwt_identity()
1084        data = mongo.user.find({"email": current_user, "eventTitle":{"$exists": True}})
1085        response = []
1086        date="10/23/2023"
1087        for item in data:
1088            res = {"eventName": item["eventTitle"], "date": date}
1089            response.append(res)
1090        # Response should be in this format [{eventName: Yoga, date: "12/11/2023"},{eventName: Swimming, date: "11/10/2023"}]
1091        # For Example { Potato: 50, Acai: 20, Cheeseburger: 80 }
1092        statusCode = 200
1093    except Exception as e:
1094        response = {"status": "Error", "message": str(e)}
1095        statusCode = 500
1096    return jsonify(response),statusCode
1097
1098def calculate_tdee(height,weight,age,sex,activityLevel):
1099    if height and weight and age and sex and activityLevel:
1100        pass
1101    else:
1102        return None
1103    kg_weight = float(weight)*0.45359237
1104    cm_height = float(height)*30.48
1105    common_calc_for_male_female = (10*kg_weight) + (6.25*cm_height) - (5*int(age))
1106    if sex == "Male":
1107        bmr = common_calc_for_male_female + 5
1108    else:
1109        bmr = common_calc_for_male_female - 161
1110    personal_activity_levels = {'Minimal': 1.2,'Light': 1.375, 'Moderate': 1.55, 'Heavy':1.725, 'Athlete': 1.9}
1111    tdee = int((bmr * personal_activity_levels[activityLevel]))
1112    return tdee
api = <Flask 'base'>
jwt = <flask_jwt_extended.jwt_manager.JWTManager object>
mongo = Database(MongoClient(host=['localhost:27017'], document_class=dict, tz_aware=False, connect=True), 'test')
def setup_mongo_client(app):
30def setup_mongo_client(app):
31    global mongo
32    if app.config['TESTING']:
33        # Use mongomock for testing
34        app.mongo_client = mongomock.MongoClient()
35        mongo = app.mongo_client["test"]
36    else:
37        # Use a real MongoDB connection for production
38        app.mongo_client = MongoClient('localhost', 27017)
39        mongo = app.mongo_client["test"]
@api.route('/token', methods=['POST'])
def create_token():
44@api.route('/token', methods=["POST"]) # pragma: no cover
45def create_token():
46    """
47    Create a new access token
48
49    ---
50    tags:
51      - Authentication
52    parameters:
53      - name: email
54        in: formData
55        type: string
56        required: true
57        description: User email
58      - name: password
59        in: formData
60        type: string
61        required: true
62        description: User password
63    responses:
64      200:
65        description: Login successful
66      401:
67        description: Invalid email or password
68    """
69    email = request.json.get("email", None)
70    password = request.json.get("password", None)
71    user = mongo.user.find_one({"email": email})
72    if (user is not None and (user["password"] == password)):
73        access_token = create_access_token(identity=email)
74        return jsonify({"message": "Login successful", "access_token":access_token})
75    else:
76        print("Invalid email or password")
77        return jsonify({"message": "Invalid email or password"}),401

Create a new access token


tags:

  • Authentication parameters:
  • name: email in: formData type: string required: true description: User email
  • name: password in: formData type: string required: true description: User password responses: 200: description: Login successful 401: description: Invalid email or password
@api.route('/google-login', methods=['POST'])
def google_login():
79@api.route("/google-login", methods=["POST"])
80def google_login():
81    email = request.json.get("email", None)
82    firstName = request.json.get("first_name", None)
83    lastName = request.json.get("last_name", None)
84    user = mongo.user.find_one({"email": email})
85    if (user is None):
86        mongo.user.insert_one({"email": email, "first_name": firstName, "last_name": lastName})
87    access_token = create_access_token(identity=email)
88    return jsonify({"message": "Login successful", "access_token":access_token})
@api.route('/register', methods=['POST'])
def register():
 92@api.route("/register", methods=["POST"])
 93def register():
 94    """
 95    Register a new user
 96
 97    ---
 98    tags:
 99      - User Registration
100    parameters:
101      - name: email
102        in: formData
103        type: string
104        required: true
105        description: User email
106      - name: password
107        in: formData
108        type: string
109        required: true
110        description: User password
111      - name: firstName
112        in: formData
113        type: string
114        required: true
115        description: User's first name
116      - name: lastName
117        in: formData
118        type: string
119        required: true
120        description: User's last name
121    responses:
122      200:
123        description: Registration successful
124      409:
125        description: User already exists
126      500:
127        description: Registration failed
128    """
129
130    email = request.json.get('email', None)
131    password = request.json.get('password', None)
132    first_name = request.json.get('firstName', None)
133    last_name = request.json.get('lastName', None)
134    new_document = {
135    "email": email,
136    "password": password,
137    "first_name": first_name,
138    "last_name": last_name,
139    }
140    query = {
141        "email": email,
142    }
143    try:
144        inserted = mongo.user.update_one(query, {"$set": new_document}, upsert=True)
145        if (inserted.upserted_id):
146            response = jsonify({"msg": "register successful"})
147        else:   
148            print("User already exists")
149            response = jsonify({"msg": "User already exists"})
150    except Exception as e:
151        response = jsonify({"msg": "register failed"})
152
153    return response

Register a new user


tags:

  • User Registration parameters:
  • name: email in: formData type: string required: true description: User email
  • name: password in: formData type: string required: true description: User password
  • name: firstName in: formData type: string required: true description: User's first name
  • name: lastName in: formData type: string required: true description: User's last name responses: 200: description: Registration successful 409: description: User already exists 500: description: Registration failed
@api.route('/logout', methods=['POST'])
def logout():
155@api.route("/logout", methods=["POST"])
156def logout():
157    """
158    Logout the user and clear their session
159
160    ---
161    tags:
162      - User Logout
163    responses:
164      200:
165        description: Logout successful
166    """
167    response = jsonify({"msg": "logout successful"})
168    unset_jwt_cookies(response)
169    return response

Logout the user and clear their session


tags:

  • User Logout responses: 200: description: Logout successful
@api.route('/events', methods=['GET'])
def get_events():
171@api.route('/events', methods=['GET'])
172def get_events():
173    """
174    Retrieve a list of events
175
176    This endpoint retrieves a list of events from the database.
177
178    ---
179    tags:
180      - Events
181    responses:
182      200:
183        description: A list of events
184        schema:
185          type: array
186          items:
187            type: object
188            properties:
189              _id:
190                type: string
191              # Add more properties as needed
192      404:
193        description: No events found
194    """
195    events_collection = mongo.events
196    events = list(events_collection.find({}))
197    for event in events:
198        event["_id"] = str(event["_id"]) # Convert ObjectId to string
199    return jsonify(events)

Retrieve a list of events

This endpoint retrieves a list of events from the database.


tags:

  • Events responses: 200: description: A list of events schema: type: array items: type: object properties: _id: type: string # Add more properties as needed 404: description: No events found
@api.route('/is-enrolled', methods=['POST'])
@jwt_required()
def is_enrolled():
201@api.route('/is-enrolled', methods=['POST'])
202@jwt_required()
203def is_enrolled():
204    """
205    Check if the user is enrolled in an event
206
207    This endpoint checks if the authenticated user is enrolled in a specific event.
208
209    ---
210    tags:
211      - Events
212    parameters:
213      - in: body
214        name: data
215        description: Data containing the eventTitle
216        required: true
217        schema:
218          type: object
219          properties:
220            eventTitle:
221              type: string
222        example:
223          eventTitle: "Event Name"
224    security:
225      - JWT: []
226    responses:
227      200:
228        description: Indicates whether the user is enrolled
229        schema:
230          type: object
231          properties:
232            isEnrolled:
233              type: boolean
234      401:
235        description: Unauthorized access
236    """
237
238    data = request.json
239    eventTitle = data['eventTitle']
240    current_user = get_jwt_identity()
241    enrollment = mongo.user.find_one({"email": current_user, "eventTitle": eventTitle})
242
243    if enrollment:
244        return jsonify({"isEnrolled": True})
245    else:
246        return jsonify({"isEnrolled": False})

Check if the user is enrolled in an event

This endpoint checks if the authenticated user is enrolled in a specific event.


tags:

  • Events parameters:
  • in: body name: data description: Data containing the eventTitle required: true schema: type: object properties: eventTitle: type: string example: eventTitle: "Event Name" security:
  • JWT: [] responses: 200: description: Indicates whether the user is enrolled schema: type: object properties: isEnrolled: type: boolean 401: description: Unauthorized access
@api.route('/enroll', methods=['POST'])
@jwt_required()
def enroll_event():
249@api.route('/enroll', methods=['POST']) # pragma: no cover
250@jwt_required()
251def enroll_event(): # pragma: no cover
252    """
253    Enroll the user in an event
254
255    This endpoint allows an authenticated user to enroll in an event.
256
257    ---
258    tags:
259      - Events
260    parameters:
261      - in: body
262        name: data
263        description: Data containing the eventTitle
264        required: true
265        schema:
266          type: object
267          properties:
268            eventTitle:
269              type: string
270        example:
271          eventTitle: "Event Name"
272    security:
273      - JWT: []
274    responses:
275      200:
276        description: User successfully enrolled in the event
277        schema:
278          type: object
279          properties:
280            status:
281              type: string
282              example: "Data saved successfully"
283      500:
284        description: An error occurred while enrolling the user
285    """
286    data = request.get_json()  # get data from POST request
287    current_user = get_jwt_identity()
288    try:
289        # Insert data into MongoDB
290        mongo.user.insert_one({
291            "email": current_user,
292            "eventTitle": data['eventTitle']
293        })
294        response = {"status": "Data saved successfully"}
295    except Exception as e:
296        response = {"status": "Error", "message": str(e)}
297    
298    return jsonify(response)

Enroll the user in an event

This endpoint allows an authenticated user to enroll in an event.


tags:

  • Events parameters:
  • in: body name: data description: Data containing the eventTitle required: true schema: type: object properties: eventTitle: type: string example: eventTitle: "Event Name" security:
  • JWT: [] responses: 200: description: User successfully enrolled in the event schema: type: object properties: status: type: string example: "Data saved successfully" 500: description: An error occurred while enrolling the user
@api.route('/unenroll', methods=['POST'])
@jwt_required()
def unenroll_event():
300@api.route('/unenroll', methods=['POST']) # pragma: no cover
301@jwt_required()
302def unenroll_event(): # pragma: no cover
303    """
304    Unenroll the user from an event
305
306    This endpoint allows an authenticated user to unenroll from an event.
307
308    ---
309    tags:
310      - Events
311    parameters:
312      - in: body
313        name: data
314        description: Data containing the eventTitle
315        required: true
316        schema:
317          type: object
318          properties:
319            eventTitle:
320              type: string
321        example:
322          eventTitle: "Event Name"
323    security:
324      - JWT: []
325    responses:
326      200:
327        description: User successfully unenrolled from the event
328        schema:
329          type: object
330          properties:
331            status:
332              type: string
333              example: "Data saved successfully"
334      500:
335        description: An error occurred while unenrolling the user
336    """
337    data = request.get_json()  # get data from POST request
338    current_user = get_jwt_identity()
339    try:
340        # Insert data into MongoDB
341        mongo.user.delete_one({
342            "email": current_user,
343            "eventTitle": data['eventTitle']
344        })
345        response = {"status": "Data saved successfully"}
346    except Exception as e:
347        response = {"status": "Error", "message": str(e)}
348    
349    return jsonify(response)

Unenroll the user from an event

This endpoint allows an authenticated user to unenroll from an event.


tags:

  • Events parameters:
  • in: body name: data description: Data containing the eventTitle required: true schema: type: object properties: eventTitle: type: string example: eventTitle: "Event Name" security:
  • JWT: [] responses: 200: description: User successfully unenrolled from the event schema: type: object properties: status: type: string example: "Data saved successfully" 500: description: An error occurred while unenrolling the user
@api.route('/profile')
@jwt_required()
def my_profile():
351@api.route('/profile')
352@jwt_required()
353def my_profile(): # pragma: no cover
354    """
355    Retrieve user profile information
356
357    This endpoint allows an authenticated user to retrieve their profile information.
358
359    ---
360    tags:
361      - User
362    security:
363      - JWT: []
364    responses:
365      200:
366        description: User profile information retrieved successfully
367        schema:
368          type: object
369        example:
370          {
371            "_id": "12345",
372            "email": "user@example.com",
373            "first_name": "John",
374            "last_name": "Doe",
375            "age": 30,
376            "weight": 70,
377            "height": 175
378          }
379      401:
380        description: Unauthorized. User must be logged in to access their profile.
381      404:
382        description: User profile not found.
383      500:
384        description: An error occurred while retrieving the user profile.
385    """
386    current_user = get_jwt_identity()
387    profile = mongo.user.find_one({"email": current_user})
388    return jsonify(json_util.dumps(profile))

Retrieve user profile information

This endpoint allows an authenticated user to retrieve their profile information.


tags:

  • User security:
  • JWT: [] responses: 200: description: User profile information retrieved successfully schema: type: object example: { "_id": "12345", "email": "user@example.com", "first_name": "John", "last_name": "Doe", "age": 30, "weight": 70, "height": 175 } 401: description: Unauthorized. User must be logged in to access their profile. 404: description: User profile not found. 500: description: An error occurred while retrieving the user profile.
@api.route('/caloriesConsumed', methods=['POST'])
@jwt_required()
def addUserConsumedCalories():
390@api.route('/caloriesConsumed',methods=["POST"])
391@jwt_required()
392def addUserConsumedCalories(): # pragma: no cover
393    """
394    Add consumed calories for a user
395
396    This endpoint allows an authenticated user to add consumed calories for a specific date.
397
398    ---
399    tags:
400      - User
401    security:
402      - JWT: []
403    parameters:
404      - name: body
405        in: body
406        required: true
407        schema:
408          type: object
409          properties:
410            intakeDate:
411              type: string
412              format: date
413              description: The date for which calories are being recorded (e.g., "2023-10-17").
414            intakeFoodItem:
415              type: string
416              description: The name of the food item.
417            intakeCalories:
418              type: integer
419              description: The number of calories consumed for the food item.
420    responses:
421      200:
422        description: Calories consumed data saved successfully.
423        schema:
424          type: object
425        example:
426          {
427            "status": "Data saved successfully"
428          }
429      401:
430        description: Unauthorized. User must be logged in to add consumed calories.
431      500:
432        description: An error occurred while saving consumed calories data.
433    """
434    data = request.get_json()  # get data from POST request
435    current_user = get_jwt_identity()
436    try:
437        # Insert data into MongoDB
438        mongo.user.update_one({'email': current_user, "consumedDate": data['intakeDate']}, {"$push": {"foodConsumed": {"item":data["intakeFoodItem"],"calories":data["intakeCalories"]}}}, upsert=True)
439        response = {"status": "Data saved successfully"}
440        statusCode = 200
441    except Exception as e:
442        response = {"status": "Error", "message": str(e)}
443        statusCode = 500
444    return jsonify(response),statusCode

Add consumed calories for a user

This endpoint allows an authenticated user to add consumed calories for a specific date.


tags:

  • User security:
  • JWT: [] parameters:
  • name: body in: body required: true schema: type: object properties: intakeDate: type: string format: date description: The date for which calories are being recorded (e.g., "2023-10-17"). intakeFoodItem: type: string description: The name of the food item. intakeCalories: type: integer description: The number of calories consumed for the food item. responses: 200: description: Calories consumed data saved successfully. schema: type: object example: { "status": "Data saved successfully" } 401: description: Unauthorized. User must be logged in to add consumed calories. 500: description: An error occurred while saving consumed calories data.
@api.route('/profileUpdate', methods=['POST'])
@jwt_required()
def profileUpdate():
446@api.route('/profileUpdate',methods=["POST"])
447@jwt_required()
448def profileUpdate(): # pragma: no cover
449    """
450    Update user profile
451
452    This endpoint allows an authenticated user to update their profile information.
453
454    ---
455    tags:
456      - User
457    security:
458      - JWT: []
459    parameters:
460      - name: body
461        in: body
462        required: true
463        schema:
464          type: object
465          properties:
466            firstName:
467              type: string
468              description: The user's first name.
469            lastName:
470              type: string
471              description: The user's last name.
472            age:
473              type: integer
474              description: The user's age.
475            weight:
476              type: number
477              description: The user's weight.
478            height:
479              type: number
480              description: The user's height.
481            sex:
482              type: string
483              description: The user's sex.
484    responses:
485      200:
486        description: User profile updated successfully.
487        schema:
488          type: object
489        example:
490          {
491            "msg": "Update successful"
492          }
493      401:
494        description: Unauthorized. User must be logged in to update their profile.
495      500:
496        description: An error occurred while updating the user's profile.
497    """
498    current_user = get_jwt_identity()
499    first_name = request.json.get('firstName', None)
500    last_name = request.json.get('lastName', None)
501    age = request.json.get('age', None)
502    weight = request.json.get('weight', None)
503    height = request.json.get('height', None)
504    sex = request.json.get('sex', None)
505    activityLevel = request.json.get('activityLevel', None)
506    bmi = (0.453*float(weight))/((0.3048*float(height))**2)
507    bmi = round(bmi,2)
508    tdee = calculate_tdee(height, weight, age, sex, activityLevel)
509    new_document = {
510    "first_name": first_name,
511    "last_name": last_name,
512    "age": age,
513    "weight": weight,
514    "height": height,
515    "sex": sex,
516    "bmi": bmi,
517    "target_calories": tdee,
518    }
519    query = {
520        "email": current_user,
521    }
522    try:
523        mongo.user.update_one(query, {"$set": new_document}, upsert=True)
524        response = jsonify({"msg": "update successful"})
525    except Exception as e:
526        response = jsonify({"msg": "update failed"})
527
528    return response

Update user profile

This endpoint allows an authenticated user to update their profile information.


tags:

  • User security:
  • JWT: [] parameters:
  • name: body in: body required: true schema: type: object properties: firstName: type: string description: The user's first name. lastName: type: string description: The user's last name. age: type: integer description: The user's age. weight: type: number description: The user's weight. height: type: number description: The user's height. sex: type: string description: The user's sex. responses: 200: description: User profile updated successfully. schema: type: object example: { "msg": "Update successful" } 401: description: Unauthorized. User must be logged in to update their profile. 500: description: An error occurred while updating the user's profile.
@api.route('/goalsUpdate', methods=['POST'])
@jwt_required()
def goalsUpdate():
530@api.route('/goalsUpdate',methods=["POST"])
531@jwt_required()
532def goalsUpdate(): # pragma: no cover
533    """
534    Update user goals
535
536    This endpoint allows an authenticated user to update their fitness goals, such as target weight, target calories, and target goal.
537
538    ---
539    tags:
540      - User
541    security:
542      - JWT: []
543    parameters:
544      - name: body
545        in: body
546        required: true
547        schema:
548          type: object
549          properties:
550            targetWeight:
551              type: number
552              description: The user's target weight goal.
553            targetCalories:
554              type: number
555              description: The user's target daily calorie intake goal.
556            activityLevel:
557              type: string
558              description: The user's activity level.
559    responses:
560      200:
561        description: User goals updated successfully.
562        schema:
563          type: object
564        example:
565          {
566            "msg": "Update successful"
567          }
568      401:
569        description: Unauthorized. User must be logged in to update their goals.
570      500:
571        description: An error occurred while updating the user's goals.
572    """
573    current_user = get_jwt_identity()
574    targetWeight = request.json.get('targetWeight', None)
575    activityLevel = request.json.get('activityLevel', None)
576
577    new_document = {
578        "target_weight": targetWeight,
579        "activity_level": activityLevel
580    }
581    query = {
582        "email": current_user,
583    }
584    try:
585        profile = mongo.user.find_one(query)
586        tdee = calculate_tdee(profile["height"], profile["weight"], profile["age"], profile["sex"], activityLevel)
587        if tdee:  
588          new_document["target_calories"] = tdee
589        mongo.user.update_one(query, {"$set": new_document}, upsert=True)
590        response = jsonify({"msg": "update successful"})
591    except Exception as e:
592        response = jsonify({"msg": "update failed"})
593
594    return response

Update user goals

This endpoint allows an authenticated user to update their fitness goals, such as target weight, target calories, and target goal.


tags:

  • User security:
  • JWT: [] parameters:
  • name: body in: body required: true schema: type: object properties: targetWeight: type: number description: The user's target weight goal. targetCalories: type: number description: The user's target daily calorie intake goal. activityLevel: type: string description: The user's activity level. responses: 200: description: User goals updated successfully. schema: type: object example: { "msg": "Update successful" } 401: description: Unauthorized. User must be logged in to update their goals. 500: description: An error occurred while updating the user's goals.
@api.route('/caloriesBurned', methods=['POST'])
@jwt_required()
def addUserBurnedCalories():
597@api.route('/caloriesBurned',methods=["POST"])
598@jwt_required()
599def addUserBurnedCalories(): # pragma: no cover
600    """
601    Add user's burned calories
602
603    This endpoint allows an authenticated user to add information about calories burned on a specific date.
604
605    ---
606    tags:
607      - User
608    security:
609      - JWT: []
610    parameters:
611      - name: body
612        in: body
613        required: true
614        schema:
615          type: object
616          properties:
617            burnoutDate:
618              type: string
619              format: date
620              description: The date on which calories were burned.
621            burntoutCalories:
622              type: number
623              description: The number of calories burned on the specified date.
624    responses:
625      200:
626        description: Calories burned data saved successfully.
627        schema:
628          type: object
629        example:
630          {
631            "status": "Data saved successfully"
632          }
633      401:
634        description: Unauthorized. User must be logged in to add burned calories data.
635      500:
636        description: An error occurred while saving the burned calories data.
637    """
638    data = request.get_json()  # get data from POST request
639    current_user = get_jwt_identity()
640    try:
641        # Insert data into MongoDB
642        mongo.user.update_one({'email': current_user, "consumedDate": data['burnoutDate']}, {"$inc": {"burntCalories": int(data["burntoutCalories"])}}, upsert=True)
643        response = {"status": "Data saved successfully"}
644        statusCode = 200
645    except Exception as e:
646        response = {"status": "Error", "message": str(e)}
647        statusCode = 500
648    return jsonify(response),statusCode

Add user's burned calories

This endpoint allows an authenticated user to add information about calories burned on a specific date.


tags:

  • User security:
  • JWT: [] parameters:
  • name: body in: body required: true schema: type: object properties: burnoutDate: type: string format: date description: The date on which calories were burned. burntoutCalories: type: number description: The number of calories burned on the specified date. responses: 200: description: Calories burned data saved successfully. schema: type: object example: { "status": "Data saved successfully" } 401: description: Unauthorized. User must be logged in to add burned calories data. 500: description: An error occurred while saving the burned calories data.
@api.route('/createFood', methods=['POST'])
def createFood():
650@api.route('/createFood', methods=["POST"])
651def createFood():
652    """
653    Create a custom food
654
655    This endpoint allows an authenticated user to create their custom food item with the amount of calories it has.
656
657    ---
658    tags:
659      - User
660    parameters:
661      - name: body
662        in: body
663        required: true
664        schema:
665          type: object
666          properties:
667            foodName:
668              type: string
669              format: food item name
670              description: The name of the food item being created.
671            calories:
672              type: number
673              description: The number of calories in the created food item.
674    responses:
675      200:
676        description: Food item created successfully
677        schema:
678          type: object
679        example:
680          {
681            "status": "Data saved successfully"
682          }
683      401:
684        description: Unauthorized. User must be logged in to create custom food.
685      500:
686        description: An error occurred while creating the custom food.
687
688    """
689    data = request.get_json() # get data from POST request
690    foodName = data['foodName']
691    calories = data['calories']
692    try:
693        # Insert data into MongoDB
694        mongo.food.insert_one({'food': foodName, "calories": calories})
695        response = {"status": "Data saved successfully"}
696        statusCode = 200
697    except Exception as e:
698        response = {"status": "Error", "message": str(e)}
699        statusCode = 500
700    return jsonify(response),statusCode

Create a custom food

This endpoint allows an authenticated user to create their custom food item with the amount of calories it has.


tags:

  • User parameters:
  • name: body in: body required: true schema: type: object properties: foodName: type: string format: food item name description: The name of the food item being created. calories: type: number description: The number of calories in the created food item. responses: 200: description: Food item created successfully schema: type: object example: { "status": "Data saved successfully" } 401: description: Unauthorized. User must be logged in to create custom food. 500: description: An error occurred while creating the custom food.
@api.route('/createMeal', methods=['POST'])
@jwt_required()
def createMeal():
702@api.route('/createMeal', methods=["POST"])
703@jwt_required()
704def createMeal():
705    """
706    Create a custom meal
707
708    This endpoint allows an authenticated user to create their own meals with different food items as the ingredients.
709
710    ---
711    tags:
712      - User
713    security:
714      - JWT: []
715    parameters:
716      - name: body
717        in: body
718        required: true
719        schema:
720          type: object
721          properties:
722            mealName:
723              type: string
724              format: Meal name
725              description: The name of the meal item being created.
726            ingredients:
727              type: list
728              description: Is a list of the ingredients in the meal.
729    responses:
730      200:
731        description: Meal created successfully
732        schema:
733          type: object
734        example:
735          {
736            "status": "Data saved successfully"
737          }
738      401:
739        description: Unauthorized. User must be logged in to create custom meal.
740      500:
741        description: An error occurred while creating the custom meal.
742
743    """
744    data = request.get_json() # get data from POST request
745    current_user = get_jwt_identity()
746    mealName = data['mealName']
747    ingredients = data['ingredients']
748    calories = 0
749    for item in ingredients:
750        food_item = mongo.food.find_one({"food": item})
751        calories += int(food_item["calories"])
752    try:
753        # Insert data into MongoDB
754        mongo.food.insert_one({'food': mealName, "calories": calories})
755        mongo.user.insert_one({
756            "email": current_user,
757            "meal_name": mealName,
758            "ingredients": ingredients,
759            "total_calories": calories
760        })
761        response = {"status": "Data saved successfully"}
762        statusCode = 200
763    except Exception as e:
764        response = {"status": "Error", "message": str(e)}
765        statusCode = 500
766    return jsonify(response),statusCode

Create a custom meal

This endpoint allows an authenticated user to create their own meals with different food items as the ingredients.


tags:

  • User security:
  • JWT: [] parameters:
  • name: body in: body required: true schema: type: object properties: mealName: type: string format: Meal name description: The name of the meal item being created. ingredients: type: list description: Is a list of the ingredients in the meal. responses: 200: description: Meal created successfully schema: type: object example: { "status": "Data saved successfully" } 401: description: Unauthorized. User must be logged in to create custom meal. 500: description: An error occurred while creating the custom meal.
@api.route('/weekHistory', methods=['POST'])
@jwt_required()
def getWeekHistory():
768@api.route('/weekHistory',methods=["POST"])
769@jwt_required()
770def getWeekHistory(): # pragma: no cover
771    """
772    Get user's weekly history
773
774    This endpoint allows an authenticated user to retrieve their food consumption and calories burned history for the past week.
775
776    ---
777    tags:
778      - User
779    security:
780      - JWT: []
781    parameters:
782      - name: body
783        in: body
784        required: true
785        schema:
786          type: object
787          properties:
788            todayDate:
789              type: string
790              format: date
791              description: The date for the end of the week (today's date).
792    responses:
793      200:
794        description: Successfully retrieved the user's weekly history.
795        schema:
796          type: array
797          items:
798            type: object
799            properties:
800              dayIndex:
801                type: integer
802                description: Integer from 0 to 6 representing the day index.
803              date:
804                type: string
805                format: date
806                description: The date for each day in the week.
807              foodConsumed:
808                type: array
809                items:
810                  type: object
811                  properties:
812                    item:
813                      type: string
814                      description: Food item name.
815                    calories:
816                      type: number
817                      description: Calories consumed from the food item.
818                description: A list of dictionaries containing food items and their consumed calories.
819              caloriesConsumed:
820                type: number
821                description: The sum of all calories consumed for that day.
822              exceededDailyLimit:
823                type: boolean
824                description: Indicates whether the calories consumed exceeded the daily limit.
825              burntCalories:
826                type: number
827                description: Calories burned on that day.
828        example:
829          [
830            {
831              "dayIndex": 0,
832              "date": "10/13/2023",
833              "foodConsumed": [
834                {
835                  "item": "Chicken Salad",
836                  "calories": 500
837                },
838                {
839                  "item": "Onion Soup",
840                  "calories": 300
841                },
842                {
843                  "item": "Potato Salad",
844                  "calories": 500
845                },
846                {
847                  "item": "Cheese Burger",
848                  "calories": 500
849                }
850              ],
851              "caloriesConsumed": 1800,
852              "exceededDailyLimit": false,
853              "burntCalories": 1200
854            },
855            {
856              "dayIndex": 1,
857              "date": "10/12/2023",
858              "foodConsumed": [...],
859              "caloriesConsumed": ...,
860              "exceededDailyLimit": ...,
861              "burntCalories": ...
862            },
863            ...
864          ]
865      401:
866        description: Unauthorized. User must be logged in to retrieve weekly history.
867      500:
868        description: An error occurred while retrieving the user's weekly history.
869    """
870    data = request.get_json()  # get data from POST request
871    current_user = get_jwt_identity()
872    todayDate = datetime.strptime(data["todayDate"],"%m/%d/%Y")
873    dates = [(todayDate-timedelta(days=x)).strftime("%m/%d/%Y") for x in range(7)]
874    calorieLimit = 1000
875    result = []
876    try:
877        for index,dateToFind in enumerate(dates):
878            # Every day's res item should like this
879            # {
880            #   dayIndex: 0,               #Interger from 0-6
881            #   date: "10/13/2023",        #Date 0=today, 6=7th day ago from today
882            #   foodConsumed: [            # A list of dicts, each dict contains a food item and its calories
883            #     {
884            #       item: "Chicken Salad",
885            #       calories: 500,
886            #     },
887            #     {
888            #       item: "Onion Soup",
889            #       calories: 300,
890            #     },
891            #     {
892            #       item: "Potato Salad",
893            #       calories: 500,
894            #     },
895            #     {
896            #       item: "Cheese Burger",
897            #       calories: 500,
898            #     },
899            #   ],
900            #   caloriesConsumed: 1800,    # the sum of all calories consumed from above list
901            #   exceededDailyLimit: false, # true or false based on whether caloriesConsumed is > limit user set
902            #   burntCalories: 1200,       # calories burnt out on that day
903            # }
904            res = {}
905            data = mongo.user.find_one({'email': current_user, "consumedDate": dateToFind})
906            res["dayIndex"] = index
907            res["date"] = dateToFind
908            if data:
909                if "foodConsumed" in data:
910                    res["foodConsumed"] = data["foodConsumed"]
911                    res["caloriesConsumed"] = reduce(lambda a,b: a+b, [int(item["calories"]) for item in data["foodConsumed"]])
912                    res["exceededDailyLimit"] = res["caloriesConsumed"]>calorieLimit
913                if "burntCalories" in data:
914                    res["burntCalories"] = data["burntCalories"]
915            if "foodConsumed" not in res:
916                res["foodConsumed"] = []
917            if "caloriesConsumed" not in res:
918                res["caloriesConsumed"] = 0
919            if "burntCalories" not in res:
920                res["burntCalories"] = 0
921            if "exceededDailyLimit" not in res:
922                res["exceededDailyLimit"] = False
923            result.append(res)
924        response = result
925        statusCode = 200
926    except Exception as e:
927        response = {"status": "Error", "message": str(e)}
928        statusCode = 500
929    return jsonify(response),statusCode

Get user's weekly history

This endpoint allows an authenticated user to retrieve their food consumption and calories burned history for the past week.


tags:

  • User security:
  • JWT: [] parameters:
  • name: body in: body required: true schema: type: object properties: todayDate: type: string format: date description: The date for the end of the week (today's date). responses: 200: description: Successfully retrieved the user's weekly history. schema: type: array items: type: object properties: dayIndex: type: integer description: Integer from 0 to 6 representing the day index. date: type: string format: date description: The date for each day in the week. foodConsumed: type: array items: type: object properties: item: type: string description: Food item name. calories: type: number description: Calories consumed from the food item. description: A list of dictionaries containing food items and their consumed calories. caloriesConsumed: type: number description: The sum of all calories consumed for that day. exceededDailyLimit: type: boolean description: Indicates whether the calories consumed exceeded the daily limit. burntCalories: type: number description: Calories burned on that day. example: [ { "dayIndex": 0, "date": "10/13/2023", "foodConsumed": [ { "item": "Chicken Salad", "calories": 500 }, { "item": "Onion Soup", "calories": 300 }, { "item": "Potato Salad", "calories": 500 }, { "item": "Cheese Burger", "calories": 500 } ], "caloriesConsumed": 1800, "exceededDailyLimit": false, "burntCalories": 1200 }, { "dayIndex": 1, "date": "10/12/2023", "foodConsumed": [...], "caloriesConsumed": ..., "exceededDailyLimit": ..., "burntCalories": ... }, ... ] 401: description: Unauthorized. User must be logged in to retrieve weekly history. 500: description: An error occurred while retrieving the user's weekly history.
@api.route('/myMeals', methods=['GET'])
@jwt_required()
def getMyMeals():
931@api.route("/myMeals",methods=["GET"])
932@jwt_required()
933def getMyMeals():
934    """
935    Get My Meals
936
937    This endpoint allows an authenticated user to retrieve the custom meals that they have created.
938
939    ---
940    tags:
941      - User
942      - Meals
943    security:
944      - JWT: []
945    responses:
946      200:
947        description: Successfully retrieved the custom meals created by user
948        schema:
949          type: object
950          properties:
951            mealName:
952              type: string
953              description: Name of the custom meal
954            ingredients:
955              type: array
956              description: List of ingredients in the meal
957          example:
958            {
959            "mealName":"My meal",
960            "ingredients":["Eggs","Toast"],
961            }
962      401:
963        description: Unauthorized. User must be logged in to retrieve the food calorie mapping.
964      500:
965        description: An error occurred while retrieving the food calorie mapping.
966    """
967    current_user = get_jwt_identity()
968    result = []
969    try:
970        data = mongo.user.find({"email": current_user,"meal_name":{"$exists": True}})
971        for meal in data:
972            cal_info = []
973            for item in meal['ingredients']:
974                food_item = mongo.food.find_one({'food':item})
975                cal_info.append({str(item):food_item['calories']})
976            res={}
977            res['meal_name']=meal['meal_name']
978            res['ingredients']=meal['ingredients']
979            res['total_calories']=meal['total_calories']
980            result.append(res)
981        response = result
982        statusCode = 200
983    except Exception as e:
984        response = {"status": "Error", "message": str(e)}
985        statusCode = 500
986    return jsonify(response),statusCode

Get My Meals

This endpoint allows an authenticated user to retrieve the custom meals that they have created.


tags:

  • User
  • Meals security:
  • JWT: [] responses: 200: description: Successfully retrieved the custom meals created by user schema: type: object properties: mealName: type: string description: Name of the custom meal ingredients: type: array description: List of ingredients in the meal example: { "mealName":"My meal", "ingredients":["Eggs","Toast"], } 401: description: Unauthorized. User must be logged in to retrieve the food calorie mapping. 500: description: An error occurred while retrieving the food calorie mapping.
@api.route('/foodCalorieMapping', methods=['GET'])
@jwt_required()
def getFoodCalorieMapping():
 989@api.route('/foodCalorieMapping',methods=["GET"])
 990@jwt_required()
 991def getFoodCalorieMapping(): 
 992    """
 993    Get food calorie mapping
 994
 995    This endpoint allows an authenticated user to retrieve a mapping of food items to their respective calorie values.
 996
 997    ---
 998    tags:
 999      - Food
1000    security:
1001      - JWT: []
1002    responses:
1003      200:
1004        description: Successfully retrieved the food calorie mapping.
1005        schema:
1006          type: object
1007          properties:
1008            foodItem:
1009              type: integer
1010              description: Food item name.
1011            calories:
1012              type: number
1013              description: Calories associated with the food item.
1014        example:
1015          {
1016            "Potato": 50,
1017            "Acai": 20,
1018            "Cheeseburger": 80,
1019            ...
1020          }
1021      401:
1022        description: Unauthorized. User must be logged in to retrieve the food calorie mapping.
1023      500:
1024        description: An error occurred while retrieving the food calorie mapping.
1025    """
1026    try:
1027        data = mongo.food.find()
1028        # Response should be in this format {foodItem: calories, foodItem: calories....} 
1029        # For Example { Potato: 50, Acai: 20, Cheeseburger: 80 }
1030        response = {item["food"]:item["calories"] for item in data}
1031        statusCode = 200
1032    except Exception as e:
1033        response = {"status": "Error", "message": str(e)}
1034        statusCode = 500
1035    return jsonify(response),statusCode

Get food calorie mapping

This endpoint allows an authenticated user to retrieve a mapping of food items to their respective calorie values.


tags:

  • Food security:
  • JWT: [] responses: 200: description: Successfully retrieved the food calorie mapping. schema: type: object properties: foodItem: type: integer description: Food item name. calories: type: number description: Calories associated with the food item. example: { "Potato": 50, "Acai": 20, "Cheeseburger": 80, ... } 401: description: Unauthorized. User must be logged in to retrieve the food calorie mapping. 500: description: An error occurred while retrieving the food calorie mapping.
@api.route('/usersEvents', methods=['GET'])
@jwt_required()
def getUserRegisteredEvents():
1037@api.route('/usersEvents',methods=["GET"]) 
1038@jwt_required()
1039def getUserRegisteredEvents(): 
1040    """
1041    Get user's registered events
1042
1043    This endpoint allows an authenticated user to retrieve the events they are registered for.
1044
1045    ---
1046    tags:
1047      - Events
1048    security:
1049      - JWT: []
1050    responses:
1051      200:
1052        description: Successfully retrieved the user's registered events.
1053        schema:
1054          type: array
1055          items:
1056            type: object
1057            properties:
1058              eventName:
1059                type: string
1060                description: Name of the event.
1061              date:
1062                type: string
1063                format: date
1064                description: Date of the event.
1065            example:
1066              [
1067                {
1068                  "eventName": "Yoga",
1069                  "date": "2023-12-11"
1070                },
1071                {
1072                  "eventName": "Swimming",
1073                  "date": "2023-11-10"
1074                },
1075                ...
1076              ]
1077      401:
1078        description: Unauthorized. User must be logged in to retrieve their registered events.
1079      500:
1080        description: An error occurred while retrieving the user's registered events.
1081    """
1082    try:
1083        # current_user = get_jwt_identity()
1084        current_user = get_jwt_identity()
1085        data = mongo.user.find({"email": current_user, "eventTitle":{"$exists": True}})
1086        response = []
1087        date="10/23/2023"
1088        for item in data:
1089            res = {"eventName": item["eventTitle"], "date": date}
1090            response.append(res)
1091        # Response should be in this format [{eventName: Yoga, date: "12/11/2023"},{eventName: Swimming, date: "11/10/2023"}]
1092        # For Example { Potato: 50, Acai: 20, Cheeseburger: 80 }
1093        statusCode = 200
1094    except Exception as e:
1095        response = {"status": "Error", "message": str(e)}
1096        statusCode = 500
1097    return jsonify(response),statusCode

Get user's registered events

This endpoint allows an authenticated user to retrieve the events they are registered for.


tags:

  • Events security:
  • JWT: [] responses: 200: description: Successfully retrieved the user's registered events. schema: type: array items: type: object properties: eventName: type: string description: Name of the event. date: type: string format: date description: Date of the event. example: [ { "eventName": "Yoga", "date": "2023-12-11" }, { "eventName": "Swimming", "date": "2023-11-10" }, ... ] 401: description: Unauthorized. User must be logged in to retrieve their registered events. 500: description: An error occurred while retrieving the user's registered events.
def calculate_tdee(height, weight, age, sex, activityLevel):
1099def calculate_tdee(height,weight,age,sex,activityLevel):
1100    if height and weight and age and sex and activityLevel:
1101        pass
1102    else:
1103        return None
1104    kg_weight = float(weight)*0.45359237
1105    cm_height = float(height)*30.48
1106    common_calc_for_male_female = (10*kg_weight) + (6.25*cm_height) - (5*int(age))
1107    if sex == "Male":
1108        bmr = common_calc_for_male_female + 5
1109    else:
1110        bmr = common_calc_for_male_female - 161
1111    personal_activity_levels = {'Minimal': 1.2,'Light': 1.375, 'Moderate': 1.55, 'Heavy':1.725, 'Athlete': 1.9}
1112    tdee = int((bmr * personal_activity_levels[activityLevel]))
1113    return tdee