Compare commits

...
Sign in to create a new pull request.

158 commits

Author SHA1 Message Date
de8cba207c refresh config 2025-01-29 14:06:54 +01:00
a78723825b Fix nullpointer on empty message 2025-01-29 11:08:47 +01:00
2d03ccbe3e Je savais qu'un client pouvais changer beaucoup de fois d'avis, je savais pas que c'était aussi le cas du p***** de dev frontend 2025-01-28 21:21:44 +01:00
fbb8514afd Remove timelimit for admin (PuzzleElement, PuzzleResponse) 2025-01-28 18:50:03 +01:00
e746d6fe2b Remove login for SSE + set admin get to post 2025-01-28 00:23:49 +01:00
51d6d311fb can back restart pls 2025-01-27 21:13:12 +01:00
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
8041ddb470 fix...faut pas faire 2 choses en même temps 2023-10-01 23:27:11 +02:00
4f11822c12 prod & completion 2023-10-01 22:44:23 +02:00
894ed9fb46 Fix leaderboard -> only one player per groups was showing 2023-09-26 14:01:56 +02:00
087cf59ae0 check input on modify 2023-09-26 13:39:51 +02:00
89d6e14c9c check input on creating 2023-09-26 13:39:12 +02:00
7fb0408b52 Fix puzzle response when puzzle didnt stary 2023-09-25 11:20:07 +02:00
2fc73af4f2 debug response byte 2023-09-24 21:37:39 +02:00
ac8df18e99 Il faudra vraiment qu'on commence à lancer les environnements en local 2023-09-23 17:35:44 +02:00
d321a3e088 Mon code s'update vraiment sur le serveur ? 2023-09-23 17:32:17 +02:00
cf6167a12f Vous trouvez sa chiant de voir commit pour update le programme ? moi aussi quand il faut debug 2023-09-23 17:30:09 +02:00
bdd5fa4081 [Debug] websocket auth 2023-09-23 17:24:24 +02:00
66eb81210c Framework not updated? 2023-09-23 17:19:29 +02:00
c6393ef4f3 With calling the framework... 2023-09-23 12:14:11 +02:00
93b048ed7d Move WebSocket auth in framework 2023-09-23 12:13:23 +02:00
a0d7848109 Fixed DynamicLogs 2023-09-23 11:56:31 +02:00
abb46f0915 Test fix readJson in websocket 2023-09-23 11:49:42 +02:00
798702f677 Fix user settings route 2023-09-22 14:20:06 +02:00
a58fd656b5 debugging 2023-09-22 14:13:37 +02:00
092e58b11d Fix sql column in profile settings 2023-09-22 14:08:22 +02:00
6222d17524 Change auth when websocket 2023-09-22 08:56:18 +02:00
b20d11b224 merge from prod changment 2023-09-21 19:52:50 +02:00
e1a750cbe3 Limit ws logs to admin 2023-09-19 20:32:13 +02:00
26514c0961 [tmp] remove score loss 2023-09-19 20:27:08 +02:00
33a23af493 debug \t or \r problemes in puzzles answer 2023-09-19 19:57:46 +02:00
8a138b52d6 Re-add email & pseudo verification 2023-09-19 19:13:56 +02:00
cfd0114590 Debug response without access to ram xD 2023-09-18 18:10:31 +02:00
b04bce2be6 Debug response 2023-09-18 18:01:42 +02:00
3c423c7122 Fix du fix de multipart 2023-09-18 12:42:40 +02:00
1ac2fe4a4f Fix log & fix(?) multipart data with \n 2023-09-18 12:41:07 +02:00
f079e4e617 Imagine.... les 2023-09-18 12:30:07 +02:00
75baf14253 [tmp] fix player rank 2023-09-18 12:24:18 +02:00
c419013c40 update framework & reboot 2023-09-18 12:19:32 +02:00
081930f415 [tmp] ...tables with s 2023-09-18 12:01:26 +02:00
5b6c122178 [tmp] remove chapter 1 from leaderboard 2023-09-18 11:59:22 +02:00
cc24278a3f Change log & tmp remove git users 2023-09-18 11:47:03 +02:00
cc8ad713a7 Test & Remove debug for Theo 2023-09-18 08:47:55 +02:00
e50034dd00 little test for groups 2023-09-18 08:46:11 +02:00
cf5695e011 [tmp] and completion 2023-09-18 07:50:27 +02:00
ecea0a396c [tmp] Fix group on chapter 1 2023-09-18 07:46:47 +02:00
f92462db82 debug from front 2023-09-17 20:44:01 +02:00
018a132466 ForgotPassword -> POST 2023-09-17 11:06:01 +02:00
9e56d83343 Fix forgot password -> code data type checker 2023-09-17 11:01:07 +02:00
3da54bbe17 Merge branch 'dev' of https://git.peerat.dev/Peer-at-Code/peer-at-code-backend into dev 2023-09-16 12:17:47 +02:00
dbfd936d32 fix json strings 2023-09-16 12:17:24 +02:00
772dd2d23f Update show for puzzle and chapter 2023-09-16 09:25:38 +02:00
fe904774c0 fix lost '{' in begin of json 2023-09-15 23:07:34 +02:00
e5081f6c13 It's alreight 2023-09-14 00:13:51 +02:00
9ad98cbedf ...je...oui 2023-09-14 00:11:42 +02:00
449cb027b3 debug 2023-09-14 00:08:52 +02:00
6d017e1d5a by one ? 2023-09-14 00:07:05 +02:00
30d221e35a byte array ? 2023-09-14 00:04:11 +02:00
6c6eba29f8 length ? 2023-09-14 00:00:58 +02:00
e237be36b6 no json ? 2023-09-13 23:56:08 +02:00
e185258a54 Null ? 2023-09-13 23:52:23 +02:00
0248b7b07c New Json lib 2023-09-13 23:48:14 +02:00
c3621da722 Bakc into functional 2023-09-13 15:42:28 +02:00
5e2d84895d Test json with \n 2023-09-13 00:03:50 +02:00
18ec7fb396 Forgot Password 2023-09-11 18:18:46 +02:00
6470bd8be7 Update Framework (headers update) 2023-09-11 15:46:29 +02:00
6824ced972 add show and start_date to puzzle 2023-09-11 14:06:27 +02:00
62c2a923ae It finally works (clean code later) 2023-09-09 22:13:03 +02:00
fa09374178 Some day ? 2023-09-09 22:09:13 +02:00
2d1c67fc65 Good rsa key ? 2023-09-09 21:59:23 +02:00
3c7aa052dc wtf ? 2023-09-09 21:42:14 +02:00
735534ea2d 2048 key into 4096 2023-09-09 21:33:59 +02:00
119e789900 private...public...what the dif ? 2023-09-09 21:19:37 +02:00
514452c295 debug gitea content 2023-09-09 21:17:42 +02:00
58d890737d ssh-rsa for git key 2023-09-09 21:12:35 +02:00
75277c5b03 Email sender 2023-09-09 20:58:41 +02:00
a68bc91459 fix get player when no fetch group 2023-09-09 20:47:56 +02:00
f6560a85fd constructor INTO Object andrew ! 2023-09-09 20:36:28 +02:00
c4dcbbb977 fix 500 & fix json int 2023-09-09 20:33:52 +02:00
12e0bd7bac fix check int in form response 2023-09-09 20:11:46 +02:00
76e9c4376a Include error 500 from framework 2023-09-08 21:35:38 +02:00
dbb47bd8c5 get('firstnae') 2023-09-08 20:18:51 +02:00
a06eb168e7 Swagger 2023-09-08 14:34:44 +02:00
8dbb5e3474 Design pattern builder =D 2023-09-08 12:27:54 +02:00
262875fd62 Send mail on register 2023-09-08 12:24:03 +02:00
26eea355f1 Move register data in mail confirmation 2023-09-08 12:20:16 +02:00
e2cf4f8542 Configuration -> add default values 2023-09-08 11:32:58 +02:00
1f2e30a7d1 Forget to remove... 2023-09-08 02:26:09 +02:00
4f8b45f074 Merge from my branch september 2023-09-08 02:18:19 +02:00
c2428ebd94 au passage, je dégage l'exception quand route par défaut 2023-09-06 23:09:12 +02:00
e1fde6bd5a Merge branch 'dev' of https://git.peerat.dev/Peer-at-Code/peer-at-code-backend into dev 2023-09-06 22:58:23 +02:00
e815346b93 Fix Annotation processor problems 2023-09-06 22:58:05 +02:00
743e230f85 forget to change key value order in main map 2023-09-05 12:03:20 +02:00
bff438073a Register with email confirmation - to test w/ Theo 2023-09-05 11:44:24 +02:00
5161916f54 Mail sended ! 2023-09-04 16:22:47 +02:00
3ad9e91365 Add jakarta lib + mail test 2023-09-04 16:04:35 +02:00
ecdf99365b Push mailConfirmation route 2023-09-04 14:56:48 +02:00
c80d9ce31d Rajout route mail confirmation 2023-09-04 14:46:09 +02:00
6b652c8adf MailConfiguration to Mail from config 2023-09-04 13:12:51 +02:00
234a4a4795 from static to POO 2023-09-04 13:10:33 +02:00
bd0460e754 forget to add new file 2023-09-04 13:01:48 +02:00
eeac351b02 mail configuration 2023-09-04 12:51:14 +02:00
97d8c0b7de Update Framework dependecy 2023-09-04 09:29:59 +02:00
50dacdff15 refractor package & adapte to framework 2023-08-29 16:46:50 +02:00
5481dbd2cf Refractor back for new versions of the framework 2023-07-26 17:03:21 +02:00
f4dd642b78 Moved Framework 2023-07-05 15:03:03 +02:00
125 changed files with 5222 additions and 3725 deletions

View file

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
<classpathentry exported="true" kind="lib" path="json-simple-1.1.1.jar"/>
<classpathentry exported="true" kind="lib" path="mysql-connector-java-8.0.28.jar"/>
<classpathentry exported="true" kind="lib" path="password4j-1.6.3.jar"/>
<classpathentry exported="true" kind="lib" path="slf4j-api-2.0.6.jar"/>
<classpathentry exported="true" kind="lib" path="jose4j-0.9.3.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
<classpathentry kind="src" path=".apt_generated">
<attributes>
@ -16,5 +16,9 @@
</classpathentry>
<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="PeerAtCodeFramework.jar"/>
<classpathentry exported="true" kind="lib" path="angus-activation-2.0.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.3.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

2
.gitignore vendored
View file

