From e7897d4dbfc94965ee3fbdf6a439c5eb2c383d88 Mon Sep 17 00:00:00 2001 From: Dhruvil Patel <38077836+dhruvilp@users.noreply.github.com> Date: Sat, 16 Feb 2019 18:17:50 -0500 Subject: [PATCH 1/8] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index d9c26e9..4635deb 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,10 @@ This project is a mobile application for hackers, organizers, mentors, sponsors We had started using an inhouse hybrid mobile application to keep track of analytics to get a better idea of how certain aspects of the hackathon were running such as food consumption and optimization for checkin. This project expanded into a public native mobile application so hackers had easier access to their QR code as well as organizers with their scanners. Additional information of the hackathon were incorporated so that everyone would be able to stay up to date on events that are happeneing wherever they may be in the venue. +## Style Guide +Coming Soon... +We'll be using LINTER for Dart (https://github.com/dart-lang/linter) + ## Installation Guide ### For Architects From 8a19544b7e701353252e1f5c823abc0293a12690 Mon Sep 17 00:00:00 2001 From: mjrb Date: Mon, 18 Feb 2019 00:48:56 -0500 Subject: [PATCH 2/8] move models in their own folder and add more lcs functionality --- lib/hackru_service.dart | 76 +++++++++++++++++++++++++++++-------- lib/models.dart | 84 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 15 deletions(-) create mode 100644 lib/models.dart diff --git a/lib/hackru_service.dart b/lib/hackru_service.dart index 132299a..69ecac4 100644 --- a/lib/hackru_service.dart +++ b/lib/hackru_service.dart @@ -1,7 +1,9 @@ import 'package:http/http.dart' as http; import 'dart:convert'; +import 'package:HackRU/models.dart'; -const _lcsUrl = 'https://7c5l6v7ip3.execute-api.us-west-2.amazonaws.com/lcs-test'; +const _lcsUrl = 'https://7c5l6v7ip3.execute-api.us-west-2.amazonaws.com/lcs-test'; // prod +//const _lcsUrl = 'https://7c5l6v7ip3.execute-api.us-west-2.amazonaws.com/lcs-test'; // test const _miscUrl = 'http://hackru-misc.s3-website-us-west-2.amazonaws.com'; var client = new http.Client(); @@ -10,13 +12,24 @@ Future getMisc(String endpoint) { return client.get(_miscUrl + endpoint); } -Future getLcs(String endpoint) { - return client.get(_lcsUrl + endpoint); +String toParam(LcsCredential credential) { + var param = ""; + if (credential != null) { + if (credential.isExpired()) { + throw CredentialExpired(); + } + param = "?token="+credential.token; + } + return param; } -Future postLcs(String endpoint, dynamic body) { +Future getLcs(String endpoint, [LcsCredential credential]) { + return client.get(_lcsUrl + endpoint + toParam(credential)); +} + +Future postLcs(String endpoint, dynamic body, [LcsCredential credential]) { var encodedBody = jsonEncode(body); - return client.post(_lcsUrl + endpoint, + return client.post(_lcsUrl + endpoint + toParam(credential), headers: {"content-Type": "applicationi/json"}, body: encodedBody ); @@ -28,17 +41,14 @@ Future> sitemap() async { return await response.body.split("\n"); } -class HelpResource { - final String name; - final String description; - final String url; - - HelpResource(this.name, this.description, this.url); +Future> events() async { + var response = await getMisc("/events.txt"); + return await response.body.split("\n"); +} - HelpResource.fromJson(Map json) - : name = json['name'], - description = json['desc'], - url = json['url']; +Future labelUrl() async { + var response = await getMisc("/label-url.txt"); + return response.body; } Future> helpResources() async { @@ -50,3 +60,39 @@ Future> helpResources() async { } // lcs functions + +Future login(String email, String password) async { + var result = await postLcs("/authorize", { + "email": email, + "password": password, + }); + var body = jsonDecode(result.body); + // quirk with lcs where it puts the actual result as a string + // inside the normal body + if (body["statusCode"] == 200) { + var auth = jsonDecode(body["body"])["auth"]; + return LcsCredential.fromJson(auth); + } else if (body["statusCode"] == 403) { + throw LcsLoginFailed(); + } else { + throw LcsError; + } +} +// not yet working + +Future getUser(LcsCredential credential, [String targetEmail]) async { + if (targetEmail == null) { + targetEmail = credential.email; + } + var result = await postLcs("/read", { + "email": credential.email, + "token": credential.token, + "query": {"\$match":{"email": targetEmail}} + },credential); + if (result.statusCode == 200) { + var firstUser = jsonDecode(result.body)["body"][0]; + return User.fromJson(firstUser); + } else { + throw LcsError(); + } +} diff --git a/lib/models.dart b/lib/models.dart new file mode 100644 index 0000000..3e3b995 --- /dev/null +++ b/lib/models.dart @@ -0,0 +1,84 @@ +class LcsCredential { + final String email; + final String token; + final DateTime expiration; + + LcsCredential(this.email, this.token, this.expiration); + + @override + String toString() { + return "LcsCredentail{email: ${this.email}, " + + "token: ${this.token}, " + + "expiration: ${this.expiration}}"; + } + + bool isExpired() { + return this.expiration.isBefore(DateTime.now()); + } + + LcsCredential.fromJson(Map json) + : email = json["email"], + token = json["token"], + expiration = DateTime.parse(json["valid_until"]); +} + +class HelpResource { + final String name; + final String description; + final String url; + + HelpResource(this.name, this.description, this.url); + + @override + String toString() { + return "HelpResource{name: ${this.name}, " + + "description: ${this.description}, " + + "url: ${this.url}}"; + } + + HelpResource.fromJson(Map json) + : name = json["name"], + description = json['desc'], + url = json["url"]; +} + +class User { + final String name; + final String email; + final Map dayOf; // this should always be a bool really + + User(this.name, this.email, this.dayOf); + + @override + String toString() { + return "User{name: ${this.name}, " + + "email: ${this.email}, " + + "dayOf: ${this.dayOf}"; + } + + // check if a hacker has already attended an event + bool alreadyDid(String event) { + if (!this.dayOf.containsKey(event)) { + return false; + } else { + return this.dayOf[event]; + } + } + + User.fromJson(Map json) + : name = (json["first_name"] ?? "") + " " + (json["last_name"] ?? ""), + email = json["email"], + dayOf = json["day_of"]; +} + +class LcsError implements Exception { + String errorMessage() => "There was an issue trying to use lcs"; +} + +class LcsLoginFailed implements Exception { + String errorMessage() => "bad username or password"; +} + +class CredentialExpired implements Exception { + String errorMessage() => "credential expired user must log in"; +} From 74929f20d050416263ef6ddd4d48413c576735b9 Mon Sep 17 00:00:00 2001 From: mjrb Date: Mon, 18 Feb 2019 00:55:07 -0500 Subject: [PATCH 3/8] add some tests for lcs functions --- lib/test.dart | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 lib/test.dart diff --git a/lib/test.dart b/lib/test.dart new file mode 100644 index 0000000..c15ac38 --- /dev/null +++ b/lib/test.dart @@ -0,0 +1,77 @@ +import 'package:HackRU/hackru_service.dart'; +import 'package:HackRU/models.dart'; +import 'dart:io' show Platform; + +var env = Platform.environment; + +void testHelpResources() async { + var result = await helpResources(); + print("test helpResources"); + result.forEach((resource) { + print(resource); + }); +} + +void testSitemap() async { + var result = await sitemap(); + print("test sitemap"); + print(result); +} + +void testEvents() async { + var result = await events(); + print("test events"); + print(result); +} + +void testLabelUrl() async { + var result = await labelUrl(); + print("test label-url"); + print(result); +} + +void testExpired() { + print("test catch expired credential"); + var l = LcsCredential("test", "account", DateTime.now()); + assert(l.isExpired()); +} + +void testLogin() async { + try { + await login("bogus", "login"); + print("failed to catch bad login"); + } on LcsLoginFailed catch (e) { + print("caught failed login"); + } + var l = await login(env["LCS_USER"], env["LCS_PASSWORD"]); + assert(!l.isExpired()); +} + +void testPostLcsExpired() async { + print("test for postLcs to catch expired credentials"); + var cred = LcsCredential("Bogus", "Cred", DateTime.now()); + try { + await postLcs("/read", {}, cred); + assert(false); // should have thrown CredentialExpired + } on CredentialExpired catch(e) { + print("succesfully caught expired credential"); + } +} + +void testGetUser() async { + var cred = await login(env["LCS_USER"], env["LCS_PASSWORD"]); + var user = await getUser(cred); + print("test get user"); + print(user); +} + +void main() async { + testHelpResources(); + testSitemap(); + testEvents(); + testLabelUrl(); + testExpired(); + testLogin(); + testPostLcsExpired(); + testGetUser(); +} From 275f762b4633b781711dd0dfd87112af6ba401c5 Mon Sep 17 00:00:00 2001 From: mjrb Date: Mon, 18 Feb 2019 00:55:24 -0500 Subject: [PATCH 4/8] models moved --- lib/screens/help.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/screens/help.dart b/lib/screens/help.dart index 9088e4d..2dea7da 100644 --- a/lib/screens/help.dart +++ b/lib/screens/help.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:HackRU/colors.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:HackRU/hackru_service.dart'; +import 'package:HackRU/models.dart'; class HelpButton extends StatelessWidget { HelpButton({@required this.resource}); From ed2e4064693cfa5785963056d71974640f6d185b Mon Sep 17 00:00:00 2001 From: mjrb Date: Wed, 20 Feb 2019 01:38:35 -0500 Subject: [PATCH 5/8] test instructions and update todo --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4635deb..8845997 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,13 @@ To learn about Flutter App Development: - [Online documentation: (https://flutter.io/docs], which offers tutorials, samples, guidance on mobile development, and a full API reference. +### Running tests +1. also have command line dart installed +2. setup test users and use the test endpoint in hackru-service +3. `export LCS_USER=""` for LCS_USER, LCS_PASSWORD, LCS_USER2, LCS_PASSWORD2 + - lcs user should have the director role +4. `cd lib && dart test.dart` + ### For Users Coming Soon... @@ -53,11 +60,10 @@ List of features goes here... ### Needs To Be Done 1) Write a String Parser for Announcement Messages from Slack (we need to remove emojies and user mentions) -2) QR Code Scanner UI is working, but need to connect with BackEnd (LCS) -2) QR Code Gen UI is working, but need to connect with BackEnd (LCS) -3) LogIn/SignUp UI is working but need to connect with BackEnd (LCS) +2) QR Code Scanner UI is working, but need to connect with BackEnd (LCS) (Code Exists) +2) QR Code Gen UI is working, but need to connect with BackEnd (LCS) (Code Exists) +3) LogIn/SignUp UI is working but need to connect with BackEnd (LCS) (Code Exists) 4) "About Page" (which will include Flutter App Dev Team Members, HackRU Rnd Reference, and about the app) -5) "Help/Tool Page" (hoping to add buttons which will redirect to inApp webview for "HelpQ", "HackRU Website", "Team Builder", and whatever hackers need in one click) ## Links to Further docs TBA From 15adf1bd62bf437f523cb8d2015e7e72dfa71ad8 Mon Sep 17 00:00:00 2001 From: mjrb Date: Wed, 20 Feb 2019 01:40:17 -0500 Subject: [PATCH 6/8] add function to update dayof --- lib/hackru_service.dart | 51 +++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/lib/hackru_service.dart b/lib/hackru_service.dart index 69ecac4..003a1f0 100644 --- a/lib/hackru_service.dart +++ b/lib/hackru_service.dart @@ -27,12 +27,20 @@ Future getLcs(String endpoint, [LcsCredential credential]) { return client.get(_lcsUrl + endpoint + toParam(credential)); } -Future postLcs(String endpoint, dynamic body, [LcsCredential credential]) { +Future postLcs(String endpoint, dynamic body, [LcsCredential credential]) async { var encodedBody = jsonEncode(body); - return client.post(_lcsUrl + endpoint + toParam(credential), + var result = await client.post(_lcsUrl + endpoint + toParam(credential), headers: {"content-Type": "applicationi/json"}, body: encodedBody ); + var decoded = jsonDecode(result.body); + if(decoded["statusCode"] != result.statusCode) { + print(decoded); + print("!!!!!!!!!!!!WARNING"); + print("body and container status code dissagree actual ${result.statusCode} body: ${decoded['statusCode']}"); + print(endpoint); + } + return result; } // misc functions @@ -61,6 +69,7 @@ Future> helpResources() async { // lcs functions +// /authorize can give wrong status codes Future login(String email, String password) async { var result = await postLcs("/authorize", { "email": email, @@ -75,10 +84,9 @@ Future login(String email, String password) async { } else if (body["statusCode"] == 403) { throw LcsLoginFailed(); } else { - throw LcsError; + throw LcsError(result); } } -// not yet working Future getUser(LcsCredential credential, [String targetEmail]) async { if (targetEmail == null) { @@ -87,12 +95,37 @@ Future getUser(LcsCredential credential, [String targetEmail]) async { var result = await postLcs("/read", { "email": credential.email, "token": credential.token, - "query": {"\$match":{"email": targetEmail}} - },credential); + "query": {"email": targetEmail} + }, credential); if (result.statusCode == 200) { - var firstUser = jsonDecode(result.body)["body"][0]; - return User.fromJson(firstUser); + var users = jsonDecode(result.body)["body"]; + if (users.length < 1) { + throw NoSuchUser(); + } + return User.fromJson(users[0]); } else { - throw LcsError(); + throw LcsError(result); + } +} + +// /update can give wrong status codes +// check if the user credential belongs to is role.director first. or else it will break :( +void updateUserDayOf(LcsCredential credential, User user, String event) async { + print(event); + var result = await postLcs("/update", { + "updates": {"\$set":{"day_of.$event": true}}, + "user_email": user.email, + "auth_email": credential.email, + "auth": credential.token, + }, credential); + + var decoded = jsonDecode(result.body); + if (decoded["statusCode"] == 400) { + throw UpdateError(decoded["body"]); + } else if (decoded["statusCode"] == 403) { + // BROKEN BECAUSE LCS + throw PermissionError(); + } else if (decoded["statusCode"] != 200){ + throw LcsError(result); } } From de15160599241057b96a9a8de80a63dc39550866 Mon Sep 17 00:00:00 2001 From: mjrb Date: Wed, 20 Feb 2019 01:41:22 -0500 Subject: [PATCH 7/8] more errors, beter generic LcsError, have User also grab store roles --- lib/models.dart | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/lib/models.dart b/lib/models.dart index 3e3b995..1eb92ad 100644 --- a/lib/models.dart +++ b/lib/models.dart @@ -1,3 +1,6 @@ +import 'package:http/http.dart' as http; +import 'dart:convert'; + class LcsCredential { final String email; final String token; @@ -45,14 +48,16 @@ class HelpResource { class User { final String name; final String email; + final Map role; // role.director, admin, organizer final Map dayOf; // this should always be a bool really - User(this.name, this.email, this.dayOf); + User(this.name, this.email, this.dayOf, this.role); @override String toString() { return "User{name: ${this.name}, " + "email: ${this.email}, " + + "role: ${this.role}, " + "dayOf: ${this.dayOf}"; } @@ -68,17 +73,50 @@ class User { User.fromJson(Map json) : name = (json["first_name"] ?? "") + " " + (json["last_name"] ?? ""), email = json["email"], - dayOf = json["day_of"]; + dayOf = json["day_of"], + role = json["role"]; } class LcsError implements Exception { - String errorMessage() => "There was an issue trying to use lcs"; + String lcsError; + int code; + LcsError(http.Response res) { + this.code = res.statusCode; + if (res.statusCode >= 500) { + this.lcsError = "internal error with lcs"; + } else { + var body = jsonDecode(res.body); + this.code = body["statusCode"]; + this.lcsError = body["body"]; + } + } + String errorMessage() => "LCS error $code: $lcsError"; + String toString() => errorMessage(); } class LcsLoginFailed implements Exception { String errorMessage() => "bad username or password"; + String toString() => errorMessage(); } class CredentialExpired implements Exception { String errorMessage() => "credential expired user must log in"; + String toString() => errorMessage(); +} + +class NoSuchUser implements Exception { + String errorMessage() => "no user with that email"; + String toString() => errorMessage(); +} + +class PermissionError implements Exception { + String errorMessage() => "you don't have permission to do that"; + String toString() => errorMessage(); +} + +class UpdateError implements Exception { + final String lcsMessage; + UpdateError(this.lcsMessage); + String errorMessage() => "Failed to update user: $lcsMessage"; + String toString() => errorMessage(); } From f80f6c31caa44b3c3a12f756838b901351394a6d Mon Sep 17 00:00:00 2001 From: mjrb Date: Wed, 20 Feb 2019 01:42:15 -0500 Subject: [PATCH 8/8] test updating dayof and checking for nonexistant user --- lib/test.dart | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/lib/test.dart b/lib/test.dart index c15ac38..0324d03 100644 --- a/lib/test.dart +++ b/lib/test.dart @@ -64,6 +64,39 @@ void testGetUser() async { print("test get user"); print(user); } +void testOtherUser() async { + var cred = await login(env["LCS_USER"], env["LCS_PASSWORD"]); + var user = await getUser(cred, "test1@regist.er"); + try { + var baduser = await getUser(cred, "fail@email.com"); + assert(false); + } on NoSuchUser catch(error) { + print("successfuly caught attempt to get nonexistent user"); + } + print("test get a different user"); + print(user); +} + +void testUpdateDayOf() async { + var cred = await login(env["LCS_USER"], env["LCS_PASSWORD"]); + var user = await getUser(cred, env["LCS_USER2"]); + await updateUserDayOf(cred, user, "fake_event${DateTime.now().millisecondsSinceEpoch}"); + var user2 = await getUser(cred, env["LCS_USER2"]); + print("test update user day_of"); + print(user); + print(user2); +} +/* +// !%$#@*&!!!! +void testUpdateDayOfPerm() async { + var cred = await login(env["LCS_USER2"], env["LCS_PASSWORD2"]); + var user = await getUser(cred, "LCS_USER"); + await updateUserDayOf(cred, user, "fake_event${DateTime.now().millisecondsSinceEpoch}"); + var user2 = await getUser(cred, "LCS_USER"); + print("test update user day_of"); + print(user); + print(user2); +}*/ void main() async { testHelpResources(); @@ -74,4 +107,6 @@ void main() async { testLogin(); testPostLcsExpired(); testGetUser(); + testOtherUser(); + testUpdateDayOf(); }