Compare commits

...

53 commits

Author SHA1 Message Date
e4cbca8f1c jsp 2025-01-27 17:18:54 +01:00
5c43347710 SEE for groups messages 2025-01-26 15:14:10 +01:00
7b40c6edea Fix given dependencies 2025-01-26 11:16:20 +01:00
7e871f824c Adding system to dynamicly update SQL's statements without restarting the app 2025-01-26 11:01:29 +01:00
0bfba6d99c Database Repository -> Share Connection to DB 2025-01-25 12:11:20 +01:00
35b97d1a25 Refractor fat class DatabaseRepository + DataBaseQuery 2025-01-25 12:02:12 +01:00
a0cf7989b4 Set Max Players in Groups in Configuration (was hardcoded) 2025-01-24 23:27:41 +01:00
ed050b17fe update framework 2025-01-24 23:16:06 +01:00
5f02e31507 Accept accent for firstname & lastname in register 2024-09-17 22:16:49 +02:00
758ee3b960 Reduce UUID for forgotpassword too... 2024-09-17 09:12:21 +02:00
066d4f5d9f Reduce UUID 2024-09-17 09:11:22 +02:00
47510f3d91 Only one UUID for check code and remove redirect URL 2024-09-17 08:52:44 +02:00
901d7930fa Update framework | internal update : Any RentationPolicy in the chat ? 2024-09-16 08:19:41 +02:00
2a1912b474 Update framework | internal update : exception when named dependency not found 2024-09-16 08:12:42 +02:00
a8985b14b1 Update framework | internal update : adding constructor location of failed dependency injecton 2024-09-16 08:04:14 +02:00
d89a11fba0 Rework verify code from unlogged action 2024-09-16 07:52:37 +02:00
ee9739f5d3 Update Framework with dependencies injector 2024-06-30 18:37:13 +02:00
6550cf03f1 hot fix forgot 2024-04-16 15:17:55 +02:00
28cd04406b hot fix admin panel 2024-04-16 14:54:03 +02:00
e78ef96cfd Hot Fix groups 2024-04-16 14:48:43 +02:00
b223b6bad4 Hot Fix cg 2024-04-16 14:03:30 +02:00
c3d81f2020 hot fix chapter 2024-04-16 13:52:28 +02:00
1d67dfdfd9 Fix save config 2024-04-16 12:02:41 +02:00
1012a489ab [test restart] 2024-04-16 12:01:38 +02:00
e915f6baa2 [test restart] 2024-04-16 12:00:29 +02:00
9a0966322e Fix save config 2024-04-16 11:58:32 +02:00
5b8699cf9d Add WebHook for refreshing leaderboard 2024-04-16 11:56:29 +02:00
634bcbadf4 Export & Import jwt privte key in config 2024-04-16 11:51:55 +02:00
19b3f6391b fix chapter event 2024-04-15 21:00:23 +02:00
50ccad4b24 fix chapter event 2024-04-15 19:45:40 +02:00
88d4bfb8ee Fix json escape in specific old case & remove avatar 2024-04-14 22:03:48 +02:00
d0bdc316bf Fix json encodage problems 2024-04-14 14:37:55 +02:00
7030adbfba Debug json format ? 2024-04-14 14:20:20 +02:00
aef778570e Add rules for " 2024-04-14 14:15:09 +02:00
cb9107bc58 Fix puzzle encodage 2024-04-14 09:41:47 +02:00
2560279ef4 Fix admin puzzle details + implement puzzle list 2024-04-05 13:42:46 +02:00
710e3eccb8 Add Exception logs 2024-04-02 12:12:47 +02:00
f6d2d7f96f Fix puzzles tags in admin routes 2024-04-01 21:26:57 +02:00
15f0791777 Add players count in group list for a chapter 2024-03-31 12:06:35 +02:00
f23904d860 Limit group size 2024-03-29 15:26:42 +01:00
f722a4db22 Debugging.... password hash too long 2024-03-28 20:58:16 +01:00
700054f586 Update dependencies 2024-03-28 20:41:42 +01:00
94abf83731 Add start & end dates in chapter element 2024-03-28 18:39:41 +01:00
c60dee21b4 Fix chapterlist npe 2024-03-28 18:37:41 +01:00
575d679113 Add start & end dates in chapter 2024-03-28 18:36:16 +01:00
250758c3bf Route get groups by chapter 2024-03-26 21:14:22 +01:00
d089ff237a Admin CRUD Tags 2024-03-21 10:27:30 +01:00
a7b87bcf12 Fix admin get chapter&puzzle 2024-03-18 12:07:01 +01:00
d43ae3b989 Response code on admin page for non-admin user + add state tests 2024-03-15 14:33:47 +01:00
bc73dc6624 State Case Test 2024-03-14 17:20:23 +01:00
7c3558f5a8 admin CRUD chapter & puzzle 2024-03-14 13:55:57 +01:00
3b98624df9 Admin logs -> request type in String + base route for editing chapter & puzzle 2024-03-14 13:17:07 +01:00
68dd312a42 Add Admin Interceptors 2024-03-13 11:24:37 +01:00
63 changed files with 2695 additions and 1010 deletions

View file

@ -17,8 +17,8 @@
<classpathentry kind="lib" path="Treasure.jar"/> <classpathentry kind="lib" path="Treasure.jar"/>
<classpathentry exported="true" kind="lib" path="JDA-5.0.0-beta.8-withDependencies.jar"/> <classpathentry exported="true" kind="lib" path="JDA-5.0.0-beta.8-withDependencies.jar"/>
<classpathentry exported="true" kind="lib" path="PeerAtCodeFramework.jar"/> <classpathentry exported="true" kind="lib" path="PeerAtCodeFramework.jar"/>
<classpathentry exported="true" kind="lib" path="angus-activation-2.0.1.jar"/> <classpathentry exported="true" kind="lib" path="angus-activation-2.0.2.jar"/>
<classpathentry exported="true" kind="lib" path="jakarta.activation-api-2.1.2.jar"/> <classpathentry exported="true" kind="lib" path="jakarta.activation-api-2.1.3.jar"/>
<classpathentry exported="true" kind="lib" path="jakarta.mail-2.0.2.jar"/> <classpathentry exported="true" kind="lib" path="jakarta.mail-2.0.3.jar"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,6 @@
/chapter/0
GET
Authorization: Bearer <token:test@peerat.dev>
400

View file

@ -0,0 +1,8 @@
/chapters
GET
Authorization: Bearer <token:test@peerat.dev>
200
[]

View file

@ -0,0 +1,8 @@
/leaderboard/
GET
Authorization: Bearer <token:test@peerat.dev>
200
[]

View file

@ -0,0 +1,6 @@
/puzzle/0
GET
Authorization: Bearer <token:test@peerat.dev>
400

View file

@ -0,0 +1,6 @@
/admin/chapter/0
GET
Authorization: Bearer <token:test@peerat.dev>
401

Binary file not shown.

View file