@ -2,6 +2,8 @@
bin/
.project
config.txt
config-test.txt
dist/
testApi/
.apt_generated/*
/.apt_generated/

BIN
PeerAtCodeFramework.jar Normal file

Binary file not shown.

Binary file not shown.

BIN
angus-activation-2.0.2.jar Normal file

Binary file not shown.

127
database-schem.sql Normal file
View file

@ -0,0 +1,127 @@
DROP TABLE IF EXISTS `containsTags`;
DROP TABLE IF EXISTS `tags`;
DROP TABLE IF EXISTS `containsBadges`;
DROP TABLE IF EXISTS `badges`;
DROP TABLE IF EXISTS `containsGroups`;
DROP TABLE IF EXISTS `nextPart`;
DROP TABLE IF EXISTS `groups`;
DROP TABLE IF EXISTS `completions`;
DROP TABLE IF EXISTS `players`;
DROP TABLE IF EXISTS `puzzles`;
DROP TABLE IF EXISTS `chapters`;
CREATE TABLE `players` (
`id_player` int(11) NOT NULL AUTO_INCREMENT,
`pseudo` varchar(100) NOT NULL,
`email` varchar(100) NOT NULL,
`passwd` varchar(150) NOT NULL,
`firstname` varchar(100) NOT NULL,
`lastname` varchar(100) NOT NULL,
`description` varchar(200) DEFAULT NULL,
`avatar` blob DEFAULT NULL,
PRIMARY KEY (`id_player`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE badges (
id_badge int(11) NOT NULL AUTO_INCREMENT,
name varchar(50) NOT NULL,
logo mediumblob DEFAULT NULL,
level int(11) DEFAULT 1,
PRIMARY KEY (id_badge)
);
CREATE TABLE `chapters` (
`id_chapter` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(150) NOT NULL,
`start_date` datetime DEFAULT NULL,
`end_date` datetime DEFAULT NULL,
PRIMARY KEY (`id_chapter`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `puzzles` (
`id_puzzle` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(150) NOT NULL,
`content` text NOT NULL,
`soluce` blob NOT NULL,
`verify` text DEFAULT NULL,
`score_max` int(11) NOT NULL,
`fk_chapter` int(11) NOT NULL,
PRIMARY KEY (`id_puzzle`),
KEY `fk_chapter` (`fk_chapter`),
CONSTRAINT `puzzles_ibfk_1` FOREIGN KEY (`fk_chapter`) REFERENCES `chapters` (`id_chapter`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `groups` (
`id_group` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(150) DEFAULT NULL,
`fk_chapter` int(11) DEFAULT NULL,
`fk_puzzle` int(11) DEFAULT NULL,
PRIMARY KEY (`id_group`),
KEY `fk_chapter` (`fk_chapter`),
KEY `fk_puzzle` (`fk_puzzle`),
CONSTRAINT `groups_ibfk_1` FOREIGN KEY (`fk_chapter`) REFERENCES `chapters` (`id_chapter`),
CONSTRAINT `groups_ibfk_2` FOREIGN KEY (`fk_puzzle`) REFERENCES `puzzles` (`id_puzzle`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `nextPart` (
`origin` int(11) NOT NULL,
`next` int(11) NOT NULL,
PRIMARY KEY (`origin`,`next`),
KEY `next` (`next`),
CONSTRAINT `nextPart_ibfk_1` FOREIGN KEY (`origin`) REFERENCES `puzzles` (`id_puzzle`),
CONSTRAINT `nextPart_ibfk_2` FOREIGN KEY (`next`) REFERENCES `puzzles` (`id_puzzle`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `completions` (
`id_completion` int(11) NOT NULL AUTO_INCREMENT,
`fk_puzzle` int(11) NOT NULL,
`fk_player` int(11) NOT NULL,
`tries` int(11) DEFAULT 0,
`code` blob DEFAULT NULL,
`score` int(11) DEFAULT 0,
`fileName` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id_completion`),
KEY `fk_puzzle` (`fk_puzzle`),
KEY `fk_player` (`fk_player`),
CONSTRAINT `completions_ibfk_1` FOREIGN KEY (`fk_puzzle`) REFERENCES `puzzles` (`id_puzzle`),
CONSTRAINT `completions_ibfk_2` FOREIGN KEY (`fk_player`) REFERENCES `players` (`id_player`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `tags` (
`id_tag` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id_tag`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `containsBadges` (
`fk_player` int(11) NOT NULL,
`fk_badge` int(11) NOT NULL,
PRIMARY KEY (`fk_player`,`fk_badge`),
KEY `fk_badge` (`fk_badge`),
CONSTRAINT `containsBadges_ibfk_1` FOREIGN KEY (`fk_player`) REFERENCES `players` (`id_player`),
CONSTRAINT `containsBadges_ibfk_2` FOREIGN KEY (`fk_badge`) REFERENCES `badges` (`id_badge`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `containsGroups` (
`fk_player` int(11) NOT NULL,
`fk_group` int(11) NOT NULL,
PRIMARY KEY (`fk_player`,`fk_group`),
KEY `fk_group` (`fk_group`),
CONSTRAINT `containsGroups_ibfk_1` FOREIGN KEY (`fk_player`) REFERENCES `players` (`id_player`),
CONSTRAINT `containsGroups_ibfk_2` FOREIGN KEY (`fk_group`) REFERENCES `groups` (`id_group`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `containsTags` (
`fk_tag` int(11) NOT NULL,
`fk_puzzle` int(11) NOT NULL,
PRIMARY KEY (`fk_tag`,`fk_puzzle`),
KEY `fk_puzzle` (`fk_puzzle`),
CONSTRAINT `containsTags_ibfk_1` FOREIGN KEY (`fk_tag`) REFERENCES `tags` (`id_tag`),
CONSTRAINT `containsTags_ibfk_2` FOREIGN KEY (`fk_puzzle`) REFERENCES `puzzles` (`id_puzzle`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO chapters (id_chapter, name) VALUES (1, 'chapter 1');
INSERT INTO players (pseudo, email, passwd,firstname,lastname) VALUES ('userTest', 'test@peerat.dev', '$argon2id$v=19$m=15360,t=2,p=1$$cAQwfs30Bf2rQGj86bpz7i59TlsuOFPiXeNpLlVu4AY', 'a','b')

Binary file not shown.

BIN
jakarta.mail-2.0.3.jar Normal file

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

@ -1,136 +0,0 @@
package be.jeffcheasey88.peeratcode;
import static be.jeffcheasey88.peeratcode.framework.RequestType.OPTIONS;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.regex.Matcher;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import be.jeffcheasey88.peeratcode.framework.Client;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Locker;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.Router;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Completion;
import be.jeffcheasey88.peeratcode.model.Group;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
import be.jeffcheasey88.peeratcode.routes.BadgeDetails;
import be.jeffcheasey88.peeratcode.routes.ChapterElement;
import be.jeffcheasey88.peeratcode.routes.ChapterList;
import be.jeffcheasey88.peeratcode.routes.DynamicLeaderboard;
import be.jeffcheasey88.peeratcode.routes.Leaderboard;
import be.jeffcheasey88.peeratcode.routes.Login;
import be.jeffcheasey88.peeratcode.routes.PlayerDetails;
import be.jeffcheasey88.peeratcode.routes.PuzzleElement;
import be.jeffcheasey88.peeratcode.routes.PuzzleResponse;
import be.jeffcheasey88.peeratcode.routes.Register;
import be.jeffcheasey88.peeratcode.routes.Result;
import be.jeffcheasey88.peeratcode.routes.groups.GroupCreate;
import be.jeffcheasey88.peeratcode.routes.groups.GroupJoin;
import be.jeffcheasey88.peeratcode.routes.groups.GroupList;
import be.jeffcheasey88.peeratcode.routes.groups.GroupQuit;
public class Main{
public static void main(String[] args) throws Exception{
Configuration config = new Configuration("config.txt");
config.load();
Class.forName("com.mysql.cj.jdbc.Driver");
Router router = new Router(new DatabaseRepository(config), config.getTokenIssuer(),
config.getTokenExpiration());
router.setDefault((matcher, user, reader, writer) -> {
writer.response(404, "Access-Control-Allow-Origin: *");
writer.write("404 not Found.\n");
writer.flush();
writer.close();
});
router.register(new Response(){
@Route(path = "^(.*)$", type = OPTIONS)
@Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
writer.response(200, "Access-Control-Allow-Origin: *",
"Access-Control-Allow-Methods: *", "Access-Control-Allow-Headers: *");
}
});
initRoutes(router, config);
// RouteExtracter extracter = new RouteExtracter(router);
// extracter.extract();
startWebServer(config, router);
}
private static void initRoutes(Router router, Configuration config){
router.register(new ChapterElement(router.getDataBase()));
router.register(new ChapterList(router.getDataBase()));
router.register(new PuzzleElement(router.getDataBase()));
router.register(new Register(router.getDataBase(), router, config.getUsersFiles()));
router.register(new Login(router.getDataBase(), router));
router.register(new Result(router.getDataBase()));
router.register(new Leaderboard(router.getDataBase()));
router.register(new PlayerDetails(router.getDataBase()));
router.register(new BadgeDetails(router.getDataBase()));
Locker<Group> groupLock = new Locker<>();
router.register(new GroupCreate(router.getDataBase(), groupLock, config.getGroupJoinMinutes()));
DynamicLeaderboard dlb = new DynamicLeaderboard(router.getDataBase());
router.register(dlb);
Locker<Completion> leaderboard = dlb.getLocker();
router.register(new PuzzleResponse(router.getDataBase(), config.getUsersFiles(), leaderboard));
router.register(new GroupList(router.getDataBase()));
router.register(new GroupJoin(router.getDataBase(), config.getGroupJoinMinutes(), config.getGroupQuitMinutes(), leaderboard));
router.register(new GroupQuit(router.getDataBase(), config.getGroupJoinMinutes(), leaderboard));
// Bot bot = new Bot(config, router.getDataBase(), groupLock);
// bot.start();
}
private static void startWebServer(Configuration config, Router router) throws IOException {
if (config.useSsl()) { // Not needed with the use of a proxy
SSLServerSocket server = null;
try {
System.setProperty("javax.net.ssl.keyStore", config.getSslKeystore());
System.setProperty("javax.net.ssl.keyStorePassword", config.getSslKeystorePasswd());
SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
server = (SSLServerSocket) ssf.createServerSocket(config.getTcpPort());
while (!server.isClosed()) {
Socket socket = server.accept();
Client client = new Client(socket, router);
client.start();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (server != null) {
server.close();
}
}
} else {
try (ServerSocket server = new ServerSocket(config.getTcpPort())) {
while (!server.isClosed()) {
Socket socket = server.accept();
Client client = new Client(socket, router);
client.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

View file

@ -1,49 +0,0 @@
package be.jeffcheasey88.peeratcode.bonus.extract;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Map.Entry;
import be.jeffcheasey88.peeratcode.framework.RequestType;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.Router;
//A noter que le but est d'extraire des informations sans modifier le code source,
//comme les tests unitaire, ici je veux générer un élément textuel qui me donnera l'état des routes,
//je ne vais donc pas modifier la classe router pour donner un accès au route.
public class RouteExtracter {
private Router router;
public RouteExtracter(Router router){
this.router = router;
}
public void extract() throws Exception{
Field field = Router.class.getDeclaredField("responses");
field.setAccessible(true);
Map<RequestType, Map<Response, Route>> responses = (Map<RequestType, Map<Response, Route>>) field.get(this.router);
for(Entry<RequestType, Map<Response, Route>> types : responses.entrySet()){
for(Entry<Response, Route> routes : types.getValue().entrySet()){
System.out.println("["+types.getKey()+"] ("+routes.getValue().needLogin()+") "+routes.getValue().path());
}
}
}
public void extractDoc() throws Exception{
Field field = Router.class.getDeclaredField("responses");
field.setAccessible(true);
Map<RequestType, Map<Response, Route>> responses = (Map<RequestType, Map<Response, Route>>) field.get(this.router);
for(Map<Response, Route> route : responses.values()){
for(Response response : route.keySet()){
Method method = response.getClass().getDeclaredMethod("exec",
Response.class.getDeclaredMethods()[0].getParameterTypes());
for(RouteDoc doc : method.getDeclaredAnnotationsByType(RouteDoc.class)){
System.out.println(doc.path()+((doc.path().isEmpty() ? "":"\n"))+" ["+doc.responseCode()+"] "+doc.responseDescription());
}
}
}
}
}

View file

@ -1,60 +0,0 @@
package be.jeffcheasey88.peeratcode.framework;
import java.net.Socket;
import java.util.Arrays;
import org.jose4j.jwa.AlgorithmConstraints.ConstraintType;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
public class Client extends Thread{
private HttpReader reader;
private HttpWriter writer;
private Router router;
public Client(Socket socket, Router router) throws Exception{
this.reader = new HttpReader(socket);
this.writer = new HttpWriter(socket);
this.router = router;
}
@Override
public void run(){
try{
String[] headers = reader.readLine().split("\\s");
System.out.println(Arrays.toString(headers));
reader.readHeaders();
router.exec(RequestType.valueOf(headers[0]), headers[1], isLogin(reader), reader, writer);
writer.flush();
writer.close();
}catch(Exception e){
e.printStackTrace();
}
}
private User isLogin(HttpReader reader) throws Exception{
String auth = reader.getHeader("Authorization");
if(auth == null) return null;
auth = auth.substring(7);
try{
JwtConsumer jwtConsumer = new JwtConsumerBuilder()
.setRequireExpirationTime()
.setAllowedClockSkewInSeconds(30)
.setExpectedIssuer(this.router.getTokenIssuer())
.setVerificationKey(this.router.getWebKey().getKey())
.setJwsAlgorithmConstraints(ConstraintType.PERMIT, AlgorithmIdentifiers.RSA_USING_SHA256).build();
JwtClaims jwtClaims = jwtConsumer.processToClaims(auth);
return new User(jwtClaims);
}catch(Exception e){
writer.response(401, "Access-Control-Allow-Origin: *");
writer.flush();
writer.close();
throw e;
}
}
}

View file

@ -1,138 +0,0 @@
package be.jeffcheasey88.peeratcode.framework;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.simple.parser.JSONParser;
public class HttpReader{
private static Pattern HEADER_PATTERN = Pattern.compile("^([^:]*):\\s+(.*)$");
private Socket socket;
private InputStream in;
private BufferedReader reader;
private Map<String, String> headers;
public HttpReader(Socket socket) throws Exception{
this.socket = socket;
this.in = socket.getInputStream();
this.reader = new BufferedReader(new InputStreamReader(in));
this.headers = new HashMap<>();
}
public HttpReader(HttpReader origin) throws Exception{
this.socket = origin.socket;
this.in = origin.in;
this.reader = origin.reader;
}
public boolean isClosed(){
return this.socket.isClosed();
}
public void readHeaders() throws Exception{
String line;
while(((line = reader.readLine()) != null) && (line.length() > 0)){
Matcher matcher = HEADER_PATTERN.matcher(line);
matcher.matches();
this.headers.put(matcher.group(1).toLowerCase(), matcher.group(2));
}
}
public String getHeader(String key){
return this.headers.get(key.toLowerCase());
}
public int read(byte[] buffer) throws IOException{
return this.in.read(buffer);
}
public int read(char[] buffer) throws IOException{
return this.reader.read(buffer);
}
public String readLine() throws IOException{
return this.reader.readLine();
}
public boolean ready() throws IOException{
return this.reader.ready();
}
public int readInt() throws Exception{
int result = 0;
result += this.in.read() << 24;
result += this.in.read() << 16;
result += this.in.read() << 8;
result += this.in.read();
return result;
}
public <T> T readJson() throws Exception{
String line = "";
while (ready()){
char[] c = new char[1];
read(c);
line += c[0];
if (c[0] == '}'){
Object parse;
try {
parse = new JSONParser().parse(line);
if (parse != null)
return (T) parse;
}catch(Exception e){}
}
}
return null;
}
/*
*
------WebKitFormBoundaryNUjiLBAMuX2dhxU7
Content-Disposition: form-data; name="answer"
12
------WebKitFormBoundaryNUjiLBAMuX2dhxU7
Content-Disposition: form-data; name="filename"
webpack.js
------WebKitFormBoundaryNUjiLBAMuX2dhxU7
Content-Disposition: form-data; name="code_file"; filename="webpack.js"
Content-Type: text/javascript
------WebKitFormBoundaryNUjiLBAMuX2dhxU7--
*
*/
public List<String> readMultiPartData() throws Exception{
List<String> list = new ArrayList<>();
String boundary = getHeader("content-type");
if(boundary == null) return list;
boundary = boundary.split(";")[1].split("=")[1];
readLine();
while(ready()){
String line;
while (((line = readLine()) != null) && (line.length() > 0));
String buffer = "";
while (((line = readLine()) != null) && (!line.startsWith("--"+boundary))){
buffer += line;
}
list.add(buffer);
}
return list;
}
}

View file

@ -1,101 +0,0 @@
package be.jeffcheasey88.peeratcode.framework;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class HttpWriter{
private OutputStream out;
private BufferedWriter writer;
public HttpWriter(Socket socket) throws Exception{
this.out = socket.getOutputStream();
this.writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
}
public HttpWriter(HttpWriter origin) throws Exception{
this.out = origin.out;
this.writer = origin.writer;
}
public void write(byte[] buffer) throws IOException{
this.out.write(buffer);
this.out.flush();
}
public void write(String message) throws IOException{
this.writer.write(message);
}
public void flush() throws IOException{
this.writer.flush();
}
public void close() throws IOException{
this.writer.close();
}
public void response(int code, String... headers) throws Exception{
write("HTTP/1.1 "+code+codeMessage(code)+"\n");
for(String header : headers) write(header+"\n");
write("\n");
flush();
StackTraceElement[] e = Thread.currentThread().getStackTrace();
System.out.println(e[2]+" -> response "+code);
}
private static String[] HEIGHTBITS = new String[7];
private static String[] NINEBITS = new String[206];
static {
HEIGHTBITS[0] = " OK";
HEIGHTBITS[1] = " Created";
HEIGHTBITS[2] = " Accepted";
HEIGHTBITS[3] = " Non-Authoritative Information";
HEIGHTBITS[4] = " No Content";
HEIGHTBITS[5] = " Reset Content";
HEIGHTBITS[6] = " Partial Content";
NINEBITS[0] = " Multiple Choices";
NINEBITS[1] = " Moved Permanently";
NINEBITS[2] = " Temporary Redirect";
NINEBITS[3] = " See Other";
NINEBITS[4] = " Not Modified";
NINEBITS[5] = " Use Proxy";
NINEBITS[100] = " Bad Request";
NINEBITS[101] = " Unauthorized";
NINEBITS[102] = " Payment Required";
NINEBITS[103] = " Forbidden";
NINEBITS[104] = " Not Found";
NINEBITS[105] = " Method Not Allowed";
NINEBITS[106] = " Not Acceptable";
NINEBITS[107] = " Proxy Authentication Required";
NINEBITS[108] = " Request Time-Out";
NINEBITS[109] = " Conflict";
NINEBITS[110] = " Gone";
NINEBITS[111] = " Length Required";
NINEBITS[112] = " Precondition Failed";
NINEBITS[113] = " Request Entity Too Large";
NINEBITS[114] = " Request-URI Too Large";
NINEBITS[115] = " Unsupported Media Type";
NINEBITS[200] = " Internal Server Error";
NINEBITS[201] = " Not Implemented";
NINEBITS[202] = " Bad Gateway";
NINEBITS[203] = " Service Unavailable";
NINEBITS[204] = " Gateway Timeout";
NINEBITS[205] = " HTTP Version Not Supported";
}
private static String codeMessage(int code){
if(code == 100) return " Continue";
if(code >> 8 == 0) return HEIGHTBITS[code-200];
return NINEBITS[code-300];
}
}

View file

@ -1,59 +0,0 @@
package be.jeffcheasey88.peeratcode.framework;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class Locker<V>{
private Map<Key, BlockingQueue<V>> map;
public Locker(){
this.map = new HashMap<>();
}
public void init(Key key){
this.map.put(key, new LinkedBlockingQueue<>());
}
public void remove(Key key){
this.map.remove(key);
}
private BlockingQueue<V> get(Key key){
return this.map.get(key);
}
public void setValue(V value){
for(Entry<Key, BlockingQueue<V>> entry : this.map.entrySet()){
entry.getValue().add(value);
this.unlock(entry.getKey());
}
}
public V getValue(Key key){
BlockingQueue<V> queue = get(key);
if(queue.isEmpty()) return null;
return queue.poll();
}
public void lock(Key key) throws InterruptedException{
BlockingQueue<V> queue = get(key);
if(queue.isEmpty()){
synchronized(queue){
queue.wait();
}
}
}
public void unlock(Key key){
BlockingQueue<V> queue = get(key);
synchronized(queue){
queue.notify();
}
}
public static class Key{ public Key(){} }
}

View file

@ -1,7 +0,0 @@
package be.jeffcheasey88.peeratcode.framework;
public enum RequestType{
GET, POST, OPTIONS;
}

View file

@ -1,9 +0,0 @@
package be.jeffcheasey88.peeratcode.framework;
import java.util.regex.Matcher;
public interface Response{
void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception;
}

View file

@ -1,19 +0,0 @@
package be.jeffcheasey88.peeratcode.framework;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Route{
String path() default "^.*$";
RequestType type() default RequestType.GET;
boolean needLogin() default false;
boolean websocket() default false;
}

View file

@ -1,178 +0,0 @@
package be.jeffcheasey88.peeratcode.framework;
import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jwk.RsaJwkGenerator;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.lang.JoseException;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class Router{
private Map<RequestType, Map<Response, Route>> responses;
private Map<Response, Pattern> patterns;
private Response noFileFound;
private RsaJsonWebKey rsaJsonWebKey;
private DatabaseRepository repo;
private String token_issuer;
private int token_expiration;
public Router(DatabaseRepository repo, String token_issuer, int token_expiration) throws Exception{
this.repo = repo;
this.token_issuer = token_issuer;
this.token_expiration = token_expiration;
this.responses = new HashMap<>();
for(RequestType type : RequestType.values()) this.responses.put(type, new HashMap<>());
this.patterns = new HashMap<>();
this.rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
}
public DatabaseRepository getDataBase(){
return this.repo;
}
public void register(Response response){
try{
Method method = response.getClass().getDeclaredMethod("exec",
Response.class.getDeclaredMethods()[0].getParameterTypes());
Route route = method.getAnnotation(Route.class);
this.responses.get(route.type()).put(response, route);
this.patterns.put(response, Pattern.compile(route.path()));
}catch(Exception e){
throw new IllegalArgumentException(e);
}
}
public void setDefault(Response response){
this.noFileFound = response;
}
public void exec(RequestType type, String path, User user, HttpReader reader, HttpWriter writer) throws Exception{
if(type == null) return;
for(Entry<Response, Route> routes : this.responses.get(type).entrySet()){
Matcher matcher = this.patterns.get(routes.getKey()).matcher(path);
if(matcher.matches()){
if(user == null && routes.getValue().needLogin()){
writer.response(401, "Access-Control-Allow-Origin: *");
return;
}
if(routes.getValue().websocket()){
switchToWebSocket(reader, writer);
reader = new WebSocketReader(reader);
writer = new WebSocketWriter(writer);
}
routes.getKey().exec(matcher, user, reader, writer);
return;
}
}
if(noFileFound != null) noFileFound.exec(null, user, reader, writer);
}
public RsaJsonWebKey getWebKey(){
return this.rsaJsonWebKey;
}
public String getTokenIssuer(){
return this.token_issuer;
}
public String createAuthUser(int id) throws JoseException{
JwtClaims claims = new JwtClaims();
claims.setIssuer(token_issuer); // who creates the token and signs it
claims.setExpirationTimeMinutesInTheFuture(token_expiration);
claims.setGeneratedJwtId(); // a unique identifier for the token
claims.setIssuedAtToNow(); // when the token was issued/created (now)
claims.setNotBeforeMinutesInThePast(2); // time before which the token is not yet valid (2 minutes ago)
claims.setClaim("id", id);
JsonWebSignature jws = new JsonWebSignature();
jws.setPayload(claims.toJson());
jws.setKey(rsaJsonWebKey.getPrivateKey());
jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId());
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
return jws.getCompactSerialization();
}
private void switchToWebSocket(HttpReader reader, HttpWriter writer) throws Exception{
String key = reader.getHeader("Sec-WebSocket-Key");
if (key == null) throw new IllegalArgumentException();
writer.write("HTTP/1.1 101 Switching Protocols\n");
writer.write("Connection: Upgrade\n");
writer.write("Upgrade: websocket\n");
writer.write("Sec-WebSocket-Accept: " + printBase64Binary(MessageDigest.getInstance("SHA-1")
.digest((key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes("UTF-8"))) + "\n");
writer.write("\n");
writer.flush();
}
// From javax.xml.bind.DatatypeConverter
private String printBase64Binary(byte[] array){
char[] arrayOfChar = new char[(array.length + 2) / 3 * 4];
int i = _printBase64Binary(array, 0, array.length, arrayOfChar, 0);
assert i == arrayOfChar.length;
return new String(arrayOfChar);
}
private int _printBase64Binary(byte[] paramArrayOfbyte, int paramInt1, int paramInt2,
char[] paramArrayOfchar, int paramInt3){
int i = paramInt2;
int j;
for (j = paramInt1; i >= 3; j += 3){
paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
paramArrayOfchar[paramInt3++] = encode(
(paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF);
paramArrayOfchar[paramInt3++] = encode(
(paramArrayOfbyte[j + 1] & 0xF) << 2 | paramArrayOfbyte[j + 2] >> 6 & 0x3);
paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j + 2] & 0x3F);
i -= 3;
}
if (i == 1){
paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j] & 0x3) << 4);
paramArrayOfchar[paramInt3++] = '=';
paramArrayOfchar[paramInt3++] = '=';
}
if (i == 2){
paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2);
paramArrayOfchar[paramInt3++] = encode(
(paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF);
paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j + 1] & 0xF) << 2);
paramArrayOfchar[paramInt3++] = '=';
}
return paramInt3;
}
private char encode(int paramInt){
return encodeMap[paramInt & 0x3F];
}
private static final char[] encodeMap = initEncodeMap();
private static char[] initEncodeMap(){
char[] arrayOfChar = new char[64];
byte b;
for (b = 0; b < 26; b++)
arrayOfChar[b] = (char) (65 + b);
for (b = 26; b < 52; b++)
arrayOfChar[b] = (char) (97 + b - 26);
for (b = 52; b < 62; b++)
arrayOfChar[b] = (char) (48 + b - 52);
arrayOfChar[62] = '+';
arrayOfChar[63] = '/';
return arrayOfChar;
}
}

