Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend #4

Closed
wants to merge 24 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[ADD] backend
WilliamJlvt committed May 15, 2024
commit 66922e850774f8e4287505a0661d4df8f3b2270a
6 changes: 6 additions & 0 deletions .env.schema
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
MYSQL_ROOT_PASSWORD=
MYSQL_DATABASE=
JDBC_URL=
JDBC_USER=
JDBC_PASSWORD=
SALT_ROUNDS=
8 changes: 8 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM mariadb:latest

ARG ENV_FILE
ENV MARIADB_ROOT_PASSWORD=""

COPY schema.sql /docker-entrypoint-initdb.d/

CMD ["mariadb"]
17 changes: 17 additions & 0 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM gradle:7.3.1-jdk11 AS build

COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src

RUN gradle shadowJar --no-daemon

FROM openjdk:11-jre-slim

COPY wait-for-it.sh /wait-for-it.sh
RUN chmod +x /wait-for-it.sh

COPY --from=build /home/gradle/src/build/libs/spotiflyx_api-1.0.jar /app.jar

EXPOSE 7070

ENTRYPOINT ["/wait-for-it.sh", "mariadb:3306", "--", "java", "-jar", "/app.jar"]
42 changes: 42 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '7.1.2'
}

group = 'fr.william'
version = '1.0-SNAPSHOT'

sourceCompatibility = 11

repositories {
mavenCentral()
}

dependencies {
implementation 'io.javalin:javalin:6.1.3'
implementation 'org.slf4j:slf4j-simple:2.0.10'
implementation 'org.mongodb:mongo-java-driver:3.12.11'
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.9'
implementation 'com.google.code.gson:gson:2.8.8'
implementation 'org.json:json:20231013'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.1'
implementation 'org.mindrot:jbcrypt:0.4'
implementation 'io.jsonwebtoken:jjwt-api:0.11.2'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.2'
implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.3'
}

