Skip to content
This repository has been archived by the owner on Feb 5, 2024. It is now read-only.

Commit

Permalink
Merge pull request #3 from HackRU/moar-lcs
Browse files Browse the repository at this point in the history
Moar lcs
  • Loading branch information
dhruvilp committed Feb 20, 2019
2 parents 1dc1d09 + f80f6c3 commit b179480
Show file tree
Hide file tree
Showing 5 changed files with 343 additions and 19 deletions.
18 changes: 14 additions & 4 deletions README.md
Expand Up @@ -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
Expand All @@ -33,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="<username>"` 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...
Expand All @@ -49,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
Expand Down
109 changes: 94 additions & 15 deletions 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();
Expand All @@ -10,16 +12,35 @@ Future<http.Response> getMisc(String endpoint) {
return client.get(_miscUrl + endpoint);
}

Future<http.Response> 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<http.Response> postLcs(String endpoint, dynamic body) {
Future<http.Response> getLcs(String endpoint, [LcsCredential credential]) {
return client.get(_lcsUrl + endpoint + toParam(credential));
}

Future<http.Response> postLcs(String endpoint, dynamic body, [LcsCredential credential]) async {
var encodedBody = jsonEncode(body);
return client.post(_lcsUrl + endpoint,
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
Expand All @@ -28,17 +49,14 @@ Future<List<String>> 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<List<String>> events() async {
var response = await getMisc("/events.txt");
return await response.body.split("\n");
}

HelpResource.fromJson(Map<String, dynamic> json)
: name = json['name'],
description = json['desc'],
url = json['url'];
Future<String> labelUrl() async {
var response = await getMisc("/label-url.txt");
return response.body;
}

Future<List<HelpResource>> helpResources() async {
Expand All @@ -50,3 +68,64 @@ Future<List<HelpResource>> helpResources() async {
}

// lcs functions

// /authorize can give wrong status codes
Future<LcsCredential> 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(result);
}
}

Future<User> getUser(LcsCredential credential, [String targetEmail]) async {
if (targetEmail == null) {
targetEmail = credential.email;
}
var result = await postLcs("/read", {
"email": credential.email,
"token": credential.token,
"query": {"email": targetEmail}
}, credential);
if (result.statusCode == 200) {
var users = jsonDecode(result.body)["body"];
if (users.length < 1) {
throw NoSuchUser();
}
return User.fromJson(users[0]);
} else {
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);
}
}
122 changes: 122 additions & 0 deletions lib/models.dart
@@ -0,0 +1,122 @@
import 'package:http/http.dart' as http;
import 'dart:convert';

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<String, dynamic> 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<String, dynamic> json)
: name = json["name"],
description = json['desc'],
url = json["url"];
}

class User {
final String name;
final String email;
final Map<String, dynamic> role; // role.director, admin, organizer
final Map<String, dynamic> dayOf; // this should always be a bool really

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}";
}

// 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<String, dynamic> json)
: name = (json["first_name"] ?? "") + " " + (json["last_name"] ?? ""),
email = json["email"],
dayOf = json["day_of"],
role = json["role"];
}

class LcsError implements Exception {
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();
}
1 change: 1 addition & 0 deletions lib/screens/help.dart
Expand Up @@ -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});
Expand Down

0 comments on commit b179480

Please sign in to comment.