View file

@ -1,27 +0,0 @@
package be.jeffcheasey88.peeratcode.framework;
import org.jose4j.jwt.JwtClaims;
import be.jeffcheasey88.peeratcode.framework.Locker.Key;
public class User{
private int id;
private Key key;
public User(JwtClaims jwtClaims){
this.id = ((Long) jwtClaims.getClaimValue("id")).intValue();
}
public void setKey(Key key){
this.key = key;
}
public Key getKey(){
return this.key;
}
public int getId(){
return this.id;
}
}

View file

@ -1,62 +0,0 @@
package be.jeffcheasey88.peeratcode.framework;
import java.io.IOException;
public class WebSocketReader extends HttpReader{
public WebSocketReader(HttpReader origin) throws Exception{
super(origin);
}
@Override
public String readLine() throws IOException{
//read websocket found on StackOverFlow
int buffLenth = 1024;
int len = 0;
byte[] b = new byte[buffLenth];
// rawIn is a Socket.getInputStream();
while (true){
len = read(b);
if (len != -1){
byte rLength = 0;
int rMaskIndex = 2;
int rDataStart = 0;
// b[0] is always text in my case so no need to check;
byte data = b[1];
byte op = (byte) 127;
rLength = (byte) (data & op);
if (rLength == (byte) 126)
rMaskIndex = 4;
if (rLength == (byte) 127)
rMaskIndex = 10;
byte[] masks = new byte[4];
int j = 0;
int i = 0;
for (i = rMaskIndex; i < (rMaskIndex + 4); i++){
masks[j] = b[i];
j++;
}
rDataStart = rMaskIndex + 4;
int messLen = len - rDataStart;
byte[] message = new byte[messLen];
for (i = rDataStart, j = 0; i < len; i++, j++){
message[j] = (byte) (b[i] ^ masks[j % 4]);
}
return new String(message);
} else
break;
}
return null;
}
}

View file

@ -1,61 +0,0 @@
package be.jeffcheasey88.peeratcode.framework;
import java.io.IOException;
public class WebSocketWriter extends HttpWriter{
public WebSocketWriter(HttpWriter origin) throws Exception{
super(origin);
}
@Override
public void write(String message) throws IOException{
//write websocket found on StackOverFlow
byte[] rawData = message.getBytes();
int frameCount = 0;
byte[] frame = new byte[10];
frame[0] = (byte) 129;
if (rawData.length <= 125){
frame[1] = (byte) rawData.length;
frameCount = 2;
} else if (rawData.length >= 126 && rawData.length <= 65535){
frame[1] = (byte) 126;
int len = rawData.length;
frame[2] = (byte) ((len >> 8) & (byte) 255);
frame[3] = (byte) (len & (byte) 255);
frameCount = 4;
} else {
frame[1] = (byte) 127;
int len = rawData.length;
frame[2] = (byte) ((len >> 56) & (byte) 255);
frame[3] = (byte) ((len >> 48) & (byte) 255);
frame[4] = (byte) ((len >> 40) & (byte) 255);
frame[5] = (byte) ((len >> 32) & (byte) 255);
frame[6] = (byte) ((len >> 24) & (byte) 255);
frame[7] = (byte) ((len >> 16) & (byte) 255);
frame[8] = (byte) ((len >> 8) & (byte) 255);
frame[9] = (byte) (len & (byte) 255);
frameCount = 10;
}
int bLength = frameCount + rawData.length;
byte[] reply = new byte[bLength];
int bLim = 0;
for (int i = 0; i < frameCount; i++){
reply[bLim] = frame[i];
bLim++;
}
for (int i = 0; i < rawData.length; i++){
reply[bLim] = rawData[i];
bLim++;
}
write(reply);
flush();
}
}

View file

@ -1,110 +0,0 @@
package be.jeffcheasey88.peeratcode.parser.java;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Class {
private static Pattern PATTERN = Pattern.compile("^(\\s*([^\\{]*)\\{(.*)\\})\\s*$");
private int modifier;
private String name;
private List<Variable> vars;
private List<Function> functions;
public Class(){}
public int parse(String content) throws Exception{
Matcher matcher = PATTERN.matcher(content);
matcher.matches();
String[] split = matcher.group(2).split("\\s+");
for(int i = 0; i < split.length-1; i++){
this.modifier+=JavaParser.getModifier(split[i]);
}
this.name = split[split.length-1];
this.vars = new ArrayList<>();
this.functions = new ArrayList<>();
content = matcher.group(3);
Pattern empty = Pattern.compile("^\\s*$");
while(!(empty.matcher(content).matches())){
int quotes = indexOf(content,";");
int braces = indexOf(content,"\\{");
int equals = indexOf(content,"=");
if(quotes < braces && quotes < equals){
boolean quote = false;
Variable last = null;
do {
Variable variable = (last == null) ? new Variable() : new Variable(last.getModifier(), last.getType());
int index = variable.parse(content);
this.vars.add(variable);
content = content.substring(index);
quote = content.startsWith(",");
if(quote) {
content = content.substring(1);
last = variable;
}
}while(quote);
}else if(equals < braces){
//variable with value
boolean quote = false;
Variable last = null;
do {
Variable variable = (last == null) ? new Variable() : new Variable(last.getModifier(), last.getType());
int index = variable.parse(content);
this.vars.add(variable);
content = content.substring(index);
quote = content.startsWith(",");
if(quote) {
content = content.substring(1);
last = variable;
}else if(indexOf(content, "=") < indexOf(content, ";")){
Operation operation = new Operation();
index = operation.parse(content);
content = content.substring(index);
break;
}
}while(quote);
}else{
System.out.println("Function "+content);
Function func = new Function();
int index = func.parse(content);
this.functions.add(func);
content = content.substring(index);
System.out.println("End "+content);
}
}
return matcher.group(1).length();
}
private int indexOf(String value, String target){
return value.split(target)[0].length();
}
public int getModifier(){
return this.modifier;
}
public String getName(){
return this.name;
}
public List<Variable> getVariables(){
return this.vars;
}
public void show(){
System.out.println(Modifier.toString(modifier)+" "+this.name+"{");
for(Variable v : this.vars) v.show(1);
System.out.println();
for(Function f : this.functions) f.show(1);
System.out.println("}");
}
}

View file

@ -1,94 +0,0 @@
package be.jeffcheasey88.peeratcode.parser.java;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public class CleanerPool {
private static String CONSTANT_REPLACER_STRING = "$STRING_STATEMENT_CONSTANT_";
private static String CONSTANT_REPLACER_CHAR = "$CHAR_STATEMENT_CONSTANT_";
private static String CONSTANT_REPLACER_GENERIC = "$GENERIC_STATEMENT_CONSTANT_";
private List<String> constants;
private CleanerPool(){
this.constants = new ArrayList<>();
}
public String clean(String statement){
char[] chars = statement.toCharArray();
StringBuilder builder = new StringBuilder();
for(int i = 0; i < chars.length; i++){
char current = chars[i];
if(current== '"'){
int constantPos = this.constants.size();
String constant = cutConstant(chars, i);
i+=constant.length()+1;
builder.append(CONSTANT_REPLACER_STRING+constantPos);
this.constants.add(constant);
}else{
builder.append(current);
}
}
for(String s : constants){
System.out.println("CONSTANT="+s);
}
return builder.toString();
}
public boolean isConstant(String region){
return region.startsWith(CONSTANT_REPLACER_STRING);
}
public String getConstant(String replacer){
if(!replacer.startsWith(CONSTANT_REPLACER_STRING)) return null;
return this.constants.get(Integer.parseInt(replacer.replace(CONSTANT_REPLACER_STRING,"")));
}
public List<String> getConstants(){
return this.constants;
}
private static Pattern parenthesisPattern = Pattern.compile("^\\$SQL_STATEMENT_PARENTHESIS_([0-9]*$)");
public boolean isParenthesis(String region){
return parenthesisPattern.matcher(region).matches();
}
private String cutConstant(char[] chars, int pos){
StringBuilder builder = new StringBuilder();
for(int i = pos+1; i < chars.length; i++){
char current = chars[i];
if(current == '"'){
if(current == '\\'){ //toChange
builder.append(current);
}else break;
}else{
builder.append(current);
}
}
return builder.toString();
}
public static interface Cutter{
String execute(String value, List<String> constants, String pattern);
default String cutOpenable(String value, List<String> constants, String pattern, char open, char close){
StringBuilder builder = new StringBuilder();
for(char c : value.toCharArray()){
if(c == open){
}else if(c == close){
}
}
return builder.toString();
}
}
}

View file

@ -1,85 +0,0 @@
package be.jeffcheasey88.peeratcode.parser.java;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Function {
private static Pattern PATTERN = Pattern.compile("^(\\s*([^(]*)\\(([^)]*)\\)\\s*([^{]*)\\{)(.*)$");
private int modifier;
private String name;
private String exceptions;
private String parameters;
private List<Function> functions;
private List<Operation> operations;
public Function(){
this.functions = new ArrayList<>();
this.operations = new ArrayList<>();
}
public int parse(String content) throws Exception{
Matcher matcher = PATTERN.matcher(content);
matcher.matches();
String[] split = matcher.group(2).split("\\s+");
for(int i = 0; i < split.length-2; i++){
this.modifier+=JavaParser.getModifier(split[i]);
}
this.name = split[split.length-1];
this.parameters = matcher.group(3);
this.exceptions = matcher.group(4);
String body = matcher.group(5);
int offset = 0;
int index = 0;
do {
int end = body.indexOf('}');
int braces = body.indexOf('{');
int quotes = body.indexOf(';');
if((end < 0) || (end < braces && end < quotes)){
if(end > 0) offset+=end;
break;
}
if(braces < 0 && quotes < 0){
if(end > 0) offset+=end;
break;
}
if(braces >= 0 && braces < quotes){
Function func = new Function();
index = func.parse(body.substring(0, end+1));
this.functions.add(func);
}else{
Operation op = new Operation();
index = op.parse(body.substring(0, end+1));
this.operations.add(op);
}
offset+=index+1;
body = body.substring(index);
}while(offset > -1);
return matcher.group(1).length()+offset;
}
public void show(int tab){
String start = "";
for(int i = 0; i < tab; i++) start+="\t";
System.out.println(start+Modifier.toString(modifier)+" "+name+"("+parameters+") "+exceptions+" {");
for(Operation o : this.operations) o.show(tab+1);
System.out.println();
for(Function f : this.functions) f.show(tab+1);
System.out.println(start+"}");
}
@Override
public String toString(){
return "Function[name="+name+",param="+parameters+",exception="+exceptions+"]";
}
}

View file

@ -1,28 +0,0 @@
package be.jeffcheasey88.peeratcode.parser.java;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Import {
private static Pattern PATTERN = Pattern.compile("^\\s*(import\\s+([^;]*);).*$");
public static boolean isImport(String content){
return PATTERN.matcher(content).matches();
}
private String name;
public Import(){}
public int parse(String content) throws Exception{
Matcher matcher = PATTERN.matcher(content);
matcher.matches();
this.name = matcher.group(2);
return matcher.group(1).length();
}
public String getName(){
return this.name;
}
}

View file

@ -1,96 +0,0 @@
package be.jeffcheasey88.peeratcode.parser.java;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
public class JavaParser {
public static void main(String[] args) throws Exception {
File file = new File("C:\\Users\\jeffc\\eclipse-workspace\\peer-at-code-backend\\src\\be\\jeffcheasey88\\peeratcode\\parser\\java\\Import.java");
BufferedReader reader = new BufferedReader(new FileReader(file));
JavaParser parser = new JavaParser(reader);
parser.parse();
System.out.println("SHOW-----------------");
parser.show();
}
private Package pack;
private List<Import> imports;
private Class clazz;
private BufferedReader reader;
public JavaParser(BufferedReader reader){
this.reader = reader;
}
public void parse() throws Exception{
String content = "";
int index;
String line;
while((line = reader.readLine()) != null) content+=line;
// content = CleanerPool.getterToDelete.clean(content);
this.pack = new Package();
index = this.pack.parse(content);
content = content.substring(index);
this.imports = new ArrayList<>();
while(Import.isImport(content)){
Import imp = new Import();
index = imp.parse(content);
this.imports.add(imp);
content = content.substring(index);
}
this.clazz = new Class();
index = this.clazz.parse(content);
content = content.substring(index);
}
public Package getPackage(){
return this.pack;
}
public List<Import> getImports(){
return this.imports;
}
public Class getClazz(){
return this.clazz;
}
public void show(){
System.out.println("package "+this.pack.getName()+";");
System.out.println();
for(Import i : this.imports) System.out.println("import "+i.getName()+";");
System.out.println();
this.clazz.show();
}
public static int getModifier(String modifier){
switch(modifier){
case "public": return Modifier.PUBLIC;
case "private": return Modifier.PRIVATE;
case "protected": return Modifier.PROTECTED;
case "static": return Modifier.STATIC;
case "final": return Modifier.FINAL;
case "synchronized": return Modifier.SYNCHRONIZED;
case "volatile": return Modifier.VOLATILE;
case "transient": return Modifier.TRANSIENT;
case "native": return Modifier.NATIVE;
case "abstract": return Modifier.ABSTRACT;
case "strictfp": return Modifier.STRICT;
default: break;
}
return 0;
}
}

View file

@ -1,29 +0,0 @@
package be.jeffcheasey88.peeratcode.parser.java;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Operation {
private static Pattern VARIABLE_PATTERN = Pattern.compile("^(\\s*([^;]*)).*$");
private String tmp;
public Operation(){}
public int parse(String content) throws Exception{
Matcher matcher = VARIABLE_PATTERN.matcher(content);
if(matcher.matches()){
this.tmp = matcher.group(2);
return matcher.group(1).length()+1;
}
return 0;
}
public void show(int tab){
String start = "";
for(int i = 0; i < tab; i++) start+="\t";
System.out.println(start+tmp+";");
}
}

View file

@ -1,24 +0,0 @@
package be.jeffcheasey88.peeratcode.parser.java;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Package {
private static Pattern PATTERN = Pattern.compile("^(\\s*package\\s+([^;]*);).*$");
private String name;
public Package(){}
public int parse(String content) throws Exception{
Matcher matcher = PATTERN.matcher(content);
matcher.matches();
this.name = matcher.group(2);
return matcher.group(1).length();
}
public String getName(){
return this.name;
}
}

View file

@ -1,127 +0,0 @@
package be.jeffcheasey88.peeratcode.parser.java;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Variable {
private static Pattern PATTERN = Pattern.compile("^(\\s*)(.*)$");
private int modifier;
private String name;
private String type;
private Variable value;
public Variable(){}
public Variable(int modifier, String type){
this.modifier = modifier;
this.type = type;
}
public int parse(String content) throws Exception{
Matcher matcher = PATTERN.matcher(content);
matcher.matches();
int offset = matcher.group(1).length();
String body = matcher.group(2);
int equals = indexOf(body, "=");
int quote = indexOf(body,",");
int quotes = indexOf(body, ";");
int min = Math.min(quote, quotes);
body = body.substring(0, min);
if(equals < quote && equals < quotes){
assigment(body);
}else{
onlyDefine(body);
}
return offset+min;
}
private void assigment(String content){
}
private void onlyDefine(String content){
content = generiqueTypes(content);
System.out.println(content);
String[] values = content.split("\\s+");
for(String value : values){
int modifier = JavaParser.getModifier(value);
if(modifier > 0){
this.modifier+=modifier;
continue;
}
if(this.type == null){
this.type = value;
continue;
}
this.name = value;
}
}
private String generiqueTypes(String content){
System.out.println(content);
String result = "";
int opened = 0;
for(char c : content.toCharArray()){
if(c == '<') opened++;
else if(c == '>') opened--;
if(opened > 0){
if(Character.isWhitespace(c)) continue;
}
result+=c;
}
result = result.replaceAll("(>\\s*)", "> ").replace("> >", ">>");
return result;
}
private int indexOf(String value, String target){
return value.split(target)[0].length();
}
public int getModifier(){
return this.modifier;
}
public String getName(){
return this.name;
}
public String getType(){
return this.type;
}
public Variable getValue(){
return this.value;
}
public void show(int tab){
String start = "";
for(int i = 0; i < tab; i++) start+="\t";
System.out.println(start+Modifier.toString(modifier)+" "+type+" "+name+(value == null ? ";":"="+value+";"));
}
public static class Value extends Variable{
private String value;
public Value(String value){
this.value = value;
}
public String value(){
return this.value;
}
@Override
public String toString(){
return this.value;
}
}
}

View file

