Added Register Workflow Request Handler and fixed some bugs
This commit is contained in:
@@ -3,6 +3,7 @@ package dev.coph.flightscore.backend;
|
||||
import dev.coph.flightscore.backend.config.Config;
|
||||
import dev.coph.flightscore.backend.provider.ProviderManager;
|
||||
import dev.coph.flightscore.backend.requestHandler.auth.LoginRequestHandler;
|
||||
import dev.coph.flightscore.backend.requestHandler.auth.RegisterRequestHandler;
|
||||
import dev.coph.flightscore.backend.user.UserProvider;
|
||||
import dev.coph.flightscore.backend.user.permission.PermissionProvider;
|
||||
import dev.coph.flightscore.backend.user.role.RoleProvider;
|
||||
@@ -78,6 +79,7 @@ public class Backend {
|
||||
|
||||
logger.info("Loading routes...");
|
||||
webServer.registerRequestHandler(new LoginRequestHandler(this));
|
||||
webServer.registerRequestHandler(new RegisterRequestHandler(this));
|
||||
|
||||
logger.success("Routes loaded!");
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package dev.coph.flightscore.backend.country;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class CountryRepository {
|
||||
private static final Map<String, Locale> byCode = Arrays.stream(Locale.getISOCountries())
|
||||
.map(code -> new Locale("", code))
|
||||
.collect(Collectors.toMap(locale -> locale.getCountry().toLowerCase(), locale -> locale));
|
||||
|
||||
private static final Map<String, Locale> byName = byCode.values().stream()
|
||||
.collect(Collectors.toMap(locale -> locale.getDisplayCountry(Locale.ENGLISH).toLowerCase(), locale -> locale));
|
||||
|
||||
public static Locale fromCode(String code) {
|
||||
return byCode.get(code.toLowerCase());
|
||||
}
|
||||
|
||||
public static Locale fromName(String name) {
|
||||
return byName.get(name.toLowerCase());
|
||||
}
|
||||
|
||||
public static List<Locale> all() {
|
||||
return new ArrayList<>(byCode.values());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -47,7 +47,7 @@ public class LoginRequestHandler {
|
||||
|
||||
if (email == null || password == null) {
|
||||
response.setStatus(HttpStatus.BAD_REQUEST_400);
|
||||
ResponseUtil.writeAnswer(response, callback, "Missing email or password");
|
||||
ResponseUtil.writeAnswer(response, callback, "Invalid body");
|
||||
return;
|
||||
}
|
||||
var loginResponse = backend.userProvider().login(email, password);
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package dev.coph.flightscore.backend.requestHandler.auth;
|
||||
|
||||
import dev.coph.flightscore.backend.Backend;
|
||||
import dev.coph.flightscore.backend.country.CountryRepository;
|
||||
import dev.coph.simplelogger.Logger;
|
||||
import dev.coph.simplerequest.body.Body;
|
||||
import dev.coph.simplerequest.body.JsonBody;
|
||||
import dev.coph.simplerequest.handler.RequestHandler;
|
||||
import dev.coph.simplerequest.handler.RequestMethod;
|
||||
import dev.coph.simplerequest.util.ResponseUtil;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
public class RegisterRequestHandler {
|
||||
private final Logger logger = Logger.of("RH - Register");
|
||||
private final Backend backend;
|
||||
|
||||
|
||||
public RegisterRequestHandler(Backend backend) {
|
||||
this.backend = backend;
|
||||
}
|
||||
|
||||
|
||||
@RequestHandler(
|
||||
path = "/auth/register",
|
||||
method = RequestMethod.POST
|
||||
)
|
||||
public void handle(Response response, Callback callback, Body body) {
|
||||
JsonBody json;
|
||||
try {
|
||||
json = body.asJSON();
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to parse JSON body", e);
|
||||
response.setStatus(HttpStatus.BAD_REQUEST_400);
|
||||
ResponseUtil.writeAnswer(response, callback, "Invalid body");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
String email = json.getString("email", response, callback, "Invalid body");
|
||||
if (email == null) return;
|
||||
String fistName = json.getString("firstName", response, callback, "Invalid body");
|
||||
if (fistName == null) return;
|
||||
String lastName = json.getString("lastName", response, callback, "Invalid body");
|
||||
if (lastName == null) return;
|
||||
String phoneNumber = json.getString("phoneNumber", response, callback, "Invalid body");
|
||||
if (phoneNumber == null) return;
|
||||
String countryString = json.getString("country", response, callback, "Invalid body");
|
||||
if (countryString == null) return;
|
||||
String password = json.getString("password", response, callback, "Invalid body");
|
||||
if (password == null) return;
|
||||
|
||||
if (backend.userProvider().userExists(email)) {
|
||||
logger.warn("User with email " + email + " already exists");
|
||||
response.setStatus(HttpStatus.CONFLICT_409);
|
||||
ResponseUtil.writeAnswer(response, callback, "User already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
Locale country = CountryRepository.fromCode(countryString);
|
||||
|
||||
var loginResponse = backend.userProvider().register(fistName, lastName, email, phoneNumber, password, country);
|
||||
|
||||
if (!loginResponse.success()) {
|
||||
ResponseUtil.writeAnswer(response, callback, loginResponse.message());
|
||||
return;
|
||||
}
|
||||
|
||||
var responseObject = new JSONObject();
|
||||
|
||||
responseObject.put("accessToken", loginResponse.accessToken());
|
||||
responseObject.put("refreshToken", loginResponse.refreshToken());
|
||||
|
||||
ResponseUtil.writeSuccessfulAnswer(response, callback, responseObject);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ import dev.coph.simpleutilities.ulid.ULID;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@Getter
|
||||
@Accessors(fluent = true)
|
||||
public class User {
|
||||
@@ -14,25 +16,28 @@ public class User {
|
||||
private String lastName;
|
||||
private String email;
|
||||
private String phoneNumber;
|
||||
private Locale country;
|
||||
private Role role;
|
||||
private boolean blocked;
|
||||
|
||||
public User(ULID id, String firstname, String lastname, String email, String phoneNumber, boolean blocked) {
|
||||
public User(ULID id, String firstname, String lastname, String email, String phoneNumber, Locale country, boolean blocked) {
|
||||
this.id = id;
|
||||
this.firstName = firstname;
|
||||
this.lastName = lastname;
|
||||
this.email = email;
|
||||
this.phoneNumber = phoneNumber;
|
||||
this.country = country;
|
||||
this.blocked = blocked;
|
||||
}
|
||||
|
||||
public User(ULID id, String firstname, String lastname, String email, String phoneNumber, boolean blocked, Role role) {
|
||||
public User(ULID id, String firstname, String lastname, String email, String phoneNumber, Locale country, boolean blocked, Role role) {
|
||||
this.id = id;
|
||||
this.firstName = firstname;
|
||||
this.lastName = lastname;
|
||||
this.email = email;
|
||||
this.phoneNumber = phoneNumber;
|
||||
this.role = role;
|
||||
this.country = country;
|
||||
this.blocked = blocked;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package dev.coph.flightscore.backend.user;
|
||||
import dev.coph.flightscore.backend.Backend;
|
||||
import dev.coph.flightscore.backend.actionResult.LoginActionResult;
|
||||
import dev.coph.flightscore.backend.config.Config;
|
||||
import dev.coph.flightscore.backend.country.CountryRepository;
|
||||
import dev.coph.flightscore.backend.provider.Provider;
|
||||
import dev.coph.flightscore.backend.user.role.Role;
|
||||
import dev.coph.flightscore.backend.utils.Hash;
|
||||
@@ -20,11 +21,13 @@ import dev.coph.simplesql.database.attributes.DataType;
|
||||
import dev.coph.simplesql.query.Query;
|
||||
import dev.coph.simpleutilities.ulid.ULID;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.json.JSONArray;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@@ -62,6 +65,7 @@ public class UserProvider implements Provider {
|
||||
.column("lastname", DataType.VARCHAR, 255)
|
||||
.column("email", DataType.VARCHAR, 255, ColumnType.UNIQUE, true)
|
||||
.column("phoneNumber", DataType.VARCHAR, 255)
|
||||
.column("country", DataType.CHAR, 2)
|
||||
.column("password", DataType.VARCHAR, 255, true)
|
||||
.column(new Column("blocked", DataType.BOOLEAN, true).defaultValue(false))
|
||||
.column("role", DataType.BINARY, 26)
|
||||
@@ -127,6 +131,7 @@ public class UserProvider implements Provider {
|
||||
resultSet.getString("lastname"),
|
||||
resultSet.getString("email"),
|
||||
resultSet.getString("phoneNumber"),
|
||||
CountryRepository.fromCode(resultSet.getString("country")),
|
||||
resultSet.getBoolean("blocked"),
|
||||
role
|
||||
);
|
||||
@@ -138,6 +143,7 @@ public class UserProvider implements Provider {
|
||||
resultSet.getString("lastname"),
|
||||
resultSet.getString("email"),
|
||||
resultSet.getString("phoneNumber"),
|
||||
CountryRepository.fromCode(resultSet.getString("country")),
|
||||
resultSet.getBoolean("blocked")
|
||||
);
|
||||
userReference.set(user);
|
||||
@@ -197,6 +203,7 @@ public class UserProvider implements Provider {
|
||||
resultSet.getString("lastname"),
|
||||
resultSet.getString("email"),
|
||||
resultSet.getString("phoneNumber"),
|
||||
CountryRepository.fromCode(resultSet.getString("country")),
|
||||
resultSet.getBoolean("blocked"),
|
||||
role
|
||||
);
|
||||
@@ -208,6 +215,7 @@ public class UserProvider implements Provider {
|
||||
resultSet.getString("lastname"),
|
||||
resultSet.getString("email"),
|
||||
resultSet.getString("phoneNumber"),
|
||||
CountryRepository.fromCode(resultSet.getString("country")),
|
||||
resultSet.getBoolean("blocked")
|
||||
);
|
||||
userReference.set(user);
|
||||
@@ -298,7 +306,7 @@ public class UserProvider implements Provider {
|
||||
return new LoginActionResult(user, accessToken, refreshToken);
|
||||
}
|
||||
|
||||
public LoginActionResult register(String firstName, String lastName, String email, String phoneNumber, String password) {
|
||||
public LoginActionResult register(String firstName, String lastName, String email, String phoneNumber, String password, Locale country) {
|
||||
Role role = backend.roleProvider().defaultRole();
|
||||
|
||||
var userId = ULID.randomUlid();
|
||||
@@ -313,10 +321,15 @@ public class UserProvider implements Provider {
|
||||
.entry("email", email)
|
||||
.entry("phoneNumber", phoneNumber)
|
||||
.entry("password", hashedPassword)
|
||||
.entry("role", role.id().toString());
|
||||
.entry("country", country.getCountry());
|
||||
|
||||
if (role != null)
|
||||
insert.entry("role", role.id().toString());
|
||||
|
||||
query.executeQuery(insert);
|
||||
|
||||
User user = new User(userId, firstName, lastName, email, phoneNumber, false, role);
|
||||
User user = new User(userId, firstName, lastName, email, phoneNumber, country, false, role);
|
||||
|
||||
userCache.put(user.id(), user);
|
||||
|
||||
long expiresAt = System.currentTimeMillis() + JWT_EXPIRATION_TIME;
|
||||
@@ -336,17 +349,36 @@ public class UserProvider implements Provider {
|
||||
return new LoginActionResult(user, accessToken, refreshToken);
|
||||
}
|
||||
|
||||
public boolean userExists(String email) {
|
||||
Query query = new Query(backend.databaseAdapter());
|
||||
AtomicBoolean exists = new AtomicBoolean(false);
|
||||
var select = Query.select()
|
||||
.table("users")
|
||||
.condition("email", email)
|
||||
.columnKey("id")
|
||||
.resultActionAfterQuery(srs -> {
|
||||
srs.next(_ -> exists.set(true), () -> exists.set(false), e -> logger.error("Error checking if user exists", e));
|
||||
});
|
||||
query.executeQuery(select);
|
||||
return exists.get();
|
||||
}
|
||||
|
||||
private String createAccessToken(User user, long expiresAt) {
|
||||
try {
|
||||
return new JWT.Builder()
|
||||
JWT.Builder builder = new JWT.Builder()
|
||||
.audience("flightscore-api")
|
||||
.issuer("flightscore-api")
|
||||
.subject(user.email())
|
||||
.claim("id", user.id().toString())
|
||||
.claim("role", user.role().id().toString())
|
||||
.subject(user.id().toString())
|
||||
.expiresAt(expiresAt / 1000)
|
||||
.issuedAt(System.currentTimeMillis() / 1000)
|
||||
.sign(JWT_SECRET);
|
||||
.issuedAt(System.currentTimeMillis() / 1000);
|
||||
|
||||
if (user.role() != null) {
|
||||
JSONArray permissions = new JSONArray();
|
||||
user.role().permissions().forEach(permission -> permissions.put(permission.name()));
|
||||
builder.claim("permission", permissions.toString());
|
||||
builder.claim("role", user.role().id().toString());
|
||||
}
|
||||
return builder.sign(JWT_SECRET);
|
||||
} catch (JwtException e) {
|
||||
logger.error("Error creating JWT", e);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
type: environment
|
||||
model: environment
|
||||
id: ev_rnW4WEytTs
|
||||
workspaceId: wk_gViMDNsLC9
|
||||
createdAt: 2025-07-25T17:21:10.849676300
|
||||
updatedAt: 2026-02-15T19:39:14.624560900
|
||||
name: Global Variables
|
||||
public: true
|
||||
base: true
|
||||
parentModel: workspace
|
||||
parentId: null
|
||||
variables:
|
||||
- enabled: true
|
||||
name: BASE_URL
|
||||
value: http://127.0.0.1:8080
|
||||
id: 9FaWWJII9c
|
||||
- enabled: true
|
||||
name: email
|
||||
value: jan.meinl@coph.dev
|
||||
id: 5g83mX2k0a
|
||||
- enabled: true
|
||||
name: firstname
|
||||
value: Jan
|
||||
id: CDpsUgXN2G
|
||||
- enabled: true
|
||||
name: lastname
|
||||
value: Meinl
|
||||
id: WJrnFEGNTM
|
||||
- enabled: true
|
||||
name: password
|
||||
value: TMm#J0r0iAlKliG6gBP73OnaN#ldOI&x
|
||||
id: sCrraX5tUu
|
||||
- enabled: true
|
||||
name: phoneNumber
|
||||
value: '+4915202989709'
|
||||
id: U8B5xaQqXb
|
||||
color: null
|
||||
sortPriority: 0.0
|
||||
@@ -0,0 +1,13 @@
|
||||
type: folder
|
||||
model: folder
|
||||
id: fl_gBnxCkQD7y
|
||||
createdAt: 2025-07-24T10:00:13.759993700
|
||||
updatedAt: 2025-07-24T10:00:13.759994200
|
||||
workspaceId: wk_gViMDNsLC9
|
||||
folderId: null
|
||||
authentication: {}
|
||||
authenticationType: null
|
||||
description: ''
|
||||
headers: []
|
||||
name: Auth
|
||||
sortPriority: -1753351200000.0
|
||||
@@ -0,0 +1,31 @@
|
||||
type: http_request
|
||||
model: http_request
|
||||
id: rq_eRxcYSQsbe
|
||||
createdAt: 2026-02-15T19:37:26.962157100
|
||||
updatedAt: 2026-02-15T19:39:42.170904100
|
||||
workspaceId: wk_gViMDNsLC9
|
||||
folderId: fl_gBnxCkQD7y
|
||||
authentication: {}
|
||||
authenticationType: null
|
||||
body:
|
||||
text: |-
|
||||
{
|
||||
"firstName": "${[ firstname ]}",
|
||||
"lastName": "${[ lastname ]}",
|
||||
"email": "${[ email ]}",
|
||||
"phoneNumber": "${[ phoneNumber ]}",
|
||||
"country": "de",
|
||||
"password": "${[ password ]}"
|
||||
}
|
||||
bodyType: application/json
|
||||
description: ''
|
||||
headers:
|
||||
- enabled: true
|
||||
name: Content-Type
|
||||
value: application/json
|
||||
id: d7yQvygRwt
|
||||
method: POST
|
||||
name: Register
|
||||
sortPriority: -1753351216695.0
|
||||
url: ${[ BASE_URL ]}/auth/register
|
||||
urlParameters: []
|
||||
@@ -0,0 +1,27 @@
|
||||
type: http_request
|
||||
model: http_request
|
||||
id: rq_qMQNa95s3H
|
||||
createdAt: 2025-07-24T10:00:16.697661100
|
||||
updatedAt: 2025-07-25T17:35:16.939160200
|
||||
workspaceId: wk_gViMDNsLC9
|
||||
folderId: fl_gBnxCkQD7y
|
||||
authentication: {}
|
||||
authenticationType: null
|
||||
body:
|
||||
text: |-
|
||||
{
|
||||
"email":"${[ email ]}",
|
||||
"password":"${[ password ]}"
|
||||
}
|
||||
bodyType: application/json
|
||||
description: ''
|
||||
headers:
|
||||
- enabled: true
|
||||
name: Content-Type
|
||||
value: application/json
|
||||
id: bMujbbncVX
|
||||
method: POST
|
||||
name: Login
|
||||
sortPriority: -1753351216695.0
|
||||
url: ${[ BASE_URL ]}/auth/login
|
||||
urlParameters: []
|
||||
@@ -0,0 +1,14 @@
|
||||
type: workspace
|
||||
model: workspace
|
||||
id: wk_gViMDNsLC9
|
||||
createdAt: 2025-07-24T09:59:20.801215
|
||||
updatedAt: 2025-07-24T09:59:22.805146400
|
||||
authentication: {}
|
||||
authenticationType: null
|
||||
description: ''
|
||||
headers: []
|
||||
name: FlightScore
|
||||
encryptionKeyChallenge: eUE0azNuQwGJlYhActHWAdNJxx20lcK8NFEhIOxgSadHRtl/TBAjdViFGuBpTqe2IxTYA9GbNSNeofdXpXD7psJqTH/UsWrzK2mqE7MwUbClYLVwi26gDREvzu7TK+aTJiA=
|
||||
settingValidateCertificates: true
|
||||
settingFollowRedirects: true
|
||||
settingRequestTimeout: 0
|
||||
Reference in New Issue
Block a user