-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
446 additions
and
0 deletions.
There are no files selected for viewing
48 changes: 48 additions & 0 deletions
48
src/main/java/com/jgarivera/qwest/auth/presentation/PageController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package com.jgarivera.qwest.auth.presentation; | ||
|
||
import com.jgarivera.qwest.auth.domain.User; | ||
import com.jgarivera.qwest.auth.domain.UserRepository; | ||
import com.jgarivera.qwest.shared.UUIDFactory; | ||
import jakarta.validation.Valid; | ||
import org.springframework.security.crypto.password.PasswordEncoder; | ||
import org.springframework.stereotype.Controller; | ||
import org.springframework.validation.BindingResult; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.ModelAttribute; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
|
||
@Controller("auth") | ||
class PageController { | ||
|
||
private final UserRepository repository; | ||
private final UUIDFactory uuidFactory; | ||
private final PasswordEncoder passwordEncoder; | ||
|
||
PageController(UserRepository repository, UUIDFactory uuidFactory, PasswordEncoder passwordEncoder) { | ||
this.repository = repository; | ||
this.uuidFactory = uuidFactory; | ||
this.passwordEncoder = passwordEncoder; | ||
} | ||
|
||
@GetMapping("/login") | ||
String login() { | ||
return "pages/login"; | ||
} | ||
|
||
@GetMapping("/register") | ||
String register(@ModelAttribute("form") RegistrationForm form) { | ||
return "pages/register"; | ||
} | ||
|
||
@PostMapping("/register") | ||
String register(@Valid @ModelAttribute("form") RegistrationForm form, BindingResult result) { | ||
if (result.hasErrors()) { | ||
return "pages/register"; | ||
} | ||
|
||
User user = form.toUser(uuidFactory, passwordEncoder); | ||
repository.save(user); | ||
|
||
return "redirect:/login?registered"; | ||
} | ||
} |
95 changes: 95 additions & 0 deletions
95
src/main/java/com/jgarivera/qwest/auth/presentation/RegistrationForm.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package com.jgarivera.qwest.auth.presentation; | ||
|
||
import com.jgarivera.qwest.auth.domain.EmailAddress; | ||
import com.jgarivera.qwest.auth.domain.PersonalName; | ||
import com.jgarivera.qwest.auth.domain.User; | ||
import com.jgarivera.qwest.auth.domain.UserId; | ||
import com.jgarivera.qwest.auth.domain.Username; | ||
import com.jgarivera.qwest.shared.UUIDFactory; | ||
import jakarta.validation.constraints.NotBlank; | ||
import jakarta.validation.constraints.Pattern; | ||
import org.springframework.security.crypto.password.PasswordEncoder; | ||
|
||
class RegistrationForm { | ||
|
||
@NotBlank(message = "First name must not be blank") | ||
private String firstName; | ||
private String middleName; | ||
@NotBlank(message = "Last name must not be blank") | ||
private String lastName; | ||
|
||
@NotBlank(message = "Email must not be blank") | ||
@Pattern( | ||
regexp = EmailAddress.VALID_EMAIL_ADDRESS_REGEX, | ||
message = "Email address must be valid" | ||
) | ||
private String email; | ||
|
||
@NotBlank(message = "Username must not be blank") | ||
@Pattern( | ||
regexp = Username.VALID_USERNAME_REGEX, | ||
message = "Username must only contain letters, numbers, underscores, and be between 8 to 30 characters" | ||
) | ||
private String username; | ||
|
||
@NotBlank(message = "Password must not be blank") | ||
private String password; | ||
|
||
public User toUser(UUIDFactory uuidFactory, PasswordEncoder passwordEncoder) { | ||
return new User( | ||
new UserId(uuidFactory.create()), | ||
new PersonalName(firstName, middleName, lastName), | ||
new EmailAddress(email), | ||
new Username(username), | ||
passwordEncoder.encode(password) | ||
); | ||
} | ||
|
||
public String getFirstName() { | ||
return firstName; | ||
} | ||
|
||
public void setFirstName(String firstName) { | ||
this.firstName = firstName; | ||
} | ||
|
||
public String getMiddleName() { | ||
return middleName; | ||
} | ||
|
||
public void setMiddleName(String middleName) { | ||
this.middleName = middleName; | ||
} | ||
|
||
public String getLastName() { | ||
return lastName; | ||
} | ||
|
||
public void setLastName(String lastName) { | ||
this.lastName = lastName; | ||
} | ||
|
||
public String getEmail() { | ||
return email; | ||
} | ||
|
||
public void setEmail(String email) { | ||
this.email = email; | ||
} | ||
|
||
public String getUsername() { | ||
return username; | ||
} | ||
|
||
public void setUsername(String username) { | ||
this.username = username; | ||
} | ||
|
||
public String getPassword() { | ||
return password; | ||
} | ||
|
||
public void setPassword(String password) { | ||
this.password = password; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
<!DOCTYPE html> | ||
<html xmlns="http://www.w3.org/1999/xhtml" | ||
xmlns:th="http://www.thymeleaf.org" | ||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" | ||
layout:decorate="~{layouts/default}"> | ||
<head> | ||
<title>Log in</title> | ||
</head> | ||
|
||
<body> | ||
<section layout:fragment="~{app-content}"> | ||
<div class="content"> | ||
<h1>Log in</h1> | ||
<p> | ||
Welcome back! | ||
</p> | ||
<p class="is-size-7"> | ||
Are you new here? Register <a th:href="@{/register}">here</a>! | ||
</p> | ||
|
||
<div class="container is-max-desktop"> | ||
<div th:if="${param.registered}" class="notification is-success"> | ||
You have successfully registered! You may now log in. | ||
</div> | ||
<div th:if="${param.error}" class="notification is-danger"> | ||
There was an error with your login. Please make sure your username and password are correct. | ||
</div> | ||
|
||
<form method="post" th:action="@{/login}" class="form-horizontal"> | ||
<fieldset> | ||
<div class="field"> | ||
<label class="label" for="username">Username</label> | ||
<div class="control"> | ||
<input id="username" name="username" type="text" class="input"> | ||
</div> | ||
</div> | ||
|
||
<div class="field"> | ||
<label class="label" for="password">Password</label> | ||
<div class="control"> | ||
<input id="password" name="password" type="password" class="input"> | ||
</div> | ||
</div> | ||
|
||
<div class="field"> | ||
<div class="control"> | ||
<button type="submit" class="button is-primary">Log in</button> | ||
</div> | ||
</div> | ||
</fieldset> | ||
</form> | ||
</div> | ||
</div> | ||
</section> | ||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<!DOCTYPE html> | ||
<html xmlns="http://www.w3.org/1999/xhtml" | ||
xmlns:th="http://www.thymeleaf.org" | ||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" | ||
layout:decorate="~{layouts/default}"> | ||
<head> | ||
<title>Register</title> | ||
</head> | ||
|
||
<body> | ||
<section layout:fragment="~{app-content}"> | ||
<div class="content"> | ||
<h1>Register an account</h1> | ||
<p> | ||
Your questing begins here! | ||
</p> | ||
|
||
<div class="container is-max-desktop"> | ||
<form method="post" th:action="@{/register}" th:object="${form}" class="form-horizontal"> | ||
<fieldset> | ||
<div class="columns"> | ||
<div class="column"> | ||
<div class="field"> | ||
<label class="label" for="firstName">First Name</label> | ||
<div class="control"> | ||
<input id="firstName" name="firstName" type="text" class="input" | ||
th:classappend="${#fields.hasErrors('firstName')} ? is-danger" | ||
th:field="*{firstName}"> | ||
</div> | ||
<p class="help is-danger" th:if="${#fields.hasErrors('firstName')}" | ||
th:errors="*{firstName}"></p> | ||
</div> | ||
</div> | ||
<div class="column"> | ||
<div class="field"> | ||
<label class="label" for="middleName">Middle Name</label> | ||
<div class="control"> | ||
<input id="middleName" name="middleName" type="text" class="input" | ||
th:classappend="${#fields.hasErrors('middleName')} ? is-danger" | ||
th:field="*{middleName}"> | ||
</div> | ||
<p class="help is-danger" th:if="${#fields.hasErrors('middleName')}" | ||
th:errors="*{middleName}"></p> | ||
</div> | ||
</div> | ||
<div class="column"> | ||
<div class="field"> | ||
<label class="label" for="lastName">Last Name</label> | ||
<div class="control"> | ||
<input id="lastName" name="lastName" type="text" class="input" | ||
th:classappend="${#fields.hasErrors('lastName')} ? is-danger" | ||
th:field="*{lastName}"> | ||
</div> | ||
<p class="help is-danger" th:if="${#fields.hasErrors('lastName')}" | ||
th:errors="*{lastName}"></p> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<div class="field"> | ||
<label class="label" for="email">Email Address</label> | ||
<div class="control"> | ||
<input id="email" name="email" type="text" class="input" | ||
th:classappend="${#fields.hasErrors('email')} ? is-danger" th:field="*{email}"> | ||
</div> | ||
<p class="help is-danger" th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></p> | ||
</div> | ||
|
||
<div class="field"> | ||
<label class="label" for="username">Username</label> | ||
<div class="control"> | ||
<input id="username" name="username" type="text" class="input" | ||
th:classappend="${#fields.hasErrors('username')} ? is-danger" th:field="*{username}"> | ||
</div> | ||
<p class="help is-danger" th:if="${#fields.hasErrors('username')}" th:errors="*{username}"></p> | ||
</div> | ||
|
||
<div class="field"> | ||
<label class="label" for="password">Password</label> | ||
<div class="control"> | ||
<input id="password" name="password" type="password" class="input" | ||
th:classappend="${#fields.hasErrors('password')} ? is-danger" th:field="*{password}"> | ||
</div> | ||
<p class="help is-danger" th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></p> | ||
</div> | ||
|
||
<div class="field"> | ||
<div class="control"> | ||
<button type="submit" class="button is-primary">Register</button> | ||
</div> | ||
</div> | ||
|
||
</fieldset> | ||
</form> | ||
</div> | ||
</div> | ||
</section> | ||
</body> | ||
|
||
</html> |
Oops, something went wrong.