@ -1,259 +0,0 @@
package be.jeffcheasey88.peeratcode.repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
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 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"
+ "WHERE 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"
+ "WHERE cGs.fk_player = ? AND p.id_puzzle = ?"),
// PLAYERS
GET_PLAYER_SIMPLE("SELECT pseudo, email, firstname, lastname, description FROM players WHERE id_player = ?"),
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 players p ON p.id_player = c.fk_player GROUP BY fk_player ORDER BY rank) AS ranks WHERE ranks.fk_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
FIRST_TRY("CREATE OR REPLACE TRIGGER FirstTry\r\n"
+ "AFTER INSERT\r\n"
+ " ON completions FOR EACH ROW\r\n"
+ "BEGIN\r\n"
+ " DECLARE badge INT;\r\n"
+ " DECLARE contain INT;\r\n"
+ " \r\n"
+ " SELECT id_badge\r\n"
+ " INTO @badge\r\n"
+ " FROM badges\r\n"
+ " WHERE name = 'FirstTry';\r\n"
+ " \r\n"
+ " IF @badge is not null THEN\r\n"
+ " \r\n"
+ " SELECT count(*)\r\n"
+ " INTO @contain\r\n"
+ " FROM containsBadges\r\n"
+ " WHERE fk_badge = @badge AND fk_player = NEW.fk_player;\r\n"
+ " \r\n"
+ " IF (@contain = 0) THEN\r\n"
+ " INSERT INTO containsBadges(fk_player, fk_badge) VALUES (NEW.fk_player, @badge);\r\n"
+ " END IF;\r\n"
+ " END IF;\r\n"
+ "END;"),
EventParticipation("CREATE OR REPLACE TRIGGER EventParticipation\r\n"
+ "AFTER INSERT\r\n"
+ " ON completions FOR EACH ROW\r\n"
+ "BEGIN\r\n"
+ " DECLARE badge INT;\r\n"
+ " DECLARE endDate datetime;\r\n"
+ " DECLARE player INT;\r\n"
+ " DECLARE contain INT;\r\n"
+ "\r\n"
+ " SELECT id_badge\r\n"
+ " INTO badge\r\n"
+ " FROM badges\r\n"
+ " WHERE name = 'EventParticipation';\r\n"
+ "\r\n"
+ " IF @badge is not null THEN\r\n"
+ "\r\n"
+ " SELECT c.end_date, i.fk_player\r\n"
+ " INTO endDate, player\r\n"
+ " FROM inserted i\r\n"
+ " JOIN puzzles p ON i.fk_puzzle = p.id_puzzle\r\n"
+ " JOIN chapters c on p.fk_chapter = c.id_chapter;\r\n"
+ "\r\n"
+ " IF @endDate is not null THEN\r\n"
+ "\r\n"
+ " SELECT count(*)\r\n"
+ " INTO contain\r\n"
+ " FROM containsBadges\r\n"
+ " WHERE fk_badge = badge AND fk_player = player;\r\n"
+ "\r\n"
+ " IF (@contain = 0) THEN\r\n"
+ " INSERT INTO containsBadges(fk_player, fk_badge) VALUES (@player, @badge);\r\n"
+ " END IF;\r\n"
+ " END IF;\r\n"
+ " END IF;\r\n"
+ "END;");
private String request;
DatabaseQuery(DatabaseQuery parent, String request) {
this.request = parent.request + request;
}
DatabaseQuery(String request) {
this.request = request;
}
public PreparedStatement prepare(Connection con) throws SQLException {
return con.prepareStatement(this.request);
}
@Override
public String toString() {
return this.request;
}
}
/*
*
SELECT p.*, scores.score, scores.completions, scores.tries, scores.rank, 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 GROUP BY c.fk_player)
AS scores
LEFT OUTER JOIN containsGroups cg ON scores.fk_player = cg.fk_player
LEFT OUTER JOIN groups g ON cg.fk_group = g.id_group
WHERE p.id_player = scores.fk_player AND "),
*
*/
/* TRIGGER PLACE
*
CREATE OR REPLACE TRIGGER FirstTry
AFTER INSERT
ON completions FOR EACH ROW
BEGIN
DECLARE badge INT;
DECLARE contain INT;
SELECT id_badge
INTO @badge
FROM badges
WHERE name = 'FirstTry';
IF @badge is not null THEN
SELECT count(*)
INTO @contain
FROM containsBadges
WHERE fk_badge = @badge AND fk_player = NEW.fk_player;
IF (@contain = 0) THEN
IF (NEW.score >= 0 AND NEW.tries < 2) THEN
INSERT INTO containsBadges(fk_player, fk_badge) VALUES (NEW.fk_player, @badge);
END IF;
END IF;
END IF;
END;
CREATE OR REPLACE TRIGGER EventParticipation
AFTER INSERT
ON completions FOR EACH ROW
BEGIN
DECLARE badge INT;
DECLARE endDate datetime;
DECLARE player INT;
DECLARE contain INT;
SELECT id_badge
INTO badge
FROM badges
WHERE name = 'EventParticipation';
IF @badge is not null THEN
SELECT c.end_date, i.fk_player
INTO endDate, player
FROM inserted i
JOIN puzzles p ON i.fk_puzzle = p.id_puzzle
JOIN chapters c on p.fk_chapter = c.id_chapter;
IF @endDate is not null THEN
SELECT count(*)
INTO contain
FROM containsBadges
WHERE fk_badge = badge AND fk_player = player;
IF (@contain = 0) THEN
INSERT INTO containsBadges(fk_player, fk_badge) VALUES (@player, @badge);
END IF;
END IF;
END IF;
END;
*
*/

View file

@ -1,699 +0,0 @@
package be.jeffcheasey88.peeratcode.repository;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import com.password4j.Hash;
import com.password4j.Password;
import be.jeffcheasey88.peeratcode.Configuration;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Badge;
import be.jeffcheasey88.peeratcode.model.Chapter;
import be.jeffcheasey88.peeratcode.model.Completion;
import be.jeffcheasey88.peeratcode.model.Group;
import be.jeffcheasey88.peeratcode.model.Player;
import be.jeffcheasey88.peeratcode.model.Puzzle;
public class DatabaseRepository {
private Connection con;
private Configuration config;
public DatabaseRepository(Configuration config) {
this.config = config;
}
// testTrigger();
// }
//
// private void testTrigger(){
// try {
// ensureConnection();
// }catch(Exception e){
// e.printStackTrace();
// }
// System.out.println("connection ensured");
//
// try {
// PreparedStatement log = this.con.prepareStatement("DROP TABLE mycustomlog;");
// log.execute();
// }catch(Exception e){
// e.printStackTrace();
// }
// System.out.println("log dropped");
//
// try {
// PreparedStatement log = this.con.prepareStatement("CREATE TABLE mycustomlog(\r\n"
// + " message VARCHAR(255),\r\n"
// + " primary key (message)\r\n"
// + ");");
// log.execute();
// }catch(Exception e){
// e.printStackTrace();
// }
// System.out.println("log created");
//
// try {
// System.out.println(DatabaseQuery.FIRST_TRY.toString());
// DatabaseQuery.FIRST_TRY.prepare(this.con).execute();
// }catch(Exception e){
// e.printStackTrace();
// }
//
// System.out.println("trigger inserted");
//
// try {
// insertCompletion(new Completion(1, 1, 1, null, 1));
// } catch (SQLException e1) {
// e1.printStackTrace();
// }
//
// try {
// showLog();
// } catch (Exception e) {
// e.printStackTrace();
// }
// System.out.println("------------------------------");
// }
//
// private void showLog() throws Exception{
// ensureConnection();
//
// PreparedStatement stmt = this.con.prepareStatement("SELECT * FROM mycustomlog");
// ResultSet result = stmt.executeQuery();
// while(result.next()){
// System.out.println("[LOG] "+result.getString("message"));
// }
// }
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);
}
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"),
fileName, completionResult.getInt("score"), puzzleName);
}
private Player makePlayer(ResultSet playerResult, int id) throws SQLException {
Player p = new Player(playerResult.getString("pseudo"), playerResult.getString("email"),
playerResult.getString("firstName"), playerResult.getString("lastName"),
playerResult.getString("description"));
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));
}
}
// 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 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) {
Hash hash = Password.hash(password).withArgon2();
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, hash.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;
}
}
} 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 = con.prepareStatement(DatabaseQuery.CHECK_PASSWORD.toString());
DatabaseQuery.PUZZLES_IN_CHAPTER_QUERY.prepare(this.con);
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;
}
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);
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 = DatabaseQuery.INSERT_COMPLETION.prepare(this.con);
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();
}
public boolean insertGroup(Group group, User creator) throws SQLException {
Integer groupId = getGroupId(group);
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 {
ensureConnection();
PreparedStatement stmt = DatabaseQuery.GET_GROUP_FOR_PLAYER.prepare(this.con);
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 = 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, User 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;
}
public boolean leaveGroup(Group group, User user) throws SQLException {
Integer id = getGroupId(group);
if (id != null) {
PreparedStatement stmt = DatabaseQuery.LEAVE_GROUP.prepare(this.con);
stmt.setInt(1, user.getId());
stmt.setInt(2, id);
return stmt.executeUpdate() >= 0;
}
return false;
}
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

@ -1,47 +0,0 @@
package be.jeffcheasey88.peeratcode.routes;
import java.util.Base64;
import java.util.regex.Matcher;
import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Badge;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class BadgeDetails implements Response {
private final DatabaseRepository databaseRepo;
public BadgeDetails(DatabaseRepository databaseRepo) {
this.databaseRepo = databaseRepo;
}
@RouteDoc(path = "/badge/<id>", responseCode = 200, responseDescription = "JSON contenant les informations du badge")
@RouteDoc(responseCode = 400, responseDescription = "Aucun id donner")
@Route(path = "^\\/badge\\/([0-9]+)$", needLogin = true)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
if (matcher.groupCount() > 0) {
int badgeId = Integer.parseInt(matcher.group(1));
Badge badge = databaseRepo.getBadge(badgeId);
JSONObject badgeJSON = new JSONObject();
if (badge != null) {
badgeJSON.put("name", badge.getName());
if (badge.getLogo() != null)
badgeJSON.put("logo", Base64.getEncoder().encodeToString(badge.getLogo()));
badgeJSON.put("level", badge.getLevel());
}
writer.response(200, "Access-Control-Allow-Origin: *");
writer.write(badgeJSON.toJSONString().replace("\\", ""));
} else {
writer.response(400, "Access-Control-Allow-Origin: *");
}
}
}

View file

@ -1,59 +0,0 @@
package be.jeffcheasey88.peeratcode.routes;
import java.util.regex.Matcher;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Chapter;
import be.jeffcheasey88.peeratcode.model.Puzzle;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class ChapterElement implements Response {
private final DatabaseRepository databaseRepo;
public ChapterElement(DatabaseRepository databaseRepo) {
this.databaseRepo = databaseRepo;
}
@RouteDoc(path = "/chapter/<id>", responseCode = 200, responseDescription = "JSON contenant les informations du chapitre demander")
@RouteDoc(responseCode = 400, responseDescription = "Aucun id donner")
@Route(path = "^\\/chapter\\/([0-9]+)$", needLogin = true)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception{
Chapter chapter = databaseRepo.getChapter(Integer.parseInt(matcher.group(1)));
if (chapter != null){
JSONObject chapterJSON = new JSONObject();
chapterJSON.put("id", chapter.getId());
chapterJSON.put("name", chapter.getName());
if (chapter.getStartDate() != null)
chapterJSON.put("startDate", chapter.getStartDate().toString());
if (chapter.getEndDate() != null)
chapterJSON.put("endDate", chapter.getEndDate().toString());
JSONArray puzzles = new JSONArray();
for (Puzzle puzzle : chapter.getPuzzles()){
JSONObject puzzleJSON = new JSONObject();
puzzleJSON.put("id", puzzle.getId());
puzzleJSON.put("name", puzzle.getName());
puzzleJSON.put("scoreMax", puzzle.getScoreMax());
if (puzzle.getTags() != null) puzzleJSON.put("tags", puzzle.getJsonTags());
int score = this.databaseRepo.getScore(user.getId(), puzzle.getId());
if(score >= 0) puzzleJSON.put("score", score);
puzzles.add(puzzleJSON);
}
chapterJSON.put("puzzles", puzzles);
writer.response(200, "Access-Control-Allow-Origin: *");
writer.write(chapterJSON.toJSONString());
} else {
writer.response(400, "Access-Control-Allow-Origin: *");
}
}
}

View file

@ -1,51 +0,0 @@
package be.jeffcheasey88.peeratcode.routes;
import java.util.List;
import java.util.regex.Matcher;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Chapter;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class ChapterList implements Response {
private final DatabaseRepository databaseRepo;
public ChapterList(DatabaseRepository databaseRepo) {
this.databaseRepo = databaseRepo;
}
@RouteDoc(path = "/chapters", responseCode = 200, responseDescription = "JSON contenant les informations des chapitres")
@RouteDoc(responseCode = 400, responseDescription = "Aucun chapitre trouver")
@Route(path = "^\\/chapters$", needLogin = true)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
List<Chapter> allChapters = databaseRepo.getAllChapters();
if (allChapters != null) {
JSONArray chaptersJSON = new JSONArray();
for (Chapter chapter : allChapters) {
JSONObject chapterJSON = new JSONObject();
chapterJSON.put("id", chapter.getId());
chapterJSON.put("name", chapter.getName());
if (chapter.getStartDate() != null)
chapterJSON.put("startDate", chapter.getStartDate().toString());
if (chapter.getEndDate() != null)
chapterJSON.put("endDate", chapter.getEndDate().toString());
chaptersJSON.add(chapterJSON);
}
writer.response(200, "Access-Control-Allow-Origin: *");
writer.write(chaptersJSON.toJSONString());
} else {
writer.response(400, "Access-Control-Allow-Origin: *");
}
}
}

View file

@ -1,92 +0,0 @@
package be.jeffcheasey88.peeratcode.routes;
import java.io.IOException;
import java.util.SortedSet;
import java.util.regex.Matcher;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Chapter;
import be.jeffcheasey88.peeratcode.model.Group;
import be.jeffcheasey88.peeratcode.model.Player;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class Leaderboard implements Response {
private final DatabaseRepository databaseRepo;
public Leaderboard(DatabaseRepository databaseRepo) {
this.databaseRepo = databaseRepo;
}
@RouteDoc(path = "/leaderboard/{id}", responseCode = 200, responseDescription = "JSON contenant le leaderboard")
@Route(path = "^\\/leaderboard\\/?(\\d+)?$")
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
writer.response(200, "Access-Control-Allow-Origin: *");
if (matcher.group(1) != null) {
groupsLeaderboard(Integer.parseInt(matcher.group(1)), writer);
} else {
playersLeaderboard(writer);
}
}
public final void groupsLeaderboard(int chapterId, HttpWriter writer) throws IOException {
Chapter chInfo = databaseRepo.getChapter(chapterId);
SortedSet<Group> allGroupsForChapter = databaseRepo.getAllGroupForChapterLeaderboard(chapterId);
JSONObject leaderboardJSON = new JSONObject();
if (chInfo.getStartDate() != null)
leaderboardJSON.put("start_date", chInfo.getStartDate().toString());
if (chInfo.getEndDate() != null)
leaderboardJSON.put("end_date", chInfo.getEndDate().toString());
JSONArray groupsJSON = new JSONArray();
if (allGroupsForChapter != null) {
int rank = 1;
int sameRankCount = 1;
Group previousGroup = null;
for (Group g : allGroupsForChapter) {
if (previousGroup != null) {
if (g.compareTo(previousGroup) == 0) {
sameRankCount++;
} else {
rank = rank + sameRankCount;
sameRankCount = 1;
}
}
groupsJSON.add(g.toJson(rank));
previousGroup = g;
}
}
leaderboardJSON.put("groups", groupsJSON);
writer.write(leaderboardJSON.toJSONString().replace("\\", ""));
}
public final void playersLeaderboard(HttpWriter writer) throws IOException {
SortedSet<Player> allPlayers = databaseRepo.getAllPlayerForLeaderboard();
JSONArray playersJSON = new JSONArray();
if (allPlayers != null) {
for (Player player : allPlayers) {
JSONObject playerJSON = new JSONObject();
playerJSON.put("pseudo", player.getPseudo());
if (player.getGroups() != null)
playerJSON.put("groups", player.getJsonGroups());
// if (player.getAvatar() != null)
// playerJSON.put("avatar", Base64.getEncoder().encodeToString(player.getAvatar()));
playerJSON.put("rank", player.getRank());
playerJSON.put("score", player.getTotalScore());
playerJSON.put("completions", player.getTotalCompletion());
playerJSON.put("tries", player.getTotalTries());
playersJSON.add(playerJSON);
}
}
writer.write(playersJSON.toJSONString().replace("\\", ""));
}
}

View file

@ -1,53 +0,0 @@
package be.jeffcheasey88.peeratcode.routes;
import static be.jeffcheasey88.peeratcode.framework.RequestType.POST;
import java.util.regex.Matcher;
import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.Router;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class Login implements Response {
private DatabaseRepository databaseRepo;
private Router router;
public Login(DatabaseRepository databaseRepo, Router router) {
this.databaseRepo = databaseRepo;
this.router = router;
}
@RouteDoc(path = "/login", responseCode = 200, responseDescription = "L'utilisateur est inscrit")
@RouteDoc(responseCode = 403, responseDescription = "L'utilisateur est connecté")
@RouteDoc(responseCode = 400, responseDescription = "Aucune données fournie / données invalide")
@Route(path = "^\\/login$", type = POST)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
if (user != null) {
writer.response(403, "Access-Control-Allow-Origin: *");
return;
}
JSONObject informations = reader.readJson();
if (informations != null) {
String pseudo = (String) informations.get("pseudo");
String password = (String) informations.get("passwd");
int id;
if ((id = databaseRepo.login(pseudo, password)) >= 0) {
writer.response(200, "Access-Control-Allow-Origin: *",
"Access-Control-Expose-Headers: Authorization",
"Authorization: Bearer " + this.router.createAuthUser(id));
return;
}
}
writer.response(400, "Access-Control-Allow-Origin: *");
}
}

View file

@ -1,61 +0,0 @@
package be.jeffcheasey88.peeratcode.routes;
import java.util.Base64;
import java.util.regex.Matcher;
import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Player;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class PlayerDetails implements Response {
private final DatabaseRepository databaseRepo;
public PlayerDetails(DatabaseRepository databaseRepo) {
this.databaseRepo = databaseRepo;
}
@RouteDoc(path = "/player/{id}", responseCode = 200, responseDescription = "JSON contenant les informations de l'utilisateur")
@RouteDoc(responseCode = 400, responseDescription = "Utilisateur introuvable dans la base de donnée")
@Route(path = "^\\/player\\/?(.+)?$", needLogin = true)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
Player player;
if (matcher.group(1) != null) {
player = databaseRepo.getPlayerDetails(matcher.group(1));
} else {
player = databaseRepo.getPlayerDetails(user.getId());
}
JSONObject playerJSON = new JSONObject();
if (player != null) {
playerJSON.put("pseudo", player.getPseudo());
playerJSON.put("email", player.getEmail());
playerJSON.put("firstname", player.getFirstname());
playerJSON.put("lastname", player.getLastname());
playerJSON.put("description", player.getDescription());
if (player.getGroups() != null)
playerJSON.put("groups", player.getJsonGroups());
playerJSON.put("rank", player.getRank());
playerJSON.put("score", player.getTotalScore());
playerJSON.put("completions", player.getTotalCompletion());
playerJSON.put("completionsList", player.getJsonCompletions());
playerJSON.put("tries", player.getTotalTries());
if (player.getBadges() != null)
playerJSON.put("badges", player.getJsonBadges());
if (player.getAvatar() != null)
playerJSON.put("avatar", Base64.getEncoder().encodeToString(player.getAvatar()));
writer.response(200, "Access-Control-Allow-Origin: *");
writer.write(playerJSON.toJSONString().replace("\\", ""));
} else {
writer.response(400, "Access-Control-Allow-Origin: *");
}
}
}

