Added base profile page, navbar, changed some href binding
This commit is contained in:
parent
e4dd1c243e
commit
4e7643f976
@ -7,12 +7,14 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal
|
|||||||
import org.springframework.stereotype.Controller
|
import org.springframework.stereotype.Controller
|
||||||
import org.springframework.ui.Model
|
import org.springframework.ui.Model
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
|
import org.springframework.web.bind.annotation.ModelAttribute
|
||||||
import org.springframework.web.bind.annotation.PostMapping
|
import org.springframework.web.bind.annotation.PostMapping
|
||||||
import org.springframework.web.bind.annotation.RequestMapping
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
import org.springframework.web.bind.annotation.RequestParam
|
import org.springframework.web.bind.annotation.RequestParam
|
||||||
import org.springframework.web.multipart.MultipartFile
|
import org.springframework.web.multipart.MultipartFile
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import javax.validation.Valid
|
||||||
import javax.validation.constraints.NotEmpty
|
import javax.validation.constraints.NotEmpty
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@ -78,6 +80,37 @@ class ImageController
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/user")
|
||||||
|
class MemberController
|
||||||
|
@Autowired constructor(
|
||||||
|
val memberRepository: MemberRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
fun memberDetails(@AuthenticationPrincipal userDetails: CustomUserDetails, model: Model) : String {
|
||||||
|
val user = DisplayUser(userDetails.getId(), userDetails.username, userDetails.getEmail(), "", "")
|
||||||
|
model.addAttribute("userData", user)
|
||||||
|
return "user"
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
fun updateLoggedInUser(@Valid @ModelAttribute userData: DisplayUser, @AuthenticationPrincipal userDetails: CustomUserDetails, model: Model): String {
|
||||||
|
if (userData.id == userDetails.getId() && passwordEncoder().matches(userData.oldPassword, userDetails.password)) {
|
||||||
|
val user = memberRepository.findById(userDetails.getId()).get()
|
||||||
|
user.email = userData.email
|
||||||
|
if (userData.password.isNotEmpty()) user.password = passwordEncoder().encode(userData.password)
|
||||||
|
memberRepository.save(user)
|
||||||
|
model.addAttribute("message", "Your profile has been updated")
|
||||||
|
} else {
|
||||||
|
model.addAttribute("error", "Incorrect existing password")
|
||||||
|
}
|
||||||
|
model.addAttribute("userData", DisplayUser(userData.id, userData.username, userData.email, userData.password, ""))
|
||||||
|
return "user"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping("/upload")
|
@RequestMapping("/upload")
|
||||||
class UploadController
|
class UploadController
|
||||||
|
12
src/main/kotlin/uk/co/neviyn/booru/Request.kt
Normal file
12
src/main/kotlin/uk/co/neviyn/booru/Request.kt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package uk.co.neviyn.booru
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank
|
||||||
|
import javax.validation.constraints.Positive
|
||||||
|
|
||||||
|
data class DisplayUser(
|
||||||
|
@field:Positive val id: Long,
|
||||||
|
val username: String,
|
||||||
|
val email: String,
|
||||||
|
val password: String,
|
||||||
|
@field:NotBlank val oldPassword: String
|
||||||
|
)
|
@ -21,7 +21,7 @@ class SecurityConfig
|
|||||||
val userDetailsService: CustomUserDetailsService
|
val userDetailsService: CustomUserDetailsService
|
||||||
) : WebSecurityConfigurerAdapter() {
|
) : WebSecurityConfigurerAdapter() {
|
||||||
override fun configure(http: HttpSecurity) {
|
override fun configure(http: HttpSecurity) {
|
||||||
http.authorizeRequests().antMatchers("/upload").hasAuthority("USER")
|
http.authorizeRequests().antMatchers("/upload/**", "/user/**").hasAuthority("USER")
|
||||||
.anyRequest().permitAll().and()
|
.anyRequest().permitAll().and()
|
||||||
.formLogin().loginPage("/login").permitAll().and()
|
.formLogin().loginPage("/login").permitAll().and()
|
||||||
.logout().logoutSuccessUrl("/").permitAll().and()
|
.logout().logoutSuccessUrl("/").permitAll().and()
|
||||||
@ -50,6 +50,10 @@ constructor(
|
|||||||
override fun isCredentialsNonExpired(): Boolean = true
|
override fun isCredentialsNonExpired(): Boolean = true
|
||||||
|
|
||||||
override fun isEnabled(): Boolean = member.enabled
|
override fun isEnabled(): Boolean = member.enabled
|
||||||
|
|
||||||
|
fun getId(): Long = member.id
|
||||||
|
|
||||||
|
fun getEmail(): String = member.email
|
||||||
}
|
}
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||||
<body>
|
<body>
|
||||||
<div th:fragment="header" th:remove="tag">
|
<div th:fragment="header" th:remove="tag">
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
@ -10,5 +10,33 @@
|
|||||||
<script th:src="@{/webjars/bootstrap/5.0.0-beta3/js/bootstrap.bundle.min.js}"></script>
|
<script th:src="@{/webjars/bootstrap/5.0.0-beta3/js/bootstrap.bundle.min.js}"></script>
|
||||||
<link th:href="@{/webjars/bootstrap-icons/1.4.1/font/bootstrap-icons.css}" rel="stylesheet">
|
<link th:href="@{/webjars/bootstrap-icons/1.4.1/font/bootstrap-icons.css}" rel="stylesheet">
|
||||||
</div>
|
</div>
|
||||||
|
<div th:fragment="navbar">
|
||||||
|
<form id="logoutForm" method="POST" th:action="@{/logout}">
|
||||||
|
<input name="${_csrf.parameterName}" type="hidden" value="${_csrf.token}"/>
|
||||||
|
</form>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="/">
|
||||||
|
Booru
|
||||||
|
</a>
|
||||||
|
<button aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation" class="navbar-toggler"
|
||||||
|
data-bs-target="#navbarNavAltMarkup" data-bs-toggle="collapse" type="button">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
|
||||||
|
<div class="navbar-nav me-auto">
|
||||||
|
<a class="nav-link" th:href="${#mvc.url('IC#getGalleryPage').build()}">Posts</a>
|
||||||
|
<a class="nav-link" th:href="${#mvc.url('UC#showUploadPage').build()}">Upload</a>
|
||||||
|
<a class="nav-link" th:href="${#mvc.url('MC#memberDetails').build()}">My Account</a>
|
||||||
|
</div>
|
||||||
|
<div sec:authorize="isAuthenticated()" class="d-flex">
|
||||||
|
<span sec:authentication="name" class="navbar-text"></span>
|
||||||
|
<a class="nav-link" onclick="document.forms['logoutForm'].submit()" style="cursor: pointer"><i
|
||||||
|
class="bi bi-box-arrow-right me-1"></i>Logout</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -5,6 +5,7 @@
|
|||||||
<title>Gallery</title>
|
<title>Gallery</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div th:replace="fragments :: navbar"></div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-2" th:each="image : ${imagePage.content}">
|
<div class="col-2" th:each="image : ${imagePage.content}">
|
||||||
|
@ -14,12 +14,16 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
<a href="/gallery" class="text-decoration-none">Browse all</a>
|
<a th:href="${#mvc.url('IC#getGalleryPage').build()}" class="text-decoration-none">Browse All</a>
|
||||||
|
<span class="text-secondary"> |</span>
|
||||||
|
<a th:href="${#mvc.url('UC#showUploadPage').build()}" class="text-decoration-none">Upload New</a>
|
||||||
|
<span class="text-secondary"> |</span>
|
||||||
|
<a th:href="${#mvc.url('MC#memberDetails').build()}" class="text-decoration-none">My Account</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<form class="col-6 text-center" action="/gallery">
|
<form class="col-xs-12 col-sm-9 col-md-6 text-center" action="/gallery">
|
||||||
<!--suppress HtmlFormInputWithoutLabel -->
|
<!--suppress HtmlFormInputWithoutLabel -->
|
||||||
<input class="form-control" id="imageSearch" pattern="[a-zA-Z0-9\s_]*" placeholder="Ex: blue_eyes smile" type="search" name="tags">
|
<input class="form-control" id="imageSearch" pattern="[a-zA-Z0-9\s_]*" placeholder="Ex: blue_eyes smile" type="search" name="tags">
|
||||||
<button class="btn btn-primary mt-1 w-25" type="submit">Search</button>
|
<button class="btn btn-primary mt-1 w-25" type="submit">Search</button>
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center mt-3">
|
<div class="row justify-content-center mt-3">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<a class="btn btn-secondary btn-lg" href="/" role="button">Home</a>
|
<a class="btn btn-secondary btn-lg" th:href="${#mvc.url('BC#landingPage').build()}" role="button">Home</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
<title>Upload</title>
|
<title>Upload</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div th:replace="fragments :: navbar"></div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
@ -12,7 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<form action="/upload" class="mb-3 col-6 text-center" enctype="multipart/form-data" method="POST">
|
<form th:action="${#mvc.url('UC#uploadFile').build()}" class="mb-3 col-6 text-center" enctype="multipart/form-data" method="POST">
|
||||||
<input th:name="${_csrf.parameterName}" type="hidden" th:value="${_csrf.token}"/>
|
<input th:name="${_csrf.parameterName}" type="hidden" th:value="${_csrf.token}"/>
|
||||||
<label class="form-label" for="formFile">Image file</label>
|
<label class="form-label" for="formFile">Image file</label>
|
||||||
<input class="form-control" id="formFile" name="file" type="file" th:accept="${@imageConfigurationProperties.typeListForFormFilter()}">
|
<input class="form-control" id="formFile" name="file" type="file" th:accept="${@imageConfigurationProperties.typeListForFormFilter()}">
|
||||||
|
56
src/main/resources/templates/user.html
Normal file
56
src/main/resources/templates/user.html
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta th:replace="fragments :: header"/>
|
||||||
|
<title>My Account</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div th:replace="fragments :: navbar"></div>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mt-3 justify-content-center">
|
||||||
|
<div class="col">
|
||||||
|
<h2 class="display-2 text-center mb-3">Profile</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form method="post" th:action="${#mvc.url('MC#updateLoggedInUser').build()}" th:object="${userData}">
|
||||||
|
<div class="row justify-content-center mb-3">
|
||||||
|
<div class="col-8">
|
||||||
|
<input th:field="*{id}" type="hidden"/>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-text">Username</span>
|
||||||
|
<input aria-label="Username" class="form-control" readonly th:field="*{username}" type="text">
|
||||||
|
</div>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-text">Email</span>
|
||||||
|
<input aria-label="Email" class="form-control" th:field="*{email}" type="text">
|
||||||
|
</div>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-text">Password</span>
|
||||||
|
<input aria-label="Password" class="form-control" th:field="*{password}" type="password">
|
||||||
|
</div>
|
||||||
|
<p>Please enter your existing password to update your profile.</p>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<span class="input-group-text">Existing Password</span>
|
||||||
|
<input aria-label="Existing Password" class="form-control form-control-lg" th:field="*{oldPassword}"
|
||||||
|
type="password">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-2 d-grid">
|
||||||
|
<button class="btn btn-primary btn-lg" type="submit">Update</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col text-center">
|
||||||
|
<span class="text-success" th:text="${message}"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col text-center">
|
||||||
|
<span class="has-error text-danger" th:text="${error}"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
Loading…
Reference in New Issue
Block a user