diff --git a/backend/models/energy.py b/backend/models/energy.py index e8cebb1..969a739 100644 --- a/backend/models/energy.py +++ b/backend/models/energy.py @@ -93,7 +93,7 @@ def calculate_carbon_emissions(self) -> float: electricity_carbon_emissions = (self.electricity * 0.17) / self.household else: # self.province == "Nunavut" electricity_carbon_emissions = (self.electricity * 0.84) / self.household - return sum([heating_oil_carbon_emissions, natural_gas_carbon_emissions, electricity_carbon_emissions]) + return int(sum([heating_oil_carbon_emissions, natural_gas_carbon_emissions, electricity_carbon_emissions])) def __repr__(self) -> str: return f'Energy ID: {self.oid.__str__()}' diff --git a/backend/models/food.py b/backend/models/food.py index 3308e65..dcd2482 100644 --- a/backend/models/food.py +++ b/backend/models/food.py @@ -27,7 +27,6 @@ class FoodEntry(CARBON_MODEL): milk: int food_waste: int - # food measurements in # of 100g servings def __init__(self, oid: ObjectId, user_id: ObjectId, carbon_emissions: int, date: Union[str, datetime], beef: int, lamb: int, pork: int, chicken: int, fish: int, cheese: int, milk: int, @@ -84,15 +83,14 @@ def calculate_carbon_emissions(self) -> float: cheese_carbon_emissions = self.cheese * 2.3 milk_carbon_emissions = self.milk * 0.8 food_waste_carbon_emissions = self.food_waste * 0.0025 - return sum([beef_carbon_emissions, lamb_carbon_emissions, pork_carbon_emissions, - chicken_carbon_emissions, fish_carbon_emissions, cheese_carbon_emissions, - milk_carbon_emissions, food_waste_carbon_emissions]) + return int(sum([beef_carbon_emissions, lamb_carbon_emissions, pork_carbon_emissions, + chicken_carbon_emissions, fish_carbon_emissions, cheese_carbon_emissions, + milk_carbon_emissions, food_waste_carbon_emissions])) def __repr__(self) -> str: return f'Food ID: {self.oid.__str__()}' - class FoodEntryRecommendation(DB_MODEL): beef_recommendation: str lamb_recommendation: str @@ -177,7 +175,7 @@ def from_food_entry(food_entry: FoodEntry) -> FoodEntryRecommendation: recommendation3 = "Try opting for low-impact plant protein sources like peas, legumes and tofu" recommendations = [recommendation1, recommendation2, recommendation3] lamb_recommendation = random.choice(recommendations) - + if pork_carbon_emissions > submetric_threshold: recommendation1 = "Try opting for white meat (fish, chicken, etc.)" recommendation2 = "Consider alternate forms of protein (chicken, fish, eggs, etc.)" diff --git a/backend/postman/Backend.postman_collection.json b/backend/postman/Backend.postman_collection.json index f61fe52..53f926a 100644 --- a/backend/postman/Backend.postman_collection.json +++ b/backend/postman/Backend.postman_collection.json @@ -59,14 +59,41 @@ } }, "url": { - "raw": "{{LocalBaseURL}}/users/user_email/yazan@gmail.com", + "raw": "{{LocalBaseURL}}/users/user_email/yazan@armoush.ca", "host": [ "{{LocalBaseURL}}" ], "path": [ "users", "user_email", - "yazan@gmail.com" + "yazan@armoush.ca" + ] + } + }, + "response": [] + }, + { + "name": "Get Top Users", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"count\": 3\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{LocalBaseURL}}/users/get_top_users", + "host": [ + "{{LocalBaseURL}}" + ], + "path": [ + "users", + "get_top_users" ] } }, @@ -586,7 +613,7 @@ "bearer": [ { "key": "token", - "value": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjBiYmQyOTllODU2MmU3MmYyZThkN2YwMTliYTdiZjAxMWFlZjU1Y2EiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vY2FyYm9uLXRyYWNrLXN5c3RlbSIsImF1ZCI6ImNhcmJvbi10cmFjay1zeXN0ZW0iLCJhdXRoX3RpbWUiOjE3MDExMjc0NTAsInVzZXJfaWQiOiJ3UFVEaEFiM0Q5ZHpoeDJXa1RBZlBLbnhGSG0xIiwic3ViIjoid1BVRGhBYjNEOWR6aHgyV2tUQWZQS254RkhtMSIsImlhdCI6MTcwMTEyNzQ1MCwiZXhwIjoxNzAxMTMxMDUwLCJlbWFpbCI6InlhemFuQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyJ5YXphbkBnbWFpbC5jb20iXX0sInNpZ25faW5fcHJvdmlkZXIiOiJwYXNzd29yZCJ9fQ.YcyzOeOgXiurm2W8lw2YwvIL2Pfweezu2ASK_RK3MuVRUw2Z1AXwWTJyDbjioYfaXS2GwurtJ3u-q7TqPlL4MmTwb5G09F7cmbNBvbEBQTtOhK9TmyNlMcGV0Gtkaf3J7xebL4qcwQ9aI_lZ1MGS9tMYn8gwArxIVs8nNPxkSFUicrj_buf3Jan6kNMfVIQOOUg9cqocn3VoxInAI9fjbxyliZ7LDF3rNBzBNsXQoOJ6UlHqEcd_Up2oLGsEm3HnIArtPzn4V_BNcmkaZh2cx28KDUjUPpTVHdWguEPUkA_CFhDTYdts7ReisAQviKTkhIxDkCGsUtllWU0Q4fTNcg", + "value": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjAzMmNjMWNiMjg5ZGQ0NjI2YTQzNWQ3Mjk4OWFlNDMyMTJkZWZlNzgiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vY2FyYm9uLXRyYWNrLXN5c3RlbSIsImF1ZCI6ImNhcmJvbi10cmFjay1zeXN0ZW0iLCJhdXRoX3RpbWUiOjE3MDI4NTg2NzEsInVzZXJfaWQiOiIzb1F2UzlRSlo2WEZwUXJJUnk5VGZTWXU4NFUyIiwic3ViIjoiM29RdlM5UUpaNlhGcFFySVJ5OVRmU1l1ODRVMiIsImlhdCI6MTcwMjg1ODY3MSwiZXhwIjoxNzAyODYyMjcxLCJlbWFpbCI6ImFobWFkQGFybW91c2guY2EiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsiYWhtYWRAYXJtb3VzaC5jYSJdfSwic2lnbl9pbl9wcm92aWRlciI6InBhc3N3b3JkIn19.FW2RaJ4OR5FhyKvsTgxTPJoRvPOyIYRwwOl6aqKIzFEdu1k6R48nBHrIJcKYc3HYNKX_czgFfboeTOQNO3Jb5B3sWDO81awn1xa4dySKOa24DUr71EkVdUlGgB38TjhLZiyweuMGg0e6pLu4OqSXu3MRg-91LzHS3hA2L7X-TOfhCS7zoLS7hAJi5X_NHmD5PIOiRwSqvzyQq7jd6HJ4r2ukiIsz8YKP4zKWNNwFPrpMLc_D0SzgE7-DXGe17B2NH2H2IhYpKCuY0iRSV6zXWqk5E3RET98VNuVFBUQDjRf9mlBnPEtqC0nZTNYDFU_qAMgk6G0XtGVM3IIanCBjWw", "type": "string" } ] diff --git a/backend/routes/users.py b/backend/routes/users.py index 9fb7775..17d3a0c 100644 --- a/backend/routes/users.py +++ b/backend/routes/users.py @@ -15,7 +15,7 @@ @carbon_auth.auth.login_required def get_user(user_id: str) -> Response: try: - query = {"_id": ObjectId(user_id)} + query = {"_id": ObjectId(user_id), "archived": False} item = CarbonTrackDB.users_coll.find_one(query) item = User.from_json(item).to_json() return jsonify({"user": item}) @@ -31,7 +31,7 @@ def get_top_users() -> Response: # Monthly _top_monthly_users = ( - CarbonTrackDB.users_coll.find().sort("monthly_score", -1).limit(count) + CarbonTrackDB.users_coll.find({"archived": False}).sort("monthly_score", -1).limit(count) ) top_monthly_users = [] rank = 1 @@ -96,7 +96,7 @@ def get_top_users() -> Response: @carbon_auth.auth.login_required def get_user_by_email(user_email: str) -> Response: try: - query = {"email": user_email} + query = {"email": user_email, "archived": False} item = CarbonTrackDB.users_coll.find_one(query) item = User.from_json(item).to_json() return jsonify({"user": item}) @@ -113,7 +113,7 @@ def get_current_user() -> Response: print(current_user) # Construct the query to find the user in MongoDB - query = {"uid": current_user["uid"]} + query = {"uid": current_user["uid"], "archived": False} # Fetch user data from MongoDB mongo_user = CarbonTrackDB.users_coll.find_one(query) @@ -160,11 +160,15 @@ def create_user() -> Response: @carbon_auth.auth.login_required def delete_user(user_id: str) -> Response: try: - query = {"_id": ObjectId(user_id)} + query = {"_id": ObjectId(user_id), "archived": False} item = CarbonTrackDB.users_coll.find_one(query) - item = User.from_json(item).to_json() - CarbonTrackDB.users_coll.delete_one(query) - return jsonify({"deleted user": item}) + item = User.from_json(item) + CarbonTrackDB.users_coll.update_one(query, { + '$set': { + 'archived': True + } + }) + return jsonify({"user": item}) except CarbonTrackError as e: abort(code=400, description=f"{e}") @@ -173,7 +177,7 @@ def delete_user(user_id: str) -> Response: @carbon_auth.auth.login_required def update_user(user_id: str) -> Response: try: - query = {"_id": ObjectId(user_id)} + query = {"_id": ObjectId(user_id), "archived": False} user = User.from_json(request.get_json()["user"]).to_json() del user["_id"] del user["email"] @@ -189,7 +193,7 @@ def update_user(user_id: str) -> Response: @carbon_auth.auth.login_required def update_user_email(uid: str) -> Response: try: - query = {"uid": uid} + query = {"uid": uid, "archived": False} new_email = request.get_json().get("email", "") current_user = carbon_auth.auth.current_user() @@ -212,7 +216,7 @@ def update_user_name(user_id: str) -> Response: try: new_name = request.get_json().get("newName", "") - query = {"uid": user_id} + query = {"uid": user_id, "archived": False} current_user = carbon_auth.auth.current_user() print(current_user) diff --git a/frontend/app.json b/frontend/app.json index 92ae6a5..3f6774e 100644 --- a/frontend/app.json +++ b/frontend/app.json @@ -2,15 +2,17 @@ "expo": { "plugins": [ [ - "expo-image-picker", + "expo-build-properties", { - "photosPermission": "The app accesses your photos to let you share them with your friends." + "ios": { + "useFrameworks": "static" + } } ] ], - "name": "CarbonTrack", + "name": "CarbonTrack for Individuals", "slug": "CarbonTrack", - "version": "1.0.0", + "version": "1.0.2", "orientation": "portrait", "icon": "./assets/icon.png", "userInterfaceStyle": "light", @@ -23,7 +25,8 @@ "**/*" ], "ios": { - "supportsTablet": true + "supportsTablet": true, + "bundleIdentifier": "club.usec.carbontrack" }, "android": { "adaptiveIcon": { @@ -31,7 +34,8 @@ }, "permissions": [ "android.permission.RECORD_AUDIO" - ] + ], + "package": "com.carbontrack.usec" }, "web": { "favicon": "./assets/favicon.png" diff --git a/frontend/assets/adaptive-icon.png b/frontend/assets/adaptive-icon.png index 03d6f6b..d1450d3 100644 Binary files a/frontend/assets/adaptive-icon.png and b/frontend/assets/adaptive-icon.png differ diff --git a/frontend/assets/icon.png b/frontend/assets/icon.png index a0b1526..d1450d3 100644 Binary files a/frontend/assets/icon.png and b/frontend/assets/icon.png differ diff --git a/frontend/eas.json b/frontend/eas.json new file mode 100644 index 0000000..e1c9ec4 --- /dev/null +++ b/frontend/eas.json @@ -0,0 +1,18 @@ +{ + "cli": { + "version": ">= 5.9.2" + }, + "build": { + "development": { + "developmentClient": true, + "distribution": "internal" + }, + "preview": { + "distribution": "internal" + }, + "production": {} + }, + "submit": { + "production": {} + } +} diff --git a/frontend/package.json b/frontend/package.json index d7f415d..f2e10d5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,7 +17,7 @@ "@react-native-community/slider": "^4.4.2", "@react-native-firebase/app": "^18.7.1", "@react-native-firebase/auth": "^18.7.1", - "@react-native-firebase/firestore": "^18.6.0", + "@react-native-firebase/firestore": "^18.7.1", "@react-native-firebase/storage": "^18.7.1", "@react-native-picker/picker": "^2.5.1", "@react-navigation/bottom-tabs": "^6.5.11", @@ -28,6 +28,7 @@ "bson-objectid": "^2.0.4", "events": "^3.3.0", "expo": "~49.0.12", + "expo-build-properties": "^0.8.3", "expo-cli": "6.3.10", "expo-font": "~11.4.0", "expo-image-picker": "~14.3.2", diff --git a/frontend/src/APIs/UsersAPI.ts b/frontend/src/APIs/UsersAPI.ts index f399a68..0460323 100644 --- a/frontend/src/APIs/UsersAPI.ts +++ b/frontend/src/APIs/UsersAPI.ts @@ -35,6 +35,16 @@ export const UsersAPI = { } }, + deleteUser: async (userID: ObjectId) => { + try { + const res = await FLASK_HTTPS.delete(routeName + '/user/' + userID.toString()); + return res.data.user as User; + } catch (error) { + console.error('Error fetching user from Flask BE: ', error); + return undefined; + } + }, + getTopUsers: async (count: number) => { try { const res = await FLASK_HTTPS.post(routeName + '/get_top_users', { diff --git a/frontend/src/components/appNavigation.tsx b/frontend/src/components/appNavigation.tsx index 737b986..00cdfa8 100644 --- a/frontend/src/components/appNavigation.tsx +++ b/frontend/src/components/appNavigation.tsx @@ -22,7 +22,7 @@ import DashBoardScreen from '../screens/dashboard'; import CommunityHub from '../screens/communityHub'; import FootprintDecomp from '../screens/footpringDecomp'; -import SettingsScreen from '../screens/settings'; +import SettingsScreen from '../screens/settings/settings'; import UpdatePasswordScreen from '../screens/settings/updatePassword'; import UpdateProfileScreen from '../screens/settings/updateProfile'; import UpdateHomeScreen from '../screens/settings/updateHomeScreen'; diff --git a/frontend/src/screens/Energy/energyHistory.tsx b/frontend/src/screens/Energy/energyHistory.tsx index 997fe00..5623214 100644 --- a/frontend/src/screens/Energy/energyHistory.tsx +++ b/frontend/src/screens/Energy/energyHistory.tsx @@ -35,7 +35,7 @@ export default function EnergyHistory(): JSX.Element { const [expandedStates, setExpandedStates] = useState(Array(100).fill(false)); const [monthlyData, setMonthlyData] = useState(); const [startDate] = useState(new Date(2023, 8, 1)); - const [endDate] = useState(new Date(2023, 11, 31)); + const [endDate] = useState(new Date(2024, 3, 30)); const navigation = useNavigation(); const [energyEntry, setEnergyEntry] = useState(); const [recommendationForToday, setRecommendationForToday] = useState(); diff --git a/frontend/src/screens/Food/foodHistory.tsx b/frontend/src/screens/Food/foodHistory.tsx index 765103c..66039e1 100644 --- a/frontend/src/screens/Food/foodHistory.tsx +++ b/frontend/src/screens/Food/foodHistory.tsx @@ -31,7 +31,7 @@ export default function FoodHistory(): JSX.Element { const [expandedStates, setExpandedStates] = useState(Array(100).fill(false)); const [monthlyData, setMonthlyData] = useState(); const [startDate] = useState(new Date(2023, 8, 1)); - const [endDate] = useState(new Date(2023, 11, 31)); + const [endDate] = useState(new Date(2024, 3, 30)); const navigation = useNavigation(); const [foodEntry, setFoodEntry] = useState(); const [recommendationForToday, setRecommendationForToday] = useState(); diff --git a/frontend/src/screens/Transportation/transportationHistory.tsx b/frontend/src/screens/Transportation/transportationHistory.tsx index 73aadd3..a808b34 100644 --- a/frontend/src/screens/Transportation/transportationHistory.tsx +++ b/frontend/src/screens/Transportation/transportationHistory.tsx @@ -34,7 +34,7 @@ export default function TransportationHistory(): JSX.Element { const [expandedStates, setExpandedStates] = useState(Array(100).fill(false)); const [monthlyData, setMonthlyData] = useState(); const [startDate] = useState(new Date(2023, 8, 1)); - const [endDate] = useState(new Date(2023, 11, 31)); + const [endDate] = useState(new Date(2024, 3, 30)); const navigation = useNavigation(); const [transportationEntry, setTransportationEntry] = useState(); const [recommendationForToday, setRecommendationForToday] = diff --git a/frontend/src/screens/settings.tsx b/frontend/src/screens/settings/settings.tsx similarity index 80% rename from frontend/src/screens/settings.tsx rename to frontend/src/screens/settings/settings.tsx index 2417cb4..bd1caa2 100644 --- a/frontend/src/screens/settings.tsx +++ b/frontend/src/screens/settings/settings.tsx @@ -1,15 +1,15 @@ import React, { useEffect, useState } from 'react'; import { View, Text, StyleSheet, TouchableOpacity} from 'react-native'; -import Colors from '../../assets/colorConstants'; +import Colors from '../../../assets/colorConstants'; import { useFonts } from 'expo-font'; -import {type RootStackParamList} from '../components/types'; +import {type RootStackParamList} from '../../components/types'; import type { StackNavigationProp } from '@react-navigation/stack'; import { useNavigation } from '@react-navigation/native'; import { Entypo,FontAwesome, Feather } from '@expo/vector-icons'; import { getAuth, onAuthStateChanged } from 'firebase/auth'; -import firebaseService from '../utilities/firebase'; -import { UsersAPI } from '../APIs/UsersAPI'; -import { type User } from '../models/User'; +import firebaseService from '../../utilities/firebase'; +import { UsersAPI } from '../../APIs/UsersAPI'; +import { type User } from '../../models/User'; export type StackNavigation = StackNavigationProp; export default function SettingsScreen(): JSX.Element { @@ -20,8 +20,8 @@ export default function SettingsScreen(): JSX.Element { const [loaded] = useFonts({ - Montserrat: require('../../assets/fonts/MontserratThinRegular.ttf'), - Josefin: require('../../assets/fonts/JosefinSansThinRegular.ttf'), + Montserrat: require('../../../assets/fonts/MontserratThinRegular.ttf'), + Josefin: require('../../../assets/fonts/JosefinSansThinRegular.ttf'), }); const auth = getAuth(); @@ -55,6 +55,21 @@ export default function SettingsScreen(): JSX.Element { } + const handleDeleteAccount =async ():Promise => { + try{ + if (user !== undefined || user != null){ + await UsersAPI.deleteUser(user._id); + console.log("User has been deleted!") + navigation.navigate('Home'); + } + } catch(error){ + console.error("Deleting Account Error:", error) + } + + } + + + if (!loaded) { return <>; @@ -84,10 +99,10 @@ export default function SettingsScreen(): JSX.Element { - + {void handleDeleteAccount()}}> - Accessibility - + Delete Account + {void handleLogOut()}}>