View file

@ -1,72 +0,0 @@
package be.jeffcheasey88.peeratcode.routes;
import java.time.LocalDateTime;
import java.util.regex.Matcher;
import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Chapter;
import be.jeffcheasey88.peeratcode.model.Completion;
import be.jeffcheasey88.peeratcode.model.Puzzle;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class PuzzleElement implements Response {
private final DatabaseRepository databaseRepo;
public PuzzleElement(DatabaseRepository databaseRepo) {
this.databaseRepo = databaseRepo;
}
@RouteDoc(path = "/puzzle/<id>", responseCode = 200, responseDescription = "JSON contenant les informations du puzzle")
@RouteDoc(responseCode = 400, responseDescription = "puzzle introuvable dans la base de donnée")
@RouteDoc(responseCode = 423, responseDescription = "L'utilisateur essaye de voir le puzzle en dehors de l'event")
@Route(path = "^\\/puzzle\\/([0-9]+)$", needLogin = true)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
Puzzle puzzle = databaseRepo.getPuzzle(extractId(matcher));
if (puzzle != null){
Chapter chapter = this.databaseRepo.getChapter(puzzle);
if(chapter.getStartDate() != null){
if(LocalDateTime.now().isBefore(chapter.getStartDate().toLocalDateTime())){
writer.response(423, "Access-Control-Allow-Origin: *");
return;
}
}
// if(chapter.getEndDate() != null){
// if(LocalDateTime.now().isAfter(chapter.getEndDate().toLocalDateTime())){
// writer.response(423, "Access-Control-Allow-Origin: *");
// return;
// }
// }
JSONObject puzzleJSON = new JSONObject();
puzzleJSON.put("id", puzzle.getId());
puzzleJSON.put("name", puzzle.getName());
puzzleJSON.put("content", puzzle.getContent());
puzzleJSON.put("scoreMax", puzzle.getScoreMax());
if(puzzle.getTags() != null) puzzleJSON.put("tags", puzzle.getJsonTags());
Completion completion = this.databaseRepo.getCompletionGroup(user.getId(), puzzle.getId());
if(completion != null && completion.getScore() >= 0){
puzzleJSON.put("score", completion.getScore());
puzzleJSON.put("tries", completion.getTries());
}
if(puzzle.getDepend() > 0) puzzleJSON.put("depend", puzzle.getDepend());
writer.response(200, "Access-Control-Allow-Origin: *", "Content-Type: application/json");
writer.write(puzzleJSON.toJSONString());
}
else {
writer.response(400, "Access-Control-Allow-Origin: *");
}
}
private int extractId(Matcher matcher) {
return Integer.parseInt(matcher.group(1));
}
}

View file

@ -1,159 +0,0 @@
package be.jeffcheasey88.peeratcode.routes;
import static be.jeffcheasey88.peeratcode.framework.RequestType.POST;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Locker;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Chapter;
import be.jeffcheasey88.peeratcode.model.Completion;
import be.jeffcheasey88.peeratcode.model.Group;
import be.jeffcheasey88.peeratcode.model.Player;
import be.jeffcheasey88.peeratcode.model.Puzzle;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class PuzzleResponse implements Response {
private final DatabaseRepository databaseRepo;
private final String usersFilesPath;
private final Locker<Completion> leaderboard;
public PuzzleResponse(DatabaseRepository databaseRepo, String initUsersFilesPath, Locker<Completion> locker){
this.databaseRepo = databaseRepo;
usersFilesPath = initUsersFilesPath;
this.leaderboard = locker;
}
@RouteDoc(path = "/puzzleResponse/<id>", responseCode = 200, responseDescription = "Bonne réponse, json contenant les points + tries")
@RouteDoc(responseCode = 400, responseDescription = "Pas de réponse")
@RouteDoc(responseCode = 403, responseDescription = "Déjà répondu")
@RouteDoc(responseCode = 406, responseDescription = "Mauvaise réponse")
@RouteDoc(responseCode = 423, responseDescription = "L'utilisateur essaye de répondre en dehors de l'event")
@Route(path = "^\\/puzzleResponse\\/([0-9]+)$", type = POST, needLogin = true)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception{
ReceivedResponse received = new ReceivedResponse(matcher, reader);
if (received.getResponse() == null){
writer.response(400, "Access-Control-Allow-Origin: *");
return;
}
//saveSourceCode(received, databaseRepo.getPlayer(user.getId()));
JSONObject responseJSON = new JSONObject();
if(this.databaseRepo.getScore(user.getId(), received.getPuzzleId()) > 0){
writer.response(403, "Access-Control-Allow-Origin: *");
return;
}
Puzzle currentPuzzle = databaseRepo.getPuzzle(received.getPuzzleId());
Chapter chapter = this.databaseRepo.getChapter(currentPuzzle);
if(chapter.getStartDate() != null){
if(LocalDateTime.now().isBefore(chapter.getStartDate().toLocalDateTime())){
writer.response(423, "Access-Control-Allow-Origin: *");
return;
}
}
if(chapter.getEndDate() != null){
if(LocalDateTime.now().isAfter(chapter.getEndDate().toLocalDateTime())){
if(Arrays.equals(currentPuzzle.getSoluce(), received.getResponse())){
writer.response(200, "Access-Control-Allow-Origin: *", "Content-Type: application/json");
JSONObject theoSaisPasJusteRecevoir200 = new JSONObject();
theoSaisPasJusteRecevoir200.put("success", true);
writer.write(theoSaisPasJusteRecevoir200.toJSONString());
return;
}
writer.response(423, "Access-Control-Allow-Origin: *");
return;
}
Group group = this.databaseRepo.getPlayerGroup(user.getId(), chapter.getId());
if(group == null){
writer.response(423, "Access-Control-Allow-Origin: *");
return;
}
}
Completion completion = databaseRepo.insertOrUpdatePuzzleResponse(received.getPuzzleId(), user.getId(),
received.getFileName(), received.getSourceCode(), received.getResponse(), currentPuzzle);
if(completion == null){
writer.response(400, "Access-Control-Allow-Origin: *");
return;
}
if(completion.getScore() > 0){
writer.response(200, "Access-Control-Allow-Origin: *", "Content-Type: application/json");
responseJSON.put("score", completion.getScore());
responseJSON.put("tries", completion.getTries());
}else{
writer.response(406, "Access-Control-Allow-Origin: *", "Content-Type: application/json");
responseJSON.put("tries", completion.getTries());
}
writer.write(responseJSON.toJSONString());
writer.flush();
leaderboard.setValue(completion);
}
private void saveSourceCode(ReceivedResponse received, Player player){
try{
Path path = Paths.get(String.format("%s/%s/puz%04d-%s", usersFilesPath, player.getPseudo(),
received.getPuzzleId(), received.getFileName()));
Files.write(path, received.getSourceCode());
}catch (IOException e){
System.err.println("ERREUR D'ENREGISTREMENT DU CODE POUR PUZZLE_RESPONSE : " + e.toString());
}
}
}
class ReceivedResponse {
private int puzzleId;
private byte[] response;
private String fileName;
private byte[] sourceCode;
public ReceivedResponse(Matcher matcher, HttpReader reader) throws Exception {
puzzleId = Integer.parseInt(matcher.group(1));
List<String> multiPartData = reader.readMultiPartData();
if (multiPartData != null && multiPartData.size() > 0) {
this.response = multiPartData.get(0).getBytes();
if (multiPartData.size() == 3) {
this.fileName = multiPartData.get(1);
this.sourceCode = multiPartData.get(2).getBytes();
}
}
}
public int getPuzzleId() {
return puzzleId;
}
public byte[] getResponse() {
return response;
}
public String getFileName() {
return fileName;
}
public byte[] getSourceCode() {
return sourceCode;
}
}

View file

@ -1,91 +0,0 @@
package be.jeffcheasey88.peeratcode.routes;
import static be.jeffcheasey88.peeratcode.framework.RequestType.POST;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.Router;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class Register implements Response {
private DatabaseRepository databaseRepo;
private Router router;
private String usersFilesPath;
public Register(DatabaseRepository databaseRepo, Router router, String initUsersFilesPath) {
this.databaseRepo = databaseRepo;
this.router = router;
usersFilesPath = initUsersFilesPath;
}
@RouteDoc(path = "/register", responseCode = 200, responseDescription = "L'utilisateur est inscrit")
@RouteDoc(responseCode = 403, responseDescription = "L'utilisateur est connecté")
@RouteDoc(responseCode = 400, responseDescription = "Aucune données fournie / données invalide")
@Route(path = "^\\/register$", type = POST)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception{
if (user != null){
writer.response(403, "Access-Control-Allow-Origin: *");
return;
}
JSONObject informations = reader.readJson();
if (informations != null) {
boolean allFieldsFilled = informations.containsKey("pseudo") && informations.containsKey("email")
&& informations.containsKey("passwd") && informations.containsKey("firstname")
&& informations.containsKey("lastname") && informations.containsKey("description")
&& informations.containsKey("sgroup") && informations.containsKey("avatar");
if (!allFieldsFilled) {
writer.response(403, "Access-Control-Allow-Origin: *");
return;
}
String pseudo = (String) informations.get("pseudo");
String email = (String) informations.get("email");
String password = (String) informations.get("passwd");
String firstname = (String) informations.get("firstname");
String lastname = (String) informations.get("lastname");
String description = (String) informations.get("description");
String group = (String) informations.get("sgroup");
String avatar = (String) informations.get("avatar");
boolean pseudoAvailable = databaseRepo.checkPseudoAvailability(pseudo);
boolean emailAvailable = databaseRepo.checkEmailAvailability(email);
if (pseudoAvailable && emailAvailable) {
int id;
if ((id = databaseRepo.register(pseudo, email, password, firstname, lastname, description, group,
avatar)) >= 0) {
writer.response(200, "Access-Control-Allow-Origin: *",
"Access-Control-Expose-Headers: Authorization",
"Authorization: Bearer " + this.router.createAuthUser(id));
createFolderToSaveSourceCode(pseudo);
return;
}
} else {
writer.response(400, "Access-Control-Allow-Origin: *");
JSONObject error = new JSONObject();
error.put("username_valid", pseudoAvailable);
error.put("email_valid", emailAvailable);
writer.write(error.toJSONString());
return;
}
}
writer.response(400, "Access-Control-Allow-Origin: *");
}
private void createFolderToSaveSourceCode(String pseudo) throws IOException {
Files.createDirectories(Paths.get(String.format("%s/%s", usersFilesPath, pseudo)));
}
}

View file

@ -1,37 +0,0 @@
package be.jeffcheasey88.peeratcode.routes;
import java.util.regex.Matcher;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class Result implements Response {
private DatabaseRepository repo;
public Result(DatabaseRepository repo) {
this.repo = repo;
}
@RouteDoc(path = "/result/<id>", responseCode = 200, responseDescription = "Le score")
@RouteDoc(responseCode = 425, responseDescription = "Puzzle pas compléter")
@Route(path = "^\\/result\\/(\\d+)$", needLogin = true)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
int puzzle = Integer.parseInt(matcher.group(1));
int score = this.repo.getScore(user.getId(), puzzle);
if (score < 0) {
writer.response(425, "Access-Control-Allow-Origin: *");
} else {
writer.response(200, "Access-Control-Allow-Origin: *");
writer.write(score + "");
}
}
}

View file

@ -1,67 +0,0 @@
package be.jeffcheasey88.peeratcode.routes.groups;
import static be.jeffcheasey88.peeratcode.framework.RequestType.POST;
import java.time.LocalDateTime;
import java.util.regex.Matcher;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Locker;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Chapter;
import be.jeffcheasey88.peeratcode.model.Group;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class GroupCreate implements Response {
private Locker<Group> locker;
private DatabaseRepository repo;
private int groupDelay;
public GroupCreate(DatabaseRepository repo, Locker<Group> locker, int groupDelay){
this.repo = repo;
this.locker = locker;
this.groupDelay = groupDelay;
}
@RouteDoc(path = "/groupCreate", responseCode = 200, responseDescription = "Le groupe a été créé")
@RouteDoc(responseCode = 403, responseDescription = "L'utilisateur est déjà dans le groupe / ne peux pas le rejoindre")
@RouteDoc(responseCode = 423, responseDescription = "L'utilisateur essaye de crée un groupe après le délai maximum de création de l'event")
@Route(path = "^\\/groupCreate$", type = POST, needLogin = true)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception{
Group newGroup = new Group(reader.readJson());
if (this.repo.getPlayerGroup(user.getId(), newGroup.getLinkToChapter()) == null) {
try {
if(this.repo.getGroupId(newGroup) == null) throw new NullPointerException();
writer.response(403, "Access-Control-Allow-Origin: *");
return;
}catch(NullPointerException e){
if(newGroup.getLinkToChapter() != null){
Chapter chapter = this.repo.getChapter(newGroup.getLinkToChapter());
if(chapter.getStartDate() != null){
LocalDateTime start = chapter.getStartDate().toLocalDateTime().plusMinutes(this.groupDelay);
if(LocalDateTime.now().isAfter(start)){
writer.response(423, "Access-Control-Allow-Origin: *");
return;
}
}
}
if (this.repo.insertGroup(newGroup, user)) {
writer.response(200, "Access-Control-Allow-Origin: *");
locker.setValue(newGroup);
} else {
writer.response(403, "Access-Control-Allow-Origin: *");
}
}
}else {
writer.response(403, "Access-Control-Allow-Origin: *");
}
}
}

View file

@ -1,76 +0,0 @@
package be.jeffcheasey88.peeratcode.routes.groups;
import static be.jeffcheasey88.peeratcode.framework.RequestType.POST;
import java.time.LocalDateTime;
import java.util.regex.Matcher;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Locker;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Chapter;
import be.jeffcheasey88.peeratcode.model.Completion;
import be.jeffcheasey88.peeratcode.model.Group;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class GroupJoin implements Response{
private DatabaseRepository repo;
private int groupDelay;
private String waitTime;
private final Locker<Completion> leaderboard;
public GroupJoin(DatabaseRepository repo, int groupDelay, String waitTime, Locker<Completion> locker){
this.repo = repo;
this.groupDelay = groupDelay;
this.waitTime = waitTime;
this.leaderboard = locker;
}
@RouteDoc(path = "/groupJoin", responseCode = 200, responseDescription = "L'utilisateur a rejoint le groupe")
@RouteDoc(responseCode = 403, responseDescription = "L'utilisateur est déjà dedans / ne peux pas le rejoindre")
@RouteDoc(responseCode = 423, responseDescription = "L'utilisateur essaye de rejoindre un groupe après le délai maximum de création de l'event")
@RouteDoc(responseCode = 409, responseDescription = "L'utilisateur est un peu débile... ou pas ?")
@Route(path = "^\\/groupJoin$", type = POST, needLogin = true)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception{
Group group = new Group(reader.readJson());
Group userGroup = this.repo.getPlayerGroup(user.getId(), group.getLinkToChapter());
if(group.equals(userGroup)){
writer.response(403, "Access-Control-Allow-Origin: *");
return;
}
if(group.getLinkToChapter() == null){
writer.response(409, "Access-Control-Allow-Origin: *");
writer.write(waitTime);
return;
}
if(group.getLinkToChapter() != null){
Chapter chapter = this.repo.getChapter(group.getLinkToChapter());
if(chapter.getStartDate() != null){
LocalDateTime start = chapter.getStartDate().toLocalDateTime().plusMinutes(this.groupDelay);
if(LocalDateTime.now().isAfter(start)){
writer.response(423, "Access-Control-Allow-Origin: *");
return;
}
}
}
if (this.repo.insertUserInGroup(group, user)) {
writer.response(200, "Access-Control-Allow-Origin: *");
leaderboard.setValue(new Completion(0, 0, 0, null, 0));
} else {
writer.response(403, "Access-Control-Allow-Origin: *");
}
}
}

View file

@ -1,34 +0,0 @@
package be.jeffcheasey88.peeratcode.routes.groups;
import java.util.regex.Matcher;
import org.json.simple.JSONArray;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Group;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class GroupList implements Response {
private DatabaseRepository repo;
public GroupList(DatabaseRepository repo) {
this.repo = repo;
}
@RouteDoc(path = "/groups", responseCode = 200, responseDescription = "JSON avec la liste des groups")
@Route(path = "^\\/groups$", needLogin = true)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
writer.response(200, "Access-Control-Allow-Origin: *");
JSONArray result = new JSONArray();
for(Group group : this.repo.getAllGroups()) result.add(group.toJson());
writer.write(result.toJSONString());
}
}

View file

@ -1,68 +0,0 @@
package be.jeffcheasey88.peeratcode.routes.groups;
import static be.jeffcheasey88.peeratcode.framework.RequestType.POST;
import java.time.LocalDateTime;
import java.util.regex.Matcher;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Locker;
import be.jeffcheasey88.peeratcode.framework.Response;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Chapter;
import be.jeffcheasey88.peeratcode.model.Completion;
import be.jeffcheasey88.peeratcode.model.Group;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
public class GroupQuit implements Response{
private DatabaseRepository repo;
private int groupDelay;
private final Locker<Completion> leaderboard;
public GroupQuit(DatabaseRepository repo, int groupDelay, Locker<Completion> locker){
this.repo = repo;
this.groupDelay = groupDelay;
this.leaderboard = locker;
}
@RouteDoc(path = "/groupQuit", responseCode = 200, responseDescription = "L'utilisateur à quitter le groupe")
@RouteDoc(responseCode = 403, responseDescription = "L'utilisateur n'est pas dans le groupe / n'a pas pu le quittez")
@RouteDoc(responseCode = 423, responseDescription = "L'utilisateur essaye de quitter un groupe après le délai maximum de création de l'event")
@Route(path = "^\\/groupQuit$", type = POST, needLogin = true)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception{
Group group = new Group(reader.readJson());
Group userGroup = this.repo.getPlayerGroup(user.getId(), group.getLinkToChapter());
if(!group.equals(userGroup)){
writer.response(403, "Access-Control-Allow-Origin: *");
return;
}
if(group.getLinkToChapter() != null){
Chapter chapter = this.repo.getChapter(group.getLinkToChapter());
if(chapter.getStartDate() != null){
LocalDateTime start = chapter.getStartDate().toLocalDateTime().plusMinutes(this.groupDelay);
if(LocalDateTime.now().isAfter(start)){
writer.response(423, "Access-Control-Allow-Origin: *");
return;
}
}
}
if (this.repo.leaveGroup(group, user)) {
writer.response(200, "Access-Control-Allow-Origin: *");
leaderboard.setValue(new Completion(0, 0, 0, null, 0));
} else {
writer.response(403, "Access-Control-Allow-Origin: *");
}
}
}

