diff --git a/app_backend/app/routers/user.py b/app_backend/app/routers/user.py index 2c8b632..acc3ea8 100644 --- a/app_backend/app/routers/user.py +++ b/app_backend/app/routers/user.py @@ -5,6 +5,7 @@ import json from bson import BSON from bson import json_util, ObjectId +import bcrypt from app.auth_handler import signJWT from database import db @@ -35,20 +36,34 @@ async def login(login: UserLogin, resp: Response): email = login.email password = login.password - user = { - "email": email, - "password": password - } + # get user with email + user = db.get_user_by_email(email, display_password=True) - db_user: dict = db.get_user(user) - - if db_user is None: + # check if user exists + if user is None: + resp.status_code = status.HTTP_400_BAD_REQUEST + return {"err": "Invalid email or password."} + + # check if password is correct + try: + if user['password'] != password and not bcrypt.checkpw(password.encode('utf-8'), user['password']): + resp.status_code = status.HTTP_400_BAD_REQUEST + return {"err": "Invalid email or password."} + except TypeError: resp.status_code = status.HTTP_400_BAD_REQUEST - return {"err": "This user does not exist. Please try different credentials."}, {}, None + return {"err": "Invalid email or password."} - db_user["_id"] = str(db_user['_id']) + # if db_user is None: + # resp.status_code = status.HTTP_400_BAD_REQUEST + # return {"err": "This user does not exist. Please try different credentials."}, {}, None - return {"msg": "Successfully logged in"}, signJWT(db_user['_id'], email), json.dumps(db_user, sort_keys=True, indent=4, default=json_util.default) + user["_id"] = str(user['_id']) + + # drop password from user + user.pop("password") + + return {"msg": "Successfully logged in"}, signJWT(user['_id'], email), \ + json.dumps(user, sort_keys=True, indent=4, default=json_util.default) """ register implements the /register/ route @@ -91,11 +106,14 @@ async def register(login: UserRegister, resp: Response): resp.status_code = status.HTTP_400_BAD_REQUEST return {"err": "Invalid password. It must be 8 to 20 characters and have at least one upper case letter, one lower case letter, and one digit."} + # hash the password + hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()) + # adds user to the database new_user = { "name": name, "email": email, - "password": password + "password": hashed_password } msg = db.save_user_in_db(new_user) diff --git a/app_backend/database.py b/app_backend/database.py index 5d81e2c..14cf5a4 100644 --- a/app_backend/database.py +++ b/app_backend/database.py @@ -59,10 +59,12 @@ def get_user_by_uuid(self, uuid): users = self.db["users"] return users.find_one({"_id": ObjectId(uuid)}, {"password": 0}) - def get_user_by_email(self, email): + def get_user_by_email(self, email, display_password=False): users = self.db["users"] - return users.find_one({'email': email}, {"password": 0}) - + if display_password: + return users.find_one({"email": email}) + else: + return users.find_one({'email': email}, {"password": 0}) def get_user(self, login_info: dict): users = self.db["users"] diff --git a/app_backend/requirements.txt b/app_backend/requirements.txt index d91a11b..6d6a7bc 100644 --- a/app_backend/requirements.txt +++ b/app_backend/requirements.txt @@ -34,3 +34,4 @@ uvicorn==0.15.0 wrapt==1.12.1 firebase_admin pyjwt +bcrypt \ No newline at end of file diff --git a/app_backend/tests/user_test.py b/app_backend/tests/user_test.py index 8c27272..a12d5d2 100644 --- a/app_backend/tests/user_test.py +++ b/app_backend/tests/user_test.py @@ -26,7 +26,8 @@ def to_json(self): for test_case in test_cases: response = client.post("user/login", json=test_case.to_json()) - msg, _, _ = response.json() + msg = response.json() + print(msg) assert response.status_code == test_case.expects_code assert ("err" in msg) == test_case.expects_err diff --git a/quack_app/ios/Flutter/AppFrameworkInfo.plist b/quack_app/ios/Flutter/AppFrameworkInfo.plist index 8d4492f..658d8c4 100644 --- a/quack_app/ios/Flutter/AppFrameworkInfo.plist +++ b/quack_app/ios/Flutter/AppFrameworkInfo.plist @@ -2,25 +2,25 @@ - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 9.0 + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 diff --git a/quack_app/ios/Runner.xcodeproj/project.pbxproj b/quack_app/ios/Runner.xcodeproj/project.pbxproj index 1659361..adf4e25 100644 --- a/quack_app/ios/Runner.xcodeproj/project.pbxproj +++ b/quack_app/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ @@ -121,7 +121,6 @@ 5230E246B24F0BE2311519A2 /* Pods-Runner.release.xcconfig */, 0131A6EFB3849AFCEB303739 /* Pods-Runner.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -156,7 +155,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -322,6 +321,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -340,7 +340,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -353,13 +353,17 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = quack_icon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + CURRENT_PROJECT_VERSION = 133; + DEVELOPMENT_TEAM = HWH6G9P2V2; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.example.quackApp; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = works.dd.quack; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -390,6 +394,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -414,7 +419,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -445,6 +450,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -463,11 +469,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -477,13 +484,17 @@ isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = quack_icon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + CURRENT_PROJECT_VERSION = 133; + DEVELOPMENT_TEAM = HWH6G9P2V2; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.example.quackApp; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = works.dd.quack; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -496,13 +507,17 @@ isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_APPICON_NAME = quack_icon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + CURRENT_PROJECT_VERSION = 133; + DEVELOPMENT_TEAM = HWH6G9P2V2; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.example.quackApp; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = works.dd.quack; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/quack_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/quack_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140c..c87d15a 100644 --- a/quack_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/quack_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - - - + + - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - quack_app - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - UIStatusBarHidden - - + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Quack + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + quack_app + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + diff --git a/quack_app/lib/components/station_list.dart b/quack_app/lib/components/station_list.dart index bc24e06..1741b6f 100644 --- a/quack_app/lib/components/station_list.dart +++ b/quack_app/lib/components/station_list.dart @@ -80,7 +80,9 @@ class _StationListState extends State { .menuFilteredBy((item) => mainFilter(item) && widget.filter(item)); // Set all FoodItems that has name in favorites to be favorited + // debugPrint(favorites.toString()); for (FoodItem item in stationCurrentItems) { + // debugPrint(item.getName()); item.setIsFavorite(favorites.contains(item.getName())); } diff --git a/quack_app/lib/core/food/food_item.dart b/quack_app/lib/core/food/food_item.dart index 7b24630..3b00474 100644 --- a/quack_app/lib/core/food/food_item.dart +++ b/quack_app/lib/core/food/food_item.dart @@ -31,6 +31,7 @@ class FoodItem { Future toggleFavorite() async { await User().userData.toggleFavorite(getName(), !_isFavorite).then((response) => { if (response) { + this._isFavorite = !this._isFavorite } }); diff --git a/quack_app/lib/core/user/user_data.dart b/quack_app/lib/core/user/user_data.dart index 78714ad..356fd88 100644 --- a/quack_app/lib/core/user/user_data.dart +++ b/quack_app/lib/core/user/user_data.dart @@ -47,9 +47,8 @@ class UserData { _friends = await loadFriends(); // If the type of data["favorites"] is List, then assign it to _favorites // Otherwise, if it is List, then convert it to List - if (data["favorites"] is List) { - _favorites = data["favorites"]; - } + // debugPrint(data["favorites"].runtimeType.toString()); + _favorites = List.from(data["favorites"]); return Future.value(true); } @@ -82,6 +81,11 @@ class UserData { // If the response code is 200, return true if (response.statusCode == 200) { + if (!_favorites.contains(name) && state) { + _favorites.add(name); + } else if (_favorites.contains(name) && !state) { + _favorites.remove(name); + } return Future.value(true); } else { return Future.value(false); diff --git a/quack_app/pubspec.yaml b/quack_app/pubspec.yaml index c1444b1..d44f82b 100644 --- a/quack_app/pubspec.yaml +++ b/quack_app/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+1 +version: 1.0.0+133 environment: sdk: ">=2.12.0 <3.0.0"