Updated more UI. Enhanced login capabilities. Started work on querying data.

This commit is contained in:
Gnarwhal 2021-02-07 22:50:48 -05:00
parent 40a0e4046a
commit 052052d76b
Signed by: Gnarwhal
GPG key ID: 0989A73D8C421174
29 changed files with 706 additions and 424 deletions

View file

@ -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<String> 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<String> 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);
}
}
}

View file

@ -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) {
}
}

View file

@ -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("{}");
}
}

View file

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

View file

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

View file

@ -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<Achievement> achievements;
public Achievements() { achievements = new ArrayList<Achievement>(); }
// 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<Achievement> getAchievements() { return achievements; }
public void setAchievements(List<Achievement> achievements) { this.achievements = achievements; }
// End Getters/Setters
public void addAchievement(Achievement achievement) { this.achievements.add(achievement); };
}

View file

@ -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<String> 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<String> getPlatforms() { return platforms; }
public void setPlatforms(List<String> platforms) { this.platforms = platforms; }
public void addToPlatforms(String platform) { this.platforms.add(platform); }
}

View file

@ -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<String> 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<String> getPlatforms() { return platforms; }
public void setPlatforms(List<String> platforms) { this.platforms = platforms; }
public void addToPlatforms(String platform) { this.platforms.add(platform); }
// End Getters/Setters
}
@JsonProperty("games")
private List<Game> games;
public Games() { games = new ArrayList<Game>(); }
// Start Getters/Setters
public List<Game> getGames() { return games; }
public void setGames(List<Game> games) { this.games = games; }
// End Getters/Setters
public void addGame(Game game) { this.games.add(game); }
}

View file

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

View file

@ -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<String> platforms;
@JsonProperty("games")
private List<Game> games;
@JsonProperty("achievements")
private List<Achievement> achievements;
public Profile(int id, String username, List<String> platforms, List<Game> games, List<Achievement> 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<String> getPlatforms() {
return platforms;
}
public void setPlatforms(List<String> platforms) {
this.platforms = platforms;
}
public List<Game> getGames() {
return games;
}
public void setGames(List<Game> games) {
this.games = games;
}
public List<Achievement> getAchievements() {
return achievements;
}
public void setAchievements(List<Achievement> achievements) {
this.achievements = achievements;
}
}

View file

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

View file

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

View file

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

View file

@ -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);
}
}

View file

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

View file

@ -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<Achievement> getUsers() {
}
public List<Game> getGames() {
}
public List<Profile> getProfiles() {
}*/
}

View file

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