From 052052d76bdef1b67c20c6f047a726212fa3230b Mon Sep 17 00:00:00 2001 From: Gnarwhal Date: Sun, 7 Feb 2021 22:50:48 -0500 Subject: [PATCH] Updated more UI. Enhanced login capabilities. Started work on querying data. --- .../achievements/controllers/Controller.java | 65 -------- .../controllers/DataController.java | 11 ++ .../controllers/LoginController.java | 49 ++++-- .../main/java/achievements/data/APError.java | 36 ++++ .../java/achievements/data/Achievement.java | 157 ++++++++++++++++++ .../java/achievements/data/Achievements.java | 64 ------- .../src/main/java/achievements/data/Game.java | 47 ++++++ .../main/java/achievements/data/Games.java | 57 ------- .../java/achievements/data/InternalError.java | 21 --- .../main/java/achievements/data/Profile.java | 73 ++++++++ .../main/java/achievements/data/Session.java | 43 +++++ .../data/query/NumericFilter.java | 32 ++++ .../achievements/data/query/StringFilter.java | 21 +++ .../achievements/misc/SessionManager.java | 12 +- .../services/AuthenticationService.java | 23 ++- .../achievements/services/DataService.java | 40 +++++ .../java/achievements/services/DbService.java | 92 ---------- frontend/webpage/login.html | 48 +++--- frontend/webpage/scripts/index.js | 65 ++++++-- frontend/webpage/scripts/login.js | 73 ++++---- frontend/webpage/styles/common.css | 26 ++- frontend/webpage/styles/index.css | 15 +- frontend/webpage/styles/login.css | 35 +++- .../templates/achievements_page.html.template | 6 +- .../templates/games_page.html.template | 2 +- .../templates/profile_page.html.template | 7 +- sql/CreateTables.sql | 6 +- sql/{CreateUserSP.sql => CreateUser.sql} | Bin 976 -> 1232 bytes sql/GetUserLogin.sql | 4 +- 29 files changed, 706 insertions(+), 424 deletions(-) delete mode 100644 backend/src/main/java/achievements/controllers/Controller.java create mode 100644 backend/src/main/java/achievements/controllers/DataController.java create mode 100644 backend/src/main/java/achievements/data/APError.java create mode 100644 backend/src/main/java/achievements/data/Achievement.java delete mode 100644 backend/src/main/java/achievements/data/Achievements.java create mode 100644 backend/src/main/java/achievements/data/Game.java delete mode 100644 backend/src/main/java/achievements/data/Games.java delete mode 100644 backend/src/main/java/achievements/data/InternalError.java create mode 100644 backend/src/main/java/achievements/data/Profile.java create mode 100644 backend/src/main/java/achievements/data/Session.java create mode 100644 backend/src/main/java/achievements/data/query/NumericFilter.java create mode 100644 backend/src/main/java/achievements/data/query/StringFilter.java create mode 100644 backend/src/main/java/achievements/services/DataService.java delete mode 100644 backend/src/main/java/achievements/services/DbService.java rename sql/{CreateUserSP.sql => CreateUser.sql} (76%) diff --git a/backend/src/main/java/achievements/controllers/Controller.java b/backend/src/main/java/achievements/controllers/Controller.java deleted file mode 100644 index 7595ba5..0000000 --- a/backend/src/main/java/achievements/controllers/Controller.java +++ /dev/null @@ -1,65 +0,0 @@ -package achievements.controllers; - -import achievements.data.Achievements; -import achievements.data.Games; -import achievements.data.InternalError; -import achievements.services.DbService; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import static org.springframework.web.bind.annotation.RequestMethod.GET; - -@RestController -public class Controller { - - @Autowired - private DbService db; - - public Controller() {} - - @RequestMapping(value = { "/achievements", "/achievements/{Name}" }, method = GET, produces = "application/json") - public ResponseEntity fetchAchievements(@PathVariable(value = "Name", required = false) String getName) { - var achievements = (Achievements) null; - if (getName == null) { - achievements = db.getAchievements("%"); - } else { - achievements = db.getAchievements(getName); - } - var mapper = new ObjectMapper(); - try { - if (achievements == null) { - return new ResponseEntity(mapper.writeValueAsString(new InternalError("Could not get achievements from database")), HttpStatus.INTERNAL_SERVER_ERROR); - } else { - return new ResponseEntity(mapper.writeValueAsString(achievements), HttpStatus.OK); - } - } catch (JsonProcessingException e) { - e.printStackTrace(); - return new ResponseEntity("{}", HttpStatus.INTERNAL_SERVER_ERROR); - } - } - - @RequestMapping(value = { "/games", "/games/{Name}" }, method = GET, produces = "application/json") - public ResponseEntity fetchGames(@PathVariable(value = "Name", required = false) String getName) { - var games = (Games) null; - if (getName == null) { - games = db.getGames("%"); - } else { - games = db.getGames(getName); - } - var mapper = new ObjectMapper(); - try { - if (games == null) { - return new ResponseEntity(mapper.writeValueAsString(new InternalError("Could not get games from database")), HttpStatus.INTERNAL_SERVER_ERROR); - } else { - return new ResponseEntity(mapper.writeValueAsString(games), HttpStatus.OK); - } - } catch (JsonProcessingException e) { - e.printStackTrace(); - return new ResponseEntity("{}", HttpStatus.INTERNAL_SERVER_ERROR); - } - } -} diff --git a/backend/src/main/java/achievements/controllers/DataController.java b/backend/src/main/java/achievements/controllers/DataController.java new file mode 100644 index 0000000..e518812 --- /dev/null +++ b/backend/src/main/java/achievements/controllers/DataController.java @@ -0,0 +1,11 @@ +package achievements.controllers; + +import achievements.data.Profile; +import org.springframework.web.bind.annotation.RequestBody; + +public class DataController { + + public void getProfile(@RequestBody Profile.Query query) { + + } +} diff --git a/backend/src/main/java/achievements/controllers/LoginController.java b/backend/src/main/java/achievements/controllers/LoginController.java index ff52ce6..01eceb5 100644 --- a/backend/src/main/java/achievements/controllers/LoginController.java +++ b/backend/src/main/java/achievements/controllers/LoginController.java @@ -1,5 +1,7 @@ package achievements.controllers; +import achievements.data.APError; +import achievements.data.Session; import achievements.data.User; import achievements.services.AuthenticationService; import org.springframework.beans.factory.annotation.Autowired; @@ -7,7 +9,6 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import static org.springframework.web.bind.annotation.RequestMethod.POST; @@ -20,8 +21,8 @@ public class LoginController { /** * Acceptable codes - * 0 => Success - * 1 => Email already registered + * 0 => Success + * 1 => Email already registered * * -1 => Unknown error */ @@ -29,11 +30,17 @@ public class LoginController { public ResponseEntity createUser(@RequestBody User user) { var response = authService.createUser(user); if (response.status == 0) { - return ResponseEntity.ok("{ \"key\": \"" + authService.session().generate(response.id) + "\", \"id\": " + response.id + " }"); + return ResponseEntity.ok( + new Session( + authService.session().generate(response.id), + response.id, + response.hue + ) + ); } else if (response.status > 0) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("{ \"code\": " + response.status + " }"); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new APError(response.status)); } else { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{ \"code\": " + response.status + " }"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new APError(response.status)); } } @@ -43,24 +50,34 @@ public class LoginController { * User should only ever recieve -1, 0, or 1. The specific authentication error should be hidden. * * Acceptable codes - * 0 => Success - * 1 => Unregistered email address - * 2 => Incorrect password + * 0 => Success + * 1 => Unregistered email address + * 2 => Incorrect password * * -1 => Unknown error */ @RequestMapping(value = "/login", method = POST, consumes = "application/json", produces = "application/json") - public ResponseEntity login(@RequestParam(value = "guest", required = false) boolean guest, @RequestBody User user) { - var response = guest ? - authService.GUEST : - authService.login(user); + public ResponseEntity login(@RequestBody User user) { + var response = authService.login(user); if (response.status == 0) { - return ResponseEntity.ok("{ \"key\": \"" + authService.session().generate(response.id) + "\", \"id\": " + response.id + " }"); + return ResponseEntity.ok( + new Session( + authService.session().generate(response.id), + response.id, + response.hue + ) + ); } else if (response.status > 0) { // Hardcoded 1 response code - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("{ \"code\": 1 }"); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new APError(1)); } else { - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{ \"code\": " + response.status + " }"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new APError(response.status)); } } + + @RequestMapping(value = "/logout", method = POST, consumes = "application/json", produces = "application/json") + public ResponseEntity logout(@RequestBody Session session) { + authService.logout(session); + return ResponseEntity.ok("{}"); + } } diff --git a/backend/src/main/java/achievements/data/APError.java b/backend/src/main/java/achievements/data/APError.java new file mode 100644 index 0000000..b6f8df2 --- /dev/null +++ b/backend/src/main/java/achievements/data/APError.java @@ -0,0 +1,36 @@ +package achievements.data; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class APError { + + @JsonProperty("code") + private int code; + @JsonProperty("message") + private String message; + + public APError(int code) { + this.code = code; + } + + public APError(int code, String message) { + this.code = code; + this.message = message; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/backend/src/main/java/achievements/data/Achievement.java b/backend/src/main/java/achievements/data/Achievement.java new file mode 100644 index 0000000..c4f8127 --- /dev/null +++ b/backend/src/main/java/achievements/data/Achievement.java @@ -0,0 +1,157 @@ +package achievements.data; + +import achievements.data.query.NumericFilter; +import achievements.data.query.StringFilter; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Achievement { + + public static class Query { + + @JsonProperty("sessionKey") + private String sessionKey; + @JsonProperty("name") + private StringFilter name; + @JsonProperty("stages") + private NumericFilter stages; + @JsonProperty("completion") + private NumericFilter completion; + @JsonProperty("difficulty") + private NumericFilter difficulty; + @JsonProperty("quality") + private NumericFilter quality; + + public Query(String sessionKey, StringFilter name, NumericFilter stages, NumericFilter completion, NumericFilter difficulty, NumericFilter quality) { + this.sessionKey = sessionKey; + this.name = name; + this.stages = stages; + this.completion = completion; + this.difficulty = difficulty; + this.quality = quality; + } + + public String getSessionKey() { + return sessionKey; + } + + public void setSessionKey(String sessionKey) { + this.sessionKey = sessionKey; + } + + public StringFilter getName() { + return name; + } + + public void setName(StringFilter name) { + this.name = name; + } + + public NumericFilter getStages() { + return stages; + } + + public void setStages(NumericFilter stages) { + this.stages = stages; + } + + public NumericFilter getCompletion() { + return completion; + } + + public void setCompletion(NumericFilter completion) { + this.completion = completion; + } + + public NumericFilter getDifficulty() { + return difficulty; + } + + public void setDifficulty(NumericFilter difficulty) { + this.difficulty = difficulty; + } + + public NumericFilter getQuality() { + return quality; + } + + public void setQuality(NumericFilter quality) { + this.quality = quality; + } + } + + @JsonProperty("ID") + private int id; + @JsonProperty("game") + private int gameId; + @JsonProperty("name") + private String name; + @JsonProperty("description") + private String description; + @JsonProperty("stages") + private int stages; + @JsonProperty("completion") + private float completion; + @JsonProperty("difficulty") + private float difficulty; + @JsonProperty("quality") + private float quality; + + public Achievement(int id, int gameId, String name, String description, int stages, float completion, float difficulty, float quality) { + this.id = id; + this.gameId = gameId; + this.name = name; + this.description = description; + this.stages = stages; + this.completion = completion; + this.difficulty = difficulty; + this.quality = quality; + } + + public int getId() { return id; } + + public void setId(int id) { this.id = id; } + + public int getGameId() { + return gameId; + } + + public void setGameId(int gameId) { + this.gameId = gameId; + } + + public String getName() { return name; } + + public void setName(String name) { this.name = name; } + + public String getDescription() { return description; } + + public void setDescription(String description) { this.description = description; } + + public int getStages() { return stages; } + + public void setStages(int stages) { this.stages = stages; } + + public float getCompletion() { + return completion; + } + + public void setCompletion(float completion) { + this.completion = completion; + } + + public float getDifficulty() { + return difficulty; + } + + public void setDifficulty(float difficulty) { + this.difficulty = difficulty; + } + + public float getQuality() { + return quality; + } + + public void setQuality(float quality) { + this.quality = quality; + } +} diff --git a/backend/src/main/java/achievements/data/Achievements.java b/backend/src/main/java/achievements/data/Achievements.java deleted file mode 100644 index 4b2033f..0000000 --- a/backend/src/main/java/achievements/data/Achievements.java +++ /dev/null @@ -1,64 +0,0 @@ -package achievements.data; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.ArrayList; -import java.util.List; - -public class Achievements { - - public static class Achievement { - - @JsonProperty("name") - private String name; - @JsonProperty("description") - private String description; - @JsonProperty("stages") - private int stages; - - public Achievement(String name, String description, int stages) { - this.name = name; - this.description = description; - this.stages = stages; - } - - // Start Getters/Setters - public String getName() { return name; } - - public void setName(String name) { this.name = name; } - - public String getDescription() { return description; } - - public void setDescription(String description) { this.description = description; } - - public int getStages() { return stages; } - - public void setStages(int stages) { this.stages = stages; } - // End Getters/Setters - } - - @JsonProperty("gameID") - private int gameID; - @JsonProperty("gameName") - private String gameName; - @JsonProperty("achievements") - private List achievements; - - public Achievements() { achievements = new ArrayList(); } - - // Start Getters/Setters - public int getGameID() { return gameID; } - - public void setGameID(int gameID) { this.gameID = gameID; } - - public String getGameName() { return gameName; } - - public void setGameName(String gameName) { this.gameName = gameName; } - - public List getAchievements() { return achievements; } - - public void setAchievements(List achievements) { this.achievements = achievements; } - // End Getters/Setters - - public void addAchievement(Achievement achievement) { this.achievements.add(achievement); }; -} diff --git a/backend/src/main/java/achievements/data/Game.java b/backend/src/main/java/achievements/data/Game.java new file mode 100644 index 0000000..1299b0e --- /dev/null +++ b/backend/src/main/java/achievements/data/Game.java @@ -0,0 +1,47 @@ +package achievements.data; + +import achievements.data.query.StringFilter; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.ArrayList; +import java.util.List; + +public class Game { + + public static class Query { + @JsonProperty("name") + private StringFilter name; + @JsonProperty("platforms") + private StringFilter platforms; + } + + @JsonProperty("ID") + private int id; + @JsonProperty("name") + private String name; + @JsonProperty("platforms") + private List platforms; + @JsonProperty("achievementCount") + private int achievementCount; + + public Game(int id, String name, String platform) { + this.id = id; + this.name = name; + this.platforms = new ArrayList<>(); + this.platforms.add(platform); + } + + public int getId() { return id; } + + public void setId(int id) { this.id = id; } + + public String getName() { return name; } + + public void setName(String name) { this.name = name; } + + public List getPlatforms() { return platforms; } + + public void setPlatforms(List platforms) { this.platforms = platforms; } + + public void addToPlatforms(String platform) { this.platforms.add(platform); } +} diff --git a/backend/src/main/java/achievements/data/Games.java b/backend/src/main/java/achievements/data/Games.java deleted file mode 100644 index 57ab9c6..0000000 --- a/backend/src/main/java/achievements/data/Games.java +++ /dev/null @@ -1,57 +0,0 @@ -package achievements.data; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.ArrayList; -import java.util.List; - -public class Games { - - public static class Game { - - @JsonProperty("ID") - private int id; - @JsonProperty("name") - private String name; - @JsonProperty("platforms") - private List platforms; - - public Game(int id, String name, String platform) { - this.id = id; - this.name = name; - this.platforms = new ArrayList<>(); - this.platforms.add(platform); - } - - // Start Getters/Setters - public int getId() { return id; } - - public void setId(int id) { this.id = id; } - - public String getName() { return name; } - - public void setName(String name) { this.name = name; } - - public List getPlatforms() { return platforms; } - - public void setPlatforms(List platforms) { this.platforms = platforms; } - - public void addToPlatforms(String platform) { this.platforms.add(platform); } - // End Getters/Setters - - } - - @JsonProperty("games") - private List games; - - public Games() { games = new ArrayList(); } - - // Start Getters/Setters - public List getGames() { return games; } - - public void setGames(List games) { this.games = games; } - // End Getters/Setters - - public void addGame(Game game) { this.games.add(game); } - -} diff --git a/backend/src/main/java/achievements/data/InternalError.java b/backend/src/main/java/achievements/data/InternalError.java deleted file mode 100644 index 16486a5..0000000 --- a/backend/src/main/java/achievements/data/InternalError.java +++ /dev/null @@ -1,21 +0,0 @@ -package achievements.data; - -import com.fasterxml.jackson.annotation.JsonProperty; - -public class InternalError { - - @JsonProperty - private String message; - - public InternalError(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/backend/src/main/java/achievements/data/Profile.java b/backend/src/main/java/achievements/data/Profile.java new file mode 100644 index 0000000..c505eda --- /dev/null +++ b/backend/src/main/java/achievements/data/Profile.java @@ -0,0 +1,73 @@ +package achievements.data; + +import achievements.data.query.StringFilter; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class Profile { + + public static class Query { + @JsonProperty("username") + private StringFilter string; + } + + @JsonProperty("id") + private int id; + @JsonProperty("username") + private String username; + @JsonProperty("plaforms") + private List platforms; + @JsonProperty("games") + private List games; + @JsonProperty("achievements") + private List achievements; + + public Profile(int id, String username, List platforms, List games, List achievements) { + this.id = id; + this.username = username; + this.platforms = platforms; + this.games = games; + this.achievements = achievements; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public List getPlatforms() { + return platforms; + } + + public void setPlatforms(List platforms) { + this.platforms = platforms; + } + + public List getGames() { + return games; + } + + public void setGames(List games) { + this.games = games; + } + + public List getAchievements() { + return achievements; + } + + public void setAchievements(List achievements) { + this.achievements = achievements; + } +} diff --git a/backend/src/main/java/achievements/data/Session.java b/backend/src/main/java/achievements/data/Session.java new file mode 100644 index 0000000..5aaabe1 --- /dev/null +++ b/backend/src/main/java/achievements/data/Session.java @@ -0,0 +1,43 @@ +package achievements.data; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class Session { + + @JsonProperty("key") + private String key; + @JsonProperty("id") + private int id; + @JsonProperty("hue") + private int hue; + + public Session(String key, int id, int hue) { + this.key = key; + this.id = id; + this.hue = hue; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getHue() { + return hue; + } + + public void setHue(int hue) { + this.hue = hue; + } +} diff --git a/backend/src/main/java/achievements/data/query/NumericFilter.java b/backend/src/main/java/achievements/data/query/NumericFilter.java new file mode 100644 index 0000000..a9fddac --- /dev/null +++ b/backend/src/main/java/achievements/data/query/NumericFilter.java @@ -0,0 +1,32 @@ +package achievements.data.query; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class NumericFilter { + + @JsonProperty("min") + private Float min; + @JsonProperty("max") + private Float max; + + public NumericFilter(Float min, Float max) { + this.min = min; + this.max = max; + } + + public Float getMin() { + return min; + } + + public void setMin(Float min) { + this.min = min; + } + + public Float getMax() { + return max; + } + + public void setMax(Float max) { + this.max = max; + } +} diff --git a/backend/src/main/java/achievements/data/query/StringFilter.java b/backend/src/main/java/achievements/data/query/StringFilter.java new file mode 100644 index 0000000..a6f93d5 --- /dev/null +++ b/backend/src/main/java/achievements/data/query/StringFilter.java @@ -0,0 +1,21 @@ +package achievements.data.query; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class StringFilter { + + @JsonProperty("query") + private String query; + + public StringFilter(String query) { + this.query = query; + } + + public String getQuery() { + return query; + } + + public void setQuery(String query) { + this.query = query; + } +} diff --git a/backend/src/main/java/achievements/misc/SessionManager.java b/backend/src/main/java/achievements/misc/SessionManager.java index c150242..942482e 100644 --- a/backend/src/main/java/achievements/misc/SessionManager.java +++ b/backend/src/main/java/achievements/misc/SessionManager.java @@ -16,13 +16,11 @@ public class SessionManager { return key; } - public String guest() { - var key = HashManager.encode(HashManager.generateBytes(16)); - session.put(key, null); - return key; - } - - public Integer getUser(String key) { + public int getUser(String key) { return session.get(key); } + + public void remove(String key) { + session.remove(key); + } } diff --git a/backend/src/main/java/achievements/services/AuthenticationService.java b/backend/src/main/java/achievements/services/AuthenticationService.java index 1807cf7..5ff9f78 100644 --- a/backend/src/main/java/achievements/services/AuthenticationService.java +++ b/backend/src/main/java/achievements/services/AuthenticationService.java @@ -1,5 +1,6 @@ package achievements.services; +import achievements.data.Session; import achievements.data.User; import achievements.misc.DbConnectionService; import achievements.misc.Password; @@ -16,10 +17,12 @@ public class AuthenticationService { public static class LoginResponse { public int status; public Integer id; + public int hue; public LoginResponse() { this.status = 0; this.id = null; + this.hue = 0; } public LoginResponse(int status) { @@ -27,14 +30,13 @@ public class AuthenticationService { this.id = null; } - public LoginResponse(int status, int id) { + public LoginResponse(int status, int id, int hue) { this.status = status; this.id = id; + this.hue = hue; } } - public static final LoginResponse GUEST = new LoginResponse(); - @Autowired private DbConnectionService dbs; private Connection db; @@ -53,7 +55,7 @@ public class AuthenticationService { } try { - var statement = db.prepareCall("{? = call CreateUser(?, ?, ?, ?, ?)}"); + var statement = db.prepareCall("{? = call CreateUser(?, ?, ?, ?, ?, ?)}"); statement.registerOutParameter(1, Types.INTEGER); statement.setString(2, user.getEmail()); statement.setString(3, user.getUsername()); @@ -63,9 +65,14 @@ public class AuthenticationService { statement.setString(5, password.hash); statement.registerOutParameter(6, Types.INTEGER); + statement.registerOutParameter(7, Types.INTEGER); statement.execute(); - var response = new LoginResponse(statement.getInt(1), statement.getInt(6)); + var response = new LoginResponse( + statement.getInt(1), + statement.getInt(6), + statement.getInt(7) + ); statement.close(); return response; @@ -86,7 +93,7 @@ public class AuthenticationService { var salt = result.getString("Salt"); var hash = result.getString("Password"); if (Password.validate(salt, user.getPassword(), hash)) { - response = new LoginResponse(0, result.getInt("ID")); + response = new LoginResponse(0, result.getInt("ID"), result.getInt("Hue")); } else { response = new LoginResponse(2); } @@ -100,6 +107,10 @@ public class AuthenticationService { return response; } + public void logout(Session key) { + session.remove(key.getKey()); + } + public SessionManager session() { return session; } diff --git a/backend/src/main/java/achievements/services/DataService.java b/backend/src/main/java/achievements/services/DataService.java new file mode 100644 index 0000000..af76afd --- /dev/null +++ b/backend/src/main/java/achievements/services/DataService.java @@ -0,0 +1,40 @@ +package achievements.services; + +import achievements.data.Achievement; +import achievements.data.Game; +import achievements.data.Profile; +import achievements.misc.DbConnectionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.sql.Connection; +import java.util.List; + +@Service +public class DataService { + + @Autowired + private DbConnectionService dbs; + private Connection db; + + @Autowired + private AuthenticationService auth; + + @PostConstruct + private void init() { + db = dbs.getConnection(); + } + + /*public List getUsers() { + + } + + public List getGames() { + + } + + public List getProfiles() { + + }*/ +} diff --git a/backend/src/main/java/achievements/services/DbService.java b/backend/src/main/java/achievements/services/DbService.java deleted file mode 100644 index 4b9d310..0000000 --- a/backend/src/main/java/achievements/services/DbService.java +++ /dev/null @@ -1,92 +0,0 @@ -package achievements.services; - -import achievements.data.Achievements; -import achievements.data.Games; -import achievements.misc.DbConnectionService; -import achievements.misc.SessionManager; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import javax.annotation.PostConstruct; -import java.sql.*; - -@Service -public class DbService { - - @Autowired - private DbConnectionService dbs; - private Connection db; - - @PostConstruct - private void init() { - db = dbs.getConnection(); - } - - public Achievements getAchievements(String gameName) { - try { - // Create Query - CallableStatement stmt = db.prepareCall("{? = call GetAchievements(?)}"); - stmt.registerOutParameter(1, Types.INTEGER); - stmt.setString(2, gameName); - - // Read Result(s) - ResultSet results = stmt.executeQuery(); - var achievements = new Achievements(); - while (results.next()) { - // Add Result(s) to data class - int achievementGameID = results.getInt("GameID"); - String achievementGameName = results.getString("GameName"); - String achievementName = results.getString("Name"); - String achievementDescription = results.getString("Description"); - int achievementStages = results.getInt("Stages"); - // Checks if getting from specific game or all achievements - if (!gameName.equals("%")) { - achievements.setGameID(achievementGameID); - achievements.setGameName(achievementGameName); - } - achievements.addAchievement(new Achievements.Achievement(achievementName, achievementDescription, achievementStages)); - } - stmt.close(); - return achievements; - } catch (SQLException e) { - e.printStackTrace(); - return null; - } - } - - public Games getGames(String name) { - try { - // Create Query - CallableStatement stmt = db.prepareCall("{? = call GetGame(?)}"); - stmt.registerOutParameter(1, Types.INTEGER); - stmt.setString(2, name); - - // Read Result(s) - ResultSet results = stmt.executeQuery(); - var games = new Games(); - while (results.next()) { - // Add Result(s) to data class - int gameID = results.getInt("ID"); - String gameName = results.getString("Name"); - String gamePlatform = results.getString("PlatformName"); - if (!games.getGames().isEmpty()) { - var lastGame = games.getGames().get(games.getGames().size()-1); - if (lastGame.getId() == gameID) { - lastGame.addToPlatforms(gamePlatform); - } else { - games.addGame(new Games.Game(gameID,gameName,gamePlatform)); - } - } else { - games.addGame(new Games.Game(gameID,gameName,gamePlatform)); - } - - } - stmt.close(); - return games; - } catch (SQLException e) { - e.printStackTrace(); - return null; - } - } - -} diff --git a/frontend/webpage/login.html b/frontend/webpage/login.html index fd96e65..c6418f3 100644 --- a/frontend/webpage/login.html +++ b/frontend/webpage/login.html @@ -9,29 +9,37 @@ -
- -
-

Login

-
-
-
-

Egg

- - - - -
- - +
+ +
+
+
+
+
+

Login

+
+
+
+

Egg

+ + + + +
+ + +
+ +

WARNING!

+

The security of this project is questionable at best. Please refrain from using any truly sensitive data.

+
+
- -

WARNING! The security of this project is questionable at best. Please refrain from using any truly sensitive data.

diff --git a/frontend/webpage/scripts/index.js b/frontend/webpage/scripts/index.js index a9a1460..1aeb9c7 100644 --- a/frontend/webpage/scripts/index.js +++ b/frontend/webpage/scripts/index.js @@ -1,3 +1,11 @@ +let session = null; +const loadSession = () => { + session = JSON.parse(window.sessionStorage.getItem('session')); + if (session) { + document.querySelector(":root").style.setProperty('--accent-hue', session.hue); + } +}; + const expandTemplates = async () => { template.apply("navbar").values([ { section: "left" }, @@ -7,9 +15,16 @@ const expandTemplates = async () => { { item: "games", title: "Games" }, { item: "achievements", title: "Achievements" } ]); - template.apply("navbar-section-right").values([ - { item: "profile", title: "Profile" } - ]); + if (session) { + template.apply("navbar-section-right").values([ + { item: "profile", title: "Profile" }, + { item: "logout", title: "Logout" } + ]); + } else { + template.apply("navbar-section-right").values([ + { item: "login", title: "Login" } + ]); + } template.apply("content-body").values([ { page: "games", title: "Games" }, { page: "achievements", title: "Achievements" }, @@ -18,7 +33,6 @@ const expandTemplates = async () => { template.apply("extern-games-page" ).values("games_page" ); template.apply("extern-achievements-page").values("achievements_page"); template.apply("extern-profile-page" ).values("profile_page" ); - template.apply("achievements-page-list" ).fetch("achievements", "https://localhost:4730/achievements"); await template.expand(); }; @@ -32,22 +46,41 @@ const connectNavbar = () => { const navItems = document.querySelectorAll(".navbar-item"); for (const item of navItems) { - item.addEventListener("click", (clickEvent) => { - const navItemPageId = item.dataset.pageName + "-page" - for (const page of pages) { - if (page.id === navItemPageId) { - page.style.display = "block"; - } else { - page.style.display = "none"; + if (item.dataset.pageName === "logout") { + item.addEventListener("click", (clickEvent) => { + fetch('https://localhost:4730/logout', { + method: 'POST', + mode: 'cors', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ key: session.key }) + }) + .then(response => { + window.sessionStorage.removeItem('session'); + window.location.href = "/login.html"; + }); + }); + } else if (item.dataset.pageName === "login") { + item.addEventListener("click", (clickEvent) => window.location.href = "/login.html"); + } else { + item.addEventListener("click", (clickEvent) => { + const navItemPageId = item.dataset.pageName + "-page" + for (const page of pages) { + if (page.id === navItemPageId) { + page.style.display = "block"; + } else { + page.style.display = "none"; + } } - } - }); + }); + } } }; const connectProfile = () => { - const games = document.querySelector("#profile-games"); - const achievements = document.querySelector("#profile-achievements"); + const games = document.querySelector("#profile-games-header"); + const achievements = document.querySelector("#profile-achievements-header"); games.children[0].addEventListener("click", (clickEvent) => { for (const page of pages) { @@ -84,6 +117,8 @@ const loadFilters = () => { } window.addEventListener("load", async (loadEvent) => { + loadSession(); + await expandTemplates(); loadPages(); diff --git a/frontend/webpage/scripts/login.js b/frontend/webpage/scripts/login.js index 525f3de..5bd4295 100644 --- a/frontend/webpage/scripts/login.js +++ b/frontend/webpage/scripts/login.js @@ -1,4 +1,9 @@ window.addEventListener("load", (loadEvent) => { + let session = window.sessionStorage.getItem('session'); + if (session) { + window.location.href = '/'; + } + const fields = { email: document.querySelector("#email" ), username: document.querySelector("#username"), @@ -27,6 +32,18 @@ window.addEventListener("load", (loadEvent) => { } let frozen = false; + const freeze = () => { + frozen = true; + createUser.classList.add("disabled"); + login.classList.add("disabled"); + guest.classList.add("disabled"); + }; + const unfreeze = () => { + frozen = false; + createUser.classList.remove("disabled"); + login.classList.remove("disabled"); + guest.classList.remove("disabled"); + }; const switchToCreateAction = (clickEvent) => { if (!frozen) { @@ -39,6 +56,8 @@ window.addEventListener("load", (loadEvent) => { login.removeEventListener("click", loginAction); login.addEventListener("click", switchToLoginAction); + + activeAction = createUserAction; } }; const createUserAction = (clickEvent) => { @@ -52,7 +71,7 @@ window.addEventListener("load", (loadEvent) => { } else if (fields.password.value === '') { raiseError([ "password", "confirm" ], "Password cannot be empty"); } else { - frozen = true; + freeze(); fetch('https://localhost:4730/create_user', { method: 'POST', mode: 'cors', @@ -65,8 +84,7 @@ window.addEventListener("load", (loadEvent) => { .then(response =>{ const data = response.data; if (response.status === 200) { - window.sessionStorage.setItem('sessionKey', data.key); - window.sessionStorage.setItem('id', data.id ); + window.sessionStorage.setItem('session', JSON.stringify(data)); window.location.href = "/"; } else if (response.status === 500) { raiseError([], "Internal server error :("); @@ -83,7 +101,7 @@ window.addEventListener("load", (loadEvent) => { .catch(error => { console.error(error); raiseError([], "Server error :("); - }).then(() => frozen = false); + }).then(unfreeze); } } }; @@ -100,6 +118,8 @@ window.addEventListener("load", (loadEvent) => { login.removeEventListener("click", switchToLoginAction); login.addEventListener("click", loginAction); + + activeAction = loginAction; } }; const loginAction = (clickEvent) => { @@ -109,7 +129,7 @@ window.addEventListener("load", (loadEvent) => { } else if (fields.password.value === '') { raiseError([ "password" ], "Password cannot be empty"); } else { - frozen = true; + freeze(); fetch('https://localhost:4730/login', { method: 'POST', mode: 'cors', @@ -123,8 +143,7 @@ window.addEventListener("load", (loadEvent) => { const data = response.data; if (response.status === 200) { console.log(data); - window.sessionStorage.setItem('sessionKey', data.key); - window.sessionStorage.setItem('id', data.id ); + window.sessionStorage.setItem('session', JSON.stringify(data)); window.location.href = "/"; } else if (response.status === 500) { raiseError([], "Internal server error :("); @@ -136,7 +155,7 @@ window.addEventListener("load", (loadEvent) => { .catch(error => { console.error(error); raiseError([], "Unknown error :("); - }).then(() => frozen = false); + }).then(unfreeze); } } }; @@ -144,34 +163,16 @@ window.addEventListener("load", (loadEvent) => { guest.addEventListener("click", (clickEvent) => { if (!frozen) { - frozen = true; - fetch('https://localhost:4730/login?guest=true', { - method: 'POST', - mode: 'cors', - headers: { - 'Content-Type': 'application/json' - }, - body: "{}" - }) - .then(async response => ({ status: response.status, data: await response.json() })) - .then(response => { - const data = response.data; - if (response.status === 200) { - console.log(data); - window.sessionStorage.setItem('sessionKey', data.key); - window.sessionStorage.setItem('id', data.id ); - window.location.href = "/"; - } else if (response.status === 500) { - raiseError([], "Internal server error :("); - } else { - raiseError([ "email", "password" ], "Email or password is incorrect"); - fields.password.value = ''; - } - }) - .catch(error => { - console.error(error); - raiseError([], "Unknown error :("); - }).then(() => frozen = false); + window.location.href = '/'; } }); + + let activeAction = loginAction; + for (const field in fields) { + fields[field].addEventListener("keydown", (keyEvent) => { + if (keyEvent.key === "Enter") { + activeAction(); + } + }) + } }); \ No newline at end of file diff --git a/frontend/webpage/styles/common.css b/frontend/webpage/styles/common.css index e35c6f4..9598841 100644 --- a/frontend/webpage/styles/common.css +++ b/frontend/webpage/styles/common.css @@ -94,6 +94,21 @@ html, body { background-color: var(--accent-value1); } +.ap-button.disabled { + background-color: var(--accent-value1); + color: var(--accent-value0); +} + +.ap-button.disabled:hover { + background-color: var(--accent-value1); + color: var(--accent-value0); +} + +.ap-button.disabled:active { + background-color: var(--accent-value1); + color: var(--accent-value0); +} + #content-body { position: relative; @@ -109,8 +124,6 @@ html, body { } .page { - z-index: 0; - box-sizing: border-box; padding: 32px; @@ -135,9 +148,6 @@ html, body { border-radius: 8px; box-shadow: inset 0px 0px 8px 8px var(--shadow-color); - - position: relative; - z-index: -1; } .page-subsection-wrapper { @@ -290,12 +300,12 @@ html, body { } .list-page-filter-checkbox { - width: 32px; - height: 32px; + width: 28px; + height: 28px; background-color: var(--foreground); - border: 3px solid var(--foreground-dark); + border: 3px solid var(--foreground); border-radius: 8px; transition-property: background-color, border-color; diff --git a/frontend/webpage/styles/index.css b/frontend/webpage/styles/index.css index 43fd5b1..2933370 100644 --- a/frontend/webpage/styles/index.css +++ b/frontend/webpage/styles/index.css @@ -86,15 +86,27 @@ html, body { box-shadow: 0px 0px 8px 8px var(--shadow-color); border-radius: 8px; +} + +#profile-info-pfp { + width: 100%; + height: 100%; position: relative; - z-index: -1; } #profile-info-pfp-vignette { + top: 0%; + left: 0%; + width: 100%; + height: 100%; + box-shadow: inset 0px 0px 50px 30px var(--shadow-color); border-radius: 8px; + + position: absolute; + z-index: 1; } #profile-info-pfp-img { @@ -103,7 +115,6 @@ html, body { border-radius: 8px; position: relative; - z-index: -1; } .profile-list { diff --git a/frontend/webpage/styles/login.css b/frontend/webpage/styles/login.css index fd3dd10..abdc471 100644 --- a/frontend/webpage/styles/login.css +++ b/frontend/webpage/styles/login.css @@ -3,7 +3,7 @@ --element-spacing: 12px; - --error: #FA7575; + --error: #F95959; } #login-page { @@ -12,21 +12,35 @@ max-width: 1280px; } +#login-flex { + display: flex; + flex-direction: row; + justify-content: center; +} + +#login-subsection { + width: 100%; +} + +#login-elements { + display: flex; + flex-direction: column; + align-items: center; +} + #login-header { box-sizing: border-box; - padding: 0 calc(25% - 64px); - - width: 100%; + width: 50%; height: max-content; } #login-form { box-sizing: border-box; - margin: 24px calc(25% - 64px) 0; padding: 24px 0; + width: 50%; height: max-content; background-color: var(--distinction); @@ -99,6 +113,15 @@ } #warning { - color: var(--foreground); + color: var(--error); font-size: 24px; + text-align: center; + line-height: 40px; +} + +#warning-message { + margin-top: 0; + color: var(--foreground); + font-size: 18px; + text-align: center; } \ No newline at end of file diff --git a/frontend/webpage/templates/achievements_page.html.template b/frontend/webpage/templates/achievements_page.html.template index 38f1ea1..421f452 100644 --- a/frontend/webpage/templates/achievements_page.html.template +++ b/frontend/webpage/templates/achievements_page.html.template @@ -1,7 +1,7 @@
@@ -14,7 +14,7 @@
-

From Games Owned

+

My Games

@@ -51,4 +51,4 @@
-
\ No newline at end of file +
diff --git a/frontend/webpage/templates/games_page.html.template b/frontend/webpage/templates/games_page.html.template index 7aa0857..ceceacd 100644 --- a/frontend/webpage/templates/games_page.html.template +++ b/frontend/webpage/templates/games_page.html.template @@ -1,7 +1,7 @@
diff --git a/frontend/webpage/templates/profile_page.html.template b/frontend/webpage/templates/profile_page.html.template index 347fedd..80d556d 100644 --- a/frontend/webpage/templates/profile_page.html.template +++ b/frontend/webpage/templates/profile_page.html.template @@ -6,8 +6,9 @@
-
+
User's Profile Pictuer +
@@ -41,7 +42,7 @@
-
+
@@ -95,7 +96,7 @@
-
+
diff --git a/sql/CreateTables.sql b/sql/CreateTables.sql index f0eb578..2d11253 100644 --- a/sql/CreateTables.sql +++ b/sql/CreateTables.sql @@ -33,7 +33,11 @@ CREATE TABLE [User] ( Username VARCHAR(32) NOT NULL, [Password] CHAR(64) NOT NULL, [Salt] CHAR(32) NOT NULL, - Verified BIT NOT NULL CONSTRAINT VerifiedDefault DEFAULT 0 + Hue INT NOT NULL + CONSTRAINT HueDefault DEFAULT 0 + CONSTRAINT HueConstraint CHECK (0 <= Hue AND Hue <= 360), + Verified BIT NOT NULL + CONSTRAINT VerifiedDefault DEFAULT 0 PRIMARY KEY(ID) ) diff --git a/sql/CreateUserSP.sql b/sql/CreateUser.sql similarity index 76% rename from sql/CreateUserSP.sql rename to sql/CreateUser.sql index ed30d384f81059282e51457fc598f4e61711f147..6d8d6856d805b44f1765df30b9ad1744b03132d3 100644 GIT binary patch delta 247 zcmYk1F$%&!6htRlgb3mdBnL>qS`cgmQ!BO-P1ImSFsqhU;sLyf;6-vI->wEM{_gyl z+1dYVzYbn~uNSGSjslG})mi!5_wKD*tXQEE>Z&7jsSLbRs*7?^sX}{)4En!fa22ZH zDs;o$I0&c9I5*_jOrr>91-8BvCUq~(f{25&Z;7|!w`;x~!q{O>#I14I(2$Xrl-*{g QiRLiBoj@aM@O-qB4_zxNtpET3 delta 16 Xcmcb>d4YX{9OGse#yqCUJuEH&GBO2E diff --git a/sql/GetUserLogin.sql b/sql/GetUserLogin.sql index 0e5b32d..f00d750 100644 --- a/sql/GetUserLogin.sql +++ b/sql/GetUserLogin.sql @@ -1,4 +1,6 @@ CREATE PROCEDURE GetUserLogin( @email VARCHAR(254) ) AS -SELECT Id, Salt, [Password] FROM [User] WHERE Email = @email +BEGIN TRANSACTION +SELECT Id, Salt, [Password], Hue FROM [User] WHERE Email = @email +COMMIT TRANSACTION \ No newline at end of file