shadowJar {
archiveBaseName.set('spotiflyx_api')
archiveVersion.set('1.0')
archiveClassifier.set('')

manifest {
attributes(
'Implementation-Title': 'Spotiflyx API',
'Implementation-Version': version,
'Main-Class': 'fr.william.spotiflyx_api.Main'
)
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#Thu Apr 25 16:33:09 CEST 2024
#Wed May 15 09:29:59 CEST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
File renamed without changes.
File renamed without changes.
2 changes: 2 additions & 0 deletions backend/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rootProject.name = 'backend'

26 changes: 26 additions & 0 deletions backend/src/main/java/fr/william/spotiflyx_api/AuthService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package fr.william.spotiflyx_api;

import fr.william.spotiflyx_api.database.MariaDBService;
import fr.william.spotiflyx_api.token.TokenManager;

public class AuthService {

private final MariaDBService mariaDBService;

public AuthService(MariaDBService mariaDBService) {
this.mariaDBService = mariaDBService;
}

public static boolean isAuthorized(String token) {
return token != null && token.startsWith("Bearer ") && TokenManager.isValidToken(extractToken(token));
}

public static String extractToken(String token) {
return token.substring(7);
}

public void sendConfirmationEmail(String email, String token) {
// send email
}

}
31 changes: 31 additions & 0 deletions backend/src/main/java/fr/william/spotiflyx_api/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package fr.william.spotiflyx_api;

import fr.william.spotiflyx_api.database.MariaDBService;
import io.javalin.Javalin;
import io.javalin.plugin.bundled.CorsPluginConfig;

public class Main {

public final static MariaDBService postgreService = new MariaDBService();
public final static UserService userService = new UserService(postgreService);

public static void main(String[] args) {
MariaDBService.connect();
Javalin app = Javalin.create(config -> {
config.bundledPlugins.enableCors(cors -> {
cors.addRule(CorsPluginConfig.CorsRule::anyHost);
});
});

for (UserRoutes route : UserRoutes.values())
route.register(app);

app.events(event -> event.serverStopping(MariaDBService::close));
app.start(7070);
}

public static UserService getUserService() {
return userService;
}

}
9 changes: 9 additions & 0 deletions backend/src/main/java/fr/william/spotiflyx_api/UserRoute.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package fr.william.spotiflyx_api;

import io.javalin.http.Context;

public interface UserRoute {

void handle(Context ctx);

}
56 changes: 56 additions & 0 deletions backend/src/main/java/fr/william/spotiflyx_api/UserRoutes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package fr.william.spotiflyx_api;

import fr.william.spotiflyx_api.routes.*;
import io.javalin.Javalin;
import org.eclipse.jetty.http.HttpMethod;

public enum UserRoutes {

LOGIN(HttpMethod.POST, "/auth/login", new LoginRoute()),
REGISTER(HttpMethod.POST, "/auth/register", new RegisterRoute()),
CHANGE_PASSWORD(HttpMethod.PUT, "/auth/change-password", new ChangePasswordRoute()),
DELETE_ACCOUNT(HttpMethod.DELETE, "/auth/delete-account", new DeleteAccountRoute()),
GET_ACCOUNT(HttpMethod.GET, "/auth/account", new GetAccountRoute())
;

private final HttpMethod method;
private final String path;
private final UserRoute route;

UserRoutes(HttpMethod method, String path, UserRoute route) {
this.method = method;
this.path = path;
this.route = route;
}

public HttpMethod getMethod() {
return method;
}

public String getPath() {
return path;
}

public UserRoute getRoute() {
return route;
}

public void register(Javalin app) {
switch (this.method) {
case GET:
app.get(this.path, this.route::handle);
break;
case POST:
app.post(this.path, this.route::handle);
break;
case PUT:
app.put(this.path, this.route::handle);
break;
case DELETE:
app.delete(this.path, this.route::handle);
break;
default:
break;
}
}
}
74 changes: 74 additions & 0 deletions backend/src/main/java/fr/william/spotiflyx_api/UserService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package fr.william.spotiflyx_api;

import fr.william.spotiflyx_api.database.MariaDBService;
import fr.william.spotiflyx_api.response.ErrorResponse;
import fr.william.spotiflyx_api.response.Response;
import fr.william.spotiflyx_api.response.SuccessResponse;
import fr.william.spotiflyx_api.token.TokenManager;
import org.bson.Document;
import org.mindrot.jbcrypt.BCrypt;

public class UserService {

private final MariaDBService mariaDBService;

public UserService(MariaDBService mariaDBService) {
this.mariaDBService = mariaDBService;
}

public Response register(String email, String password, String firstName, String lastName) {
if (mariaDBService.emailExists(email))
return new ErrorResponse("Email already exists", 400);

String hashedPassword = BCrypt.hashpw(password, System.getenv("SALT_ROUNDS"));
mariaDBService.createUser(email, hashedPassword, firstName, lastName);
String token = TokenManager.generateToken(email);
AuthService authService = new AuthService(mariaDBService);
authService.sendConfirmationEmail(email, token);
return new SuccessResponse(new Document("token", token));
}

public Response login(String email, String password) {
if (!mariaDBService.emailExists(email))
return new ErrorResponse("Email not found", 404);

String hashedPassword = mariaDBService.getPassword(email);
if (!BCrypt.checkpw(password, hashedPassword))
return new ErrorResponse("Invalid password", 400);

String token = TokenManager.generateToken(email);
return new SuccessResponse(new Document("token", token));
}

public Response logout(String token) {
if (!AuthService.isAuthorized(token))
return new ErrorResponse("Unauthorized", 401);
TokenManager.removeToken(token);
return new SuccessResponse(new Document("message", "Logged out successfully"));
}

public Response changePassword(String id, String oldPassword, String newPassword) {
if (!mariaDBService.idExists(id))
return new ErrorResponse("Account not found", 404);

String hashedOldPassword = mariaDBService.getPassword(id);
if (!BCrypt.checkpw(oldPassword, hashedOldPassword))
return new ErrorResponse("Invalid old password", 400);

String hashedNewPassword = BCrypt.hashpw(newPassword, System.getenv("SALT_ROUNDS"));
mariaDBService.updatePassword(id, hashedNewPassword);
return new SuccessResponse(new Document("message", "Password changed successfully"));
}

public Response deleteAccount(String email, String password) {
if (!mariaDBService.emailExists(email))
return new ErrorResponse("Email not found", 404);

String hashedPassword = mariaDBService.getPassword(email);
if (!BCrypt.checkpw(password, hashedPassword))
return new ErrorResponse("Invalid password", 400);

mariaDBService.deleteUser(email);
return new SuccessResponse(new Document("message", "Account deleted successfully"));
}
}
Loading