From ed050b17feb0d33f1bf1cce241f98589c8bd140a Mon Sep 17 00:00:00 2001 From: jeffcheasey88 Date: Fri, 24 Jan 2025 23:16:06 +0100 Subject: [PATCH] update framework --- PeerAtCodeFramework.jar | Bin 542143 -> 545946 bytes src/dev/peerat/backend/Main.java | 59 ++---------- .../peerat/backend/routes/PuzzleResponse.java | 5 +- src/dev/peerat/backend/routes/Swagger.java | 5 +- .../routes/admins/ChapterController.java | 69 ++++++++++++++ .../backend/routes/admins/DynamicLogs.java | 57 ------------ .../backend/routes/admins/ExceptionLogs.java | 49 ---------- .../backend/routes/admins/LogController.java | 74 +++++++++++++++ .../routes/admins/PuzzleController.java | 88 ++++++++++++++++++ .../backend/routes/admins/TagController.java | 67 +++++++++++++ .../routes/admins/chapter/AddChapter.java | 36 ------- .../routes/admins/chapter/DeleteChapter.java | 31 ------ .../routes/admins/chapter/EditChapter.java | 37 -------- .../routes/admins/chapter/GetChapter.java | 34 ------- .../routes/admins/puzzle/AddPuzzle.java | 35 ------- .../routes/admins/puzzle/DeletePuzzle.java | 32 ------- .../routes/admins/puzzle/EditPuzzle.java | 35 ------- .../routes/admins/puzzle/GetPuzzle.java | 35 ------- .../routes/admins/puzzle/GetPuzzles.java | 41 -------- .../backend/routes/admins/tag/AddTag.java | 33 ------- .../backend/routes/admins/tag/DeleteTag.java | 31 ------ .../backend/routes/admins/tag/EditTag.java | 34 ------- .../backend/routes/admins/tag/GetTags.java | 33 ------- .../backend/routes/groups/GroupCreate.java | 6 +- .../backend/routes/groups/GroupJoin.java | 7 +- .../backend/routes/groups/GroupQuit.java | 5 +- 26 files changed, 323 insertions(+), 615 deletions(-) create mode 100644 src/dev/peerat/backend/routes/admins/ChapterController.java delete mode 100644 src/dev/peerat/backend/routes/admins/DynamicLogs.java delete mode 100644 src/dev/peerat/backend/routes/admins/ExceptionLogs.java create mode 100644 src/dev/peerat/backend/routes/admins/LogController.java create mode 100644 src/dev/peerat/backend/routes/admins/PuzzleController.java create mode 100644 src/dev/peerat/backend/routes/admins/TagController.java delete mode 100644 src/dev/peerat/backend/routes/admins/chapter/AddChapter.java delete mode 100644 src/dev/peerat/backend/routes/admins/chapter/DeleteChapter.java delete mode 100644 src/dev/peerat/backend/routes/admins/chapter/EditChapter.java delete mode 100644 src/dev/peerat/backend/routes/admins/chapter/GetChapter.java delete mode 100644 src/dev/peerat/backend/routes/admins/puzzle/AddPuzzle.java delete mode 100644 src/dev/peerat/backend/routes/admins/puzzle/DeletePuzzle.java delete mode 100644 src/dev/peerat/backend/routes/admins/puzzle/EditPuzzle.java delete mode 100644 src/dev/peerat/backend/routes/admins/puzzle/GetPuzzle.java delete mode 100644 src/dev/peerat/backend/routes/admins/puzzle/GetPuzzles.java delete mode 100644 src/dev/peerat/backend/routes/admins/tag/AddTag.java delete mode 100644 src/dev/peerat/backend/routes/admins/tag/DeleteTag.java delete mode 100644 src/dev/peerat/backend/routes/admins/tag/EditTag.java delete mode 100644 src/dev/peerat/backend/routes/admins/tag/GetTags.java diff --git a/PeerAtCodeFramework.jar b/PeerAtCodeFramework.jar index 5eb43e13012559c6973d70cd390acd8fc4337bfa..d48268bf179ffd2ad4e21ec431be34097ff4de91 100644 GIT binary patch delta 38685 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 JgBS|M{{j2gtmps$ delta 34581 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 diff --git a/src/dev/peerat/backend/Main.java b/src/dev/peerat/backend/Main.java index a5790a2..04822d4 100644 --- a/src/dev/peerat/backend/Main.java +++ b/src/dev/peerat/backend/Main.java @@ -9,47 +9,9 @@ import java.util.Map.Entry; import java.util.regex.Matcher; import dev.peerat.backend.bonus.extract.RouteExtracter; -import dev.peerat.backend.model.Completion; import dev.peerat.backend.model.Group; import dev.peerat.backend.model.PeerAtUser; 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.admins.ExceptionLogs; -import dev.peerat.backend.routes.admins.WebHookLeaderboard; -import dev.peerat.backend.routes.admins.chapter.AddChapter; -import dev.peerat.backend.routes.admins.chapter.DeleteChapter; -import dev.peerat.backend.routes.admins.chapter.EditChapter; -import dev.peerat.backend.routes.admins.chapter.GetChapter; -import dev.peerat.backend.routes.admins.puzzle.AddPuzzle; -import dev.peerat.backend.routes.admins.puzzle.DeletePuzzle; -import dev.peerat.backend.routes.admins.puzzle.EditPuzzle; -import dev.peerat.backend.routes.admins.puzzle.GetPuzzle; -import dev.peerat.backend.routes.admins.puzzle.GetPuzzles; -import dev.peerat.backend.routes.admins.tag.AddTag; -import dev.peerat.backend.routes.admins.tag.DeleteTag; -import dev.peerat.backend.routes.admins.tag.EditTag; -import dev.peerat.backend.routes.admins.tag.GetTags; -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.DependencyInjector; import dev.peerat.framework.HttpReader; @@ -61,6 +23,8 @@ import dev.peerat.framework.Response; import dev.peerat.framework.Route; import dev.peerat.framework.RouteInterceptor; import dev.peerat.framework.Router; +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; @@ -86,12 +50,13 @@ public class Main{ "Access-Control-Allow-Headers: *"); ACCESS_ROUTER = router; + Authenticator auth; if(config.getJwtKey() != null){ JsonParser parser = new JsonParser(); JsonMap json = parser.parse(config.getJwtKey()); Map params = new HashMap<>(); for(Entry entry : json.entries()) params.put(entry.getKey(), entry.getValue()); - router.configureJwt( + auth = new JwtAuthenticator().configure( (builder) -> builder.setExpectedIssuer(config.getTokenIssuer()), (claims) -> { claims.setIssuer(config.getTokenIssuer()); @@ -100,7 +65,7 @@ public class Main{ (claims) -> new PeerAtUser(claims), params); }else{ - router.configureJwt( + auth = new JwtAuthenticator().configure( (builder) -> builder.setExpectedIssuer(config.getTokenIssuer()), (claims) -> { claims.setIssuer(config.getTokenIssuer()); @@ -108,12 +73,13 @@ public class Main{ }, (claims) -> new PeerAtUser(claims)); JsonMap json = new JsonMap(); - for(Entry entry : router.exportJwtKey().entrySet()){ + for(Entry entry : ((JwtAuthenticator)auth).exportKey().entrySet()){ json.set(entry.getKey(), entry.getValue()); } config.setJwtKey(json.toString()); config.save(); } + router.setAuthenticator(auth); router.setDefault((matcher, context, reader, writer) -> { context.response(404); @@ -179,17 +145,10 @@ public class Main{ private static void initRoutes(Router router, DatabaseRepository repo, Configuration config) throws Exception{ router.registerPackages(new DependencyInjector() - .of(repo, router, config.getMail(), new RouteExtracter(router)) + .of(repo, router, config, new RouteExtracter(router)) .of("waitting", new HashMap<>()) .of("leaderboard", new Locker<>()) - .of("log", router.getLogger()) - .of("exception", router.getExceptionLogger()) - .of("groups", new Locker<>()) - .of("groupDelay", config.getGroupJoinMinutes()) - .of("waitTime", config.getGroupQuitMinutes()) - .of("usersFiles", config.getUsersFiles()) - .of("gitToken", config.getGitToken()) - .of("issuer", config.getTokenIssuer())); + .of("groups", new Locker<>())); // Bot bot = new Bot(config, repo, groupLock); // bot.start(); diff --git a/src/dev/peerat/backend/routes/PuzzleResponse.java b/src/dev/peerat/backend/routes/PuzzleResponse.java index bef440e..4ab744f 100644 --- a/src/dev/peerat/backend/routes/PuzzleResponse.java +++ b/src/dev/peerat/backend/routes/PuzzleResponse.java @@ -11,6 +11,7 @@ import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; +import dev.peerat.backend.Configuration; import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.model.Chapter; import dev.peerat.backend.model.Completion; @@ -34,9 +35,9 @@ public class PuzzleResponse implements Response { private final Locker leaderboard; - public PuzzleResponse(DatabaseRepository databaseRepo, @Injection("usersFiles") String initUsersFilesPath, @Injection("leaderboard") Locker locker){ + public PuzzleResponse(DatabaseRepository databaseRepo, Configuration config, @Injection("leaderboard") Locker locker){ this.databaseRepo = databaseRepo; - usersFilesPath = initUsersFilesPath; + usersFilesPath = config.getUsersFiles(); this.leaderboard = locker; } diff --git a/src/dev/peerat/backend/routes/Swagger.java b/src/dev/peerat/backend/routes/Swagger.java index ba271c2..afe35d4 100644 --- a/src/dev/peerat/backend/routes/Swagger.java +++ b/src/dev/peerat/backend/routes/Swagger.java @@ -2,6 +2,7 @@ package dev.peerat.backend.routes; import java.util.regex.Matcher; +import dev.peerat.backend.Configuration; import dev.peerat.backend.bonus.extract.RouteExtracter; import dev.peerat.framework.Context; import dev.peerat.framework.HttpReader; @@ -14,9 +15,9 @@ public class Swagger implements Response{ private String json; - public Swagger(RouteExtracter extracter, @Injection("issuer") String host){ + public Swagger(RouteExtracter extracter, Configuration config){ try{ - this.json = extracter.swagger(host).toString(); + this.json = extracter.swagger(config.getTokenIssuer()).toString(); }catch(Exception e){ e.printStackTrace(); json = "{}"; diff --git a/src/dev/peerat/backend/routes/admins/ChapterController.java b/src/dev/peerat/backend/routes/admins/ChapterController.java new file mode 100644 index 0000000..439a8ca --- /dev/null +++ b/src/dev/peerat/backend/routes/admins/ChapterController.java @@ -0,0 +1,69 @@ +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.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 DatabaseRepository repo; + + public ChapterController(DatabaseRepository repo){ + this.repo = repo; + } + + @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.get("start")), Timestamp.valueOf(json.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.get("start")), Timestamp.valueOf(json.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"); + } + +} diff --git a/src/dev/peerat/backend/routes/admins/DynamicLogs.java b/src/dev/peerat/backend/routes/admins/DynamicLogs.java deleted file mode 100644 index a76ff72..0000000 --- a/src/dev/peerat/backend/routes/admins/DynamicLogs.java +++ /dev/null @@ -1,57 +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.Injection; -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 locker; //Context - private DatabaseRepository repo; - - public DynamicLogs(@Injection("log") Locker 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{ - 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.getUser().getId()).getPseudo()); - json.set("path", instance.getPath()); - json.set("type", instance.getType().toString()); - json.set("code", instance.getResponseCode()); - - writer.write(json.toString()); - writer.flush(); - } - }catch(Exception e){} - locker.remove(key); - } - - - -} diff --git a/src/dev/peerat/backend/routes/admins/ExceptionLogs.java b/src/dev/peerat/backend/routes/admins/ExceptionLogs.java deleted file mode 100644 index a8fdeff..0000000 --- a/src/dev/peerat/backend/routes/admins/ExceptionLogs.java +++ /dev/null @@ -1,49 +0,0 @@ -package dev.peerat.backend.routes.admins; - -import java.util.regex.Matcher; - -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.Locker.Key; -import dev.peerat.framework.Response; -import dev.peerat.framework.Route; -import dev.peerat.framework.utils.json.JsonArray; -import dev.peerat.framework.utils.json.JsonMap; - -public class ExceptionLogs implements Response{ - - private Locker locker; - - public ExceptionLogs(@Injection("exception") Locker locker){ - this.locker = locker; - } - - @Route(path = "^/admin/exceptions$", needLogin = true, websocket = true) - public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{ - Key key = new Key(); - - locker.init(key); - try { - while(!reader.isClosed()){ - locker.lock(key); - Exception exception = locker.getValue(key); - JsonMap json = new JsonMap(); - 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); - - writer.write(json.toString()); - writer.flush(); - } - }catch(Exception e){} - locker.remove(key); - } - - - -} diff --git a/src/dev/peerat/backend/routes/admins/LogController.java b/src/dev/peerat/backend/routes/admins/LogController.java new file mode 100644 index 0000000..38a5e1b --- /dev/null +++ b/src/dev/peerat/backend/routes/admins/LogController.java @@ -0,0 +1,74 @@ +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.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 contextLocker; + private Locker exceptionLocker; + private DatabaseRepository repo; + + public LogController(Router router, DatabaseRepository repo){ + this.contextLocker = router.getLogger(); + this.exceptionLocker = router.getExceptionLogger(); + 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 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", repo.getPlayer(instance.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 void log(HttpReader reader, HttpWriter writer, Locker locker, BiConsumer 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); + } + +} diff --git a/src/dev/peerat/backend/routes/admins/PuzzleController.java b/src/dev/peerat/backend/routes/admins/PuzzleController.java new file mode 100644 index 0000000..97a6ab1 --- /dev/null +++ b/src/dev/peerat/backend/routes/admins/PuzzleController.java @@ -0,0 +1,88 @@ +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.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 DatabaseRepository repo; + + public PuzzleController(DatabaseRepository repo){ + this.repo = repo; + } + + @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.get("soluce").getBytes(), null, json.get("scoreMax").intValue(), null, -1, null); + if(repo.adminAddPuzzle(puzzle, json.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.get("soluce").getBytes(), null, json.get("scoreMax").intValue(), null, -1, null); + if(repo.adminUpdatePuzzle(Integer.parseInt(matcher.group(1)), puzzle, json.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 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()); + } +} diff --git a/src/dev/peerat/backend/routes/admins/TagController.java b/src/dev/peerat/backend/routes/admins/TagController.java new file mode 100644 index 0000000..3462ec4 --- /dev/null +++ b/src/dev/peerat/backend/routes/admins/TagController.java @@ -0,0 +1,67 @@ +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.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 DatabaseRepository repo; + + public TagController(DatabaseRepository repo){ + this.repo = repo; + } + + @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 list = repo.getAdminTags(); + JsonArray json = new JsonArray(); + for(Tag tag : list) json.add(tag.toJson()); + context.response(200); + writer.write(json.toString()); + writer.flush(); + } + + +} diff --git a/src/dev/peerat/backend/routes/admins/chapter/AddChapter.java b/src/dev/peerat/backend/routes/admins/chapter/AddChapter.java deleted file mode 100644 index 84f9dd5..0000000 --- a/src/dev/peerat/backend/routes/admins/chapter/AddChapter.java +++ /dev/null @@ -1,36 +0,0 @@ -package dev.peerat.backend.routes.admins.chapter; - -import static dev.peerat.framework.RequestType.POST; - -import java.sql.Timestamp; -import java.util.regex.Matcher; - -import dev.peerat.backend.model.Chapter; -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.Response; -import dev.peerat.framework.Route; -import dev.peerat.framework.utils.json.JsonMap; - -public class AddChapter implements Response{ - - private DatabaseRepository repo; - - public AddChapter(DatabaseRepository repo){ - this.repo = repo; - } - - @Route(path = "^/admin/chapter/$", type = POST, needLogin = true) - public void exec(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.get("start")), Timestamp.valueOf(json.get("end"))); - if(repo.adminAddChapter(chapter)){ - context.response(200); - }else{ - context.response(501); - } - } - -} diff --git a/src/dev/peerat/backend/routes/admins/chapter/DeleteChapter.java b/src/dev/peerat/backend/routes/admins/chapter/DeleteChapter.java deleted file mode 100644 index 1097d0a..0000000 --- a/src/dev/peerat/backend/routes/admins/chapter/DeleteChapter.java +++ /dev/null @@ -1,31 +0,0 @@ -package dev.peerat.backend.routes.admins.chapter; - -import static dev.peerat.framework.RequestType.DELETE; - -import java.util.regex.Matcher; - -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.Response; -import dev.peerat.framework.Route; - -public class DeleteChapter implements Response{ - - private DatabaseRepository repo; - - public DeleteChapter(DatabaseRepository repo){ - this.repo = repo; - } - - @Route(path = "^/admin/chapter/(\\d+)$", type = DELETE, needLogin = true) - public void exec(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); - } - } - -} diff --git a/src/dev/peerat/backend/routes/admins/chapter/EditChapter.java b/src/dev/peerat/backend/routes/admins/chapter/EditChapter.java deleted file mode 100644 index 12c8f6d..0000000 --- a/src/dev/peerat/backend/routes/admins/chapter/EditChapter.java +++ /dev/null @@ -1,37 +0,0 @@ -package dev.peerat.backend.routes.admins.chapter; - -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.DatabaseRepository; -import dev.peerat.framework.Context; -import dev.peerat.framework.HttpReader; -import dev.peerat.framework.HttpWriter; -import dev.peerat.framework.Response; -import dev.peerat.framework.Route; -import dev.peerat.framework.utils.json.JsonMap; - -public class EditChapter implements Response{ - - private DatabaseRepository repo; - - public EditChapter(DatabaseRepository repo){ - this.repo = repo; - } - - @Route(path = "^/admin/chapter/(\\d+)$", type = PUT, needLogin = true) - public void exec(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.get("start")), Timestamp.valueOf(json.get("end"))); - if(repo.adminUpdateChapter(Integer.parseInt(matcher.group(1)), chapter)){ - context.response(200); - }else{ - context.response(501); - } - - } - -} diff --git a/src/dev/peerat/backend/routes/admins/chapter/GetChapter.java b/src/dev/peerat/backend/routes/admins/chapter/GetChapter.java deleted file mode 100644 index 5f71b3f..0000000 --- a/src/dev/peerat/backend/routes/admins/chapter/GetChapter.java +++ /dev/null @@ -1,34 +0,0 @@ -package dev.peerat.backend.routes.admins.chapter; - -import java.util.regex.Matcher; - -import dev.peerat.backend.model.Chapter; -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.Response; -import dev.peerat.framework.Route; -import dev.peerat.framework.utils.json.JsonMap; - -public class GetChapter implements Response{ - - private DatabaseRepository repo; - - public GetChapter(DatabaseRepository repo){ - this.repo = repo; - } - - @Route(path = "^/admin/chapter/(\\d+)$", needLogin = true) - public void exec(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"); - } - -} diff --git a/src/dev/peerat/backend/routes/admins/puzzle/AddPuzzle.java b/src/dev/peerat/backend/routes/admins/puzzle/AddPuzzle.java deleted file mode 100644 index 02117dc..0000000 --- a/src/dev/peerat/backend/routes/admins/puzzle/AddPuzzle.java +++ /dev/null @@ -1,35 +0,0 @@ -package dev.peerat.backend.routes.admins.puzzle; - -import static dev.peerat.framework.RequestType.POST; - -import java.util.regex.Matcher; - -import dev.peerat.backend.model.Puzzle; -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.Response; -import dev.peerat.framework.Route; -import dev.peerat.framework.utils.json.JsonMap; - -public class AddPuzzle implements Response{ - - private DatabaseRepository repo; - - public AddPuzzle(DatabaseRepository repo){ - this.repo = repo; - } - - @Route(path = "^/admin/puzzle/$", type = POST, needLogin = true) - public void exec(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.get("soluce").getBytes(), null, json.get("scoreMax").intValue(), null, -1, null); - if(repo.adminAddPuzzle(puzzle, json.get("chapter").intValue())){ - context.response(200); - }else{ - context.response(501); - } - } - -} diff --git a/src/dev/peerat/backend/routes/admins/puzzle/DeletePuzzle.java b/src/dev/peerat/backend/routes/admins/puzzle/DeletePuzzle.java deleted file mode 100644 index ba068e3..0000000 --- a/src/dev/peerat/backend/routes/admins/puzzle/DeletePuzzle.java +++ /dev/null @@ -1,32 +0,0 @@ -package dev.peerat.backend.routes.admins.puzzle; - -import static dev.peerat.framework.RequestType.DELETE; - -import java.util.regex.Matcher; - -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.Response; -import dev.peerat.framework.Route; -import dev.peerat.framework.utils.json.JsonMap; - -public class DeletePuzzle implements Response{ - - private DatabaseRepository repo; - - public DeletePuzzle(DatabaseRepository repo){ - this.repo = repo; - } - - @Route(path = "^/admin/puzzle/(\\d+)$", type = DELETE, needLogin = true) - public void exec(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); - } - } - -} diff --git a/src/dev/peerat/backend/routes/admins/puzzle/EditPuzzle.java b/src/dev/peerat/backend/routes/admins/puzzle/EditPuzzle.java deleted file mode 100644 index 969ba40..0000000 --- a/src/dev/peerat/backend/routes/admins/puzzle/EditPuzzle.java +++ /dev/null @@ -1,35 +0,0 @@ -package dev.peerat.backend.routes.admins.puzzle; - -import static dev.peerat.framework.RequestType.PUT; - -import java.util.regex.Matcher; - -import dev.peerat.backend.model.Puzzle; -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.Response; -import dev.peerat.framework.Route; -import dev.peerat.framework.utils.json.JsonMap; - -public class EditPuzzle implements Response{ - - private DatabaseRepository repo; - - public EditPuzzle(DatabaseRepository repo){ - this.repo = repo; - } - - @Route(path = "^/admin/puzzle/(\\d+)$", type = PUT, needLogin = true) - public void exec(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.get("soluce").getBytes(), null, json.get("scoreMax").intValue(), null, -1, null); - if(repo.adminUpdatePuzzle(Integer.parseInt(matcher.group(1)), puzzle, json.get("chapter").intValue())){ - context.response(200); - }else{ - context.response(501); - } - } - -} diff --git a/src/dev/peerat/backend/routes/admins/puzzle/GetPuzzle.java b/src/dev/peerat/backend/routes/admins/puzzle/GetPuzzle.java deleted file mode 100644 index 060e9ba..0000000 --- a/src/dev/peerat/backend/routes/admins/puzzle/GetPuzzle.java +++ /dev/null @@ -1,35 +0,0 @@ -package dev.peerat.backend.routes.admins.puzzle; - -import java.util.regex.Matcher; - -import dev.peerat.backend.model.Puzzle; -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.Response; -import dev.peerat.framework.Route; -import dev.peerat.framework.utils.json.JsonMap; - -public class GetPuzzle implements Response{ - - private DatabaseRepository repo; - - public GetPuzzle(DatabaseRepository repo){ - this.repo = repo; - } - - @Route(path = "^/admin/puzzle/(\\d+)$", needLogin = true) - public void exec(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"); - } - -} diff --git a/src/dev/peerat/backend/routes/admins/puzzle/GetPuzzles.java b/src/dev/peerat/backend/routes/admins/puzzle/GetPuzzles.java deleted file mode 100644 index 0014688..0000000 --- a/src/dev/peerat/backend/routes/admins/puzzle/GetPuzzles.java +++ /dev/null @@ -1,41 +0,0 @@ -package dev.peerat.backend.routes.admins.puzzle; - -import java.util.List; -import java.util.regex.Matcher; - -import dev.peerat.backend.model.Puzzle; -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.Response; -import dev.peerat.framework.Route; -import dev.peerat.framework.utils.json.JsonArray; -import dev.peerat.framework.utils.json.JsonMap; - -public class GetPuzzles implements Response{ - - private DatabaseRepository repo; - - public GetPuzzles(DatabaseRepository repo){ - this.repo = repo; - } - - @Route(path = "^/admin/puzzles/$", needLogin = true) - public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{ - List 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()); - } - -} diff --git a/src/dev/peerat/backend/routes/admins/tag/AddTag.java b/src/dev/peerat/backend/routes/admins/tag/AddTag.java deleted file mode 100644 index 8df16dd..0000000 --- a/src/dev/peerat/backend/routes/admins/tag/AddTag.java +++ /dev/null @@ -1,33 +0,0 @@ -package dev.peerat.backend.routes.admins.tag; - -import static dev.peerat.framework.RequestType.POST; - -import java.util.regex.Matcher; - -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.Response; -import dev.peerat.framework.Route; -import dev.peerat.framework.utils.json.JsonMap; - -public class AddTag implements Response{ - - private DatabaseRepository repo; - - public AddTag(DatabaseRepository repo){ - this.repo = repo; - } - - @Route(path = "^/admin/tag/$", type = POST, needLogin = true) - public void exec(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); - } - } - -} diff --git a/src/dev/peerat/backend/routes/admins/tag/DeleteTag.java b/src/dev/peerat/backend/routes/admins/tag/DeleteTag.java deleted file mode 100644 index 84d92a0..0000000 --- a/src/dev/peerat/backend/routes/admins/tag/DeleteTag.java +++ /dev/null @@ -1,31 +0,0 @@ -package dev.peerat.backend.routes.admins.tag; - -import static dev.peerat.framework.RequestType.DELETE; - -import java.util.regex.Matcher; - -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.Response; -import dev.peerat.framework.Route; - -public class DeleteTag implements Response{ - - private DatabaseRepository repo; - - public DeleteTag(DatabaseRepository repo){ - this.repo = repo; - } - - @Route(path = "^/admin/tag/(\\d+)$", type = DELETE, needLogin = true) - public void exec(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); - } - } - -} diff --git a/src/dev/peerat/backend/routes/admins/tag/EditTag.java b/src/dev/peerat/backend/routes/admins/tag/EditTag.java deleted file mode 100644 index 08c265e..0000000 --- a/src/dev/peerat/backend/routes/admins/tag/EditTag.java +++ /dev/null @@ -1,34 +0,0 @@ -package dev.peerat.backend.routes.admins.tag; - -import static dev.peerat.framework.RequestType.PUT; - -import java.util.regex.Matcher; - -import dev.peerat.backend.model.Tag; -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.Response; -import dev.peerat.framework.Route; -import dev.peerat.framework.utils.json.JsonMap; - -public class EditTag implements Response{ - - private DatabaseRepository repo; - - public EditTag(DatabaseRepository repo){ - this.repo = repo; - } - - @Route(path = "^/admin/tag/(\\d+)$", type = PUT, needLogin = true) - public void exec(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); - } - } - -} diff --git a/src/dev/peerat/backend/routes/admins/tag/GetTags.java b/src/dev/peerat/backend/routes/admins/tag/GetTags.java deleted file mode 100644 index aa14b43..0000000 --- a/src/dev/peerat/backend/routes/admins/tag/GetTags.java +++ /dev/null @@ -1,33 +0,0 @@ -package dev.peerat.backend.routes.admins.tag; - -import java.util.List; -import java.util.regex.Matcher; - -import dev.peerat.backend.model.Tag; -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.Response; -import dev.peerat.framework.Route; -import dev.peerat.framework.utils.json.JsonArray; - -public class GetTags implements Response{ - - private DatabaseRepository repo; - - public GetTags(DatabaseRepository repo){ - this.repo = repo; - } - - @Route(path = "^/admin/tag/$", needLogin = true) - public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{ - List list = repo.getAdminTags(); - JsonArray json = new JsonArray(); - for(Tag tag : list) json.add(tag.toJson()); - context.response(200); - writer.write(json.toString()); - writer.flush(); - } - -} diff --git a/src/dev/peerat/backend/routes/groups/GroupCreate.java b/src/dev/peerat/backend/routes/groups/GroupCreate.java index 711dfc6..4739eb5 100644 --- a/src/dev/peerat/backend/routes/groups/GroupCreate.java +++ b/src/dev/peerat/backend/routes/groups/GroupCreate.java @@ -5,6 +5,7 @@ import static dev.peerat.framework.RequestType.POST; import java.time.LocalDateTime; import java.util.regex.Matcher; +import dev.peerat.backend.Configuration; import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.model.Chapter; import dev.peerat.backend.model.Group; @@ -16,7 +17,6 @@ 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; import dev.peerat.framework.utils.json.JsonMap; @@ -26,10 +26,10 @@ public class GroupCreate extends FormResponse { private DatabaseRepository repo; private int groupDelay; - public GroupCreate(DatabaseRepository repo, @Injection("groups") Locker locker, @Injection("groupDelay") int groupDelay){ + public GroupCreate(DatabaseRepository repo, @Injection("groups") Locker locker, Configuration config){ this.repo = repo; this.locker = locker; - this.groupDelay = groupDelay; + this.groupDelay = config.getGroupJoinMinutes(); validator("name", "[a-zA-Z0-9&|!?{}\\[\\]%/*\\-+=:;,_#@ ]{3,100}"); } diff --git a/src/dev/peerat/backend/routes/groups/GroupJoin.java b/src/dev/peerat/backend/routes/groups/GroupJoin.java index f90fda4..a99f7c9 100644 --- a/src/dev/peerat/backend/routes/groups/GroupJoin.java +++ b/src/dev/peerat/backend/routes/groups/GroupJoin.java @@ -5,6 +5,7 @@ import static dev.peerat.framework.RequestType.POST; import java.time.LocalDateTime; import java.util.regex.Matcher; +import dev.peerat.backend.Configuration; import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.model.Chapter; import dev.peerat.backend.model.Completion; @@ -27,10 +28,10 @@ public class GroupJoin implements Response{ private final Locker leaderboard; - public GroupJoin(DatabaseRepository repo, @Injection("groupDelay") int groupDelay, @Injection("waitTime") String waitTime, @Injection("leaderboard") Locker locker){ + public GroupJoin(DatabaseRepository repo, Configuration config, @Injection("leaderboard") Locker locker){ this.repo = repo; - this.groupDelay = groupDelay; - this.waitTime = waitTime; + this.groupDelay = config.getGroupJoinMinutes(); + this.waitTime = config.getGroupQuitMinutes(); this.leaderboard = locker; } diff --git a/src/dev/peerat/backend/routes/groups/GroupQuit.java b/src/dev/peerat/backend/routes/groups/GroupQuit.java index c319a13..cb691a4 100644 --- a/src/dev/peerat/backend/routes/groups/GroupQuit.java +++ b/src/dev/peerat/backend/routes/groups/GroupQuit.java @@ -5,6 +5,7 @@ import static dev.peerat.framework.RequestType.POST; import java.time.LocalDateTime; import java.util.regex.Matcher; +import dev.peerat.backend.Configuration; import dev.peerat.backend.bonus.extract.RouteDoc; import dev.peerat.backend.model.Chapter; import dev.peerat.backend.model.Completion; @@ -26,9 +27,9 @@ public class GroupQuit implements Response{ private final Locker leaderboard; - public GroupQuit(DatabaseRepository repo, @Injection("groupDelay") int groupDelay, @Injection("leaderboard") Locker locker){ + public GroupQuit(DatabaseRepository repo, Configuration config, @Injection("leaderboard") Locker locker){ this.repo = repo; - this.groupDelay = groupDelay; + this.groupDelay = config.getGroupJoinMinutes(); this.leaderboard = locker; }