@ -33,6 +33,7 @@ public class Configuration {
private int groupJoinMinutes; private int groupJoinMinutes;
private String groupQuitMinutes; private String groupQuitMinutes;
private int groupMaxPlayers;
private String mailUsername; private String mailUsername;
private String mailPassword; private String mailPassword;
@ -41,6 +42,12 @@ public class Configuration {
private String mailFromAddress; private String mailFromAddress;
private String git_token; private String git_token;
private String jwt_key;
private String sql_folder;
private int event_chapter;
private File _file; private File _file;
@ -57,18 +64,21 @@ public class Configuration {
return this; return this;
} }
public void load() throws Exception{ public Configuration load() throws Exception{
if(!this._file.exists()) return; if(!this._file.exists()) return this;
BufferedReader reader = new BufferedReader(new FileReader(this._file)); BufferedReader reader = new BufferedReader(new FileReader(this._file));
String line; String line;
while((line = reader.readLine()) != null){ while((line = reader.readLine()) != null){
String[] split = line.split("="); int index = line.indexOf('=');
Field field = getClass().getDeclaredField(split[0]); String key = line.substring(0, index);
String value = line.substring(index+1);
Field field = getClass().getDeclaredField(key);
if(field == null) continue; if(field == null) continue;
field.setAccessible(true); field.setAccessible(true);
injectValue(field, split[1]); injectValue(field, value);
} }
reader.close(); reader.close();
return this;
} }
private void injectValue(Field field, String value) throws IllegalAccessException { private void injectValue(Field field, String value) throws IllegalAccessException {
@ -122,7 +132,7 @@ public class Configuration {
field.setAccessible(true); field.setAccessible(true);
if(field.getName().startsWith("_")) continue; if(field.getName().startsWith("_")) continue;
Object value = field.get(this); Object value = field.get(this);
writer.write(field.getName() + "=" + value); writer.write(field.getName() + "=" + value+"\n");
} }
writer.flush(); writer.flush();
writer.close(); writer.close();
@ -131,48 +141,48 @@ public class Configuration {
public boolean isProduction(){ public boolean isProduction(){
return this.prod; return this.prod;
} }
public String getDbHost() { public String getDbHost(){
return this.db_host; return this.db_host;
} }
public int getDbPort() { public int getDbPort(){
return this.db_port; return this.db_port;
} }
public String getDbUser() { public String getDbUser(){
return this.db_user; return this.db_user;
} }
public String getDbDatabase() { public String getDbDatabase(){
return this.db_database; return this.db_database;
} }
public String getDbPassword() { public String getDbPassword(){
return this.db_password; return this.db_password;
} }
public String getSslKeystore() { public String getSslKeystore(){
return this.ssl_keystore; return this.ssl_keystore;
} }
public String getTokenIssuer() { public String getTokenIssuer(){
return this.token_issuer; return this.token_issuer;
} }
public int getTokenExpiration() { public int getTokenExpiration(){
return this.token_expiration; return this.token_expiration;
} }
public String getSslKeystorePasswd() { public String getSslKeystorePasswd(){
return this.ssl_keystorePasswd; return this.ssl_keystorePasswd;
} }
public int getTcpPort() { public int getTcpPort(){
return this.tcp_port; return this.tcp_port;
} }
public boolean useSsl() { public boolean useSsl(){
return this.use_ssl; return this.use_ssl;
} }
@ -192,6 +202,10 @@ public class Configuration {
return this.groupQuitMinutes; return this.groupQuitMinutes;
} }
public int getGroupMaxPlayers(){
return this.groupMaxPlayers;
}
public Mail getMail(){ public Mail getMail(){
return new Mail( return new Mail(
this.mailUsername, this.mailUsername,
@ -204,4 +218,20 @@ public class Configuration {
public String getGitToken(){ public String getGitToken(){
return this.git_token; return this.git_token;
} }
public String getJwtKey(){
return this.jwt_key;
}
public void setJwtKey(String key){
this.jwt_key = key;
}
public String getSqlFolder(){
return this.sql_folder;
}
public int getEventChapter(){
return this.event_chapter;
}
} }

View file

@ -2,64 +2,47 @@ package dev.peerat.backend;
import static dev.peerat.framework.RequestType.OPTIONS; import static dev.peerat.framework.RequestType.OPTIONS;
import java.lang.reflect.Method;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteExtracter; import dev.peerat.backend.bonus.extract.RouteExtracter;
import dev.peerat.backend.model.Completion;
import dev.peerat.backend.model.Group; import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.PeerAtUser; import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.ConnectionManager;
import dev.peerat.backend.repository.DatabaseBadgeRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.backend.routes.BadgeDetails;
import dev.peerat.backend.routes.ChapterElement;
import dev.peerat.backend.routes.ChapterList;
import dev.peerat.backend.routes.DynamicLeaderboard;
import dev.peerat.backend.routes.Leaderboard;
import dev.peerat.backend.routes.PlayerDetails;
import dev.peerat.backend.routes.PuzzleElement;
import dev.peerat.backend.routes.PuzzleResponse;
import dev.peerat.backend.routes.Result;
import dev.peerat.backend.routes.Swagger;
import dev.peerat.backend.routes.admins.DynamicLogs;
import dev.peerat.backend.routes.groups.GroupCreate;
import dev.peerat.backend.routes.groups.GroupJoin;
import dev.peerat.backend.routes.groups.GroupList;
import dev.peerat.backend.routes.groups.GroupQuit;
import dev.peerat.backend.routes.users.ChangePassword;
import dev.peerat.backend.routes.users.ForgotPassword;
import dev.peerat.backend.routes.users.Login;
import dev.peerat.backend.routes.users.MailConfirmation;
import dev.peerat.backend.routes.users.ProfileSettings;
import dev.peerat.backend.routes.users.Register;
import dev.peerat.backend.utils.Mail;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.DependencyInjector;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter; import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Locker; import dev.peerat.framework.Locker;
import dev.peerat.framework.Locker.Key;
import dev.peerat.framework.RequestType; import dev.peerat.framework.RequestType;
import dev.peerat.framework.Response; import dev.peerat.framework.Response;
import dev.peerat.framework.Route; import dev.peerat.framework.Route;
import dev.peerat.framework.RouteInterceptor;
import dev.peerat.framework.Router; import dev.peerat.framework.Router;
import dev.peerat.framework.Locker.Key; import dev.peerat.framework.auth.Authenticator;
import dev.peerat.framework.auth.JwtAuthenticator;
import dev.peerat.framework.utils.json.JsonMap;
import dev.peerat.framework.utils.json.JsonParser;
public class Main{ public class Main{
private static Router<PeerAtUser> ACCESS_ROUTER;
public static void main(String[] args) throws Exception{ public static void main(String[] args) throws Exception{
Configuration config = new Configuration("config.txt") Configuration config = new Configuration("config.txt")
.addDefaultValue("users_files", "/tmp/users_files"); .addDefaultValue("users_files", "/tmp/users_files");
config.load(); config.load();
Class.forName("com.mysql.cj.jdbc.Driver"); Class.forName("com.mysql.cj.jdbc.Driver");
DatabaseRepository repo = new DatabaseRepository(config); DatabaseRepository repo = new DatabaseRepository(new ConnectionManager(config), config);
Router<PeerAtUser> router = new Router<PeerAtUser>() Router<PeerAtUser> router = new Router<PeerAtUser>()
.configureJwt(
(builder) -> builder.setExpectedIssuer(config.getTokenIssuer()),
(claims) -> {
claims.setIssuer(config.getTokenIssuer()); // who creates the token and signs it
claims.setExpirationTimeMinutesInTheFuture(config.getTokenExpiration());
},
(claims) -> new PeerAtUser(claims))
.activeReOrdering(). .activeReOrdering().
addDefaultHeaders(RequestType.GET, "Access-Control-Allow-Origin: *"). addDefaultHeaders(RequestType.GET, "Access-Control-Allow-Origin: *").
addDefaultHeaders(RequestType.POST, "Access-Control-Allow-Origin: *"). addDefaultHeaders(RequestType.POST, "Access-Control-Allow-Origin: *").
@ -67,6 +50,38 @@ public class Main{
"Access-Control-Allow-Origin: *", "Access-Control-Allow-Origin: *",
"Access-Control-Allow-Methods: *", "Access-Control-Allow-Methods: *",
"Access-Control-Allow-Headers: *"); "Access-Control-Allow-Headers: *");
ACCESS_ROUTER = router;
Authenticator<PeerAtUser> auth;
if(config.getJwtKey() != null){
JsonParser parser = new JsonParser();
JsonMap json = parser.parse(config.getJwtKey());
Map<String, Object> params = new HashMap<>();
for(Entry<String, Object> entry : json.entries()) params.put(entry.getKey(), entry.getValue());
auth = new JwtAuthenticator<PeerAtUser>().configure(
(builder) -> builder.setExpectedIssuer(config.getTokenIssuer()),
(claims) -> {
claims.setIssuer(config.getTokenIssuer());
claims.setExpirationTimeMinutesInTheFuture(config.getTokenExpiration());
},
(claims) -> new PeerAtUser(claims),
params);
}else{
auth = new JwtAuthenticator<PeerAtUser>().configure(
(builder) -> builder.setExpectedIssuer(config.getTokenIssuer()),
(claims) -> {
claims.setIssuer(config.getTokenIssuer());
claims.setExpirationTimeMinutesInTheFuture(config.getTokenExpiration());
},
(claims) -> new PeerAtUser(claims));
JsonMap json = new JsonMap();
for(Entry<String, Object> entry : ((JwtAuthenticator<PeerAtUser>)auth).exportKey().entrySet()){
json.set(entry.getKey(), entry.getValue());
}
config.setJwtKey(json.toString());
config.save();
}
router.setAuthenticator(auth);
router.setDefault((matcher, context, reader, writer) -> { router.setDefault((matcher, context, reader, writer) -> {
context.response(404); context.response(404);
@ -78,11 +93,32 @@ public class Main{
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception {
context.response(200); context.response(200);
} }
}); });
initRoutes(router, repo, config); initRoutes(router, repo, config);
router.addInterceptor(new RouteInterceptor(){
@Override
public boolean intercept(Matcher matcher, Context context, HttpReader reader, HttpWriter writer, Method method){
if(method.getDeclaringClass().getPackage().getName().contains(".admins")){
try {
Group group = repo.getGroupRepository().getPlayerGroup(context.<PeerAtUser>getUser().getId(), 1);
if(!group.getName().equalsIgnoreCase("Quarter-Master - Battles PAC x CEI")){
context.response(401);
return false;
}
}catch(Exception ex){
ex.printStackTrace();
try{
context.response(401);
}catch(Exception e){}
return false;
}
}
return true;
}
});
new Thread(new Runnable(){ new Thread(new Runnable(){
public void run(){ public void run(){
Key key = new Key(); Key key = new Key();
@ -95,7 +131,7 @@ public class Main{
locker.lock(key); locker.lock(key);
Context instance = locker.getValue(key); Context instance = locker.getValue(key);
if(instance == null) continue; if(instance == null) continue;
System.out.println("["+((instance.isLogged()) ? repo.getPlayer(instance.<PeerAtUser>getUser().getId()).getPseudo() : "?")+"] "+instance.getType()+" "+instance.getPath()+" -> "+instance.getResponseCode()); System.out.println("["+((instance.isLogged()) ? repo.getPlayerRepository().getPlayer(instance.<PeerAtUser>getUser().getId()).getPseudo() : "?")+"] "+instance.getType()+" "+instance.getPath()+" -> "+instance.getResponseCode());
} }
}catch(Exception e){ }catch(Exception e){
e.printStackTrace(); e.printStackTrace();
@ -103,47 +139,37 @@ public class Main{
locker.remove(key); locker.remove(key);
} }
}).start(); }).start();
new Thread(new Runnable(){
public void run(){
Key key = new Key();
Locker<Throwable> locker = router.getExceptionLogger();
locker.init(key);
try {
while(true){
locker.lock(key);
locker.getValue(key).printStackTrace();
}
}catch(Exception e){
e.printStackTrace();
}
locker.remove(key);
}
}).start();
if(config.useSsl()) router.configureSSL(config.getSslKeystore(), config.getSslKeystorePasswd()); if(config.useSsl()) router.configureSSL(config.getSslKeystore(), config.getSslKeystorePasswd());
router.listen(config.getTcpPort(), config.useSsl()); router.listen(config.getTcpPort(), config.useSsl());
} }
private static void initRoutes(Router<PeerAtUser> router, DatabaseRepository repo, Configuration config) throws Exception{ private static void initRoutes(Router<PeerAtUser> router, DatabaseRepository repo, Configuration config) throws Exception{
Map<String, Integer> playersWaiting = new HashMap<>(); router.registerPackages("dev.peerat.backend.routes",new DependencyInjector()
Mail mail = config.getMail(); .of(repo, router, config, new RouteExtracter(router), config.getMail())
Locker<Group> groupLock = new Locker<>(); .of("waitting", new HashMap<>())
Locker<Completion> leaderboard = new Locker<>(); .of("leaderboard", new Locker<>())
.of("groups", new Locker<>())
if(config.isProduction()) .of("groupMessages", new Locker<>()));
router.
register(new Register(repo, playersWaiting, mail)).
register(new MailConfirmation(repo, router, config.getUsersFiles(), config.getGitToken(), playersWaiting, mail));
router.
register(new Login(repo, router)).
register(new ProfileSettings(repo)).
register(new ChangePassword(repo)).
register(new ForgotPassword(router, repo, mail)).
register(new DynamicLogs(router.getLogger(), repo)).
register(new ChapterElement(repo)).
register(new ChapterList(repo)).
register(new PuzzleElement(repo)).
register(new Result(repo)).
register(new Leaderboard(repo)).
register(new PlayerDetails(repo)).
register(new BadgeDetails(repo)).
register(new DynamicLeaderboard(repo, leaderboard)).
register(new PuzzleResponse(repo, config.getUsersFiles(), leaderboard)).
register(new GroupCreate(repo, groupLock, config.getGroupJoinMinutes())).
register(new GroupList(repo)).
register(new GroupJoin(repo, config.getGroupJoinMinutes(), config.getGroupQuitMinutes(), leaderboard)).
register(new GroupQuit(repo, config.getGroupJoinMinutes(), leaderboard))
.register(new Swagger(new RouteExtracter(router),config.getTokenIssuer()));
// Bot bot = new Bot(config, repo, groupLock); // Bot bot = new Bot(config, repo, groupLock);
// bot.start(); // bot.start();

View file

@ -38,7 +38,7 @@ public class Bot extends Thread{
locker.init(key); locker.init(key);
List<Group> groups = this.repo.getAllGroups(); List<Group> groups = this.repo.getGroupRepository().getAllGroups();
for(Group group : groups){ for(Group group : groups){
Integer chapter = group.getLinkToChapter(); Integer chapter = group.getLinkToChapter();
// Integer puzzle = group.getLinkToPuzzle(); // Integer puzzle = group.getLinkToPuzzle();

View file

@ -15,6 +15,7 @@ public class Group implements Comparable<Group> {
private Integer linkToChapter; private Integer linkToChapter;
// private Integer linkToPuzzle; // private Integer linkToPuzzle;
private List<Player> players; private List<Player> players;
private int playerCount;
@Override @Override
public String toString(){ public String toString(){
@ -29,10 +30,15 @@ public class Group implements Comparable<Group> {
// this.linkToPuzzle = ((Number) json.get("puzzle")).intValue(); // this.linkToPuzzle = ((Number) json.get("puzzle")).intValue();
} }
public Group(String name, Integer initChap, Integer initPuzz) { public Group(String name, Integer initChap, Integer initPuzz, int playerCount) {
this.name = name; this.name = name;
this.linkToChapter = initChap; this.linkToChapter = initChap;
// this.linkToPuzzle = initPuzz; // this.linkToPuzzle = initPuzz;
this.playerCount = playerCount;
}
public int getPlayerCount(){
return this.playerCount;
} }
@SeaBottle @SeaBottle
@ -113,6 +119,7 @@ public class Group implements Comparable<Group> {
} }
groupJSON.put("players", groupsPlayerJSON); groupJSON.put("players", groupsPlayerJSON);
} }
groupJSON.put("playerCount", this.playerCount);
return groupJSON; return groupJSON;
} }

View file

@ -0,0 +1,30 @@
package dev.peerat.backend.model;
import dev.peerat.framework.utils.json.JsonMap;
public class Tag{
private int id;
private String name;
public Tag(int id, String name){
this.id = id;
this.name = name;
}
public int getId(){
return this.id;
}
public String getName(){
return this.name;
}
public JsonMap toJson(){
JsonMap result = new JsonMap();
result.set("id", id);
result.set("name", name);
return result;
}
}

View file

@ -0,0 +1,114 @@
package dev.peerat.backend.repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Badge;
import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.model.Completion;
import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.Player;
import dev.peerat.backend.model.Puzzle;
public class BaseDatabaseQuery{
private ConnectionManager con;
private Configuration config;
public BaseDatabaseQuery(ConnectionManager con){
this.con = con;
}
public Connection ensureConnection() throws SQLException{
return this.con.ensureConnection();
}
public PreparedStatement prepare(String request) throws SQLException{
return this.con.ensureConnection().prepareStatement(request);
}
public Puzzle makePuzzle(ResultSet puzzleResult) throws SQLException {
return new Puzzle(puzzleResult.getInt("id_puzzle"), puzzleResult.getString("name"),
puzzleResult.getString("content"), puzzleResult.getBytes("soluce"), puzzleResult.getString("verify"),
puzzleResult.getInt("score_max"), puzzleResult.getString("tags"),
hasColumn(puzzleResult, "origin") ? puzzleResult.getInt("origin") : -1,
puzzleResult.getTimestamp("start_date"));
}
public Chapter makeChapter(ResultSet chapterResult) throws SQLException {
return new Chapter(chapterResult.getInt("id_chapter"), chapterResult.getString("name"),
chapterResult.getTimestamp("start_date"), chapterResult.getTimestamp("end_date"));
}
public Completion makeCompletion(ResultSet completionResult) throws SQLException {
String fileName = null;
if (hasColumn(completionResult, "fileName"))
fileName = completionResult.getString("fileName");
String puzzleName = null;
if (hasColumn(completionResult, "name"))
puzzleName = completionResult.getString("name");
return new Completion(completionResult.getInt("fk_player"), completionResult.getInt("fk_puzzle"), completionResult.getInt("tries"),
fileName, completionResult.getInt("score"), puzzleName);
}
public Player makePlayer(ResultSet playerResult, int id) throws SQLException {
Player p = new Player(playerResult.getString("pseudo"), playerResult.getString("email"),
playerResult.getString("firstName"), playerResult.getString("lastName"));
if (hasColumn(playerResult, "avatar")) {
p.setAvatar(playerResult.getBytes("avatar"));
}
if (hasColumn(playerResult, "score")) {
p.addCompletion(new Completion(playerResult.getInt("tries"), playerResult.getInt("score")));
for (int ct = 1; ct < playerResult.getInt("completions"); ct++)
{ // TODO refactor for V3
p.addCompletion(new Completion(0, 0));
}
}
if (hasColumn(playerResult, "name")) {
// Manage groups
String groupName = playerResult.getString("name");
if (groupName != null) {
p.addGroup(makeGroup(playerResult));
}
}
// ADD rank
PreparedStatement completionsStmt = con.ensureConnection().prepareStatement(DatabasePlayerRepository.GET_PLAYER_RANK());
completionsStmt.setInt(1, id);
ResultSet result = completionsStmt.executeQuery();
while (result.next()) {
p.setRank(result.getInt("rank"));
}
return p;
}
public Group makeGroup(ResultSet result) throws SQLException {
return new Group(result.getString("name"), result.getInt("fk_chapter"), result.getInt("fk_puzzle"), ((hasColumn(result, "countPlayer")) ? result.getInt("countPlayer") : 0));
}
public Player makeGroupPlayer(ResultSet result) throws SQLException {
return new Player(result.getString("pseudo"), result.getInt("score"), result.getInt("tries"));
}
public Badge makeBadge(ResultSet rs) throws SQLException {
return new Badge(rs.getString("name"), rs.getBytes("logo"), rs.getInt("level"));
}
public boolean hasColumn(ResultSet rs, String columnName) throws SQLException {
// Found on StackOverflow
ResultSetMetaData rsmd = rs.getMetaData();
int columns = rsmd.getColumnCount();
for (int x = 1; x <= columns; x++) {
if (columnName.equals(rsmd.getColumnName(x)))
return true;
}
return false;
}
}

View file

@ -0,0 +1,26 @@
package dev.peerat.backend.repository;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import dev.peerat.backend.Configuration;
public class ConnectionManager {
private Connection con;
private Configuration config;
public ConnectionManager(Configuration config){
this.config = config;
}
public Connection ensureConnection() throws SQLException {
if (con == null || (!con.isValid(5))) {
this.con = DriverManager.getConnection(
"jdbc:mysql://" + config.getDbHost() + ":" + config.getDbPort() + "/" + config.getDbDatabase() + "",
config.getDbUser(), config.getDbPassword());
}
return this.con;
}
}

View file

@ -0,0 +1,194 @@
package dev.peerat.backend.repository;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.model.Puzzle;
import dev.peerat.backend.model.Tag;
public class DatabaseAdminRepository extends BaseDatabaseQuery{
private static enum Query{
//ADMIN
ADD_CHAPTER("INSERT INTO chapters (name, start_date, end_date) VALUES (?,?,?)"),
DELETE_CHAPTER("DELETE FROM chapters WHERE id_chapter = ?"),
EDIT_CHAPTER("UPDATE chapters SET name = ?, start_date = ?, end_date = ? WHERE id_chapter = ?"),
GET_CHAPTER("SELECT * FROM chapters WHERE id_chapter = ?"),
ADD_PUZZLE("INSERT INTO puzzles (name, content, soluce, verify, score_max, fk_chapter) VALUES (?,?,?,?,?,?)"),
DELETE_PUZZLE("DELETE FROM puzzles WHERE id_puzzle = ?"),
EDIT_PUZZLE("UPDATE puzzles SET name = ?, content = ?, soluce = ?, verify = ?, score_max = ?, fk_chapter = ? WHERE id_puzzle = ?"),
GET_PUZZLE("SELECT p.*, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag WHERE p.id_puzzle = ? GROUP BY p.id_puzzle"),
GET_PUZZLES("SELECT p.*, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag GROUP BY p.id_puzzle"),
ADD_TAG("INSERT INTO tags (name) VALUES (?)"),
DELETE_TAG("DELETE FROM tags WHERE id_tag = ?"),
EDIT_TAG("UPDATE tags SET name = ? WHERE id_tag = ?"),
GET_TAGS("SELECT * FROM tags");
private String request;
Query(Query parent, String request) {
this.request = parent.request + request;
}
Query(String request) {
this.request = request;
}
public PreparedStatement prepare(BaseDatabaseQuery base) throws SQLException {
return base.prepare(this.request);
}
@Override
public String toString() {
return this.request;
}
}
private Configuration config;
public DatabaseAdminRepository(ConnectionManager con, Configuration config){
super(con);
this.config = config;
}
//ADMIN
public Chapter getAdminChapter(int id){
try {
PreparedStatement chapterStmt = Query.GET_CHAPTER.prepare(this);
chapterStmt.setInt(1, id);
ResultSet chapterResult = chapterStmt.executeQuery();
if (chapterResult.next()) {
Chapter chapter = makeChapter(chapterResult);
return chapter;
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public Puzzle getAdminPuzzle(int id){
try {
PreparedStatement chapterStmt = Query.GET_PUZZLE.prepare(this);
chapterStmt.setInt(1, id);
ResultSet chapterResult = chapterStmt.executeQuery();
if (chapterResult.next()) {
return makePuzzle(chapterResult);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public List<Puzzle> getAdminPuzzles(){
try {
PreparedStatement chapterStmt = Query.GET_PUZZLES.prepare(this);
ResultSet chapterResult = chapterStmt.executeQuery();
List<Puzzle> list = new ArrayList<>();
while(chapterResult.next()){
list.add(makePuzzle(chapterResult));
}
return list;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public List<Tag> getAdminTags(){
try {
PreparedStatement chapterStmt = Query.GET_TAGS.prepare(this);
ResultSet chapterResult = chapterStmt.executeQuery();
List<Tag> list = new ArrayList<>();
while(chapterResult.next()){
list.add(new Tag(chapterResult.getInt("id_tag"), chapterResult.getString("name")));
}
return list;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public boolean adminAddChapter(Chapter chapter) throws SQLException {
PreparedStatement statement = Query.ADD_CHAPTER.prepare(this);
statement.setString(1, chapter.getName());
statement.setTimestamp(2, chapter.getStartDate());
statement.setTimestamp(3, chapter.getEndDate());
return (statement.executeUpdate() >= 0);
}
public boolean adminAddPuzzle(Puzzle puzzle, int chapter) throws SQLException {
PreparedStatement statement = Query.ADD_PUZZLE.prepare(this);
statement.setString(1, puzzle.getName());
statement.setString(2, puzzle.getContent());
statement.setBytes(3, puzzle.getSoluce());
statement.setString(4, "");
statement.setInt(5, puzzle.getScoreMax());
statement.setInt(6, chapter);
return (statement.executeUpdate() >= 0);
}
public boolean adminAddTag(String name) throws SQLException {
PreparedStatement statement = Query.ADD_TAG.prepare(this);
statement.setString(1, name);
return (statement.executeUpdate() >= 0);
}
public boolean adminUpdateChapter(int id, Chapter chapter) throws SQLException {
PreparedStatement statement = Query.EDIT_CHAPTER.prepare(this);
statement.setString(1, chapter.getName());
statement.setTimestamp(2, chapter.getStartDate());
statement.setTimestamp(3, chapter.getEndDate());
statement.setInt(4, id);
return (statement.executeUpdate() >= 0);
}
public boolean adminUpdatePuzzle(int id, Puzzle puzzle, int chapter) throws SQLException {
PreparedStatement statement = Query.EDIT_PUZZLE.prepare(this);
statement.setString(1, puzzle.getName());
statement.setString(2, puzzle.getContent());
statement.setBytes(3, puzzle.getSoluce());
statement.setString(4, "");
statement.setInt(5, puzzle.getScoreMax());
statement.setInt(6, chapter);
statement.setInt(7, id);
return (statement.executeUpdate() >= 0);
}
public boolean adminUpdateTag(Tag tag) throws SQLException {
PreparedStatement statement = Query.EDIT_TAG.prepare(this);
statement.setString(1, tag.getName());
statement.setInt(2, tag.getId());
return (statement.executeUpdate() >= 0);
}
public boolean adminDeleteChapter(int id) throws SQLException {
PreparedStatement statement = Query.DELETE_CHAPTER.prepare(this);
statement.setInt(1, id);
return (statement.executeUpdate() >= 0);
}
public boolean adminDeletePuzzle(int id) throws SQLException {
PreparedStatement statement = Query.DELETE_PUZZLE.prepare(this);
statement.setInt(1, id);
return (statement.executeUpdate() >= 0);
}
public boolean adminDeleteTag(int id) throws SQLException {
PreparedStatement statement = Query.DELETE_TAG.prepare(this);
statement.setInt(1, id);
return (statement.executeUpdate() >= 0);
}
}

View file

@ -0,0 +1,167 @@
package dev.peerat.backend.repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.password4j.Password;
import dev.peerat.backend.Configuration;
public class DatabaseAuthRepository extends BaseDatabaseQuery{
private static enum Query{
// REGISTER
CHECK_PSEUDO_AVAILABLE_QUERY("SELECT * FROM players WHERE pseudo = ?"),
CHECK_EMAIL_AVAILABLE_QUERY("SELECT * FROM players WHERE email = ?"),
REGISTER_QUERY(
"INSERT INTO players (pseudo, email, passwd, firstname, lastname, description, avatar) VALUES (?, ?, ?, ?, ?, ?, ?)"),
REGISTER_PLAYER_IN_EXISTING_GROUP(
"INSERT INTO containsGroups (fk_player, fk_group) VALUES (?, (SELECT id_group FROM groups WHERE name = ?));"),
// LOGIN
CHECK_PASSWORD("SELECT id_player, passwd FROM players WHERE pseudo=?");
private String request;
Query(Query parent, String request) {
this.request = parent.request + request;
}
Query(String request) {
this.request = request;
}
public PreparedStatement prepare(BaseDatabaseQuery base) throws SQLException {
return base.prepare(this.request);
}
@Override
public String toString() {
return this.request;
}
}
private Configuration config;
public DatabaseAuthRepository(ConnectionManager con, Configuration config){
super(con);
this.config = config;
}
/**
* Check if a pseudo is available
*
* @param pseudo The pseudo to check
* @return True if the pseudo is available, false if it's already taken
*/
public boolean checkPseudoAvailability(String pseudo) {
return checkAvailability(pseudo, Query.CHECK_PSEUDO_AVAILABLE_QUERY.toString());
}
/**
* Check if an email is available
*
* @param email The email to check
* @return True if the email is available, false if it's already taken
*/
public boolean checkEmailAvailability(String email) {
return checkAvailability(email, Query.CHECK_EMAIL_AVAILABLE_QUERY.toString());
}
private boolean checkAvailability(String queriedString, String correspondingQuery) {
try {
PreparedStatement statement = prepare(correspondingQuery);
statement.setString(1, queriedString);
ResultSet result = statement.executeQuery();
return !result.next();
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
/**
* Register a new user
*
* @param pseudo The pseudo of the user
* @param email The email of the user
* @param password The password of the user
* @param firstname The firstname of the user
* @param lastname The lastname of the user
* @param description The description of the user
* @param sgroup The group of the user
* @param avatar The avatar of the user
* @return True if the user was registered, false if an error occurred
*/
public int register(String pseudo, String email, String password, String firstname, String lastname,
String description, String sgroup, String avatar) {
try {
String pass = Password.hash(password).withArgon2().getResult();
System.out.println("pass("+pass.length()+") "+pass);
Connection con = ensureConnection();
con.setAutoCommit(false);
try (PreparedStatement playerStatement = con.prepareStatement(Query.REGISTER_QUERY.toString(),
Statement.RETURN_GENERATED_KEYS)) {
playerStatement.setString(1, pseudo);
playerStatement.setString(2, email);
playerStatement.setString(3, Password.hash(password).withArgon2().getResult());
playerStatement.setString(4, firstname);
playerStatement.setString(5, lastname);
playerStatement.setString(6, description);
playerStatement.setString(7, avatar);
if (playerStatement.executeUpdate() == 1) {
ResultSet inserted = playerStatement.getGeneratedKeys();
if (inserted.next()) {
int newPlayerId = inserted.getInt(1);
if (!sgroup.isEmpty()) {
try (PreparedStatement containsGroupsStatement = con
.prepareStatement(Query.REGISTER_PLAYER_IN_EXISTING_GROUP.toString())) {
containsGroupsStatement.setInt(1, newPlayerId);
containsGroupsStatement.setString(2, sgroup);
containsGroupsStatement.executeUpdate();
}
}
con.commit();
con.setAutoCommit(true);
return newPlayerId;
}
}
} catch (SQLException e) {
con.rollback();
con.setAutoCommit(true);
e.printStackTrace();
}
} catch (SQLException e) {
e.printStackTrace();
}
return -1;
}
/**
* Login a user
*
* @param username The username of the user
* @param password The password of the user
* @return id the id of the user, -1 if not login successefuly
*/
public int login(String username, String password) {
try {
ensureConnection();
PreparedStatement statement = prepare(Query.CHECK_PASSWORD.toString());
statement.setString(1, username);
ResultSet result = statement.executeQuery();
if (result.next()) {
String hashedPassword = result.getString("passwd");
if (Password.check(password, hashedPassword).withArgon2())
return result.getInt("id_player");
}
} catch (SQLException e) {
}
return -1;
}
}

View file

@ -0,0 +1,69 @@
package dev.peerat.backend.repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Badge;
import dev.peerat.backend.model.Puzzle;
public class DatabaseBadgeRepository extends BaseDatabaseQuery{
public static String GET_BADGES_OF_PLAYER(){
return Query.GET_BADGES_OF_PLAYER.request;
}
private static enum Query{
// BADGES
GET_BADGE("SELECT * FROM badges WHERE id_badge = ?"),
GET_BADGES_OF_PLAYER(
"SELECT * FROM badges b LEFT JOIN containsBadges cb ON cb.fk_badge = b.id_badge WHERE cb.fk_player = ?");
private String request;
Query(Query parent, String request) {
this.request = parent.request + request;
}
Query(String request) {
this.request = request;
}
public PreparedStatement prepare(BaseDatabaseQuery base) throws SQLException {
return base.prepare(this.request);
}
@Override
public String toString() {
return this.request;
}
}
private Configuration config;
public DatabaseBadgeRepository(ConnectionManager con, Configuration config){
super(con);
this.config = config;
}
public Badge getBadge(int badgeId) {
try {
ensureConnection();
PreparedStatement completionsStmt = Query.GET_BADGE.prepare(this);
completionsStmt.setInt(1, badgeId);
ResultSet result = completionsStmt.executeQuery();
if (result.next()) {
return makeBadge(result);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}

View file

@ -0,0 +1,122 @@
package dev.peerat.backend.repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.model.Puzzle;
public class DatabaseChapterRepository extends BaseDatabaseQuery{
private static enum Query{
// CHAPTERS
SPECIFIC_CHAPTER_QUERY("SELECT * FROM chapters WHERE id_chapter = ?"),
CHAPTER_FROM_PUZZLE("SELECT c.*\r\n"
+ "FROM chapters c\r\n"
+ "JOIN puzzles p ON p.fk_chapter = c.id_chapter\r\n"
+ "WHERE p.id_puzzle = ?"),
ALL_CHAPTERS_QUERY("SELECT * FROM chapters WHERE id_chapter > 0");
private String request;
Query(Query parent, String request) {
this.request = parent.request + request;
}
Query(String request) {
this.request = request;
}
public PreparedStatement prepare(BaseDatabaseQuery base) throws SQLException {
return base.prepare(this.request);
}
@Override
public String toString() {
return this.request;
}
}
private Configuration config;
private DatabasePuzzleRepository puzzleRepo;
public DatabaseChapterRepository(ConnectionManager con, Configuration config, DatabasePuzzleRepository puzzleRepo){
super(con);
this.config = config;
this.puzzleRepo = puzzleRepo;
}
/**
* Get a specific chapter
*
* @param id The id of the chapter
* @return The chapter or null if an error occurred
*/
public Chapter getChapter(int id) {
try {
ensureConnection();
PreparedStatement chapterStmt = Query.SPECIFIC_CHAPTER_QUERY.prepare(this);
chapterStmt.setInt(1, id);
ResultSet chapterResult = chapterStmt.executeQuery();
if (chapterResult.next()) {
Chapter chapter = makeChapter(chapterResult);
List<Puzzle> puzzles = puzzleRepo.getPuzzlesInChapter(id);
chapter.setPuzzles(puzzles);
return chapter;
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public Chapter getChapter(Puzzle puzzle){
try {
ensureConnection();
PreparedStatement chapterStmt = Query.CHAPTER_FROM_PUZZLE.prepare(this);
chapterStmt.setInt(1, puzzle.getId());
ResultSet chapterResult = chapterStmt.executeQuery();
if (chapterResult.next()) {
Chapter chapter = makeChapter(chapterResult);
List<Puzzle> puzzles = puzzleRepo.getPuzzlesInChapter(chapter.getId());
chapter.setPuzzles(puzzles);
return chapter;
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* Get all chapters in the database
*
* @return List of all chapters or null if an error occurred
*/
public List<Chapter> getAllChapters() {
try {
List<Chapter> chapterList = new ArrayList<>();
ensureConnection();
PreparedStatement chapterStmt = Query.ALL_CHAPTERS_QUERY.prepare(this);
ResultSet chapterResult = chapterStmt.executeQuery();
while (chapterResult.next()) {
Chapter chapter = makeChapter(chapterResult);
chapter.setPuzzles(puzzleRepo.getPuzzlesInChapter(chapter.getId()));
chapterList.add(chapter);
}
return chapterList;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}

View file

@ -0,0 +1,162 @@
package dev.peerat.backend.repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Completion;
import dev.peerat.backend.model.Puzzle;
public class DatabaseCompletionRepository extends BaseDatabaseQuery{
private static enum Query{
// COMPLETIONS
GET_COMPLETION(
"SELECT * FROM completions WHERE fk_puzzle = ? AND fk_player = ?"),
GET_COMPLETION_GROUP("SELECT c.*\r\n"
+ "FROM completions c\r\n"
+ "WHERE c.fk_puzzle = ? AND c.fk_player IN\r\n"
+ "(select f.fk_player FROM containsGroups cgs JOIN containsGroups f ON f.fk_group = cgs.fk_group JOIN groups g ON g.id_group = cgs.fk_group WHERE g.fk_chapter = 12 AND cgs.fk_player = ?)"),
INSERT_COMPLETION(
"INSERT INTO completions (fk_puzzle, fk_player, tries, code, fileName, score) values (?, ?, ?, ?, ?, ?)"),
UPDATE_COMPLETION(
"UPDATE completions SET tries = ?, score = ?, fk_player = ? WHERE fk_puzzle = ? AND fk_player = ?"),
SCORE("SELECT score FROM completions WHERE fk_player = ? AND fk_puzzle = ?"),
SCORE_GROUP("SELECT c.score\r\n"
+ "FROM completions c\r\n"
+ "WHERE c.fk_puzzle = ? AND c.fk_player IN\r\n"
+ "(select f.fk_player FROM containsGroups cgs JOIN containsGroups f ON f.fk_group = cgs.fk_group JOIN groups g ON g.id_group = cgs.fk_group WHERE g.fk_chapter = 12 AND cgs.fk_player = ?)");
private String request;
Query(Query parent, String request) {
this.request = parent.request + request;
}
Query(String request) {
this.request = request;
}
public PreparedStatement prepare(BaseDatabaseQuery base) throws SQLException {
return base.prepare(this.request);
}
@Override
public String toString() {
return this.request;
}
}
private Configuration config;
private DatabaseChapterRepository chapterRepo;
public DatabaseCompletionRepository(ConnectionManager con, Configuration config, DatabaseChapterRepository chapterRepo){
super(con);
this.config = config;
this.chapterRepo = chapterRepo;
}
public Completion getCompletionGroup(int user, int puzzle) {
try {
PreparedStatement stmt = Query.GET_COMPLETION_GROUP.prepare(this);
stmt.setInt(1, puzzle);
stmt.setInt(2, user);
ResultSet result = stmt.executeQuery();
if (result.next())
return makeCompletion(result);
} catch (SQLException e) {
e.printStackTrace();
}
return getCompletion(user, puzzle);
}
public Completion getCompletion(int playerId, int puzzleId) {
try {
PreparedStatement completionsStmt = Query.GET_COMPLETION.prepare(this);
completionsStmt.setInt(1, puzzleId);
completionsStmt.setInt(2, playerId);
ResultSet result = completionsStmt.executeQuery();
if (result.next()) {
return makeCompletion(result);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public Completion insertOrUpdatePuzzleResponse(int puzzleId, int userId, String fileName, byte[] code,
byte[] response, Puzzle currentPuzzle){
try {
ensureConnection();
Completion completion = getCompletionGroup(userId, puzzleId);
if (completion == null){
System.out.println("Completion is null");
completion = new Completion(userId, puzzleId, fileName, code, response, currentPuzzle);
insertCompletion(completion);
} else {
System.out.println(completion);
completion.addTry(currentPuzzle, response, chapterRepo.getChapter(currentPuzzle).getId());
int lastUserId = completion.getPlayerId();
completion.updatePlayer(userId);
updateCompletion(completion, lastUserId);
}
return completion;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
private void insertCompletion(Completion newCompletion) throws SQLException {
PreparedStatement statement = Query.INSERT_COMPLETION.prepare(this);
statement.setInt(1, newCompletion.getPuzzleId());
statement.setInt(2, newCompletion.getPlayerId());
statement.setInt(3, newCompletion.getTries());
statement.setBytes(4, newCompletion.getCode());
statement.setString(5, newCompletion.getFileName());
statement.setInt(6, newCompletion.getScore());
statement.executeUpdate();
}
private void updateCompletion(Completion completionToUpdate, int user) throws SQLException{
System.out.println("update "+completionToUpdate);
PreparedStatement statement = Query.UPDATE_COMPLETION.prepare(this);
statement.setInt(1, completionToUpdate.getTries());
statement.setInt(2, completionToUpdate.getScore());
statement.setInt(3, completionToUpdate.getPlayerId());
statement.setInt(4, completionToUpdate.getPuzzleId());
statement.setInt(5, user);
statement.executeUpdate();
}
public int getScore(int user, int puzzle) {
try {
ensureConnection();
PreparedStatement stmt = Query.SCORE_GROUP.prepare(this);
stmt.setInt(1, puzzle);
stmt.setInt(2, user);
ResultSet result = stmt.executeQuery();
if (result.next())
return result.getInt("score");
stmt = Query.SCORE.prepare(this);
stmt.setInt(1, user);
stmt.setInt(2, puzzle);
result = stmt.executeQuery();
if (result.next())
return result.getInt("score");
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
}

View file

@ -0,0 +1,166 @@
package dev.peerat.backend.repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.PeerAtUser;
public class DatabaseGroupRepository extends BaseDatabaseQuery{
private static enum Query{
// GROUPS
ALL_GROUPS("SELECT * FROM groups"),
ALL_GROUPS_BY_CHAPTER("select g.*, count(cg.fk_player) as countPlayer from groups g left join containsGroups cg on cg.fk_group = g.id_group where g.fk_chapter = ? group by g.id_group"),
GET_GROUP_FOR_PLAYER("SELECT g.* FROM groups g JOIN containsGroups cg ON cg.fk_group = g.id_group WHERE cg.fk_player = ? AND g.fk_chapter = ?"), // AND g.fk_puzzle = ?
GET_GROUP_ID_BY_DATA("SELECT id_group FROM groups WHERE name = ? AND (fk_chapter = ?)"), // OR fk_puzzle = ?
GET_GROUP_USERS_COUNT("SELECT count(*) as howmany FROM containsGroups WHERE fk_group = ?"),
INSERT_GROUP("INSERT INTO groups (name, fk_chapter) VALUES (?,?)"),
INSERT_PLAYER_IN_GROUP("INSERT INTO containsGroups (fk_player, fk_group) VALUES (?,?)"),
LEAVE_GROUP("DELETE FROM containsGroups WHERE fk_player = ? AND fk_group = ?");
private String request;
Query(Query parent, String request) {
this.request = parent.request + request;
}
Query(String request) {
this.request = request;
}
public PreparedStatement prepare(BaseDatabaseQuery base) throws SQLException {
return base.prepare(this.request);
}
@Override
public String toString() {
return this.request;
}
}
private Configuration config;
public DatabaseGroupRepository(ConnectionManager con, Configuration config){
super(con);
this.config = config;
}
public List<Group> getAllGroups() {
try {
ensureConnection();
List<Group> list = new ArrayList<>();
PreparedStatement stmt = Query.ALL_GROUPS.prepare(this);
ResultSet groupResult = stmt.executeQuery();
while (groupResult.next())
list.add(makeGroup(groupResult));
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public List<Group> getAllGroupsByChapter(int chapter){
try {
ensureConnection();
List<Group> list = new ArrayList<>();
PreparedStatement stmt = Query.ALL_GROUPS_BY_CHAPTER.prepare(this);
stmt.setInt(1, chapter);
ResultSet groupResult = stmt.executeQuery();
while (groupResult.next())
list.add(makeGroup(groupResult));
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public boolean insertGroup(Group group, PeerAtUser creator) throws SQLException {
Integer groupId = getGroupId(group);
if (groupId == null)
ensureConnection();
PreparedStatement statement = Query.INSERT_GROUP.prepare(this);
statement.setString(1, group.getName());
statement.setObject(2, group.getLinkToChapter());
// statement.setObject(3, group.getLinkToPuzzle());
if (statement.executeUpdate() >= 0)
return insertUserInGroup(group, creator);
return false;
}
public Group getPlayerGroup(int user, Integer chapter) throws SQLException {
ensureConnection();
PreparedStatement stmt = Query.GET_GROUP_FOR_PLAYER.prepare(this);
stmt.setInt(1, user);
stmt.setObject(2, chapter);
// stmt.setObject(3, puzzle);
ResultSet result = stmt.executeQuery();
if (result.next())
return makeGroup(result);
return null;
}
public Integer getGroupId(Group group) throws SQLException {
ensureConnection();
PreparedStatement stmt = Query.GET_GROUP_ID_BY_DATA.prepare(this);
stmt.setString(1, group.getName());
stmt.setObject(2, group.getLinkToChapter());
// stmt.setObject(3, group.getLinkToPuzzle());
ResultSet result = stmt.executeQuery();
if (result.next())
return result.getInt("id_group");
return null;
}
public boolean insertUserInGroup(Group group, PeerAtUser user) throws SQLException{
Integer id = getGroupId(group);
if(id != null){
int howmany = numberInGroup(id);
System.out.println("join group, already have "+howmany);
if(howmany > config.getGroupMaxPlayers()) return false;
}
Group alreadyInGroup = getPlayerGroup(user.getId(), group.getLinkToChapter());
if (id != null && alreadyInGroup == null) {
PreparedStatement stmt = Query.INSERT_PLAYER_IN_GROUP.prepare(this);
stmt.setInt(1, user.getId());
stmt.setInt(2, id);
return stmt.executeUpdate() >= 0;
}
return false;
}
public int numberInGroup(int group) throws SQLException{
PreparedStatement stmt = Query.GET_GROUP_USERS_COUNT.prepare(this);
stmt.setInt(1, group);
ResultSet result = stmt.executeQuery();
if(result.next()) return result.getInt("howmany");
return 0;
}
public boolean leaveGroup(Group group, PeerAtUser user) throws SQLException {
Integer id = getGroupId(group);
if (id != null) {
PreparedStatement stmt = Query.LEAVE_GROUP.prepare(this);
stmt.setInt(1, user.getId());
stmt.setInt(2, id);
return stmt.executeUpdate() >= 0;
}
return false;
}
}

View file

@ -0,0 +1,102 @@
package dev.peerat.backend.repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.Player;
public class DatabaseLeaderboardRepository extends BaseDatabaseQuery{
private static enum Query{
// LEADERBOARD
ALL_PLAYERS_FOR_LEADERBOARD(
"select p.*, scores.*, g.* from players p ,(SELECT fk_player, SUM(c.score) AS score, COUNT(c.id_completion) AS completions, SUM(c.tries) AS tries, rank() over(ORDER BY score DESC) AS rank FROM completions c LEFT JOIN puzzles puzz on puzz.id_puzzle = c.fk_puzzle LEFT JOIN chapters chap on chap.id_chapter = puzz.fk_chapter WHERE chap.id_chapter > 1 GROUP BY c.fk_player) AS scores LEFT JOIN containsGroups cg ON scores.fk_player = cg.fk_player LEFT JOIN groups g ON cg.fk_group = g.id_group WHERE p.id_player = scores.fk_player ORDER BY g.fk_chapter"),
ALL_GROUP_FOR_CHAPTER_LEADERBOARD(
"SELECT g.*, pl.pseudo, co.score, co.tries FROM groups g LEFT JOIN containsGroups cg ON g.id_group = cg.fk_group LEFT JOIN players pl ON cg.fk_player = pl.id_player LEFT JOIN completions co ON pl.id_player = co.fk_player WHERE cg.fk_player IS NOT NULL AND fk_chapter = ? AND (co.fk_puzzle IN (SELECT id_puzzle FROM puzzles puz WHERE puz.fk_chapter = g.fk_chapter) OR co.score IS NULL);");
private String request;
Query(Query parent, String request) {
this.request = parent.request + request;
}
Query(String request) {
this.request = request;
}
public PreparedStatement prepare(BaseDatabaseQuery base) throws SQLException {
return base.prepare(this.request);
}
@Override
public String toString() {
return this.request;
}
}
private Configuration config;
public DatabaseLeaderboardRepository(ConnectionManager con, Configuration config){
super(con);
this.config = config;
}
public SortedSet<Player> getAllPlayerForLeaderboard() {
try {
ensureConnection();
PreparedStatement playersStmt = Query.ALL_PLAYERS_FOR_LEADERBOARD.prepare(this);
ResultSet result = playersStmt.executeQuery();
ArrayList<Player> players = new ArrayList<Player>();
Player tmpPlayer;
while (result.next()) {
tmpPlayer = makePlayer(result, result.getInt("id_player"));
if (!players.contains(tmpPlayer)) {
players.add(tmpPlayer);
} else {
players.get(players.indexOf(tmpPlayer)).addGroup(makeGroup(result));
}
}
return new TreeSet<Player>(players);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public SortedSet<Group> getAllGroupForChapterLeaderboard(int chapterId){
try{
ensureConnection();
PreparedStatement groupsStmt = Query.ALL_GROUP_FOR_CHAPTER_LEADERBOARD.prepare(this);
groupsStmt.setInt(1, chapterId);
ResultSet result = groupsStmt.executeQuery();
List<Group> groups = new ArrayList<Group>();
Group tmpGroup;
while (result.next()) {
tmpGroup = makeGroup(result);
if (tmpGroup != null) {
int gPosition = groups.indexOf(tmpGroup);
if (gPosition < 0) {
tmpGroup.addPlayer(makeGroupPlayer(result));
groups.add(tmpGroup);
} else {
groups.get(gPosition).addPlayer(makeGroupPlayer(result));
}
}
}
return new TreeSet<Group>(groups);
}catch(SQLException e){
e.printStackTrace();
}
return null;
}
}

View file

@ -0,0 +1,191 @@
package dev.peerat.backend.repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.password4j.Password;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Player;
import dev.peerat.backend.model.Puzzle;
public class DatabasePlayerRepository extends BaseDatabaseQuery{
public static String GET_PLAYER_RANK(){
return Query.GET_PLAYER_RANK.request;
}
private static enum Query{
// PLAYERS
GET_PLAYER_SIMPLE("SELECT pseudo, email, firstname, lastname, description FROM players WHERE id_player = ?"),
GET_PLAYER_EMAIL("SELECT id_player FROM players WHERE email = ?"),
GET_PLAYER_PSEUDO("SELECT * FROM players WHERE pseudo = ?"),
GET_PLAYER_DETAILS("SELECT p.*, g.*\r\n"
+ "FROM players p\r\n"
+ "LEFT OUTER JOIN containsGroups cg ON p.id_player = cg.fk_player\r\n"
+ "LEFT OUTER JOIN groups g ON cg.fk_group = g.id_group\r\n"
+ "LEFT OUTER JOIN completions c on p.id_player = c.fk_player\r\n"
+ "WHERE "),
GET_PLAYER_DETAILS_BY_ID(GET_PLAYER_DETAILS, " p.id_player = ? GROUP BY g.name ORDER BY g.fk_chapter, g.fk_puzzle;"),
GET_PLAYER_DETAILS_BY_PSEUDO(GET_PLAYER_DETAILS, "p.pseudo = ? GROUP BY g.name ORDER BY g.fk_chapter, g.fk_puzzle;"),
GET_PLAYER_COMPLETIONS("select c.*, p.name from completions c left join puzzles p on c.fk_puzzle = p.id_puzzle where fk_player = ?;"),
GET_PLAYER_RANK("SELECT * FROM (SELECT fk_player, RANK() OVER(ORDER BY SUM(score) DESC) rank FROM completions c LEFT JOIN puzzles puzz on puzz.id_puzzle = c.fk_puzzle LEFT JOIN chapters chap on chap.id_chapter = puzz.fk_chapter LEFT JOIN players p ON p.id_player = c.fk_player WHERE chap.id_chapter > 1 GROUP BY fk_player ORDER BY rank) AS ranks WHERE ranks.fk_player = ?;"),
UPDATE_PLAYER_INFO("UPDATE players SET pseudo = ?, email = ?, firstname = ?, lastname = ? WHERE id_player = ?"),
UPDATE_PLAYER_PASSWORD("UPDATE players SET passwd = ? WHERE id_player = ?");
private String request;
Query(Query parent, String request) {
this.request = parent.request + request;
}
Query(String request) {
this.request = request;
}
public PreparedStatement prepare(BaseDatabaseQuery base) throws SQLException {
return base.prepare(this.request);
}
@Override
public String toString() {
return this.request;
}
}
private Configuration config;
public DatabasePlayerRepository(ConnectionManager con, Configuration config){
super(con);
this.config = config;
}
public Player getPlayer(int idPlayer) {
try {
PreparedStatement completionsStmt = Query.GET_PLAYER_SIMPLE.prepare(this);
completionsStmt.setInt(1, idPlayer);
ResultSet result = completionsStmt.executeQuery();
if (result.next()) {
return makePlayer(result, idPlayer);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public int getPlayerId(String email){
try {
ensureConnection();
PreparedStatement completionsStmt = Query.GET_PLAYER_EMAIL.prepare(this);
completionsStmt.setString(1, email);
ResultSet result = completionsStmt.executeQuery();
if (result.next()) {
return result.getInt("id_player");
}
} catch (SQLException e) {
e.printStackTrace();
}
return -1;
}
public boolean updatePseudo(int id, Player player, String pseudo){
try{
PreparedStatement statment = Query.GET_PLAYER_PSEUDO.prepare(this);
statment.setString(1, pseudo);
ResultSet result = statment.executeQuery();
if(result.next()) return false;
statment = Query.UPDATE_PLAYER_INFO.prepare(this);
statment.setString(1, pseudo);
statment.setString(2, player.getEmail());
statment.setString(3, player.getFirstname());
statment.setString(4, player.getLastname());
statment.setInt(5, id);
return statment.executeUpdate() > 0;
}catch(Exception e){
e.printStackTrace();
}
return false;
}
public void updateProfile(int id, Player player, String lastname, String firstname){
try{
PreparedStatement statment = Query.UPDATE_PLAYER_INFO.prepare(this);
statment.setString(1, player.getPseudo());
statment.setString(2, player.getEmail());
statment.setString(3, firstname);
statment.setString(4, lastname);
statment.setInt(5, id);
statment.executeUpdate();
}catch(Exception e){
e.printStackTrace();
}
}
public void updatePassword(int id, String password){
try{
PreparedStatement statment = Query.UPDATE_PLAYER_PASSWORD.prepare(this);
statment.setString(1, Password.hash(password).withArgon2().getResult());
statment.setInt(2, id);
statment.executeUpdate();
}catch(Exception e){
e.printStackTrace();
}
}
public Player getPlayerDetails(int idPlayer) {
return getPlayerDetails(idPlayer, null);
}
public Player getPlayerDetails(String pseudoPlayer) {
return getPlayerDetails(-1, pseudoPlayer);
}
private Player getPlayerDetails(int id, String pseudo) {
try {
ensureConnection();
PreparedStatement completionsStmt;
if (pseudo != null) {
completionsStmt = Query.GET_PLAYER_DETAILS_BY_PSEUDO.prepare(this);
completionsStmt.setString(1, pseudo);
} else {
completionsStmt = Query.GET_PLAYER_DETAILS_BY_ID.prepare(this);
completionsStmt.setInt(1, id);
}
ResultSet result = completionsStmt.executeQuery();
Player player = null;
while (result.next()) {
if (player == null) {
id = result.getInt("id_player");
player = makePlayer(result, id);
completionsStmt = prepare(DatabaseBadgeRepository.GET_BADGES_OF_PLAYER());
completionsStmt.setInt(1, id);
ResultSet resultBadges = completionsStmt.executeQuery();
while (resultBadges.next()) {
player.addBadge(makeBadge(resultBadges));
}
} else {
player.addGroup(makeGroup(result));
}
}
// ADD completions
completionsStmt = Query.GET_PLAYER_COMPLETIONS.prepare(this);
completionsStmt.setInt(1, id);
result = completionsStmt.executeQuery();
while (result.next()) {
player.addCompletion(makeCompletion(result));
}
return player;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}

View file

@ -0,0 +1,78 @@
package dev.peerat.backend.repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Puzzle;
public class DatabasePuzzleRepository extends BaseDatabaseQuery{
private static enum Query{
SPECIFIC_PUZZLE_QUERY(
"SELECT p.*, np.origin, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN nextPart np ON p.id_puzzle = np.next LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag WHERE p.id_puzzle = ? GROUP BY p.id_puzzle"),
PUZZLES_IN_CHAPTER_QUERY(
"SELECT p.*, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag WHERE fk_chapter = ? GROUP BY p.id_puzzle");
private String request;
Query(Query parent, String request) {
this.request = parent.request + request;
}
Query(String request) {
this.request = request;
}
public PreparedStatement prepare(BaseDatabaseQuery base) throws SQLException {
return base.prepare(this.request);
}
@Override
public String toString() {
return this.request;
}
}
private Configuration config;
public DatabasePuzzleRepository(ConnectionManager con, Configuration config){
super(con);
this.config = config;
}
public List<Puzzle> getPuzzlesInChapter(int id) throws SQLException {
List<Puzzle> puzzles = new ArrayList<>();
ensureConnection();
PreparedStatement puzzleStmt = Query.PUZZLES_IN_CHAPTER_QUERY.prepare(this);
puzzleStmt.setInt(1, id);
ResultSet puzzleResult = puzzleStmt.executeQuery();
while (puzzleResult.next()) {
puzzles.add(makePuzzle(puzzleResult));
}
return puzzles;
}
/**
* Get a specific puzzle
*
* @param id The id of the puzzle
* @return The puzzle or null if an error occurred
*/
public Puzzle getPuzzle(int id) throws SQLException {
ensureConnection();
PreparedStatement puzzleStmt = Query.SPECIFIC_PUZZLE_QUERY.prepare(this);
puzzleStmt.setInt(1, id);
ResultSet puzzleResult = puzzleStmt.executeQuery();
if (puzzleResult.next()) {
return makePuzzle(puzzleResult);
}
return null;
}
}

View file

@ -5,91 +5,7 @@ import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
public enum DatabaseQuery { public enum DatabaseQuery {
// PUZZLES
SPECIFIC_PUZZLE_QUERY(
"SELECT p.*, np.origin, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN nextPart np ON p.id_puzzle = np.next LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag WHERE p.id_puzzle = ? GROUP BY p.id_puzzle"),
PUZZLES_IN_CHAPTER_QUERY(
"SELECT p.*, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag WHERE fk_chapter = ? GROUP BY p.id_puzzle"),
// CHAPTERS
SPECIFIC_CHAPTER_QUERY("SELECT * FROM chapters WHERE id_chapter = ?"),
CHAPTER_FROM_PUZZLE("SELECT c.*\r\n"
+ "FROM chapters c\r\n"
+ "JOIN puzzles p ON p.fk_chapter = c.id_chapter\r\n"
+ "WHERE p.id_puzzle = ?"),
ALL_CHAPTERS_QUERY("SELECT * FROM chapters WHERE id_chapter > 0"),
// GROUPS
ALL_GROUPS("SELECT * FROM groups"),
GET_GROUP_FOR_PLAYER("SELECT g.* FROM groups g JOIN containsGroups cg ON cg.fk_group = g.id_group WHERE cg.fk_player = ? AND g.fk_chapter = ?"), // AND g.fk_puzzle = ?
GET_GROUP_ID_BY_DATA("SELECT id_group FROM groups WHERE name = ? AND (fk_chapter = ?)"), // OR fk_puzzle = ?
INSERT_GROUP("INSERT INTO groups (name, fk_chapter) VALUES (?,?)"),
INSERT_PLAYER_IN_GROUP("INSERT INTO containsGroups (fk_player, fk_group) VALUES (?,?)"),
LEAVE_GROUP("DELETE FROM containsGroups WHERE fk_player = ? AND fk_group = ?"),
// LEADERBOARD
ALL_PLAYERS_FOR_LEADERBOARD(
"select p.*, scores.*, g.* from players p ,(SELECT fk_player, SUM(c.score) AS score, COUNT(c.id_completion) AS completions, SUM(c.tries) AS tries, rank() over(ORDER BY score DESC) AS rank FROM completions c LEFT JOIN puzzles puzz on puzz.id_puzzle = c.fk_puzzle LEFT JOIN chapters chap on chap.id_chapter = puzz.fk_chapter WHERE chap.id_chapter > 1 GROUP BY c.fk_player) AS scores LEFT JOIN containsGroups cg ON scores.fk_player = cg.fk_player LEFT JOIN groups g ON cg.fk_group = g.id_group WHERE p.id_player = scores.fk_player ORDER BY g.fk_chapter"),
ALL_GROUP_FOR_CHAPTER_LEADERBOARD(
"SELECT g.*, pl.pseudo, co.score, co.tries FROM groups g LEFT JOIN containsGroups cg ON g.id_group = cg.fk_group LEFT JOIN players pl ON cg.fk_player = pl.id_player LEFT JOIN completions co ON pl.id_player = co.fk_player WHERE cg.fk_player IS NOT NULL AND fk_chapter = ? AND (co.fk_puzzle IN (SELECT id_puzzle FROM puzzles puz WHERE puz.fk_chapter = g.fk_chapter) OR co.score IS NULL);"),
// REGISTER
CHECK_PSEUDO_AVAILABLE_QUERY("SELECT * FROM players WHERE pseudo = ?"),
CHECK_EMAIL_AVAILABLE_QUERY("SELECT * FROM players WHERE email = ?"),
REGISTER_QUERY(
"INSERT INTO players (pseudo, email, passwd, firstname, lastname, description, avatar) VALUES (?, ?, ?, ?, ?, ?, ?)"),
REGISTER_PLAYER_IN_EXISTING_GROUP(
"INSERT INTO containsGroups (fk_player, fk_group) VALUES (?, (SELECT id_group FROM groups WHERE name = ?));"),
// LOGIN
CHECK_PASSWORD("SELECT id_player, passwd FROM players WHERE pseudo=?"),
// COMPLETIONS
GET_COMPLETION(
"SELECT * FROM completions WHERE fk_puzzle = ? AND fk_player = ?"),
GET_COMPLETION_GROUP("SELECT c.*\r\n"
+ "FROM completions c\r\n"
+ "JOIN containsGroups cG on c.fk_player = cG.fk_player\r\n"
+ "JOIN containsGroups cGs on cGs.fk_group = cG.fk_group\r\n"
+ "JOIN groups g on cG.fk_group = g.id_group\r\n"
+ "JOIN puzzles p on p.id_puzzle = c.fk_puzzle\r\n"
+ "JOIN chapters ch on ch.id_chapter = p.fk_chapter\r\n"
+ "WHERE ch.id_chapter < 2 AND cGs.fk_player = ? AND p.id_puzzle = ?"),
INSERT_COMPLETION(
"INSERT INTO completions (fk_puzzle, fk_player, tries, code, fileName, score) values (?, ?, ?, ?, ?, ?)"),
UPDATE_COMPLETION(
"UPDATE completions SET tries = ?, score = ?, fk_player = ? WHERE fk_puzzle = ? AND fk_player = ?"),
SCORE("SELECT score FROM completions WHERE fk_player = ? AND fk_puzzle = ?"),
SCORE_GROUP("SELECT c.score\r\n"
+ "FROM completions c\r\n"
+ "JOIN containsGroups cG on c.fk_player = cG.fk_player\r\n"
+ "JOIN containsGroups cGs on cGs.fk_group = cG.fk_group\r\n"
+ "JOIN groups g on cG.fk_group = g.id_group\r\n"
+ "JOIN puzzles p on p.id_puzzle = c.fk_puzzle\r\n"
+ "JOIN chapters ch on ch.id_chapter = p.fk_chapter\r\n"
+ "WHERE ch.id_chapter < 2 AND cGs.fk_player = ? AND p.id_puzzle = ?"),
// PLAYERS
GET_PLAYER_SIMPLE("SELECT pseudo, email, firstname, lastname, description FROM players WHERE id_player = ?"),
GET_PLAYER_EMAIL("SELECT id_player FROM players WHERE email = ?"),
GET_PLAYER_PSEUDO("SELECT * FROM players WHERE pseudo = ?"),
GET_PLAYER_DETAILS("SELECT p.*, g.*\r\n"
+ "FROM players p\r\n"
+ "LEFT OUTER JOIN containsGroups cg ON p.id_player = cg.fk_player\r\n"
+ "LEFT OUTER JOIN groups g ON cg.fk_group = g.id_group\r\n"
+ "LEFT OUTER JOIN completions c on p.id_player = c.fk_player\r\n"
+ "WHERE "),
GET_PLAYER_DETAILS_BY_ID(GET_PLAYER_DETAILS, " p.id_player = ? GROUP BY g.name ORDER BY g.fk_chapter, g.fk_puzzle;"),
GET_PLAYER_DETAILS_BY_PSEUDO(GET_PLAYER_DETAILS, "p.pseudo = ? GROUP BY g.name ORDER BY g.fk_chapter, g.fk_puzzle;"),
GET_PLAYER_COMPLETIONS("select c.*, p.name from completions c left join puzzles p on c.fk_puzzle = p.id_puzzle where fk_player = ?;"),
GET_PLAYER_RANK("SELECT * FROM (SELECT fk_player, RANK() OVER(ORDER BY SUM(score) DESC) rank FROM completions c LEFT JOIN puzzles puzz on puzz.id_puzzle = c.fk_puzzle LEFT JOIN chapters chap on chap.id_chapter = puzz.fk_chapter LEFT JOIN players p ON p.id_player = c.fk_player WHERE chap.id_chapter > 1 GROUP BY fk_player ORDER BY rank) AS ranks WHERE ranks.fk_player = ?;"),
UPDATE_PLAYER_INFO("UPDATE players SET pseudo = ?, email = ?, firstname = ?, lastname = ? WHERE id_player = ?"),
UPDATE_PLAYER_PASSWORD("UPDATE players SET passwd = ? WHERE id_player = ?"),
// BADGES
GET_BADGE("SELECT * FROM badges WHERE id_badge = ?"), GET_BADGES_OF_PLAYER(
"SELECT * FROM badges b LEFT JOIN containsBadges cb ON cb.fk_badge = b.id_badge WHERE cb.fk_player = ?"),
//TRIGGER //TRIGGER
FIRST_TRY("CREATE OR REPLACE TRIGGER FirstTry\r\n" FIRST_TRY("CREATE OR REPLACE TRIGGER FirstTry\r\n"
+ "AFTER INSERT\r\n" + "AFTER INSERT\r\n"

View file

@ -1,695 +1,239 @@
package dev.peerat.backend.repository; package dev.peerat.backend.repository;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.SortedSet; import java.util.Map;
import java.util.TreeSet;
import com.password4j.Password;
import dev.peerat.backend.Configuration; import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Badge;
import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.model.Completion;
import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.model.Player;
import dev.peerat.backend.model.Puzzle;
public class DatabaseRepository { public class DatabaseRepository extends BaseDatabaseQuery{
private Connection con; private Connection con; //refractor chain
private Configuration config; private Configuration config;
private DatabasePuzzleRepository puzzleRepo;
private DatabaseChapterRepository chapterRepo;
private DatabaseAdminRepository adminRepo;
private DatabaseAuthRepository authRepo;
private DatabaseBadgeRepository badgeRepo;
private DatabaseCompletionRepository completionRepo;
private DatabaseGroupRepository groupRepo;
private DatabaseLeaderboardRepository leaderboardRepo;
private DatabasePlayerRepository playerRepo;
public DatabaseRepository(Configuration config) { public DatabaseRepository(ConnectionManager con, Configuration config) throws Exception {
super(con);
this.config = config; this.config = config;
}
private void ensureConnection() throws SQLException {
if (con == null || (!con.isValid(5))) {
this.con = DriverManager.getConnection(
"jdbc:mysql://" + config.getDbHost() + ":" + config.getDbPort() + "/" + config.getDbDatabase() + "",
config.getDbUser(), config.getDbPassword());
}
}
private Puzzle makePuzzle(ResultSet puzzleResult) throws SQLException {
return new Puzzle(puzzleResult.getInt("id_puzzle"), puzzleResult.getString("name"),
puzzleResult.getString("content"), puzzleResult.getBytes("soluce"), puzzleResult.getString("verify"),
puzzleResult.getInt("score_max"), puzzleResult.getString("tags"),
hasColumn(puzzleResult, "origin") ? puzzleResult.getInt("origin") : -1,
puzzleResult.getTimestamp("start_date"));
}
private Chapter makeChapter(ResultSet chapterResult) throws SQLException {
return new Chapter(chapterResult.getInt("id_chapter"), chapterResult.getString("name"),
chapterResult.getTimestamp("start_date"), chapterResult.getTimestamp("end_date"));
}
private Completion makeCompletion(ResultSet completionResult) throws SQLException {
String fileName = null;
if (hasColumn(completionResult, "fileName"))
fileName = completionResult.getString("fileName");
String puzzleName = null;
if (hasColumn(completionResult, "name"))
puzzleName = completionResult.getString("name");
return new Completion(completionResult.getInt("fk_player"), completionResult.getInt("fk_puzzle"), completionResult.getInt("tries"), this.puzzleRepo = new DatabasePuzzleRepository(con, config);
fileName, completionResult.getInt("score"), puzzleName); this.chapterRepo = new DatabaseChapterRepository(con, config, puzzleRepo);
} this.adminRepo = new DatabaseAdminRepository(con, config);
this.authRepo = new DatabaseAuthRepository(con, config);
private Player makePlayer(ResultSet playerResult, int id) throws SQLException { this.badgeRepo = new DatabaseBadgeRepository(con, config);
Player p = new Player(playerResult.getString("pseudo"), playerResult.getString("email"), this.completionRepo = new DatabaseCompletionRepository(con, config, chapterRepo);
playerResult.getString("firstName"), playerResult.getString("lastName")); this.groupRepo = new DatabaseGroupRepository(con, config);
if (hasColumn(playerResult, "avatar")) { this.leaderboardRepo = new DatabaseLeaderboardRepository(con, config);
p.setAvatar(playerResult.getBytes("avatar")); this.playerRepo = new DatabasePlayerRepository(con, config);
}
if (hasColumn(playerResult, "score")) { loadConfig(config);
p.addCompletion(new Completion(playerResult.getInt("tries"), playerResult.getInt("score")));
for (int ct = 1; ct < playerResult.getInt("completions"); ct++)
{ // TODO refactor for V3
p.addCompletion(new Completion(0, 0));
}
}
if (hasColumn(playerResult, "name")) {
// Manage groups
String groupName = playerResult.getString("name");
if (groupName != null) {
p.addGroup(makeGroup(playerResult));
}
}
// ADD rank
PreparedStatement completionsStmt = DatabaseQuery.GET_PLAYER_RANK.prepare(con);
completionsStmt.setInt(1, id);
ResultSet result = completionsStmt.executeQuery();
while (result.next()) {
p.setRank(result.getInt("rank"));
}
return p;
}
private Group makeGroup(ResultSet result) throws SQLException {
return new Group(result.getString("name"), result.getInt("fk_chapter"), result.getInt("fk_puzzle"));
}
private Player makeGroupPlayer(ResultSet result) throws SQLException {
return new Player(result.getString("pseudo"), result.getInt("score"), result.getInt("tries"));
}
private Badge makeBadge(ResultSet rs) throws SQLException {
return new Badge(rs.getString("name"), rs.getBytes("logo"), rs.getInt("level"));
}
private boolean hasColumn(ResultSet rs, String columnName) throws SQLException {
// Found on StackOverflow
ResultSetMetaData rsmd = rs.getMetaData();
int columns = rsmd.getColumnCount();
for (int x = 1; x <= columns; x++) {
if (columnName.equals(rsmd.getColumnName(x)))
return true;
}
return false;
}
private List<Puzzle> getPuzzlesInChapter(int id) throws SQLException {
List<Puzzle> puzzles = new ArrayList<>();
ensureConnection();
PreparedStatement puzzleStmt = DatabaseQuery.PUZZLES_IN_CHAPTER_QUERY.prepare(this.con);
puzzleStmt.setInt(1, id);
ResultSet puzzleResult = puzzleStmt.executeQuery();
while (puzzleResult.next()) {
puzzles.add(makePuzzle(puzzleResult));
}
return puzzles;
}
/**
* Get a specific puzzle
*
* @param id The id of the puzzle
* @return The puzzle or null if an error occurred
*/
public Puzzle getPuzzle(int id) {
try {
ensureConnection();
PreparedStatement puzzleStmt = DatabaseQuery.SPECIFIC_PUZZLE_QUERY.prepare(this.con);
puzzleStmt.setInt(1, id);
ResultSet puzzleResult = puzzleStmt.executeQuery();
if (puzzleResult.next()) {
return makePuzzle(puzzleResult);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public int getScore(int user, int puzzle) {
try {
ensureConnection();
PreparedStatement stmt = DatabaseQuery.SCORE_GROUP.prepare(this.con);
stmt.setInt(1, user);
stmt.setInt(2, puzzle);
ResultSet result = stmt.executeQuery();
if (result.next())
return result.getInt("score");
stmt = DatabaseQuery.SCORE.prepare(this.con);
stmt.setInt(1, user);
stmt.setInt(2, puzzle);
result = stmt.executeQuery();
if (result.next())
return result.getInt("score");
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
public Completion getCompletionGroup(int user, int puzzle) {
try {
PreparedStatement stmt = DatabaseQuery.GET_COMPLETION_GROUP.prepare(this.con);
stmt.setInt(1, user);
stmt.setInt(2, puzzle);
ResultSet result = stmt.executeQuery();
if (result.next())
return makeCompletion(result);
} catch (SQLException e) {
e.printStackTrace();
}
return getCompletion(user, puzzle);
}
public Completion getCompletion(int playerId, int puzzleId) {
try {
PreparedStatement completionsStmt = DatabaseQuery.GET_COMPLETION.prepare(this.con);
completionsStmt.setInt(1, puzzleId);
completionsStmt.setInt(2, playerId);
ResultSet result = completionsStmt.executeQuery();
if (result.next()) {
return makeCompletion(result);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public Player getPlayer(int idPlayer) {
try {
PreparedStatement completionsStmt = DatabaseQuery.GET_PLAYER_SIMPLE.prepare(this.con);
completionsStmt.setInt(1, idPlayer);
ResultSet result = completionsStmt.executeQuery();
if (result.next()) {
return makePlayer(result, idPlayer);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
} }
public int getPlayerId(String email){ private void loadConfig(Configuration config) throws Exception{
try { String name = DatabaseRepository.class.getPackage().getName();
PreparedStatement completionsStmt = DatabaseQuery.GET_PLAYER_EMAIL.prepare(this.con); InputStream stream = ClassLoader.getSystemClassLoader().getResourceAsStream(name.replace(".", "/"));
completionsStmt.setString(1, email); File folder = new File(config.getSqlFolder());
ResultSet result = completionsStmt.executeQuery();
if (result.next()) {
return result.getInt("id_player");
}
} catch (SQLException e) {
e.printStackTrace();
}
return -1;
}
public boolean updatePseudo(int id, Player player, String pseudo){
try{ try{
PreparedStatement statment = DatabaseQuery.GET_PLAYER_PSEUDO.prepare(this.con); BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
statment.setString(1, pseudo); String line;
ResultSet result = statment.executeQuery(); while((line = reader.readLine()) != null){
if(result.next()) return false; if(line.endsWith(".class")){
statment = DatabaseQuery.UPDATE_PLAYER_INFO.prepare(this.con); Class<?> clazz = Class.forName(name+"."+line.substring(0, line.length()-6));
statment.setString(1, pseudo); if(BaseDatabaseQuery.class.isAssignableFrom(clazz)){
statment.setString(2, player.getEmail()); for(Class<?> subClazz : clazz.getDeclaredClasses()){
statment.setString(3, player.getFirstname()); if(subClazz.isEnum()){
statment.setString(4, player.getLastname()); configure(subClazz, folder);
statment.setInt(5, id);
return statment.executeUpdate() > 0;
}catch(Exception e){
e.printStackTrace();
}
return false;
}
public void updateProfile(int id, Player player, String lastname, String firstname){
try{
PreparedStatement statment = DatabaseQuery.UPDATE_PLAYER_INFO.prepare(this.con);
statment.setString(1, player.getPseudo());
statment.setString(2, player.getEmail());
statment.setString(3, firstname);
statment.setString(4, lastname);
statment.setInt(5, id);
statment.executeUpdate();
}catch(Exception e){
e.printStackTrace();
}
}
public void updatePassword(int id, String password){
try{
PreparedStatement statment = DatabaseQuery.UPDATE_PLAYER_PASSWORD.prepare(this.con);
statment.setString(1, Password.hash(password).withArgon2().getResult());
statment.setInt(2, id);
statment.executeUpdate();
}catch(Exception e){
e.printStackTrace();
}
}
public Player getPlayerDetails(int idPlayer) {
return getPlayerDetails(idPlayer, null);
}
public Player getPlayerDetails(String pseudoPlayer) {
return getPlayerDetails(-1, pseudoPlayer);
}
private Player getPlayerDetails(int id, String pseudo) {
try {
ensureConnection();
PreparedStatement completionsStmt;
if (pseudo != null) {
completionsStmt = DatabaseQuery.GET_PLAYER_DETAILS_BY_PSEUDO.prepare(this.con);
completionsStmt.setString(1, pseudo);
} else {
completionsStmt = DatabaseQuery.GET_PLAYER_DETAILS_BY_ID.prepare(this.con);
completionsStmt.setInt(1, id);
}
ResultSet result = completionsStmt.executeQuery();
Player player = null;
while (result.next()) {
if (player == null) {
id = result.getInt("id_player");
player = makePlayer(result, id);
completionsStmt = DatabaseQuery.GET_BADGES_OF_PLAYER.prepare(this.con);
completionsStmt.setInt(1, id);
ResultSet resultBadges = completionsStmt.executeQuery();
while (resultBadges.next()) {
player.addBadge(makeBadge(resultBadges));
}
} else {
player.addGroup(makeGroup(result));
}
}
// ADD completions
completionsStmt = DatabaseQuery.GET_PLAYER_COMPLETIONS.prepare(con);
completionsStmt.setInt(1, id);
result = completionsStmt.executeQuery();
while (result.next()) {
player.addCompletion(makeCompletion(result));
}
return player;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public SortedSet<Player> getAllPlayerForLeaderboard() {
try {
ensureConnection();
PreparedStatement playersStmt = DatabaseQuery.ALL_PLAYERS_FOR_LEADERBOARD.prepare(this.con);
ResultSet result = playersStmt.executeQuery();
ArrayList<Player> players = new ArrayList<Player>();
Player tmpPlayer;
while (result.next()) {
tmpPlayer = makePlayer(result, result.getInt("id_player"));
if (!players.contains(tmpPlayer)) {
players.add(tmpPlayer);
} else {
players.get(players.indexOf(tmpPlayer)).addGroup(makeGroup(result));
}
}
return new TreeSet<Player>(players);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public SortedSet<Group> getAllGroupForChapterLeaderboard(int chapterId){
try{
ensureConnection();
PreparedStatement groupsStmt = DatabaseQuery.ALL_GROUP_FOR_CHAPTER_LEADERBOARD.prepare(this.con);
groupsStmt.setInt(1, chapterId);
ResultSet result = groupsStmt.executeQuery();
List<Group> groups = new ArrayList<Group>();
Group tmpGroup;
while (result.next()) {
tmpGroup = makeGroup(result);
if (tmpGroup != null) {
int gPosition = groups.indexOf(tmpGroup);
if (gPosition < 0) {
tmpGroup.addPlayer(makeGroupPlayer(result));
groups.add(tmpGroup);
} else {
groups.get(gPosition).addPlayer(makeGroupPlayer(result));
}
}
}
return new TreeSet<Group>(groups);
}catch(SQLException e){
e.printStackTrace();
}
return null;
}
public Badge getBadge(int badgeId) {
try {
ensureConnection();
PreparedStatement completionsStmt = DatabaseQuery.GET_BADGE.prepare(this.con);
completionsStmt.setInt(1, badgeId);
ResultSet result = completionsStmt.executeQuery();
if (result.next()) {
return makeBadge(result);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* Get a specific chapter
*
* @param id The id of the chapter
* @return The chapter or null if an error occurred
*/
public Chapter getChapter(int id) {
try {
ensureConnection();
PreparedStatement chapterStmt = DatabaseQuery.SPECIFIC_CHAPTER_QUERY.prepare(this.con);
chapterStmt.setInt(1, id);
ResultSet chapterResult = chapterStmt.executeQuery();
if (chapterResult.next()) {
Chapter chapter = makeChapter(chapterResult);
List<Puzzle> puzzles = getPuzzlesInChapter(id);
chapter.setPuzzles(puzzles);
return chapter;
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public Chapter getChapter(Puzzle puzzle){
try {
ensureConnection();
PreparedStatement chapterStmt = DatabaseQuery.CHAPTER_FROM_PUZZLE.prepare(this.con);
chapterStmt.setInt(1, puzzle.getId());
ResultSet chapterResult = chapterStmt.executeQuery();
if (chapterResult.next()) {
Chapter chapter = makeChapter(chapterResult);
List<Puzzle> puzzles = getPuzzlesInChapter(chapter.getId());
chapter.setPuzzles(puzzles);
return chapter;
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
/**
* Get all chapters in the database
*
* @return List of all chapters or null if an error occurred
*/
public List<Chapter> getAllChapters() {
try {
List<Chapter> chapterList = new ArrayList<>();
ensureConnection();
PreparedStatement chapterStmt = DatabaseQuery.ALL_CHAPTERS_QUERY.prepare(this.con);
ResultSet chapterResult = chapterStmt.executeQuery();
while (chapterResult.next()) {
Chapter chapter = makeChapter(chapterResult);
chapter.setPuzzles(getPuzzlesInChapter(chapter.getId()));
chapterList.add(chapter);
}
return chapterList;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public List<Group> getAllGroups() {
try {
ensureConnection();
List<Group> list = new ArrayList<>();
PreparedStatement stmt = DatabaseQuery.ALL_GROUPS.prepare(this.con);
ResultSet groupResult = stmt.executeQuery();
while (groupResult.next())
list.add(makeGroup(groupResult));
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Check if a pseudo is available
*
* @param pseudo The pseudo to check
* @return True if the pseudo is available, false if it's already taken
*/
public boolean checkPseudoAvailability(String pseudo) {
return checkAvailability(pseudo, DatabaseQuery.CHECK_PSEUDO_AVAILABLE_QUERY.toString());
}
/**
* Check if an email is available
*
* @param email The email to check
* @return True if the email is available, false if it's already taken
*/
public boolean checkEmailAvailability(String email) {
return checkAvailability(email, DatabaseQuery.CHECK_EMAIL_AVAILABLE_QUERY.toString());
}
private boolean checkAvailability(String queriedString, String correspondingQuery) {
try {
ensureConnection();
PreparedStatement statement = con.prepareStatement(correspondingQuery);
statement.setString(1, queriedString);
ResultSet result = statement.executeQuery();
return !result.next();
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
/**
* Register a new user
*
* @param pseudo The pseudo of the user
* @param email The email of the user
* @param password The password of the user
* @param firstname The firstname of the user
* @param lastname The lastname of the user
* @param description The description of the user
* @param sgroup The group of the user
* @param avatar The avatar of the user
* @return True if the user was registered, false if an error occurred
*/
public int register(String pseudo, String email, String password, String firstname, String lastname,
String description, String sgroup, String avatar) {
try {
ensureConnection();
con.setAutoCommit(false);
try (PreparedStatement playerStatement = con.prepareStatement(DatabaseQuery.REGISTER_QUERY.toString(),
Statement.RETURN_GENERATED_KEYS)) {
playerStatement.setString(1, pseudo);
playerStatement.setString(2, email);
playerStatement.setString(3, Password.hash(password).withArgon2().getResult());
playerStatement.setString(4, firstname);
playerStatement.setString(5, lastname);
playerStatement.setString(6, description);
playerStatement.setString(7, avatar);
if (playerStatement.executeUpdate() == 1) {
ResultSet inserted = playerStatement.getGeneratedKeys();
if (inserted.next()) {
int newPlayerId = inserted.getInt(1);
if (!sgroup.isEmpty()) {
try (PreparedStatement containsGroupsStatement = con
.prepareStatement(DatabaseQuery.REGISTER_PLAYER_IN_EXISTING_GROUP.toString())) {
containsGroupsStatement.setInt(1, newPlayerId);
containsGroupsStatement.setString(2, sgroup);
containsGroupsStatement.executeUpdate();
} }
} }
con.commit();
con.setAutoCommit(true);
return newPlayerId;
} }
continue;
} }
} catch (SQLException e) {
con.rollback();
con.setAutoCommit(true);
e.printStackTrace();
} }
} catch (SQLException e) { reader.close();
}catch(Exception e){
System.err.println("Failed to read "+name);
e.printStackTrace(); e.printStackTrace();
} }
return -1; new Thread(() -> {
} try{
WatchService watchService = FileSystems.getDefault().newWatchService();
/** Path path = folder.toPath();
* Login a user path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
* while (true) {
* @param username The username of the user WatchKey key = watchService.take();
* @param password The password of the user for(WatchEvent<?> event : key.pollEvents()){
* @return id the id of the user, -1 if not login successefuly Path edited = (Path) event.context();
*/ String targetClazz = edited.toFile().getName().split("\\.")[0];
public int login(String username, String password) { Class<?> clazz = Class.forName(name+"."+targetClazz);
try { if(BaseDatabaseQuery.class.isAssignableFrom(clazz)){
ensureConnection(); for(Class<?> subClazz : clazz.getDeclaredClasses()){
PreparedStatement statement = con.prepareStatement(DatabaseQuery.CHECK_PASSWORD.toString()); if(subClazz.isEnum()){
DatabaseQuery.PUZZLES_IN_CHAPTER_QUERY.prepare(this.con); bind(subClazz, new File(folder, edited.toFile().getName()));
statement.setString(1, username); }
ResultSet result = statement.executeQuery(); }
if (result.next()) { }
String hashedPassword = result.getString("passwd"); }
if (Password.check(password, hashedPassword).withArgon2()) key.reset();
return result.getInt("id_player"); }
}catch(Exception ex){
ex.printStackTrace();
} }
} catch (SQLException e) { }).start();
}
return -1;
} }
public Completion insertOrUpdatePuzzleResponse(int puzzleId, int userId, String fileName, byte[] code, private void configure(Class<?> clazz, File folder) throws Exception{
byte[] response, Puzzle currentPuzzle){ String name = clazz.getName().split("\\$")[0];
try { String[] split = name.split("\\.");
ensureConnection(); File file = new File(folder, split[split.length-1]+".txt");
Completion completion = getCompletionGroup(userId, puzzleId); if(file.exists()){
if (completion == null){ bind(clazz, file);
System.out.println("Completion is null"); }else{
completion = new Completion(userId, puzzleId, fileName, code, response, currentPuzzle); File parent = file.getParentFile();
insertCompletion(completion); if(!parent.exists()) parent.mkdirs();
} else { file.createNewFile();
System.out.println(completion); BufferedWriter writer = new BufferedWriter(new FileWriter(file));
completion.addTry(currentPuzzle, response, getChapter(currentPuzzle).getId()); for(Object obj : clazz.getEnumConstants()){
int lastUserId = completion.getPlayerId(); Enum instance = (Enum) obj;
completion.updatePlayer(userId); writer.write(instance.name()+"="+instance.toString().replace("\n", " ").replace("\r", " ")+"\n");
updateCompletion(completion, lastUserId);
} }
return completion; writer.flush();
} catch (SQLException e) { writer.close();
e.printStackTrace();
} }
return null;
} }
private void insertCompletion(Completion newCompletion) throws SQLException { private void bind(Class<?> clazz, File file) throws Exception{
PreparedStatement statement = DatabaseQuery.INSERT_COMPLETION.prepare(this.con); Map<String, String> map = new HashMap<>();
statement.setInt(1, newCompletion.getPuzzleId()); BufferedReader reader = new BufferedReader(new FileReader(file));
statement.setInt(2, newCompletion.getPlayerId()); String line;
statement.setInt(3, newCompletion.getTries()); while((line = reader.readLine()) != null){
statement.setBytes(4, newCompletion.getCode()); int index = line.indexOf('=');
statement.setString(5, newCompletion.getFileName()); String key = line.substring(0, index);
statement.setInt(6, newCompletion.getScore()); String value = line.substring(index+1);
statement.executeUpdate(); map.put(key, value);
}
reader.close();
for(Object obj : clazz.getEnumConstants()){
Enum instance = (Enum) obj;
String value = map.get(instance.name());
Field field = obj.getClass().getDeclaredField("request");
field.setAccessible(true);
field.set(instance, value);
}
} }
public boolean insertGroup(Group group, PeerAtUser creator) throws SQLException { public DatabasePuzzleRepository getPuzzleRepository(){
Integer groupId = getGroupId(group); return this.puzzleRepo;
if (groupId == null)
ensureConnection();
PreparedStatement statement = DatabaseQuery.INSERT_GROUP.prepare(this.con);
statement.setString(1, group.getName());
statement.setObject(2, group.getLinkToChapter());
// statement.setObject(3, group.getLinkToPuzzle());
if (statement.executeUpdate() >= 0)
return insertUserInGroup(group, creator);
return false;
} }
public Group getPlayerGroup(int user, Integer chapter) throws SQLException { public DatabaseChapterRepository getChapterRepository(){
return this.chapterRepo;
}
public DatabaseAdminRepository getAdminRepository(){
return this.adminRepo;
}
public DatabaseAuthRepository getAuthRepository(){
return this.authRepo;
}
public DatabaseBadgeRepository getBadgeRepository(){
return this.badgeRepo;
}
public DatabaseCompletionRepository getCompletionRepository(){
return this.completionRepo;
}
public DatabaseGroupRepository getGroupRepository(){
return this.groupRepo;
}
public DatabaseLeaderboardRepository getLeaderboardRepository(){
return this.leaderboardRepo;
}
public DatabasePlayerRepository getPlayerRepository(){
return this.playerRepo;
}
public void hotfix() throws Exception{
ensureConnection(); ensureConnection();
PreparedStatement stmt = DatabaseQuery.GET_GROUP_FOR_PLAYER.prepare(this.con);
stmt.setInt(1, user); PreparedStatement stmt = con.prepareStatement("SELECT c.*, g.* FROM completions c JOIN puzzles p ON c.fk_puzzle = p.id_puzzle JOIN containsGroups cg ON cg.fk_player = c.fk_player JOIN groups g ON g.id_group = cg.fk_group WHERE g.fk_chapter = 12 AND p.fk_chapter = 12;");
stmt.setObject(2, chapter); ResultSet results = stmt.executeQuery();
// stmt.setObject(3, puzzle); List<Completionz> list = new ArrayList<>();
while(results.next()){
ResultSet result = stmt.executeQuery(); Completionz complete = new Completionz(results);
if (result.next()) list.add(complete);
return makeGroup(result);
return null;
}
public Integer getGroupId(Group group) throws SQLException {
ensureConnection();
PreparedStatement stmt = DatabaseQuery.GET_GROUP_ID_BY_DATA.prepare(this.con);
stmt.setString(1, group.getName());
stmt.setObject(2, group.getLinkToChapter());
// stmt.setObject(3, group.getLinkToPuzzle());
ResultSet result = stmt.executeQuery();
if (result.next())
return result.getInt("id_group");
return null;
}
public boolean insertUserInGroup(Group group, PeerAtUser user) throws SQLException {
Integer id = getGroupId(group);
Group alreadyInGroup = getPlayerGroup(user.getId(), group.getLinkToChapter());
if (id != null && alreadyInGroup == null) {
PreparedStatement stmt = DatabaseQuery.INSERT_PLAYER_IN_GROUP.prepare(this.con);
stmt.setInt(1, user.getId());
stmt.setInt(2, id);
return stmt.executeUpdate() >= 0;
} }
return false; Map<Integer, Map<Integer, Completionz>> map = new HashMap<>();
} for(Completionz comp : list){
Map<Integer,Completionz> puz = map.get(comp.puzzle);
public boolean leaveGroup(Group group, PeerAtUser user) throws SQLException { if(puz == null){
Integer id = getGroupId(group); puz = new HashMap<>();
if (id != null) { map.put(comp.puzzle, puz);
PreparedStatement stmt = DatabaseQuery.LEAVE_GROUP.prepare(this.con); }
Completionz c = puz.get(comp.groups);
stmt.setInt(1, user.getId()); if(c == null){
stmt.setInt(2, id); puz.put(comp.groups, comp);
}else{
return stmt.executeUpdate() >= 0; if(comp.score >= c.score){
puz.put(comp.groups, comp);
System.out.println("remove compl "+c.id);
}
}
} }
return false; }
private static class Completionz{
public int id;
public int puzzle;
public int player;
public int tries;
public int score;
public int groups;
public Completionz(ResultSet result) throws Exception{
id = result.getInt("id_completion");
puzzle = result.getInt("fk_puzzle");
player = result.getInt("fk_player");
tries = result.getInt("tries");
score = result.getInt("score");
groups = result.getInt("id_group");
System.out.println(id);
}
} }
private void updateCompletion(Completion completionToUpdate, int user) throws SQLException{
System.out.println("update "+completionToUpdate);
PreparedStatement statement = DatabaseQuery.UPDATE_COMPLETION.prepare(this.con);
statement.setInt(1, completionToUpdate.getTries());
statement.setInt(2, completionToUpdate.getScore());
statement.setInt(3, completionToUpdate.getPlayerId());
statement.setInt(4, completionToUpdate.getPuzzleId());
statement.setInt(5, user);
statement.executeUpdate();
}
} }

View file

@ -5,6 +5,7 @@ import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Badge; import dev.peerat.backend.model.Badge;
import dev.peerat.backend.repository.DatabaseBadgeRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
@ -15,10 +16,10 @@ import dev.peerat.framework.utils.json.JsonMap;
public class BadgeDetails implements Response { public class BadgeDetails implements Response {
private final DatabaseRepository databaseRepo; private final DatabaseBadgeRepository databaseRepo;
public BadgeDetails(DatabaseRepository databaseRepo) { public BadgeDetails(DatabaseRepository databaseRepo) {
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo.getBadgeRepository();
} }
@RouteDoc(path = "/badge/<id>", responseCode = 200, responseDescription = "JSON contenant les informations du badge") @RouteDoc(path = "/badge/<id>", responseCode = 200, responseDescription = "JSON contenant les informations du badge")

View file

@ -6,6 +6,9 @@ import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Chapter; import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.model.PeerAtUser; import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.model.Puzzle; import dev.peerat.backend.model.Puzzle;
import dev.peerat.backend.repository.DatabaseChapterRepository;
import dev.peerat.backend.repository.DatabaseCompletionRepository;
import dev.peerat.backend.repository.DatabaseGroupRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
@ -17,10 +20,12 @@ import dev.peerat.framework.utils.json.JsonMap;
public class ChapterElement implements Response { public class ChapterElement implements Response {
private final DatabaseRepository databaseRepo; private final DatabaseChapterRepository chapterRepo;
private final DatabaseCompletionRepository completionRepo;
public ChapterElement(DatabaseRepository databaseRepo) { public ChapterElement(DatabaseRepository repo) {
this.databaseRepo = databaseRepo; this.chapterRepo = repo.getChapterRepository();
this.completionRepo = repo.getCompletionRepository();
} }
@RouteDoc(path = "/chapter/<id>", responseCode = 200, responseDescription = "JSON contenant les informations du chapitre demander") @RouteDoc(path = "/chapter/<id>", responseCode = 200, responseDescription = "JSON contenant les informations du chapitre demander")
@ -28,13 +33,15 @@ public class ChapterElement implements Response {
@Route(path = "^\\/chapter\\/([0-9]+)$", needLogin = true) @Route(path = "^\\/chapter\\/([0-9]+)$", needLogin = true)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{ public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
Chapter chapter = databaseRepo.getChapter(Integer.parseInt(matcher.group(1))); Chapter chapter = chapterRepo.getChapter(Integer.parseInt(matcher.group(1)));
if (chapter != null){ if (chapter != null){
JsonMap chapterJSON = new JsonMap(); JsonMap chapterJSON = new JsonMap();
chapterJSON.set("id", chapter.getId()); chapterJSON.set("id", chapter.getId());
chapterJSON.set("name", chapter.getName()); chapterJSON.set("name", chapter.getName());
boolean show = chapter.hasStarted(); boolean show = chapter.hasStarted();
chapterJSON.set("show", show); chapterJSON.set("show", show);
if(chapter.getStartDate() != null) chapterJSON.set("start", chapter.getStartDate().toString());
if(chapter.getEndDate() != null) chapterJSON.set("end", chapter.getEndDate().toString());
PeerAtUser user = context.getUser(); PeerAtUser user = context.getUser();
if(show){ if(show){
JsonArray puzzles = new JsonArray(); JsonArray puzzles = new JsonArray();
@ -44,7 +51,7 @@ public class ChapterElement implements Response {
puzzleJSON.set("name", puzzle.getName()); puzzleJSON.set("name", puzzle.getName());
puzzleJSON.set("scoreMax", puzzle.getScoreMax()); puzzleJSON.set("scoreMax", puzzle.getScoreMax());
if (puzzle.getTags() != null) puzzleJSON.set("tags", puzzle.getJsonTags()); if (puzzle.getTags() != null) puzzleJSON.set("tags", puzzle.getJsonTags());
int score = this.databaseRepo.getScore(user.getId(), puzzle.getId()); int score = this.completionRepo.getScore(user.getId(), puzzle.getId());
if(score >= 0) puzzleJSON.set("score", score); if(score >= 0) puzzleJSON.set("score", score);
puzzleJSON.set("show", puzzle.hasStarted()); puzzleJSON.set("show", puzzle.hasStarted());
puzzles.add(puzzleJSON); puzzles.add(puzzleJSON);

View file

@ -5,6 +5,7 @@ import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Chapter; import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.repository.DatabaseChapterRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
@ -16,10 +17,10 @@ import dev.peerat.framework.utils.json.JsonMap;
public class ChapterList implements Response { public class ChapterList implements Response {
private final DatabaseRepository databaseRepo; private final DatabaseChapterRepository databaseRepo;
public ChapterList(DatabaseRepository databaseRepo) { public ChapterList(DatabaseRepository databaseRepo) {
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo.getChapterRepository();
} }
@RouteDoc(path = "/chapters", responseCode = 200, responseDescription = "JSON contenant les informations des chapitres") @RouteDoc(path = "/chapters", responseCode = 200, responseDescription = "JSON contenant les informations des chapitres")
@ -35,6 +36,8 @@ public class ChapterList implements Response {
chapterJSON.set("id", chapter.getId()); chapterJSON.set("id", chapter.getId());
chapterJSON.set("name", chapter.getName()); chapterJSON.set("name", chapter.getName());
chapterJSON.set("show", chapter.hasStarted()); chapterJSON.set("show", chapter.hasStarted());
if(chapter.getStartDate() != null) chapterJSON.set("start", chapter.getStartDate().toString());
if(chapter.getEndDate() != null) chapterJSON.set("end", chapter.getEndDate().toString());
chaptersJSON.add(chapterJSON); chaptersJSON.add(chapterJSON);
} }
context.response(200); context.response(200);

View file

@ -8,6 +8,7 @@ import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter; import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Injection;
import dev.peerat.framework.Locker; import dev.peerat.framework.Locker;
import dev.peerat.framework.Locker.Key; import dev.peerat.framework.Locker.Key;
import dev.peerat.framework.Route; import dev.peerat.framework.Route;
@ -16,7 +17,7 @@ public class DynamicLeaderboard extends Leaderboard{
private Locker<Completion> locker; private Locker<Completion> locker;
public DynamicLeaderboard(DatabaseRepository databaseRepo, Locker<Completion> locker){ public DynamicLeaderboard(DatabaseRepository databaseRepo, @Injection("leaderboard") Locker<Completion> locker){
super(databaseRepo); super(databaseRepo);
this.locker = locker; this.locker = locker;
} }

View file

@ -0,0 +1,73 @@
package dev.peerat.backend.routes;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabaseGroupRepository;
import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context;
import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Injection;
import dev.peerat.framework.Locker;
import dev.peerat.framework.Locker.Key;
import dev.peerat.framework.Route;
public class EventSSE{
private Locker<GroupMessage> locker;
private DatabaseGroupRepository repo;
private int eventChapter;
public EventSSE(@Injection("groupMessages") Locker<GroupMessage> locker, DatabaseRepository repo, Configuration config){
this.locker = locker;
this.repo = repo.getGroupRepository();
this.eventChapter = config.getEventChapter();
}
@Route(path = "^/group/event/$", needLogin = true)
public void connect(Context context, HttpWriter writer) throws Exception {
Group group = repo.getPlayerGroup(context.<PeerAtUser>getUser().getId(), this.eventChapter);
if(group == null){
context.response(401);
return;
}
context.response(200, "Content-Type: text/event-stream");
Key key = new Key();
locker.init(key);
try {
while(true){
GroupMessage message = locker.getValue(key);
if(message.getGroup() == null || message.getGroup().equals(group.getName())){
writer.write("data: "+message.getMessage()+"\n\n");
writer.flush();
}
locker.lock(key);
}
}catch(Exception e){
e.printStackTrace();
}
locker.remove(key);
}
public static class GroupMessage{
private String group;
private String message;
public GroupMessage(String group, String message){
this.group = group;
this.message = message;
}
public String getGroup(){
return this.group;
}
public String getMessage(){
return this.message;
}
}
}

View file

@ -38,9 +38,9 @@ public class Leaderboard implements Response {
} }
public final void groupsLeaderboard(int chapterId, HttpWriter writer) throws IOException { public final void groupsLeaderboard(int chapterId, HttpWriter writer) throws IOException {
Chapter chInfo = databaseRepo.getChapter(chapterId); Chapter chInfo = databaseRepo.getChapterRepository().getChapter(chapterId);
SortedSet<Group> allGroupsForChapter = databaseRepo.getAllGroupForChapterLeaderboard(chapterId); SortedSet<Group> allGroupsForChapter = databaseRepo.getLeaderboardRepository().getAllGroupForChapterLeaderboard(chapterId);
JsonMap leaderboardJSON = new JsonMap(); JsonMap leaderboardJSON = new JsonMap();
if (chInfo.getStartDate() != null) if (chInfo.getStartDate() != null)
leaderboardJSON.set("start_date", chInfo.getStartDate().toString()); leaderboardJSON.set("start_date", chInfo.getStartDate().toString());
@ -65,11 +65,11 @@ public class Leaderboard implements Response {
} }
} }
leaderboardJSON.set("groups", groupsJSON); leaderboardJSON.set("groups", groupsJSON);
writer.write(leaderboardJSON.toString().replace("\\", "")); writer.write(leaderboardJSON.toString());
} }
public final void playersLeaderboard(HttpWriter writer) throws IOException { public final void playersLeaderboard(HttpWriter writer) throws IOException {
SortedSet<Player> allPlayers = databaseRepo.getAllPlayerForLeaderboard(); SortedSet<Player> allPlayers = databaseRepo.getLeaderboardRepository().getAllPlayerForLeaderboard();
JsonArray playersJSON = new JsonArray(); JsonArray playersJSON = new JsonArray();
if (allPlayers != null) { if (allPlayers != null) {
for (Player player : allPlayers) { for (Player player : allPlayers) {
@ -86,6 +86,6 @@ public class Leaderboard implements Response {
playersJSON.add(playerJSON); playersJSON.add(playerJSON);
} }
} }
writer.write(playersJSON.toString().replace("\\", "")); writer.write(playersJSON.toString());
} }
} }

View file

@ -1,11 +1,11 @@
package dev.peerat.backend.routes; package dev.peerat.backend.routes;
import java.util.Base64;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.PeerAtUser; import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.model.Player; import dev.peerat.backend.model.Player;
import dev.peerat.backend.repository.DatabasePlayerRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
@ -16,10 +16,10 @@ import dev.peerat.framework.utils.json.JsonMap;
public class PlayerDetails implements Response { public class PlayerDetails implements Response {
private final DatabaseRepository databaseRepo; private final DatabasePlayerRepository databaseRepo;
public PlayerDetails(DatabaseRepository databaseRepo) { public PlayerDetails(DatabaseRepository databaseRepo) {
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo.getPlayerRepository();
} }
@RouteDoc(path = "/player/{id}", responseCode = 200, responseDescription = "JSON contenant les informations de l'utilisateur") @RouteDoc(path = "/player/{id}", responseCode = 200, responseDescription = "JSON contenant les informations de l'utilisateur")
@ -50,10 +50,10 @@ public class PlayerDetails implements Response {
playerJSON.set("tries", player.getTotalTries()); playerJSON.set("tries", player.getTotalTries());
if (player.getBadges() != null) if (player.getBadges() != null)
playerJSON.set("badges", player.getJsonBadges()); playerJSON.set("badges", player.getJsonBadges());
if (player.getAvatar() != null) // if (player.getAvatar() != null)
playerJSON.set("avatar", Base64.getEncoder().encodeToString(player.getAvatar())); // playerJSON.set("avatar", Base64.getEncoder().encodeToString(player.getAvatar()));
context.response(200); context.response(200);
writer.write(playerJSON.toString().replace("\\", "")); writer.write(playerJSON.toString());
} else { } else {
context.response(400); context.response(400);
} }

View file

@ -30,9 +30,9 @@ public class PuzzleElement implements Response {
@Route(path = "^\\/puzzle\\/([0-9]+)$", needLogin = true) @Route(path = "^\\/puzzle\\/([0-9]+)$", needLogin = true)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception {
Puzzle puzzle = databaseRepo.getPuzzle(extractId(matcher)); Puzzle puzzle = databaseRepo.getPuzzleRepository().getPuzzle(extractId(matcher));
if (puzzle != null){ if (puzzle != null){
Chapter chapter = this.databaseRepo.getChapter(puzzle); Chapter chapter = this.databaseRepo.getChapterRepository().getChapter(puzzle);
if(chapter.getStartDate() != null){ if(chapter.getStartDate() != null){
if(LocalDateTime.now().isBefore(chapter.getStartDate().toLocalDateTime())){ if(LocalDateTime.now().isBefore(chapter.getStartDate().toLocalDateTime())){
context.response(423); context.response(423);
@ -54,7 +54,7 @@ public class PuzzleElement implements Response {
puzzleJSON.set("content", puzzle.getContent()); puzzleJSON.set("content", puzzle.getContent());
puzzleJSON.set("scoreMax", puzzle.getScoreMax()); puzzleJSON.set("scoreMax", puzzle.getScoreMax());
if(puzzle.getTags() != null) puzzleJSON.set("tags", puzzle.getJsonTags()); if(puzzle.getTags() != null) puzzleJSON.set("tags", puzzle.getJsonTags());
Completion completion = this.databaseRepo.getCompletionGroup(user.getId(), puzzle.getId()); Completion completion = this.databaseRepo.getCompletionRepository().getCompletionGroup(user.getId(), puzzle.getId());
if(completion != null && completion.getScore() >= 0){ if(completion != null && completion.getScore() >= 0){
puzzleJSON.set("score", completion.getScore()); puzzleJSON.set("score", completion.getScore());
puzzleJSON.set("tries", completion.getTries()); puzzleJSON.set("tries", completion.getTries());

View file

@ -11,6 +11,7 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Chapter; import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.model.Completion; import dev.peerat.backend.model.Completion;
@ -22,6 +23,7 @@ import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter; import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Injection;
import dev.peerat.framework.Locker; import dev.peerat.framework.Locker;
import dev.peerat.framework.Response; import dev.peerat.framework.Response;
import dev.peerat.framework.Route; import dev.peerat.framework.Route;
@ -33,9 +35,9 @@ public class PuzzleResponse implements Response {
private final Locker<Completion> leaderboard; private final Locker<Completion> leaderboard;
public PuzzleResponse(DatabaseRepository databaseRepo, String initUsersFilesPath, Locker<Completion> locker){ public PuzzleResponse(DatabaseRepository databaseRepo, Configuration config, @Injection("leaderboard") Locker<Completion> locker){
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo;
usersFilesPath = initUsersFilesPath; usersFilesPath = config.getUsersFiles();
this.leaderboard = locker; this.leaderboard = locker;
} }
@ -56,18 +58,18 @@ public class PuzzleResponse implements Response {
//saveSourceCode(received, databaseRepo.getPlayer(user.getId())); //saveSourceCode(received, databaseRepo.getPlayer(user.getId()));
JsonMap responseJSON = new JsonMap(); JsonMap responseJSON = new JsonMap();
if(this.databaseRepo.getScore(user.getId(), received.getPuzzleId()) > 0){ if(this.databaseRepo.getCompletionRepository().getScore(user.getId(), received.getPuzzleId()) > 0){
context.response(403); context.response(403);
return; return;
} }
Puzzle currentPuzzle = databaseRepo.getPuzzle(received.getPuzzleId()); Puzzle currentPuzzle = databaseRepo.getPuzzleRepository().getPuzzle(received.getPuzzleId());
if(!currentPuzzle.hasStarted()){ if(!currentPuzzle.hasStarted()){
context.response(423); context.response(423);
return; return;
} }
Chapter chapter = this.databaseRepo.getChapter(currentPuzzle); Chapter chapter = this.databaseRepo.getChapterRepository().getChapter(currentPuzzle);
if(!chapter.hasStarted()){ if(!chapter.hasStarted()){
context.response(423); context.response(423);
return; return;
@ -84,7 +86,7 @@ public class PuzzleResponse implements Response {
context.response(423); context.response(423);
return; return;
} }
Group group = this.databaseRepo.getPlayerGroup(user.getId(), chapter.getId()); Group group = this.databaseRepo.getGroupRepository().getPlayerGroup(user.getId(), chapter.getId());
if(group == null){ if(group == null){
context.response(423); context.response(423);
return; return;
@ -92,7 +94,7 @@ public class PuzzleResponse implements Response {
} }
Completion completion = databaseRepo.insertOrUpdatePuzzleResponse(received.getPuzzleId(), user.getId(), Completion completion = databaseRepo.getCompletionRepository().insertOrUpdatePuzzleResponse(received.getPuzzleId(), user.getId(),
received.getFileName(), received.getSourceCode(), received.getResponse(), currentPuzzle); received.getFileName(), received.getSourceCode(), received.getResponse(), currentPuzzle);
if(completion == null){ if(completion == null){
context.response(400); context.response(400);

View file

@ -4,6 +4,7 @@ import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.PeerAtUser; import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabaseCompletionRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
@ -13,10 +14,10 @@ import dev.peerat.framework.Route;
public class Result implements Response { public class Result implements Response {
private DatabaseRepository repo; private DatabaseCompletionRepository repo;
public Result(DatabaseRepository repo) { public Result(DatabaseRepository repo) {
this.repo = repo; this.repo = repo.getCompletionRepository();
} }
@RouteDoc(path = "/result/<id>", responseCode = 200, responseDescription = "Le score") @RouteDoc(path = "/result/<id>", responseCode = 200, responseDescription = "Le score")

View file

@ -2,10 +2,12 @@ package dev.peerat.backend.routes;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.bonus.extract.RouteExtracter; import dev.peerat.backend.bonus.extract.RouteExtracter;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter; import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Injection;
import dev.peerat.framework.Response; import dev.peerat.framework.Response;
import dev.peerat.framework.Route; import dev.peerat.framework.Route;
@ -13,9 +15,9 @@ public class Swagger implements Response{
private String json; private String json;
public Swagger(RouteExtracter extracter, String host){ public Swagger(RouteExtracter extracter, Configuration config){
try{ try{
this.json = extracter.swagger(host).toString(); // this.json = extracter.swagger(config.getTokenIssuer()).toString();
}catch(Exception e){ }catch(Exception e){
e.printStackTrace(); e.printStackTrace();
json = "{}"; json = "{}";

View file

@ -0,0 +1,70 @@
package dev.peerat.backend.routes.admins;
import static dev.peerat.framework.RequestType.DELETE;
import static dev.peerat.framework.RequestType.POST;
import static dev.peerat.framework.RequestType.PUT;
import java.sql.Timestamp;
import java.util.regex.Matcher;
import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.repository.DatabaseAdminRepository;
import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Route;
import dev.peerat.framework.utils.json.JsonMap;
public class ChapterController{
private DatabaseAdminRepository repo;
public ChapterController(DatabaseRepository repo){
this.repo = repo.getAdminRepository();
}
@Route(path = "^/admin/chapter/$", type = POST, needLogin = true)
public void add(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
JsonMap json = reader.readJson();
Chapter chapter = new Chapter(-1, json.get("name"), Timestamp.valueOf(json.<String>get("start")), Timestamp.valueOf(json.<String>get("end")));
if(repo.adminAddChapter(chapter)){
context.response(200);
}else{
context.response(501);
}
}
@Route(path = "^/admin/chapter/(\\d+)$", type = DELETE, needLogin = true)
public void delte(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
if(this.repo.adminDeleteChapter(Integer.parseInt(matcher.group(1)))){
context.response(200);
}else{
context.response(501);
}
}
@Route(path = "^/admin/chapter/(\\d+)$", type = PUT, needLogin = true)
public void edit(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
JsonMap json = reader.readJson();
Chapter chapter = new Chapter(-1, json.get("name"), Timestamp.valueOf(json.<String>get("start")), Timestamp.valueOf(json.<String>get("end")));
if(repo.adminUpdateChapter(Integer.parseInt(matcher.group(1)), chapter)){
context.response(200);
}else{
context.response(501);
}
}
@Route(path = "^/admin/chapter/(\\d+)$", needLogin = true)
public void get(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
Chapter chapter = this.repo.getAdminChapter(Integer.parseInt(matcher.group(1)));
JsonMap json = new JsonMap();
json.set("name", chapter.getName());
json.set("start", chapter.getStartDate());
json.set("end", chapter.getEndDate());
context.response(200);
writer.write(json.toString()+"\n");
}
}

View file

@ -1,59 +0,0 @@
package dev.peerat.backend.routes.admins;
import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Locker;
import dev.peerat.framework.Locker.Key;
import dev.peerat.framework.Response;
import dev.peerat.framework.Route;
import dev.peerat.framework.utils.json.JsonMap;
public class DynamicLogs implements Response{
private Locker<Context> locker; //Context
private DatabaseRepository repo;
public DynamicLogs(Locker<Context> locker, DatabaseRepository repo){
this.locker = locker;
this.repo = repo;
}
@RouteDoc(path = "/admin/logs", responseCode = 200, responseDescription = "L'utilisateur peux voir les logs en directe")
@RouteDoc(responseCode = 401, responseDescription = "L'utilisateur n'a pas accès à cette ressource")
@Route(path = "^/admin/logs$", needLogin = true, websocket = true)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
Group group = this.repo.getPlayerGroup(context.<PeerAtUser>getUser().getId(), 1);
if(!group.getName().equalsIgnoreCase("Quarter-Master - Battles PAC x CEI")) return;
Key key = new Key();
locker.init(key);
try {
while(!reader.isClosed()){
locker.lock(key);
Context instance = locker.getValue(key);
JsonMap json = new JsonMap();
json.set("logged", instance.isLogged());
if(instance.isLogged()) json.set("pseudo", repo.getPlayer(instance.<PeerAtUser>getUser().getId()).getPseudo());
json.set("path", instance.getPath());
json.set("type", instance.getType());
json.set("code", instance.getResponseCode());
writer.write(json.toString());
writer.flush();
}
}catch(Exception e){}
locker.remove(key);
}
}

View file

@ -0,0 +1,31 @@
package dev.peerat.backend.routes.admins;
import dev.peerat.backend.routes.EventSSE.GroupMessage;
import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader;
import dev.peerat.framework.Injection;
import dev.peerat.framework.Locker;
import dev.peerat.framework.Route;
import dev.peerat.framework.utils.json.JsonMap;
public class GroupController {
private Locker<GroupMessage> locker;
public GroupController(@Injection("groupMessages") Locker<GroupMessage> locker){
this.locker = locker;
}
@Route(path = "^/admin/event/$", needLogin = true)
public void send(Context context, HttpReader reader) throws Exception{
JsonMap json = reader.readJson();
if(!json.has("message")){
context.response(400);
return;
}
locker.setValue(new GroupMessage(json.get("group"), json.get("message")));
context.response(200);
}
}

View file

@ -0,0 +1,78 @@
package dev.peerat.backend.routes.admins;
import java.util.function.BiConsumer;
import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabaseAdminRepository;
import dev.peerat.backend.repository.DatabasePlayerRepository;
import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Locker;
import dev.peerat.framework.Locker.Key;
import dev.peerat.framework.Route;
import dev.peerat.framework.Router;
import dev.peerat.framework.utils.json.JsonArray;
import dev.peerat.framework.utils.json.JsonMap;
public class LogController {
private Locker<Context> contextLocker;
private Locker<Throwable> exceptionLocker;
private DatabaseAdminRepository repo;
private DatabasePlayerRepository playerRepo;
public LogController(Router<PeerAtUser> router, DatabaseRepository repo){
this.contextLocker = router.getLogger();
this.exceptionLocker = router.getExceptionLogger();
this.repo = repo.getAdminRepository();
this.playerRepo = repo.getPlayerRepository();
}
@RouteDoc(path = "/admin/logs", responseCode = 200, responseDescription = "L'utilisateur peux voir les logs en directe")
@RouteDoc(responseCode = 401, responseDescription = "L'utilisateur n'a pas accès à cette ressource")
@Route(path = "^/admin/logs$", needLogin = true, websocket = true)
public void logs(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
log(reader, writer, this.contextLocker, (json, instance) -> {
json.set("logged", instance.isLogged());
if(instance.isLogged()) json.set("pseudo", playerRepo.getPlayer(instance.<PeerAtUser>getUser().getId()).getPseudo());
json.set("path", instance.getPath());
json.set("type", instance.getType().toString());
json.set("code", instance.getResponseCode());
});
}
@Route(path = "^/admin/exceptions$", needLogin = true, websocket = true)
public void exceptions(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
log(reader, writer, this.exceptionLocker, (json, exception) -> {
json.set("type", exception.getClass().getSimpleName());
json.set("message", exception.getMessage());
JsonArray trace = new JsonArray();
for(StackTraceElement element : exception.getStackTrace()) trace.add(element.toString());
json.set("trace", trace);
});
}
public <T> void log(HttpReader reader, HttpWriter writer, Locker<T> locker, BiConsumer<JsonMap, T> consumer){
Key key = new Key();
locker.init(key);
try {
while(!reader.isClosed()){
locker.lock(key);
T instance = locker.getValue(key);
JsonMap json = new JsonMap();
consumer.accept(json, instance);
writer.write(json.toString());
writer.flush();
}
}catch(Exception e){}
locker.remove(key);
}
}

View file

@ -0,0 +1,89 @@
package dev.peerat.backend.routes.admins;
import static dev.peerat.framework.RequestType.DELETE;
import static dev.peerat.framework.RequestType.POST;
import static dev.peerat.framework.RequestType.PUT;
import java.util.List;
import java.util.regex.Matcher;
import dev.peerat.backend.model.Puzzle;
import dev.peerat.backend.repository.DatabaseAdminRepository;
import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Route;
import dev.peerat.framework.utils.json.JsonArray;
import dev.peerat.framework.utils.json.JsonMap;
public class PuzzleController {
private DatabaseAdminRepository repo;
public PuzzleController(DatabaseRepository repo){
this.repo = repo.getAdminRepository();
}
@Route(path = "^/admin/puzzle/$", type = POST, needLogin = true)
public void add(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
JsonMap json = reader.readJson();
Puzzle puzzle = new Puzzle(-1, json.get("name"), json.get("content"), json.<String>get("soluce").getBytes(), null, json.<Long>get("scoreMax").intValue(), null, -1, null);
if(repo.adminAddPuzzle(puzzle, json.<Long>get("chapter").intValue())){
context.response(200);
}else{
context.response(501);
}
}
@Route(path = "^/admin/puzzle/(\\d+)$", type = DELETE, needLogin = true)
public void delete(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
if(this.repo.adminDeletePuzzle(Integer.parseInt(matcher.group(1)))){
context.response(200);
}else{
context.response(501);
}
}
@Route(path = "^/admin/puzzle/(\\d+)$", type = PUT, needLogin = true)
public void edit(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
JsonMap json = reader.readJson();
Puzzle puzzle = new Puzzle(-1, json.get("name"), json.get("content"), json.<String>get("soluce").getBytes(), null, json.<Long>get("scoreMax").intValue(), null, -1, null);
if(repo.adminUpdatePuzzle(Integer.parseInt(matcher.group(1)), puzzle, json.<Long>get("chapter").intValue())){
context.response(200);
}else{
context.response(501);
}
}
@Route(path = "^/admin/puzzle/(\\d+)$", needLogin = true)
public void get(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
Puzzle puzzle = this.repo.getAdminPuzzle(Integer.parseInt(matcher.group(1)));
JsonMap json = new JsonMap();
json.set("name", puzzle.getName());
json.set("content", puzzle.getContent());
json.set("soluce", new String(puzzle.getSoluce()));
json.set("score_max", puzzle.getScoreMax());
context.response(200);
writer.write(json.toString()+"\n");
}
@Route(path = "^/admin/puzzles/$", needLogin = true)
public void getAll(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
List<Puzzle> puzzles = repo.getAdminPuzzles();
JsonArray array = new JsonArray();
for (Puzzle puzzle : puzzles){
JsonMap puzzleJSON = new JsonMap();
puzzleJSON.set("id", puzzle.getId());
puzzleJSON.set("name", puzzle.getName());
puzzleJSON.set("scoreMax", puzzle.getScoreMax());
if(puzzle.getTags() != null) puzzleJSON.set("tags", puzzle.getJsonTags());
puzzleJSON.set("show", puzzle.hasStarted());
array.add(puzzleJSON);
}
context.response(200);
writer.write(array.toString());
}
}

View file

@ -0,0 +1,68 @@
package dev.peerat.backend.routes.admins;
import static dev.peerat.framework.RequestType.DELETE;
import static dev.peerat.framework.RequestType.POST;
import static dev.peerat.framework.RequestType.PUT;
import java.util.List;
import java.util.regex.Matcher;
import dev.peerat.backend.model.Tag;
import dev.peerat.backend.repository.DatabaseAdminRepository;
import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Route;
import dev.peerat.framework.utils.json.JsonArray;
import dev.peerat.framework.utils.json.JsonMap;
public class TagController {
private DatabaseAdminRepository repo;
public TagController(DatabaseRepository repo){
this.repo = repo.getAdminRepository();
}
@Route(path = "^/admin/tag/$", type = POST, needLogin = true)
public void add(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
JsonMap json = reader.readJson();
if(repo.adminAddTag(json.get("name"))){
context.response(200);
}else{
context.response(501);
}
}
@Route(path = "^/admin/tag/(\\d+)$", type = DELETE, needLogin = true)
public void delete(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
if(this.repo.adminDeleteTag(Integer.parseInt(matcher.group(1)))){
context.response(200);
}else{
context.response(501);
}
}
@Route(path = "^/admin/tag/(\\d+)$", type = PUT, needLogin = true)
public void edit(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
JsonMap json = reader.readJson();
if(repo.adminUpdateTag(new Tag(Integer.parseInt(matcher.group(1)), json.get("name")))){
context.response(200);
}else{
context.response(501);
}
}
@Route(path = "^/admin/tag/$", needLogin = true)
public void get(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
List<Tag> list = repo.getAdminTags();
JsonArray json = new JsonArray();
for(Tag tag : list) json.add(tag.toJson());
context.response(200);
writer.write(json.toString());
writer.flush();
}
}

View file

@ -0,0 +1,28 @@
package dev.peerat.backend.routes.admins;
import java.util.regex.Matcher;
import dev.peerat.backend.model.Completion;
import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Injection;
import dev.peerat.framework.Locker;
import dev.peerat.framework.Response;
import dev.peerat.framework.Route;
public class WebHookLeaderboard implements Response{
private Locker<Completion> locker;
public WebHookLeaderboard(@Injection("leaderboard") Locker<Completion> locker){
this.locker = locker;
}
@Route(path = "^/admin/webhook/leaderboard/$", needLogin = true)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
locker.setValue(new Completion(0, 0));
context.response(200);
}
}

View file

@ -5,30 +5,35 @@ import static dev.peerat.framework.RequestType.POST;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Chapter; import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.model.Group; import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.PeerAtUser; import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabaseChapterRepository;
import dev.peerat.backend.repository.DatabaseGroupRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.backend.utils.FormResponse; import dev.peerat.backend.utils.FormResponse;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter; import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Injection;
import dev.peerat.framework.Locker; import dev.peerat.framework.Locker;
import dev.peerat.framework.Response;
import dev.peerat.framework.Route; import dev.peerat.framework.Route;
import dev.peerat.framework.utils.json.JsonMap; import dev.peerat.framework.utils.json.JsonMap;
public class GroupCreate extends FormResponse { public class GroupCreate extends FormResponse {
private Locker<Group> locker; private Locker<Group> locker;
private DatabaseRepository repo; private DatabaseGroupRepository repo;
private DatabaseChapterRepository chapterRepo;
private int groupDelay; private int groupDelay;
public GroupCreate(DatabaseRepository repo, Locker<Group> locker, int groupDelay){ public GroupCreate(DatabaseRepository repo, @Injection("groups") Locker<Group> locker, Configuration config){
this.repo = repo; this.repo = repo.getGroupRepository();
this.chapterRepo = repo.getChapterRepository();
this.locker = locker; this.locker = locker;
this.groupDelay = groupDelay; this.groupDelay = config.getGroupJoinMinutes();
validator("name", "[a-zA-Z0-9&|!?{}\\[\\]%/*\\-+=:;,_#@ ]{3,100}"); validator("name", "[a-zA-Z0-9&|!?{}\\[\\]%/*\\-+=:;,_#@ ]{3,100}");
} }
@ -54,7 +59,7 @@ public class GroupCreate extends FormResponse {
return; return;
}catch(NullPointerException e){ }catch(NullPointerException e){
if(newGroup.getLinkToChapter() != null){ if(newGroup.getLinkToChapter() != null){
Chapter chapter = this.repo.getChapter(newGroup.getLinkToChapter()); Chapter chapter = this.chapterRepo.getChapter(newGroup.getLinkToChapter());
if(chapter.getStartDate() != null){ if(chapter.getStartDate() != null){
LocalDateTime start = chapter.getStartDate().toLocalDateTime().plusMinutes(this.groupDelay); LocalDateTime start = chapter.getStartDate().toLocalDateTime().plusMinutes(this.groupDelay);
if(LocalDateTime.now().isAfter(start)){ if(LocalDateTime.now().isAfter(start)){

View file

@ -5,31 +5,37 @@ import static dev.peerat.framework.RequestType.POST;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Chapter; import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.model.Completion; import dev.peerat.backend.model.Completion;
import dev.peerat.backend.model.Group; import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.PeerAtUser; import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabaseChapterRepository;
import dev.peerat.backend.repository.DatabaseGroupRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter; import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Injection;
import dev.peerat.framework.Locker; import dev.peerat.framework.Locker;
import dev.peerat.framework.Response; import dev.peerat.framework.Response;
import dev.peerat.framework.Route; import dev.peerat.framework.Route;
public class GroupJoin implements Response{ public class GroupJoin implements Response{
private DatabaseRepository repo; private DatabaseChapterRepository chapterRepo;
private DatabaseGroupRepository groupRepo;
private int groupDelay; private int groupDelay;
private String waitTime; private String waitTime;
private final Locker<Completion> leaderboard; private final Locker<Completion> leaderboard;
public GroupJoin(DatabaseRepository repo, int groupDelay, String waitTime, Locker<Completion> locker){ public GroupJoin(DatabaseRepository repo, Configuration config, @Injection("leaderboard") Locker<Completion> locker){
this.repo = repo; this.chapterRepo = repo.getChapterRepository();
this.groupDelay = groupDelay; this.groupRepo = repo.getGroupRepository();
this.waitTime = waitTime; this.groupDelay = config.getGroupJoinMinutes();
this.waitTime = config.getGroupQuitMinutes();
this.leaderboard = locker; this.leaderboard = locker;
} }
@ -43,7 +49,7 @@ public class GroupJoin implements Response{
Group group = new Group(reader.readJson()); Group group = new Group(reader.readJson());
PeerAtUser user = context.getUser(); PeerAtUser user = context.getUser();
Group userGroup = this.repo.getPlayerGroup(user.getId(), group.getLinkToChapter()); Group userGroup = this.groupRepo.getPlayerGroup(user.getId(), group.getLinkToChapter());
if(group.equals(userGroup)){ if(group.equals(userGroup)){
context.response(403); context.response(403);
return; return;
@ -56,7 +62,7 @@ public class GroupJoin implements Response{
} }
if(group.getLinkToChapter() != null){ if(group.getLinkToChapter() != null){
Chapter chapter = this.repo.getChapter(group.getLinkToChapter()); Chapter chapter = this.chapterRepo.getChapter(group.getLinkToChapter());
if(chapter.getStartDate() != null){ if(chapter.getStartDate() != null){
LocalDateTime start = chapter.getStartDate().toLocalDateTime().plusMinutes(this.groupDelay); LocalDateTime start = chapter.getStartDate().toLocalDateTime().plusMinutes(this.groupDelay);
if(LocalDateTime.now().isAfter(start)){ if(LocalDateTime.now().isAfter(start)){
@ -66,7 +72,7 @@ public class GroupJoin implements Response{
} }
} }
if (this.repo.insertUserInGroup(group, user)) { if (this.groupRepo.insertUserInGroup(group, user)) {
context.response(200); context.response(200);
leaderboard.setValue(new Completion(0, 0, 0, null, 0)); leaderboard.setValue(new Completion(0, 0, 0, null, 0));

View file

@ -4,6 +4,7 @@ import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Group; import dev.peerat.backend.model.Group;
import dev.peerat.backend.repository.DatabaseGroupRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
@ -14,19 +15,28 @@ import dev.peerat.framework.utils.json.JsonArray;
public class GroupList implements Response { public class GroupList implements Response {
private DatabaseRepository repo; private DatabaseGroupRepository repo;
public GroupList(DatabaseRepository repo) { public GroupList(DatabaseRepository repo){
this.repo = repo; this.repo = repo.getGroupRepository();
} }
@RouteDoc(path = "/groups", responseCode = 200, responseDescription = "JSON avec la liste des groups") @RouteDoc(path = "/groups", responseCode = 200, responseDescription = "JSON avec la liste des groups")
@Route(path = "^\\/groups$", needLogin = true) @Route(path = "^\\/groups\\/?(\\d+)?$", needLogin = true)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception { public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
context.response(200); String param = matcher.group(1);
if(param == null){
JsonArray result = new JsonArray();
for(Group group : this.repo.getAllGroups()) result.add(group.toJson());
context.response(200);
writer.write(result.toString());
return;
}
int chapter = Integer.parseInt(param);
JsonArray result = new JsonArray(); JsonArray result = new JsonArray();
for(Group group : this.repo.getAllGroups()) result.add(group.toJson()); for(Group group : this.repo.getAllGroupsByChapter(chapter)) result.add(group.toJson());
context.response(200);
writer.write(result.toString()); writer.write(result.toString());
} }

View file

@ -5,29 +5,35 @@ import static dev.peerat.framework.RequestType.POST;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Chapter; import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.model.Completion; import dev.peerat.backend.model.Completion;
import dev.peerat.backend.model.Group; import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.PeerAtUser; import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabaseChapterRepository;
import dev.peerat.backend.repository.DatabaseGroupRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter; import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Injection;
import dev.peerat.framework.Locker; import dev.peerat.framework.Locker;
import dev.peerat.framework.Response; import dev.peerat.framework.Response;
import dev.peerat.framework.Route; import dev.peerat.framework.Route;
public class GroupQuit implements Response{ public class GroupQuit implements Response{
private DatabaseRepository repo; private DatabaseChapterRepository chapterRepo;
private DatabaseGroupRepository groupRepo;
private int groupDelay; private int groupDelay;
private final Locker<Completion> leaderboard; private final Locker<Completion> leaderboard;
public GroupQuit(DatabaseRepository repo, int groupDelay, Locker<Completion> locker){ public GroupQuit(DatabaseRepository repo, Configuration config, @Injection("leaderboard") Locker<Completion> locker){
this.repo = repo; this.chapterRepo = repo.getChapterRepository();
this.groupDelay = groupDelay; this.groupRepo = repo.getGroupRepository();
this.groupDelay = config.getGroupJoinMinutes();
this.leaderboard = locker; this.leaderboard = locker;
} }
@ -41,14 +47,14 @@ public class GroupQuit implements Response{
Group group = new Group(reader.readJson()); Group group = new Group(reader.readJson());
PeerAtUser user = context.getUser(); PeerAtUser user = context.getUser();
Group userGroup = this.repo.getPlayerGroup(user.getId(), group.getLinkToChapter()); Group userGroup = this.groupRepo.getPlayerGroup(user.getId(), group.getLinkToChapter());
if(!group.equals(userGroup)){ if(!group.equals(userGroup)){
context.response(403); context.response(403);
return; return;
} }
if(group.getLinkToChapter() != null){ if(group.getLinkToChapter() != null){
Chapter chapter = this.repo.getChapter(group.getLinkToChapter()); Chapter chapter = this.chapterRepo.getChapter(group.getLinkToChapter());
if(chapter.getStartDate() != null){ if(chapter.getStartDate() != null){
LocalDateTime start = chapter.getStartDate().toLocalDateTime().plusMinutes(this.groupDelay); LocalDateTime start = chapter.getStartDate().toLocalDateTime().plusMinutes(this.groupDelay);
if(LocalDateTime.now().isAfter(start)){ if(LocalDateTime.now().isAfter(start)){
@ -58,7 +64,7 @@ public class GroupQuit implements Response{
} }
} }
if (this.repo.leaveGroup(group, user)) { if (this.groupRepo.leaveGroup(group, user)) {
context.response(200); context.response(200);
leaderboard.setValue(new Completion(0, 0, 0, null, 0)); leaderboard.setValue(new Completion(0, 0, 0, null, 0));

View file

@ -4,6 +4,7 @@ import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.PeerAtUser; import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabasePlayerRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
@ -15,10 +16,10 @@ import dev.peerat.framework.utils.json.JsonMap;
public class ChangePassword implements Response{ public class ChangePassword implements Response{
private DatabaseRepository repo; private DatabasePlayerRepository repo;
public ChangePassword(DatabaseRepository repo){ public ChangePassword(DatabaseRepository repo){
this.repo = repo; this.repo = repo.getPlayerRepository();
} }
@RouteDoc(path = "/user/cpw", responseCode = 200, responseDescription = "L'utilisateur a mis à jours sont mots de passe") @RouteDoc(path = "/user/cpw", responseCode = 200, responseDescription = "L'utilisateur a mis à jours sont mots de passe")

View file

@ -2,12 +2,18 @@ package dev.peerat.backend.routes.users;
import static dev.peerat.framework.RequestType.POST; import static dev.peerat.framework.RequestType.POST;
import java.lang.reflect.Constructor;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import dev.peerat.backend.model.PeerAtUser; import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabasePlayerRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.backend.utils.FormResponse; import dev.peerat.backend.utils.FormResponse;
import dev.peerat.backend.utils.Mail; import dev.peerat.backend.utils.Mail;
@ -21,15 +27,30 @@ import dev.peerat.framework.utils.json.JsonMap;
public class ForgotPassword extends FormResponse{ public class ForgotPassword extends FormResponse{
private Router<PeerAtUser> router; private Router<PeerAtUser> router;
private DatabaseRepository repo; private DatabasePlayerRepository repo;
private Mail mail; private Mail mail;
private Map<String, Integer> codes; private Map<String, String> codes;
private List<Random> randoms;
public ForgotPassword(Router<PeerAtUser> router, DatabaseRepository repo, Mail mail){ public ForgotPassword(Router<PeerAtUser> router, DatabaseRepository repo, Mail mail){
this.router = router; this.router = router;
this.repo = repo; this.repo = repo.getPlayerRepository();
this.mail = mail; this.mail = mail;
this.codes = new HashMap<>(); this.codes = new HashMap<>();
this.randoms = new ArrayList<>();
Random random = new Random();
int randoms = random.nextInt(10)+3;
for(int i = 0; i < randoms; i++) this.randoms.add(new SecureRandom());
try {
Constructor<?> constructor = UUID.class.getDeclaredConstructor(byte[].class);
constructor.setAccessible(true);
this.uuidBuilder = constructor;
} catch (Exception e){
e.printStackTrace();
}
} }
@Route(path = "^/user/fpw$", type = POST) @Route(path = "^/user/fpw$", type = POST)
@ -54,16 +75,16 @@ public class ForgotPassword extends FormResponse{
} }
if(hasFields("code") && areValids("password")){ if(hasFields("code") && areValids("password")){
Integer checkCode = codes.get(email); String checkCode = codes.get(email);
if(checkCode == null){ if(checkCode == null){
context.response(400); context.response(400);
return; return;
} }
int code = json.<Number>get("code").intValue(); String code = json.<String>get("code");
String password = json.get("password"); String password = json.get("password");
if(code == checkCode.intValue()){ if(checkCode.equals(code)){
codes.remove(email); codes.remove(email);
repo.updatePassword(player, password); repo.updatePassword(player, password);
@ -74,18 +95,30 @@ public class ForgotPassword extends FormResponse{
context.response(400); context.response(400);
} }
}else{ }else{
int code = codeGenerator(); String code = codeGenerator();
codes.put(email, code); codes.put(email, code);
mail.send(email, "Forgot your Peer @ Code password ?", "Your check code is "+code+" !"); mail.send(email, "Forgot your Peer @ Code password ?", "Your check code is "+code+" !");
context.response(200); context.response(200);
} }
} }
private int codeGenerator(){ private Constructor<?> uuidBuilder;
int min = 1000; private int[] start = {4, 9, 14, 19};
int max = 9999;
return new Random().nextInt((max-min)) + min; private String codeGenerator() throws Exception{
Random random = new Random();
Random target = this.randoms.get(random.nextInt(this.randoms.size()));
byte[] arrayOfByte = new byte[16];
target.nextBytes(arrayOfByte);
arrayOfByte[6] = (byte)(arrayOfByte[6] & 0xF);
arrayOfByte[6] = (byte)(arrayOfByte[6] | 0x40);
arrayOfByte[8] = (byte)(arrayOfByte[8] & 0x3F);
arrayOfByte[8] = (byte)(arrayOfByte[8] | 0x80);
String uuid = uuidBuilder.newInstance(arrayOfByte).toString();
target = this.randoms.get(random.nextInt(this.randoms.size()));
int start = this.start[target.nextInt(this.start.length)];
return uuid.substring(start, start+9);
} }
} }

View file

@ -6,6 +6,7 @@ import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.PeerAtUser; import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabaseAuthRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.backend.utils.FormResponse; import dev.peerat.backend.utils.FormResponse;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
@ -17,11 +18,11 @@ import dev.peerat.framework.utils.json.JsonMap;
public class Login extends FormResponse{ public class Login extends FormResponse{
private DatabaseRepository databaseRepo; private DatabaseAuthRepository repo;
private Router<PeerAtUser> router; private Router<PeerAtUser> router;
public Login(DatabaseRepository databaseRepo, Router<PeerAtUser> router){ public Login(DatabaseRepository databaseRepo, Router<PeerAtUser> router){
this.databaseRepo = databaseRepo; this.repo = databaseRepo.getAuthRepository();
this.router = router; this.router = router;
} }
@ -41,7 +42,7 @@ public class Login extends FormResponse{
return; return;
} }
int id; int id;
if((id = databaseRepo.login(json.get("pseudo"), json.get("passwd"))) >= 0){ if((id = repo.login(json.get("pseudo"), json.get("passwd"))) >= 0){
context.response(200, context.response(200,
"Access-Control-Expose-Headers: Authorization", "Access-Control-Expose-Headers: Authorization",
"Authorization: Bearer " + this.router.createAuthUser(new PeerAtUser(id))); "Authorization: Bearer " + this.router.createAuthUser(new PeerAtUser(id)));

View file

@ -5,6 +5,7 @@ import static dev.peerat.framework.RequestType.POST;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.lang.reflect.Constructor;
import java.net.URL; import java.net.URL;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.file.Files; import java.nio.file.Files;
@ -12,11 +13,15 @@ import java.nio.file.Paths;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPublicKey; import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.Base64; import java.util.Base64;
import java.util.Base64.Encoder; import java.util.Base64.Encoder;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HttpsURLConnection;
@ -24,41 +29,44 @@ import javax.net.ssl.HttpsURLConnection;
import org.jose4j.json.internal.json_simple.JSONAware; import org.jose4j.json.internal.json_simple.JSONAware;
import org.jose4j.json.internal.json_simple.JSONObject; import org.jose4j.json.internal.json_simple.JSONObject;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.PeerAtUser; import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabaseAuthRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.backend.utils.FormResponse; import dev.peerat.backend.utils.FormResponse;
import dev.peerat.backend.utils.Mail; import dev.peerat.backend.utils.Mail;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter; import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Injection;
import dev.peerat.framework.Route; import dev.peerat.framework.Route;
import dev.peerat.framework.Router; import dev.peerat.framework.Router;
import dev.peerat.framework.utils.json.JsonMap; import dev.peerat.framework.utils.json.JsonMap;
public class MailConfirmation extends FormResponse { public class MailConfirmation extends FormResponse{
private DatabaseRepository databaseRepo; private DatabaseAuthRepository databaseRepo;
private Router<PeerAtUser> router; private Router<PeerAtUser> router;
private String usersFilesPath; private String usersFilesPath;
private KeyPairGenerator generator; private KeyPairGenerator generator;
private Encoder encoder; private Encoder encoder;
private String gitToken; private String gitToken;
private Map<String, Integer> playersWaiting; private Map<String, String> playersWaiting;
private Mail mail; private Mail mail;
private List<Random> randoms;
public MailConfirmation( public MailConfirmation(
DatabaseRepository databaseRepo, DatabaseRepository databaseRepo,
Router<PeerAtUser> router, Router<PeerAtUser> router,
String initUsersFilesPath, Configuration config,
String gitToken, @Injection("waitting") Map<String, String> playersWaiting,
Map<String, Integer> playersWaiting,
Mail mail) throws NoSuchAlgorithmException{ Mail mail) throws NoSuchAlgorithmException{
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo.getAuthRepository();
this.router = router; this.router = router;
this.usersFilesPath = initUsersFilesPath; this.usersFilesPath = config.getUsersFiles();
this.gitToken = gitToken; this.gitToken = config.getGitToken();
this.playersWaiting = playersWaiting; this.playersWaiting = playersWaiting;
this.mail = mail; this.mail = mail;
@ -66,9 +74,23 @@ public class MailConfirmation extends FormResponse {
generator.initialize(4096); generator.initialize(4096);
encoder = Base64.getEncoder(); encoder = Base64.getEncoder();
this.randoms = new ArrayList<>();
Random random = new Random();
int randoms = random.nextInt(10)+3;
for(int i = 0; i < randoms; i++) this.randoms.add(new SecureRandom());
try {
Constructor<?> constructor = UUID.class.getDeclaredConstructor(byte[].class);
constructor.setAccessible(true);
this.uuidBuilder = constructor;
} catch (Exception e){
e.printStackTrace();
}
validator("pseudo", "[a-zA-Z0-9&|!?{}\\[\\]%/*\\-+=:;,_#@ ]{3,100}"); validator("pseudo", "[a-zA-Z0-9&|!?{}\\[\\]%/*\\-+=:;,_#@ ]{3,100}");
validator("firstname", "^(?>[a-zA-Z]+ ?)+$"); validator("firstname", "^(?>[A-Za-zÀ-ÖØ-öø-ÿ]+ ?)+$");
validator("lastname", "^(?>[a-zA-Z]+ ?)+$"); validator("lastname", "^(?>[A-Za-zÀ-ÖØ-öø-ÿ]+ ?)+$");
} }
@RouteDoc(path = "/confirmation", responseCode = 200, responseDescription = "L'utilisateur est inscrit") @RouteDoc(path = "/confirmation", responseCode = 200, responseDescription = "L'utilisateur est inscrit")
@ -87,13 +109,13 @@ public class MailConfirmation extends FormResponse {
return; return;
} }
String email = json.get("email"); String email = json.get("email");
int code = json.<Number>get("code").intValue(); String code = json.<String>get("code");
String pseudo = json.get("pseudo"); String pseudo = json.get("pseudo");
String firstname = json.get("firstname"); String firstname = json.get("firstname");
String lastname = json.get("lastname"); String lastname = json.get("lastname");
String password = json.get("passwd"); String password = json.get("passwd");
Integer checkCode = playersWaiting.get(email); String checkCode = playersWaiting.get(email);
if(checkCode == null){ if(checkCode == null){
context.response(400); context.response(400);
return; return;
@ -102,7 +124,7 @@ public class MailConfirmation extends FormResponse {
boolean pseudoAvailable = databaseRepo.checkPseudoAvailability(pseudo); boolean pseudoAvailable = databaseRepo.checkPseudoAvailability(pseudo);
boolean emailAvailable = databaseRepo.checkEmailAvailability(email); boolean emailAvailable = databaseRepo.checkEmailAvailability(email);
if(pseudoAvailable && emailAvailable){ if(pseudoAvailable && emailAvailable){
if(code == checkCode.intValue()){ if(code.equals(checkCode)){
playersWaiting.remove(email); playersWaiting.remove(email);
int id = databaseRepo.register(pseudo, email, password, firstname, lastname, "", "", ""); int id = databaseRepo.register(pseudo, email, password, firstname, lastname, "", "", "");
if(id >= 0){ if(id >= 0){
@ -117,7 +139,7 @@ public class MailConfirmation extends FormResponse {
error.set("username_valid", pseudo); error.set("username_valid", pseudo);
error.set("email_valid", email); error.set("email_valid", email);
writer.write(error.toString()); writer.write(error.toString());
int ncode = codeGenerator(); String ncode = codeGenerator();
playersWaiting.put(email, ncode); playersWaiting.put(email, ncode);
mail.send(email, "Welcome @ Peer @ Code", "Your check code is "+ncode+" !"); mail.send(email, "Welcome @ Peer @ Code", "Your check code is "+ncode+" !");
} }
@ -133,13 +155,25 @@ public class MailConfirmation extends FormResponse {
} }
} }
private int codeGenerator(){ private Constructor<?> uuidBuilder;
int min = 1000; private int[] start = {4, 9, 14, 19};
int max = 9999;
return new Random().nextInt((max-min)) + min; private String codeGenerator() throws Exception{
Random random = new Random();
Random target = this.randoms.get(random.nextInt(this.randoms.size()));
byte[] arrayOfByte = new byte[16];
target.nextBytes(arrayOfByte);
arrayOfByte[6] = (byte)(arrayOfByte[6] & 0xF);
arrayOfByte[6] = (byte)(arrayOfByte[6] | 0x40);
arrayOfByte[8] = (byte)(arrayOfByte[8] & 0x3F);
arrayOfByte[8] = (byte)(arrayOfByte[8] | 0x80);
String uuid = uuidBuilder.newInstance(arrayOfByte).toString();
target = this.randoms.get(random.nextInt(this.randoms.size()));
int start = this.start[target.nextInt(this.start.length)];
return uuid.substring(start, start+9);
} }
private void createFolderToSaveSourceCode(String pseudo) throws IOException { private void createFolderToSaveSourceCode(String pseudo) throws IOException {
Files.createDirectories(Paths.get(String.format("%s/%s", usersFilesPath, pseudo))); Files.createDirectories(Paths.get(String.format("%s/%s", usersFilesPath, pseudo)));

View file

@ -5,6 +5,7 @@ import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.PeerAtUser; import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.model.Player; import dev.peerat.backend.model.Player;
import dev.peerat.backend.repository.DatabasePlayerRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.backend.utils.FormResponse; import dev.peerat.backend.utils.FormResponse;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
@ -16,10 +17,10 @@ import dev.peerat.framework.utils.json.JsonMap;
public class ProfileSettings extends FormResponse{ public class ProfileSettings extends FormResponse{
private DatabaseRepository repo; private DatabasePlayerRepository repo;
public ProfileSettings(DatabaseRepository repo){ public ProfileSettings(DatabaseRepository repo){
this.repo = repo; this.repo = repo.getPlayerRepository();
validator("pseudo", "[a-zA-Z0-9&|!?{}\\[\\]%/*\\-+=:;,_#@ ]{3,100}"); validator("pseudo", "[a-zA-Z0-9&|!?{}\\[\\]%/*\\-+=:;,_#@ ]{3,100}");
} }

View file

@ -2,30 +2,54 @@ package dev.peerat.backend.routes.users;
import static dev.peerat.framework.RequestType.POST; import static dev.peerat.framework.RequestType.POST;
import java.lang.reflect.Constructor;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.repository.DatabaseAuthRepository;
import dev.peerat.backend.repository.DatabaseRepository; import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.backend.utils.FormResponse; import dev.peerat.backend.utils.FormResponse;
import dev.peerat.backend.utils.Mail; import dev.peerat.backend.utils.Mail;
import dev.peerat.framework.Context; import dev.peerat.framework.Context;
import dev.peerat.framework.HttpReader; import dev.peerat.framework.HttpReader;
import dev.peerat.framework.HttpWriter; import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Injection;
import dev.peerat.framework.Route; import dev.peerat.framework.Route;
import dev.peerat.framework.utils.json.JsonMap; import dev.peerat.framework.utils.json.JsonMap;
public class Register extends FormResponse { public class Register extends FormResponse{
private DatabaseRepository databaseRepo; private DatabaseAuthRepository databaseRepo;
private Map<String, Integer> playersWaiting; private Map<String, String> playersWaiting;
private Mail mail; private Mail mail;
private String host;
private List<Random> randoms;
public Register(DatabaseRepository databaseRepo, Map<String, Integer> playersWaiting, Mail mail){ public Register(DatabaseRepository databaseRepo, @Injection("waitting") Map<String, String> playersWaiting, Mail mail, Configuration config){
this.databaseRepo = databaseRepo; this.databaseRepo = databaseRepo.getAuthRepository();
this.playersWaiting = playersWaiting; this.playersWaiting = playersWaiting;
this.mail = mail; this.mail = mail;
this.host = config.getTokenIssuer();
this.randoms = new ArrayList<>();
Random random = new Random();
int randoms = random.nextInt(10)+3;
for(int i = 0; i < randoms; i++) this.randoms.add(new SecureRandom());
try {
Constructor<?> constructor = UUID.class.getDeclaredConstructor(byte[].class);
constructor.setAccessible(true);
this.uuidBuilder = constructor;
} catch (Exception e){
e.printStackTrace();
}
} }
@RouteDoc(path = "/register", responseCode = 200, responseDescription = "L'utilisateur est inscrit") @RouteDoc(path = "/register", responseCode = 200, responseDescription = "L'utilisateur est inscrit")
@ -48,7 +72,7 @@ public class Register extends FormResponse {
boolean emailAvailable = databaseRepo.checkEmailAvailability(email); boolean emailAvailable = databaseRepo.checkEmailAvailability(email);
if(emailAvailable){ if(emailAvailable){
int code = codeGenerator(); String code = codeGenerator();
playersWaiting.put(email, code); playersWaiting.put(email, code);
mail.send(email, "Welcome @ Peer @ Code", "Your check code is "+code+" !"); mail.send(email, "Welcome @ Peer @ Code", "Your check code is "+code+" !");
context.response(200); context.response(200);
@ -60,11 +84,23 @@ public class Register extends FormResponse {
} }
} }
private int codeGenerator(){ private Constructor<?> uuidBuilder;
int min = 1000; private int[] start = {4, 9, 14, 19};
int max = 9999;
return new Random().nextInt((max-min)) + min; private String codeGenerator() throws Exception{
Random random = new Random();
Random target = this.randoms.get(random.nextInt(this.randoms.size()));
byte[] arrayOfByte = new byte[16];
target.nextBytes(arrayOfByte);
arrayOfByte[6] = (byte)(arrayOfByte[6] & 0xF);
arrayOfByte[6] = (byte)(arrayOfByte[6] | 0x40);
arrayOfByte[8] = (byte)(arrayOfByte[8] & 0x3F);
arrayOfByte[8] = (byte)(arrayOfByte[8] | 0x80);
String uuid = uuidBuilder.newInstance(arrayOfByte).toString();
target = this.randoms.get(random.nextInt(this.randoms.size()));
int start = this.start[target.nextInt(this.start.length)];
return uuid.substring(start, start+9);
} }
} }

View file

@ -0,0 +1,7 @@
package dev.peerat.backend.routes;
public interface DatabaseSeeder{
void setup() throws Exception;
}

View file

@ -0,0 +1,162 @@
package dev.peerat.backend.routes;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.jupiter.api.Test;
import org.opentest4j.AssertionFailedError;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.Main;
import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Locker;
import dev.peerat.framework.Locker.Key;
import dev.peerat.framework.RequestType;
import dev.peerat.framework.Router;
public class StateTestCase{
@Test
void main() throws Exception{
Locker<Boolean> locker = new Locker<>();
Thread server = new Thread(new Runnable(){
@Override
public void run(){
try {
locker.setValue(true);
Main.main(null);
} catch (Exception e){
e.printStackTrace();
};
}
});
Key key = new Key();
locker.init(key);
server.start();
Thread.sleep(3000);
locker.lock(key);
locker.unlock(key);
Configuration config = new Configuration("config.txt");
config.load();
DatabaseRepository repo = new DatabaseRepository(config);
Field field = Main.class.getDeclaredField("ACCESS_ROUTER");
field.setAccessible(true);
Router<PeerAtUser> router = (Router<PeerAtUser>) field.get(null);
Function<String, String> tokenProvider = (email) -> {
try{
return router.createAuthUser(new PeerAtUser(repo.getPlayerId(email)));
}catch(Exception ex){
ex.printStackTrace();
return null;
}
};
File dir = new File("./route-test/");
for(File cases : dir.listFiles()){
if(!cases.isDirectory()) continue;
List<File> responses = new ArrayList<>();
File dbsetup = null;
for(File file : cases.listFiles()){
if(file.getName().endsWith(".class")) dbsetup = file; else responses.add(file);
}
// Class<?> clazz = new URLClassLoader(new URL[]{cases.toURI().toURL()}).loadClass(dbsetup.getAbsolutePath().substring(cases.getAbsolutePath().length()+1).replace("/", ".").replace("\\", ".").replace(".class", ""));
// DatabaseSeeder seeder = (DatabaseSeeder) clazz.newInstance();
// seeder.setup();
for(File file : responses){
StateCase state = new StateCase(file, tokenProvider);
state.execute("127.0.0.1", config.getTcpPort());
}
}
}
public static class StateCase{
private static final Pattern TOKEN_PATTERN = Pattern.compile("^(.*)<token:(.*)>(.*)$");
private String path;
private RequestType type;
private List<String> headers;
private String payload;
private int responseCode;
private List<String> responseHeaders;
private String responsePayload;
public StateCase(File file, Function<String, String> tokenProvider) throws Exception{
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
String payloadBuffer;
this.headers = new ArrayList<>();
this.responseHeaders = new ArrayList<>();
this.path = reader.readLine();
this.type = RequestType.valueOf(reader.readLine());
while(((line = reader.readLine() )!= null) && (!line.isEmpty())) headers.add(line);
payloadBuffer = "";
while(((line = reader.readLine() )!= null) && (!line.isEmpty())) payloadBuffer+=line;
this.payload = payloadBuffer;
this.responseCode = Integer.parseInt(reader.readLine());
while(((line = reader.readLine() )!= null) && (!line.isEmpty())) responseHeaders.add(line);
payloadBuffer = "";
while(((line = reader.readLine() )!= null) && (!line.isEmpty())) payloadBuffer+=line;
this.responsePayload = payloadBuffer;
reader.close();
this.headers = Arrays.asList(this.headers.stream().<String>map((header) -> {
Matcher matcher = TOKEN_PATTERN.matcher(header);
return matcher.matches() ? matcher.group(1)+tokenProvider.apply(matcher.group(2))+matcher.group(3) : header;
}).toArray((size) -> new String[size]));
}
public void execute(String host, int port) throws Exception{
Socket socket = new Socket(host, port);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write(this.type.toString()+" "+path+" HTTP/1.1\n");
for(String header : headers) writer.write(header+"\n");
writer.write("\n");
if(payload != null) writer.write(payload+"\n");
writer.flush();
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
int responseCode;
Set<String> responseHeaders = new HashSet<>();
String responseBody = "";
String line;
responseCode = Integer.parseInt(reader.readLine().split("\\s+")[1]);
while(((line = reader.readLine() )!= null) && (!line.isEmpty())) responseHeaders.add(line);
while(((line = reader.readLine() )!= null) && (!line.isEmpty())) responseBody+=line;
socket.close();
if(this.responseCode != responseCode) throw new AssertionFailedError("Excepted "+this.responseCode+" but have "+responseCode);
}
}
}

View file

@ -0,0 +1,10 @@
package dev.peerat.backend.routes.states;
import dev.peerat.backend.routes.DatabaseSeeder;
public class AllEmptyTests implements DatabaseSeeder{
@Override
public void setup() throws Exception{}
}