View file

@ -1,4 +1,4 @@
package be.jeffcheasey88.peeratcode;
package dev.peerat.backend;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@ -7,8 +7,12 @@ import java.io.FileReader;
import java.io.FileWriter;
import java.lang.reflect.Field;
import dev.peerat.backend.utils.Mail;
public class Configuration {
private boolean prod;
private String db_host;
private int db_port;
private String db_user;
@ -29,28 +33,52 @@ public class Configuration {
private int groupJoinMinutes;
private String groupQuitMinutes;
private int groupMaxPlayers;
private File file;
private String mailUsername;
private String mailPassword;
private String mailSmtpHost;
private int mailSmtpPort;
private String mailFromAddress;
private String git_token;
private String jwt_key;
private String sql_folder;
private int event_chapter;
private File _file;
public Configuration(String path) {
this.file = new File(path);
System.out.println("Config on " + file.getAbsolutePath());
this._file = new File(path);
System.out.println("Config on " + _file.getAbsolutePath());
}
public void load() throws Exception {
if (!this.file.exists())
return;
BufferedReader reader = new BufferedReader(new FileReader(this.file));
public <T> Configuration addDefaultValue(String name, T value) throws Exception{
if(value == null) throw new IllegalArgumentException("Value cannot be null");
Field field = getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(this, value);
return this;
}
public Configuration load() throws Exception{
if(!this._file.exists()) return this;
BufferedReader reader = new BufferedReader(new FileReader(this._file));
String line;
while ((line = reader.readLine()) != null) {
String[] split = line.split("=");
Field field = getClass().getDeclaredField(split[0]);
if (field == null)
continue;
while((line = reader.readLine()) != null){
int index = line.indexOf('=');
String key = line.substring(0, index);
String value = line.substring(index+1);
Field field = getClass().getDeclaredField(key);
if(field == null) continue;
field.setAccessible(true);
injectValue(field, split[1]);
injectValue(field, value);
}
reader.close();
return this;
}
private void injectValue(Field field, String value) throws IllegalAccessException {
@ -93,72 +121,72 @@ public class Configuration {
}
public void save() throws Exception {
if (!file.exists()) {
File parent = file.getParentFile();
if (!parent.exists())
parent.mkdirs();
file.createNewFile();
if (!_file.exists()) {
File parent = _file.getParentFile();
if(!parent.exists()) parent.mkdirs();
_file.createNewFile();
}
Field[] fields = getClass().getDeclaredFields();
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
for (Field field : fields) {
BufferedWriter writer = new BufferedWriter(new FileWriter(_file));
for(Field field : fields){
field.setAccessible(true);
if (field.getName().startsWith("_"))
continue;
if(field.getName().startsWith("_")) continue;
Object value = field.get(this);
writer.write(field.getName() + "=" + value);
writer.write(field.getName() + "=" + value+"\n");
}
writer.flush();
writer.close();
}
public String getDbHost() {
public boolean isProduction(){
return this.prod;
}
public String getDbHost(){
return this.db_host;
}
public int getDbPort() {
public int getDbPort(){
return this.db_port;
}
public String getDbUser() {
public String getDbUser(){
return this.db_user;
}
public String getDbDatabase() {
public String getDbDatabase(){
return this.db_database;
}
public String getDbPassword() {
public String getDbPassword(){
return this.db_password;
}
public String getSslKeystore() {
public String getSslKeystore(){
return this.ssl_keystore;
}
public String getTokenIssuer() {
public String getTokenIssuer(){
return this.token_issuer;
}
public int getTokenExpiration() {
public int getTokenExpiration(){
return this.token_expiration;
}
public String getSslKeystorePasswd() {
public String getSslKeystorePasswd(){
return this.ssl_keystorePasswd;
}
public int getTcpPort() {
public int getTcpPort(){
return this.tcp_port;
}
public boolean useSsl() {
public boolean useSsl(){
return this.use_ssl;
}
public String getUsersFiles() {
if (users_files == null || users_files.trim().isEmpty())
users_files = "/tmp/users_files";
public String getUsersFiles(){
return users_files;
}
@ -173,4 +201,37 @@ public class Configuration {
public String getGroupQuitMinutes(){
return this.groupQuitMinutes;
}
public int getGroupMaxPlayers(){
return this.groupMaxPlayers;
}
public Mail getMail(){
return new Mail(
this.mailUsername,
this.mailPassword,
this.mailSmtpHost,
this.mailSmtpPort,
this.mailFromAddress);
}
public String getGitToken(){
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

@ -0,0 +1,184 @@
package dev.peerat.backend;
import static dev.peerat.framework.RequestType.OPTIONS;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteExtracter;
import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.ConnectionManager;
import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Context;
import dev.peerat.framework.DependencyInjector;
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.RequestType;
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;
public class Main{
private static Router<PeerAtUser> ACCESS_ROUTER;
public static void main(String[] args) throws Exception{
Configuration config = new Configuration("config.txt").addDefaultValue("users_files", "/tmp/users_files");
config.load();
Class.forName("com.mysql.cj.jdbc.Driver");
DatabaseRepository repo = new DatabaseRepository(new ConnectionManager(config), config);
Router<PeerAtUser> router = new Router<PeerAtUser>()
.activeReOrdering().
addDefaultHeaders(RequestType.GET, "Access-Control-Allow-Origin: *").
addDefaultHeaders(RequestType.POST, "Access-Control-Allow-Origin: *").
addDefaultHeaders(RequestType.OPTIONS,
"Access-Control-Allow-Origin: *",
"Access-Control-Allow-Methods: *",
"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) -> {
context.response(404);
writer.write("404 not Found.\n");
});
router.register(new Response(){
@Route(path = "^(.*)$", type = OPTIONS)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception {
context.response(200);
}
});
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(){
public void run(){
Key key = new Key();
Locker<Context> locker = router.getLogger();
locker.init(key);
try {
while(true){
locker.lock(key);
Context instance = locker.getValue(key);
if(instance == null) continue;
System.out.println("["+((instance.isLogged()) ? repo.getPlayerRepository().getPlayer(instance.<PeerAtUser>getUser().getId()).getPseudo() : "?")+"] "+instance.getType()+" "+instance.getPath()+" -> "+instance.getResponseCode());
}
}catch(Exception e){
e.printStackTrace();
}
locker.remove(key);
}
}).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());
router.listen(config.getTcpPort(), config.useSsl());
}
private static void initRoutes(Router<PeerAtUser> router, DatabaseRepository repo, Configuration config) throws Exception{
Predicate<PeerAtUser> isAdmin = (user) -> {
try {
Group group = repo.getGroupRepository().getPlayerGroup(user.getId(), 1);
return group.getName().equalsIgnoreCase("Quarter-Master - Battles PAC x CEI");
}catch(Exception ex){}
return false;
};
router.registerPackages("dev.peerat.backend.routes",new DependencyInjector()
.of(repo, router, config, new RouteExtracter(router), config.getMail(), isAdmin)
.of("waitting", new HashMap<>())
.of("leaderboard", new Locker<>())
.of("groups", new Locker<>())
.of("groupMessages", new Locker<>()));
// Bot bot = new Bot(config, repo, groupLock);
// bot.start();
}
}

View file

@ -1,12 +1,12 @@
package be.jeffcheasey88.peeratcode.bonus.discord;
package dev.peerat.backend.bonus.discord;
import java.util.List;
import be.jeffcheasey88.peeratcode.Configuration;
import be.jeffcheasey88.peeratcode.framework.Locker;
import be.jeffcheasey88.peeratcode.framework.Locker.Key;
import be.jeffcheasey88.peeratcode.model.Group;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
import dev.peerat.backend.Configuration;
import dev.peerat.backend.model.Group;
import dev.peerat.backend.repository.DatabaseRepository;
import dev.peerat.framework.Locker;
import dev.peerat.framework.Locker.Key;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.entities.Guild;
@ -38,7 +38,7 @@ public class Bot extends Thread{
locker.init(key);
List<Group> groups = this.repo.getAllGroups();
List<Group> groups = this.repo.getGroupRepository().getAllGroups();
for(Group group : groups){
Integer chapter = group.getLinkToChapter();
// Integer puzzle = group.getLinkToPuzzle();

View file

@ -1,4 +1,4 @@
package be.jeffcheasey88.peeratcode.bonus.extract;
package dev.peerat.backend.bonus.extract;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;

View file

@ -1,4 +1,4 @@
package be.jeffcheasey88.peeratcode.bonus.extract;
package dev.peerat.backend.bonus.extract;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View file

@ -0,0 +1,131 @@
package dev.peerat.backend.bonus.extract;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.framework.RequestType;
import dev.peerat.framework.Response;
import dev.peerat.framework.Route;
import dev.peerat.framework.RouteMapper;
import dev.peerat.framework.Router;
import dev.peerat.framework.utils.json.JsonArray;
import dev.peerat.framework.utils.json.JsonMap;
public class RouteExtracter {
private Router<PeerAtUser> router;
public RouteExtracter(Router<PeerAtUser> router){
this.router = router;
}
public void extract() throws Exception{
RouteMapper[] mappers = getField(Router.class, router, "mappers");
for(RequestType type : RequestType.values()){
RouteMapper mapper = mappers[type.ordinal()];
Response[] responses = getField(RouteMapper.class, mapper, "responses");
Route[] routes = getField(RouteMapper.class, mapper, "routes");
synchronized (responses){
for(int i = 0; i < responses.length; i++){
Route route = routes[i];
System.out.println("["+type+"] ("+route.needLogin()+") "+route.path());
}
}
}
}
public void extractDoc() throws Exception{
RouteMapper[] mappers = getField(Router.class, router, "mappers");
for(RequestType type : RequestType.values()){
RouteMapper mapper = mappers[type.ordinal()];
Response[] responses = getField(RouteMapper.class, mapper, "responses");
synchronized (responses){
for(int i = 0; i < responses.length; i++){
Response response = responses[i];
Method method = response.getClass().getDeclaredMethod("exec",
Response.class.getDeclaredMethods()[0].getParameterTypes());
for(RouteDoc doc : method.getDeclaredAnnotationsByType(RouteDoc.class)){
System.out.println(doc.path()+((doc.path().isEmpty() ? "":"\n"))+" ["+doc.responseCode()+"] "+doc.responseDescription());
}
}
}
}
}
public JsonMap swagger(String host) throws Exception{
JsonMap result = new JsonMap();
result.set("swagger","2.0");
JsonMap info = new JsonMap();
info.set("title", "Peer-at-code backend api routes");
info.set("description", "Using Peer-at Code Framework");
result.set("info", info);
result.set("host", host);
result.set("basePath","/");
List<Response> routes = new ArrayList<>();
RouteMapper[] mappers = getField(Router.class, router, "mappers");
for(RequestType type : RequestType.values()){
RouteMapper mapper = mappers[type.ordinal()];
Response[] responses = getField(RouteMapper.class, mapper, "responses");
synchronized (responses){
routes.addAll(Arrays.asList(responses));
}
}
Set<String> packages = new HashSet<>();
for(Response response : routes){
String name = response.getClass().getPackage().getName();
name = name.substring(name.lastIndexOf('.')+1, name.length());
packages.add(name);
}
JsonArray tags = new JsonArray();
for(String tag : packages){
JsonMap current = new JsonMap();
current.set("name", tag);
tags.add(current);
}
result.set("tags", tags);
JsonArray schemes = new JsonArray();
schemes.add("https");
result.set("schemes", schemes);
JsonMap paths = new JsonMap();
for(Response response : routes){
Method method = response.getClass().getDeclaredMethod("exec",
Response.class.getDeclaredMethods()[0].getParameterTypes());
Route route = method.getDeclaredAnnotation(Route.class);
RouteDoc[] docs = method.getDeclaredAnnotationsByType(RouteDoc.class);
if(docs.length < 1) continue;
RouteDoc base = docs[0];
JsonMap current = new JsonMap();
JsonMap data = new JsonMap();
JsonArray tag = new JsonArray();
String pack = response.getClass().getPackage().getName();
pack = pack.substring(pack.lastIndexOf('.')+1, pack.length());
tag.add(pack);
data.set("tags", tag);
current.set(route.type().toString().toLowerCase(), data);
paths.set(base.path(), current);
}
result.set("paths", paths);
return result;
}
private <E> E getField(Class<?> clazz, Object instance, String name) throws Exception{
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return (E) field.get(instance);
}
}

View file

@ -1,8 +1,5 @@
package be.jeffcheasey88.peeratcode.model;
package dev.peerat.backend.model;
import be.jeffcheasey88.peeratcode.mapping.Treasure;
@Treasure
public class Badge {
private String name;

View file

@ -1,6 +1,7 @@
package be.jeffcheasey88.peeratcode.model;
package dev.peerat.backend.model;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.List;
public class Chapter {
@ -34,6 +35,13 @@ public class Chapter {
this.puzzles = puzzles;
}
public boolean hasStarted(){
LocalDateTime now = LocalDateTime.now();
boolean show = true;
if(startDate != null) show &= now.isAfter(startDate.toLocalDateTime());
return show;
}
public Timestamp getStartDate() {
return startDate;
}

View file

@ -1,4 +1,4 @@
package be.jeffcheasey88.peeratcode.model;
package dev.peerat.backend.model;
import java.util.Arrays;
@ -11,7 +11,7 @@ public class Completion{
private int score;
private String puzzleName;
public Completion(int playerId, int puzzleId, int tries, String fileName, int score) {
public Completion(int playerId, int puzzleId, int tries, String fileName, int score){
this(playerId, puzzleId, tries, score, fileName, null, null, null, null);
}
public Completion(int playerId, int puzzleId, int tries, String fileName, int score, String puzzleName) {
@ -22,13 +22,13 @@ public class Completion{
this(playerId, puzzleId, 0, 0, fileName, file, response, currentPuzzle, null);
}
public Completion(int initTries, int initScore) {
public Completion(int initTries, int initScore){
// For group leaderboard
this(-1, -1, initTries, initScore, null, null, null, null, null);
}
public Completion(int playerId, int puzzleId, int tries, int score, String fileName, byte[] file, byte[] response,
Puzzle currentPuzzle, String initPuzzleName) {
Puzzle currentPuzzle, String initPuzzleName){
this.playerId = playerId;
this.puzzleId = puzzleId;
this.fileName = fileName;
@ -40,7 +40,7 @@ public class Completion{
this.score = score;
if (currentPuzzle != null)
addTry(currentPuzzle, response);
addTry(currentPuzzle, response, 0);
puzzleName = initPuzzleName;
}
@ -62,12 +62,17 @@ public class Completion{
return tries;
}
public void addTry(Puzzle currentPuzzle, byte[] response) {
public void addTry(Puzzle currentPuzzle, byte[] response, int chapter){
if (score <= 0){
tries++;
if (response != null && Arrays.equals(currentPuzzle.getSoluce(), response)) {
if (response != null && Arrays.equals(currentPuzzle.getSoluce(), response)){
if (tries > 1) { // Loose 5% each try with a minimum of 1 for score
score = (int) Math.ceil(currentPuzzle.getScoreMax() * (1 - ((tries - 1) / 20.)));
if(chapter < 4){
score = currentPuzzle.getScoreMax();
}else{
score = (int) Math.ceil(currentPuzzle.getScoreMax() * (1 - ((tries - 1) / 20.)));
}
// score = currentPuzzle.getScoreMax();
if (score < 1)
score = 1;
} else

View file

@ -1,35 +1,49 @@
package be.jeffcheasey88.peeratcode.model;
package dev.peerat.backend.model;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.jose4j.json.internal.json_simple.JSONArray;
import org.jose4j.json.internal.json_simple.JSONObject;
import be.jeffcheasey88.peeratcode.mapping.SeaBottle;
import dev.peerat.framework.utils.json.JsonMap;
public class Group implements Comparable<Group> {
private String name;
private Integer linkToChapter;
// private Integer linkToPuzzle;
private List<Player> players;
private int playerCount;
@Override
public String toString(){
return "Group[name="+name+", chapter="+linkToChapter+"]";
}
public Group(JSONObject json) {
public Group(JsonMap json){
this.name = (String) json.get("name");
if (json.containsKey("chapter"))
if (json.has("chapter"))
this.linkToChapter = ((Number) json.get("chapter")).intValue();
// if (json.containsKey("puzzle"))
// if (json.has("puzzle"))
// 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.linkToChapter = initChap;
// this.linkToPuzzle = initPuzz;
this.playerCount = playerCount;
}
public int getPlayerCount(){
return this.playerCount;
}
@SeaBottle
public static Group getGroup(int player){
return null;
}
public void addPlayer(Player newPlayer) {
@ -105,6 +119,7 @@ public class Group implements Comparable<Group> {
}
groupJSON.put("players", groupsPlayerJSON);
}
groupJSON.put("playerCount", this.playerCount);
return groupJSON;
}
@ -124,7 +139,7 @@ public class Group implements Comparable<Group> {
}
@Override
public int hashCode() {
public int hashCode(){
return Objects.hash(name);
}

View file

@ -0,0 +1,28 @@
package dev.peerat.backend.model;
import org.jose4j.jwt.JwtClaims;
public class PeerAtUser extends dev.peerat.framework.User{
private int id;
public PeerAtUser(int id){
this.id = id;
}
public PeerAtUser(JwtClaims claims){
this.id = ((Long) claims.getClaimValue("id")).intValue();
}
@Override
public void write(JwtClaims claims){
claims.setClaim("id", this.id);
}
public int getId(){
return this.id;
}
}

View file

@ -1,12 +1,12 @@
package be.jeffcheasey88.peeratcode.model;
package dev.peerat.backend.model;
import java.util.Base64;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import dev.peerat.framework.utils.json.JsonArray;
import dev.peerat.framework.utils.json.JsonMap;
public class Player implements Comparable<Player> {
private String pseudo;
@ -22,12 +22,12 @@ public class Player implements Comparable<Player> {
private Set<Badge> badges;
public Player(String pseudo, String email, String firstname, String lastname, String description) {
public Player(String pseudo, String email, String firstname, String lastname) {
this.pseudo = pseudo;
this.email = email;
this.firstname = firstname;
this.lastname = lastname;
this.description = description;
this.description = "";
}
public Player(String pseudo, int score, int tries) {
@ -37,6 +37,15 @@ public class Player implements Comparable<Player> {
email = ""; // TO make compareTo and equals works as usual
}
public Player(String email) {
// For player find in Map during register process
this.email = email;
}
public void setPseudo(String pseudo){
this.pseudo = pseudo;
}
public String getPseudo() {
return this.pseudo;
}
@ -61,9 +70,9 @@ public class Player implements Comparable<Player> {
return groups;
}
public JSONArray getJsonGroups() {
public JsonArray getJsonGroups() {
if (groups != null) {
JSONArray groupsJSON = new JSONArray();
JsonArray groupsJSON = new JsonArray();
for (Group group : groups) {
groupsJSON.add(group.toJson());
}
@ -112,13 +121,13 @@ public class Player implements Comparable<Player> {
return completions.size();
}
public JSONArray getJsonCompletions() {
JSONArray completionsJSON = new JSONArray();
public JsonArray getJsonCompletions() {
JsonArray completionsJSON = new JsonArray();
for (Completion completion : completions) {
JSONObject completionJSON = new JSONObject();
completionJSON.put("puzzleName", completion.getPuzzleName());
completionJSON.put("tries", completion.getTries());
completionJSON.put("score", completion.getScore());
JsonMap completionJSON = new JsonMap();
completionJSON.set("puzzleName", completion.getPuzzleName());
completionJSON.set("tries", completion.getTries());
completionJSON.set("score", completion.getScore());
completionsJSON.add(completionJSON);
}
return completionsJSON;
@ -136,17 +145,17 @@ public class Player implements Comparable<Player> {
return badges;
}
public JSONArray getJsonBadges() {
public JsonArray getJsonBadges() {
if (badges == null)
return null;
JSONArray badgesJSON = new JSONArray();
JsonArray badgesJSON = new JsonArray();
for (Badge badge : badges) {
JSONObject badgeJSON = new JSONObject();
badgeJSON.put("name", badge.getName());
JsonMap badgeJSON = new JsonMap();
badgeJSON.set("name", badge.getName());
byte[] logo = badge.getLogo();
if (logo != null)
badgeJSON.put("logo", Base64.getEncoder().encodeToString(logo));
badgeJSON.put("level", badge.getLevel());
badgeJSON.set("logo", Base64.getEncoder().encodeToString(logo));
badgeJSON.set("level", badge.getLevel());
badgesJSON.add(badgeJSON);
}
return badgesJSON;
@ -180,7 +189,7 @@ public class Player implements Comparable<Player> {
}
@Override
public int hashCode() {
public int hashCode(){
return Objects.hash(email, pseudo);
}

View file

@ -1,11 +1,13 @@
package be.jeffcheasey88.peeratcode.model;
package dev.peerat.backend.model;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import dev.peerat.framework.utils.json.JsonArray;
import dev.peerat.framework.utils.json.JsonMap;
public class Puzzle {
@ -17,9 +19,10 @@ public class Puzzle {
private int scoreMax;
private Set<String> tags;
private int depend;
private Timestamp startDate;
public Puzzle(int id, String name, String content, byte[] soluce, String verify, int scoreMax, String tags,
int depend) {
int depend, Timestamp startDate) {
this.id = id;
this.name = name;
this.content = content;
@ -28,6 +31,7 @@ public class Puzzle {
this.scoreMax = scoreMax;
setTags(tags);
this.depend = depend;
this.startDate = startDate;
}
public int getId() {
@ -59,13 +63,13 @@ public class Puzzle {
*
* @return DEATH
*/
public JSONArray getJsonTags() {
public JsonArray getJsonTags() {
if (tags == null)
return null;
JSONArray tagsJSON = new JSONArray();
JsonArray tagsJSON = new JsonArray();
for (String tag : tags) {
JSONObject tagJSON = new JSONObject();
tagJSON.put("name", tag);
JsonMap tagJSON = new JsonMap();
tagJSON.set("name", tag);
tagsJSON.add(tagJSON);
}
return tagsJSON;
@ -82,6 +86,13 @@ public class Puzzle {
return this.depend;
}
public boolean hasStarted(){
LocalDateTime now = LocalDateTime.now();
boolean show = true;
if(startDate != null) show &= now.isAfter(startDate.toLocalDateTime());
return show;
}
@Override
public boolean equals(Object object) {
if (this == object)

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

@ -0,0 +1,181 @@
package dev.peerat.backend.repository;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public enum DatabaseQuery {
//TRIGGER
FIRST_TRY("CREATE OR REPLACE TRIGGER FirstTry\r\n"
+ "AFTER INSERT\r\n"
+ " ON completions FOR EACH ROW\r\n"
+ "BEGIN\r\n"
+ " DECLARE badge INT;\r\n"
+ " DECLARE contain INT;\r\n"
+ " \r\n"
+ " SELECT id_badge\r\n"
+ " INTO @badge\r\n"
+ " FROM badges\r\n"
+ " WHERE name = 'FirstTry';\r\n"
+ " \r\n"
+ " IF @badge is not null THEN\r\n"
+ " \r\n"
+ " SELECT count(*)\r\n"
+ " INTO @contain\r\n"
+ " FROM containsBadges\r\n"
+ " WHERE fk_badge = @badge AND fk_player = NEW.fk_player;\r\n"
+ " \r\n"
+ " IF (@contain = 0) THEN\r\n"
+ " INSERT INTO containsBadges(fk_player, fk_badge) VALUES (NEW.fk_player, @badge);\r\n"
+ " END IF;\r\n"
+ " END IF;\r\n"
+ "END;"),
EventParticipation("CREATE OR REPLACE TRIGGER EventParticipation\r\n"
+ "AFTER INSERT\r\n"
+ " ON completions FOR EACH ROW\r\n"
+ "BEGIN\r\n"
+ " DECLARE badge INT;\r\n"
+ " DECLARE endDate datetime;\r\n"
+ " DECLARE player INT;\r\n"
+ " DECLARE contain INT;\r\n"
+ "\r\n"
+ " SELECT id_badge\r\n"
+ " INTO badge\r\n"
+ " FROM badges\r\n"
+ " WHERE name = 'EventParticipation';\r\n"
+ "\r\n"
+ " IF @badge is not null THEN\r\n"
+ "\r\n"
+ " SELECT c.end_date, i.fk_player\r\n"
+ " INTO endDate, player\r\n"
+ " FROM inserted i\r\n"
+ " JOIN puzzles p ON i.fk_puzzle = p.id_puzzle\r\n"
+ " JOIN chapters c on p.fk_chapter = c.id_chapter;\r\n"
+ "\r\n"
+ " IF @endDate is not null THEN\r\n"
+ "\r\n"
+ " SELECT count(*)\r\n"
+ " INTO contain\r\n"
+ " FROM containsBadges\r\n"
+ " WHERE fk_badge = badge AND fk_player = player;\r\n"
+ "\r\n"
+ " IF (@contain = 0) THEN\r\n"
+ " INSERT INTO containsBadges(fk_player, fk_badge) VALUES (@player, @badge);\r\n"
+ " END IF;\r\n"
+ " END IF;\r\n"
+ " END IF;\r\n"
+ "END;");
private String request;
DatabaseQuery(DatabaseQuery parent, String request) {
this.request = parent.request + request;
}
DatabaseQuery(String request) {
this.request = request;
}
public PreparedStatement prepare(Connection con) throws SQLException {
return con.prepareStatement(this.request);
}
@Override
public String toString() {
return this.request;
}
}
/*
*
SELECT p.*, scores.score, scores.completions, scores.tries, scores.rank, 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 GROUP BY c.fk_player)
AS scores
LEFT OUTER JOIN containsGroups cg ON scores.fk_player = cg.fk_player
LEFT OUTER JOIN groups g ON cg.fk_group = g.id_group
WHERE p.id_player = scores.fk_player AND "),
*
*/
/* TRIGGER PLACE
*
CREATE OR REPLACE TRIGGER FirstTry
AFTER INSERT
ON completions FOR EACH ROW
BEGIN
DECLARE badge INT;
DECLARE contain INT;
SELECT id_badge
INTO @badge
FROM badges
WHERE name = 'FirstTry';
IF @badge is not null THEN
SELECT count(*)
INTO @contain
FROM containsBadges
WHERE fk_badge = @badge AND fk_player = NEW.fk_player;
IF (@contain = 0) THEN
IF (NEW.score >= 0 AND NEW.tries < 2) THEN
INSERT INTO containsBadges(fk_player, fk_badge) VALUES (NEW.fk_player, @badge);
END IF;
END IF;
END IF;
END;
CREATE OR REPLACE TRIGGER EventParticipation
AFTER INSERT
ON completions FOR EACH ROW
BEGIN
DECLARE badge INT;
DECLARE endDate datetime;
DECLARE player INT;
DECLARE contain INT;
SELECT id_badge
INTO badge
FROM badges
WHERE name = 'EventParticipation';
IF @badge is not null THEN
SELECT c.end_date, i.fk_player
INTO endDate, player
FROM inserted i
JOIN puzzles p ON i.fk_puzzle = p.id_puzzle
JOIN chapters c on p.fk_chapter = c.id_chapter;
IF @endDate is not null THEN
SELECT count(*)
INTO contain
FROM containsBadges
WHERE fk_badge = badge AND fk_player = player;
IF (@contain = 0) THEN
INSERT INTO containsBadges(fk_player, fk_badge) VALUES (@player, @badge);
END IF;
END IF;
END IF;
END;
*
*/

View file

@ -0,0 +1,239 @@
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.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import dev.peerat.backend.Configuration;
public class DatabaseRepository extends BaseDatabaseQuery{
private Connection con; //refractor chain
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(ConnectionManager con, Configuration config) throws Exception {
super(con);
this.config = config;
this.puzzleRepo = new DatabasePuzzleRepository(con, config);
this.chapterRepo = new DatabaseChapterRepository(con, config, puzzleRepo);
this.adminRepo = new DatabaseAdminRepository(con, config);
this.authRepo = new DatabaseAuthRepository(con, config);
this.badgeRepo = new DatabaseBadgeRepository(con, config);
this.completionRepo = new DatabaseCompletionRepository(con, config, chapterRepo);
this.groupRepo = new DatabaseGroupRepository(con, config);
this.leaderboardRepo = new DatabaseLeaderboardRepository(con, config);
this.playerRepo = new DatabasePlayerRepository(con, config);
loadConfig(config);
}
private void loadConfig(Configuration config) throws Exception{
String name = DatabaseRepository.class.getPackage().getName();
InputStream stream = ClassLoader.getSystemClassLoader().getResourceAsStream(name.replace(".", "/"));
File folder = new File(config.getSqlFolder());
try{
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
String line;
while((line = reader.readLine()) != null){
if(line.endsWith(".class")){
Class<?> clazz = Class.forName(name+"."+line.substring(0, line.length()-6));
if(BaseDatabaseQuery.class.isAssignableFrom(clazz)){
for(Class<?> subClazz : clazz.getDeclaredClasses()){
if(subClazz.isEnum()){
configure(subClazz, folder);
}
}
}
continue;
}
}
reader.close();
}catch(Exception e){
System.err.println("Failed to read "+name);
e.printStackTrace();
}
new Thread(() -> {
try{
WatchService watchService = FileSystems.getDefault().newWatchService();
Path path = folder.toPath();
path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
while (true) {
WatchKey key = watchService.take();
for(WatchEvent<?> event : key.pollEvents()){
Path edited = (Path) event.context();
String targetClazz = edited.toFile().getName().split("\\.")[0];
Class<?> clazz = Class.forName(name+"."+targetClazz);
if(BaseDatabaseQuery.class.isAssignableFrom(clazz)){
for(Class<?> subClazz : clazz.getDeclaredClasses()){
if(subClazz.isEnum()){
bind(subClazz, new File(folder, edited.toFile().getName()));
}
}
}
}
key.reset();
}
}catch(Exception ex){
ex.printStackTrace();
}
}).start();
}
private void configure(Class<?> clazz, File folder) throws Exception{
String name = clazz.getName().split("\\$")[0];
String[] split = name.split("\\.");
File file = new File(folder, split[split.length-1]+".txt");
if(file.exists()){
bind(clazz, file);
}else{
File parent = file.getParentFile();
if(!parent.exists()) parent.mkdirs();
file.createNewFile();
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
for(Object obj : clazz.getEnumConstants()){
Enum instance = (Enum) obj;
writer.write(instance.name()+"="+instance.toString().replace("\n", " ").replace("\r", " ")+"\n");
}
writer.flush();
writer.close();
}
}
private void bind(Class<?> clazz, File file) throws Exception{
Map<String, String> map = new HashMap<>();
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine()) != null){
int index = line.indexOf('=');
String key = line.substring(0, index);
String value = line.substring(index+1);
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 DatabasePuzzleRepository getPuzzleRepository(){
return this.puzzleRepo;
}
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();
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;");
ResultSet results = stmt.executeQuery();
List<Completionz> list = new ArrayList<>();
while(results.next()){
Completionz complete = new Completionz(results);
list.add(complete);
}
Map<Integer, Map<Integer, Completionz>> map = new HashMap<>();
for(Completionz comp : list){
Map<Integer,Completionz> puz = map.get(comp.puzzle);
if(puz == null){
puz = new HashMap<>();
map.put(comp.puzzle, puz);
}
Completionz c = puz.get(comp.groups);
if(c == null){
puz.put(comp.groups, comp);
}else{
if(comp.score >= c.score){
puz.put(comp.groups, comp);
System.out.println("remove compl "+c.id);
}
}
}
}
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);
}
}
}

View file

@ -0,0 +1,46 @@
package dev.peerat.backend.routes;
import java.util.Base64;
import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Badge;
import dev.peerat.backend.repository.DatabaseBadgeRepository;
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 BadgeDetails implements Response {
private final DatabaseBadgeRepository databaseRepo;
public BadgeDetails(DatabaseRepository databaseRepo) {
this.databaseRepo = databaseRepo.getBadgeRepository();
}
@RouteDoc(path = "/badge/<id>", responseCode = 200, responseDescription = "JSON contenant les informations du badge")
@RouteDoc(responseCode = 400, responseDescription = "Aucun id donner")
@Route(path = "^\\/badge\\/([0-9]+)$", needLogin = true)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception {
if (matcher.groupCount() > 0) {
int badgeId = Integer.parseInt(matcher.group(1));
Badge badge = databaseRepo.getBadge(badgeId);
JsonMap badgeJSON = new JsonMap();
if(badge != null){
badgeJSON.set("name", badge.getName());
if(badge.getLogo() != null) badgeJSON.set("logo", Base64.getEncoder().encodeToString(badge.getLogo()));
badgeJSON.set("level", badge.getLevel());
}
context.response(200);
writer.write(badgeJSON.toString().replace("\\", ""));
} else {
context.response(400);
}
}
}

View file

@ -0,0 +1,68 @@
package dev.peerat.backend.routes;
import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.model.PeerAtUser;
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.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 ChapterElement implements Response {
private final DatabaseChapterRepository chapterRepo;
private final DatabaseCompletionRepository completionRepo;
public ChapterElement(DatabaseRepository repo) {
this.chapterRepo = repo.getChapterRepository();
this.completionRepo = repo.getCompletionRepository();
}
@RouteDoc(path = "/chapter/<id>", responseCode = 200, responseDescription = "JSON contenant les informations du chapitre demander")
@RouteDoc(responseCode = 400, responseDescription = "Aucun id donner")
@Route(path = "^\\/chapter\\/([0-9]+)$", needLogin = true)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
Chapter chapter = chapterRepo.getChapter(Integer.parseInt(matcher.group(1)));
if (chapter != null){
JsonMap chapterJSON = new JsonMap();
chapterJSON.set("id", chapter.getId());
chapterJSON.set("name", chapter.getName());
boolean show = chapter.hasStarted();
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();
if(show){
JsonArray puzzles = new JsonArray();
for (Puzzle puzzle : chapter.getPuzzles()){
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());
int score = this.completionRepo.getScore(user.getId(), puzzle.getId());
if(score >= 0) puzzleJSON.set("score", score);
puzzleJSON.set("show", puzzle.hasStarted());
puzzles.add(puzzleJSON);
}
chapterJSON.set("puzzles", puzzles);
}
context.response(200);
writer.write(chapterJSON.toString());
} else {
context.response(400);
}
}
}

View file

@ -0,0 +1,50 @@
package dev.peerat.backend.routes;
import java.util.List;
import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.repository.DatabaseChapterRepository;
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 ChapterList implements Response {
private final DatabaseChapterRepository databaseRepo;
public ChapterList(DatabaseRepository databaseRepo) {
this.databaseRepo = databaseRepo.getChapterRepository();
}
@RouteDoc(path = "/chapters", responseCode = 200, responseDescription = "JSON contenant les informations des chapitres")
@RouteDoc(responseCode = 400, responseDescription = "Aucun chapitre trouver")
@Route(path = "^\\/chapters$", needLogin = true)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception {
List<Chapter> allChapters = databaseRepo.getAllChapters();
if (allChapters != null) {
JsonArray chaptersJSON = new JsonArray();
for (Chapter chapter : allChapters) {
JsonMap chapterJSON = new JsonMap();
chapterJSON.set("id", chapter.getId());
chapterJSON.set("name", chapter.getName());
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);
}
context.response(200);
writer.write(chaptersJSON.toString());
} else {
context.response(400);
}
}
}

View file

@ -1,24 +1,25 @@
package be.jeffcheasey88.peeratcode.routes;
package dev.peerat.backend.routes;
import java.util.regex.Matcher;
import be.jeffcheasey88.peeratcode.bonus.extract.RouteDoc;
import be.jeffcheasey88.peeratcode.framework.HttpReader;
import be.jeffcheasey88.peeratcode.framework.HttpWriter;
import be.jeffcheasey88.peeratcode.framework.Locker;
import be.jeffcheasey88.peeratcode.framework.Locker.Key;
import be.jeffcheasey88.peeratcode.framework.Route;
import be.jeffcheasey88.peeratcode.framework.User;
import be.jeffcheasey88.peeratcode.model.Completion;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Completion;
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.Route;
public class DynamicLeaderboard extends Leaderboard{
private Locker<Completion> locker;
public DynamicLeaderboard(DatabaseRepository databaseRepo){
public DynamicLeaderboard(DatabaseRepository databaseRepo, @Injection("leaderboard") Locker<Completion> locker){
super(databaseRepo);
this.locker = new Locker<>();
this.locker = locker;
}
public Locker<Completion> getLocker(){
@ -28,7 +29,7 @@ public class DynamicLeaderboard extends Leaderboard{
@RouteDoc(path = "/rleaderboard/{id}", responseCode = 101, responseDescription = "WebSocket")
@Route(path = "^\\/rleaderboard\\/?(\\d+)?$", websocket = true)
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception{
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
Key key = new Key();
locker.init(key);

View file

@ -0,0 +1,65 @@
package dev.peerat.backend.routes;
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.Route;
import dev.peerat.framework.utils.json.JsonMap;
public class EventSSE{
private Locker<GroupMessage> locker;
public EventSSE(@Injection("groupMessages") Locker<GroupMessage> locker){
this.locker = locker;
}
@Route(path = "^/group/event/$", websocket = true)
public void connect(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception {
String group = reader.<JsonMap>readJson().get("group");
Key key = new Key();
locker.init(key);
try {
while(true){
locker.lock(key);
GroupMessage message = locker.getValue(key);
if(message.getGroup() == null || message.getGroup().equals(group)){
JsonMap send = new JsonMap();
send.set("message", message.getMessage());
writer.write(send.toString()+"\n");
writer.flush();
}
}
}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

@ -0,0 +1,91 @@
package dev.peerat.backend.routes;
import java.io.IOException;
import java.util.SortedSet;
import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.Player;
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 Leaderboard implements Response {
private final DatabaseRepository databaseRepo;
public Leaderboard(DatabaseRepository databaseRepo) {
this.databaseRepo = databaseRepo;
}
@RouteDoc(path = "/leaderboard/{id}", responseCode = 200, responseDescription = "JSON contenant le leaderboard")
@Route(path = "^\\/leaderboard\\/?(\\d+)?$")
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception {
context.response(200);
if (matcher.group(1) != null) {
groupsLeaderboard(Integer.parseInt(matcher.group(1)), writer);
} else {
playersLeaderboard(writer);
}
}
public final void groupsLeaderboard(int chapterId, HttpWriter writer) throws IOException {
Chapter chInfo = databaseRepo.getChapterRepository().getChapter(chapterId);
SortedSet<Group> allGroupsForChapter = databaseRepo.getLeaderboardRepository().getAllGroupForChapterLeaderboard(chapterId);
JsonMap leaderboardJSON = new JsonMap();
if (chInfo.getStartDate() != null)
leaderboardJSON.set("start_date", chInfo.getStartDate().toString());
if (chInfo.getEndDate() != null)
leaderboardJSON.set("end_date", chInfo.getEndDate().toString());
JsonArray groupsJSON = new JsonArray();
if (allGroupsForChapter != null) {
int rank = 1;
int sameRankCount = 1;
Group previousGroup = null;
for (Group g : allGroupsForChapter) {
if (previousGroup != null) {
if (g.compareTo(previousGroup) == 0) {
sameRankCount++;
} else {
rank = rank + sameRankCount;
sameRankCount = 1;
}
}
groupsJSON.add(g.toJson(rank));
previousGroup = g;
}
}
leaderboardJSON.set("groups", groupsJSON);
writer.write(leaderboardJSON.toString());
}
public final void playersLeaderboard(HttpWriter writer) throws IOException {
SortedSet<Player> allPlayers = databaseRepo.getLeaderboardRepository().getAllPlayerForLeaderboard();
JsonArray playersJSON = new JsonArray();
if (allPlayers != null) {
for (Player player : allPlayers) {
JsonMap playerJSON = new JsonMap();
playerJSON.set("pseudo", player.getPseudo());
if (player.getGroups() != null)
playerJSON.set("groups", player.getJsonGroups());
// if (player.getAvatar() != null)
// playerJSON.put("avatar", Base64.getEncoder().encodeToString(player.getAvatar()));
playerJSON.set("rank", player.getRank());
playerJSON.set("score", player.getTotalScore());
playerJSON.set("completions", player.getTotalCompletion());
playerJSON.set("tries", player.getTotalTries());
playersJSON.add(playerJSON);
}
}
writer.write(playersJSON.toString());
}
}

View file

@ -0,0 +1,62 @@
package dev.peerat.backend.routes;
import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.model.Player;
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.Response;
import dev.peerat.framework.Route;
import dev.peerat.framework.utils.json.JsonMap;
public class PlayerDetails implements Response {
private final DatabasePlayerRepository databaseRepo;
public PlayerDetails(DatabaseRepository databaseRepo) {
this.databaseRepo = databaseRepo.getPlayerRepository();
}
@RouteDoc(path = "/player/{id}", responseCode = 200, responseDescription = "JSON contenant les informations de l'utilisateur")
@RouteDoc(responseCode = 400, responseDescription = "Utilisateur introuvable dans la base de donnée")
@Route(path = "^\\/player\\/?(.+)?$", needLogin = true)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception {
Player player;
if (matcher.group(1) != null) {
player = databaseRepo.getPlayerDetails(matcher.group(1));
} else {
PeerAtUser user = context.getUser();
player = databaseRepo.getPlayerDetails(user.getId());
}
JsonMap playerJSON = new JsonMap();
if (player != null) {
playerJSON.set("pseudo", player.getPseudo());
playerJSON.set("email", player.getEmail());
playerJSON.set("firstname", player.getFirstname());
playerJSON.set("lastname", player.getLastname());
playerJSON.set("description", player.getDescription());
if (player.getGroups() != null)
playerJSON.set("groups", player.getJsonGroups());
playerJSON.set("rank", player.getRank());
playerJSON.set("score", player.getTotalScore());
playerJSON.set("completions", player.getTotalCompletion());
playerJSON.set("completionsList", player.getJsonCompletions());
playerJSON.set("tries", player.getTotalTries());
if (player.getBadges() != null)
playerJSON.set("badges", player.getJsonBadges());
// if (player.getAvatar() != null)
// playerJSON.set("avatar", Base64.getEncoder().encodeToString(player.getAvatar()));
context.response(200);
writer.write(playerJSON.toString());
} else {
context.response(400);
}
}
}

View file

@ -0,0 +1,77 @@
package dev.peerat.backend.routes;
import java.time.LocalDateTime;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.Chapter;
import dev.peerat.backend.model.Completion;
import dev.peerat.backend.model.PeerAtUser;
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 PuzzleElement implements Response {
private final DatabaseRepository databaseRepo;
private Predicate<PeerAtUser> isAdmin;
public PuzzleElement(DatabaseRepository databaseRepo, Predicate<PeerAtUser> isAdmin){
this.databaseRepo = databaseRepo;
this.isAdmin = isAdmin;
}
@RouteDoc(path = "/puzzle/<id>", responseCode = 200, responseDescription = "JSON contenant les informations du puzzle")
@RouteDoc(responseCode = 400, responseDescription = "puzzle introuvable dans la base de donnée")
@RouteDoc(responseCode = 423, responseDescription = "L'utilisateur essaye de voir le puzzle en dehors de l'event")
@Route(path = "^\\/puzzle\\/([0-9]+)$", needLogin = true)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception {
Puzzle puzzle = databaseRepo.getPuzzleRepository().getPuzzle(extractId(matcher));
if (puzzle != null){
Chapter chapter = this.databaseRepo.getChapterRepository().getChapter(puzzle);
if(chapter.getStartDate() != null && !isAdmin.test(context.getUser())){
if(LocalDateTime.now().isBefore(chapter.getStartDate().toLocalDateTime())){
context.response(423);
return;
}
}
// if(chapter.getEndDate() != null){
// if(LocalDateTime.now().isAfter(chapter.getEndDate().toLocalDateTime())){
// writer.response(423, "Access-Control-Allow-Origin: *");
// return;
// }
// }
PeerAtUser user = context.getUser();
JsonMap puzzleJSON = new JsonMap();
puzzleJSON.set("id", puzzle.getId());
puzzleJSON.set("name", puzzle.getName());
puzzleJSON.set("content", puzzle.getContent());
puzzleJSON.set("scoreMax", puzzle.getScoreMax());
if(puzzle.getTags() != null) puzzleJSON.set("tags", puzzle.getJsonTags());
Completion completion = this.databaseRepo.getCompletionRepository().getCompletionGroup(user.getId(), puzzle.getId());
if(completion != null && completion.getScore() >= 0){
puzzleJSON.set("score", completion.getScore());
puzzleJSON.set("tries", completion.getTries());
}
if(puzzle.getDepend() > 0) puzzleJSON.set("depend", puzzle.getDepend());
context.response(200, "Content-Type: application/json");
writer.write(puzzleJSON.toString());
}
else {
context.response(400);
}
}
private int extractId(Matcher matcher) {
return Integer.parseInt(matcher.group(1));
}
}

View file

@ -0,0 +1,172 @@
package dev.peerat.backend.routes;
import static dev.peerat.framework.RequestType.POST;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
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;
import dev.peerat.backend.model.Group;
import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.model.Player;
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.Injection;
import dev.peerat.framework.Locker;
import dev.peerat.framework.Response;
import dev.peerat.framework.Route;
import dev.peerat.framework.utils.json.JsonMap;
public class PuzzleResponse implements Response {
private final DatabaseRepository databaseRepo;
private final String usersFilesPath;
private final Locker<Completion> leaderboard;
private Predicate<PeerAtUser> isAdmin;
public PuzzleResponse(DatabaseRepository databaseRepo, Configuration config, @Injection("leaderboard") Locker<Completion> locker, Predicate<PeerAtUser> isAdmin){
this.databaseRepo = databaseRepo;
usersFilesPath = config.getUsersFiles();
this.leaderboard = locker;
this.isAdmin = isAdmin;
}
@RouteDoc(path = "/puzzleResponse/<id>", responseCode = 200, responseDescription = "Bonne réponse, json contenant les points + tries")
@RouteDoc(responseCode = 400, responseDescription = "Pas de réponse")
@RouteDoc(responseCode = 403, responseDescription = "Déjà répondu")
@RouteDoc(responseCode = 406, responseDescription = "Mauvaise réponse")
@RouteDoc(responseCode = 423, responseDescription = "L'utilisateur essaye de répondre en dehors de l'event")
@Route(path = "^\\/puzzleResponse\\/([0-9]+)$", type = POST, needLogin = true)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
ReceivedResponse received = new ReceivedResponse(matcher, reader);
if (received.getResponse() == null){
context.response(400);
return;
}
PeerAtUser user = context.getUser();
//saveSourceCode(received, databaseRepo.getPlayer(user.getId()));
JsonMap responseJSON = new JsonMap();
if(this.databaseRepo.getCompletionRepository().getScore(user.getId(), received.getPuzzleId()) > 0){
context.response(403);
return;
}
Puzzle currentPuzzle = databaseRepo.getPuzzleRepository().getPuzzle(received.getPuzzleId());
if(!currentPuzzle.hasStarted()){
context.response(423);
return;
}
Chapter chapter = this.databaseRepo.getChapterRepository().getChapter(currentPuzzle);
if(!chapter.hasStarted()){
context.response(423);
return;
}
if(chapter.getEndDate() != null && !isAdmin.test(context.getUser())){
if(LocalDateTime.now().isAfter(chapter.getEndDate().toLocalDateTime())){
if(Arrays.equals(currentPuzzle.getSoluce(), received.getResponse())){
context.response(200, "Content-Type: application/json");
JsonMap theoSaisPasJusteRecevoir200 = new JsonMap();
theoSaisPasJusteRecevoir200.set("success", true);
writer.write(theoSaisPasJusteRecevoir200.toString());
return;
}
context.response(423);
return;
}
Group group = this.databaseRepo.getGroupRepository().getPlayerGroup(user.getId(), chapter.getId());
if(group == null){
context.response(423);
return;
}
}
Completion completion = databaseRepo.getCompletionRepository().insertOrUpdatePuzzleResponse(received.getPuzzleId(), user.getId(),
received.getFileName(), received.getSourceCode(), received.getResponse(), currentPuzzle);
if(completion == null){
context.response(400);
return;
}
if(completion.getScore() > 0){
context.response(200, "Content-Type: application/json");
responseJSON.set("score", completion.getScore());
responseJSON.set("tries", completion.getTries());
}else{
context.response(406, "Content-Type: application/json");
responseJSON.set("tries", completion.getTries());
}
writer.write(responseJSON.toString());
writer.flush();
leaderboard.setValue(completion);
}
private void saveSourceCode(ReceivedResponse received, Player player){
try{
Path path = Paths.get(String.format("%s/%s/puz%04d-%s", usersFilesPath, player.getPseudo(),
received.getPuzzleId(), received.getFileName()));
Files.write(path, received.getSourceCode());
}catch (IOException e){
System.err.println("ERREUR D'ENREGISTREMENT DU CODE POUR PUZZLE_RESPONSE : " + e.toString());
}
}
}
class ReceivedResponse {
private int puzzleId;
private byte[] response;
private String fileName;
private byte[] sourceCode;
public ReceivedResponse(Matcher matcher, HttpReader reader) throws Exception {
puzzleId = Integer.parseInt(matcher.group(1));
List<String> multiPartData = reader.readMultiPartData();
if (multiPartData != null && multiPartData.size() > 0){
this.response = multiPartData.get(0).getBytes();
System.out.println("Puzzle response:");
System.out.println(Arrays.toString(response));
System.out.println(new String(response));
if (multiPartData.size() == 3) {
this.fileName = multiPartData.get(1);
this.sourceCode = multiPartData.get(2).getBytes();
}
}
}
public int getPuzzleId() {
return puzzleId;
}
public byte[] getResponse() {
return response;
}
public String getFileName() {
return fileName;
}
public byte[] getSourceCode() {
return sourceCode;
}
}

View file

@ -0,0 +1,41 @@
package dev.peerat.backend.routes;
import java.util.regex.Matcher;
import dev.peerat.backend.bonus.extract.RouteDoc;
import dev.peerat.backend.model.PeerAtUser;
import dev.peerat.backend.repository.DatabaseCompletionRepository;
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 Result implements Response {
private DatabaseCompletionRepository repo;
public Result(DatabaseRepository repo) {
this.repo = repo.getCompletionRepository();
}
@RouteDoc(path = "/result/<id>", responseCode = 200, responseDescription = "Le score")
@RouteDoc(responseCode = 425, responseDescription = "Puzzle pas compléter")
@Route(path = "^\\/result\\/(\\d+)$", needLogin = true)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception {
int puzzle = Integer.parseInt(matcher.group(1));
PeerAtUser user = context.getUser();
int score = this.repo.getScore(user.getId(), puzzle);
if (score < 0) {
context.response(425);
} else {
context.response(200);
writer.write(score + "");
}
}
}

View file

@ -0,0 +1,35 @@
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;
import dev.peerat.framework.HttpWriter;
import dev.peerat.framework.Injection;
import dev.peerat.framework.Response;
import dev.peerat.framework.Route;
public class Swagger implements Response{
private String json;
public Swagger(RouteExtracter extracter, Configuration config){
try{
// this.json = extracter.swagger(config.getTokenIssuer()).toString();
}catch(Exception e){
e.printStackTrace();
json = "{}";
}
}
@Route(path = "^/swagger$")
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception {
context.response(200);
writer.write(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

@ -0,0 +1,32 @@
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.RequestType;
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/$", type = RequestType.POST ,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

@ -0,0 +1,83 @@
package dev.peerat.backend.routes.groups;
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;
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.utils.FormResponse;
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.Route;
import dev.peerat.framework.utils.json.JsonMap;
public class GroupCreate extends FormResponse {
private Locker<Group> locker;
private DatabaseGroupRepository repo;
private DatabaseChapterRepository chapterRepo;
private int groupDelay;
public GroupCreate(DatabaseRepository repo, @Injection("groups") Locker<Group> locker, Configuration config){
this.repo = repo.getGroupRepository();
this.chapterRepo = repo.getChapterRepository();
this.locker = locker;
this.groupDelay = config.getGroupJoinMinutes();
validator("name", "[a-zA-Z0-9&|!?{}\\[\\]%/*\\-+=:;,_#@ ]{3,100}");
}
@RouteDoc(path = "/groupCreate", responseCode = 200, responseDescription = "Le groupe a été créé")
@RouteDoc(responseCode = 403, responseDescription = "L'utilisateur est déjà dans le groupe / ne peux pas le rejoindre")
@RouteDoc(responseCode = 423, responseDescription = "L'utilisateur essaye de crée un groupe après le délai maximum de création de l'event")
@Route(path = "^\\/groupCreate$", type = POST, needLogin = true)
public void exec(Matcher matcher, Context context, HttpReader reader, HttpWriter writer) throws Exception{
JsonMap json = json(reader);
if(!areValids("name")){
context.response(403);
return;
}
Group newGroup = new Group(json);
PeerAtUser user = context.getUser();
if (this.repo.getPlayerGroup(user.getId(), newGroup.getLinkToChapter()) == null) {
try {
if(this.repo.getGroupId(newGroup) == null) throw new NullPointerException();
context.response(403);
return;
}catch(NullPointerException e){
if(newGroup.getLinkToChapter() != null){
Chapter chapter = this.chapterRepo.getChapter(newGroup.getLinkToChapter());
if(chapter.getStartDate() != null){
LocalDateTime start = chapter.getStartDate().toLocalDateTime().plusMinutes(this.groupDelay);
if(LocalDateTime.now().isAfter(start)){
context.response(423);
return;
}
}
}
if (this.repo.insertGroup(newGroup, user)) {
context.response(200);
locker.setValue(newGroup);
} else {
context.response(403);
}
}
}else {
context.response(403);
}
}
}

Some files were not shown because too many files have changed in this diff Show more