Compare commits

...

2 commits

Author SHA1 Message Date
Dmitry Isaenko
583682106d Add settings page with 'allow/disallow registration' option for admin. Allowed for first run. 2024-01-03 20:05:53 +03:00
Dmitry Isaenko
52dd7f509a update spring boot version 2024-01-03 20:04:10 +03:00
14 changed files with 177 additions and 12 deletions

View file

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.4</version> <version>3.2.1</version>
<relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
<groupId>ru.redrise</groupId> <groupId>ru.redrise</groupId>

View file

@ -1,10 +1,8 @@
package ru.redrise.marinesco; package ru.redrise.marinesco;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
//@PreAuthorize("hasRole('USER')")
@Controller @Controller
public class RootController { public class RootController {

View file

@ -13,16 +13,19 @@ import lombok.extern.slf4j.Slf4j;
import ru.redrise.marinesco.data.RolesRepository; import ru.redrise.marinesco.data.RolesRepository;
import ru.redrise.marinesco.data.UserRepository; import ru.redrise.marinesco.data.UserRepository;
import ru.redrise.marinesco.security.UserRole; import ru.redrise.marinesco.security.UserRole;
import ru.redrise.marinesco.settings.ApplicationSettings;
@Slf4j @Slf4j
@Configuration @Configuration
public class ShinyApplicationRunner { public class ShinyApplicationRunner {
private UserRepository users; private UserRepository users;
private RolesRepository roles; private RolesRepository roles;
private ApplicationSettings settings;
public ShinyApplicationRunner(UserRepository users, RolesRepository roles) {
public ShinyApplicationRunner(UserRepository users, RolesRepository roles, ApplicationSettings settings) {
this.users = users; this.users = users;
this.roles = roles; this.roles = roles;
this.settings = settings;
} }
@Bean @Bean
@ -32,6 +35,7 @@ public class ShinyApplicationRunner {
log.info("Application first run"); log.info("Application first run");
setRoles(); setRoles();
setAdmin(args, encoder); setAdmin(args, encoder);
settings.setAllowRegistraion(true);
} else } else
log.info("Regular run"); log.info("Regular run");
}; };

View file

@ -1,4 +1,4 @@
package ru.redrise.marinesco; package ru.redrise.marinesco.security;
import java.util.List; import java.util.List;
@ -8,7 +8,7 @@ import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.Data; import lombok.Data;
import ru.redrise.marinesco.security.UserRole; import ru.redrise.marinesco.User;
//TODO: refactor along with RegistrationForm.java //TODO: refactor along with RegistrationForm.java
@Data @Data

View file

@ -16,7 +16,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import ru.redrise.marinesco.AdministatorAddUserForm;
import ru.redrise.marinesco.User; import ru.redrise.marinesco.User;
import ru.redrise.marinesco.UserGenerified; import ru.redrise.marinesco.UserGenerified;
import ru.redrise.marinesco.data.RolesRepository; import ru.redrise.marinesco.data.RolesRepository;

View file

@ -15,6 +15,8 @@ import lombok.extern.slf4j.Slf4j;
import ru.redrise.marinesco.User; import ru.redrise.marinesco.User;
import ru.redrise.marinesco.data.RolesRepository; import ru.redrise.marinesco.data.RolesRepository;
import ru.redrise.marinesco.data.UserRepository; import ru.redrise.marinesco.data.UserRepository;
import ru.redrise.marinesco.settings.ApplicationSettings;
import ru.redrise.marinesco.settings.KeyValueRepository;
@Slf4j @Slf4j
@Controller @Controller
@ -25,14 +27,18 @@ public class RegistrationController {
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
private HttpServletRequest request; private HttpServletRequest request;
private ApplicationSettings applicationSettings;
public RegistrationController(UserRepository userRepo, public RegistrationController(UserRepository userRepo,
RolesRepository rolesRepo, RolesRepository rolesRepo,
PasswordEncoder passwordEncoder, PasswordEncoder passwordEncoder,
HttpServletRequest request) { HttpServletRequest request,
ApplicationSettings applicationSettings) {
this.userRepo = userRepo; this.userRepo = userRepo;
this.rolesRepo = rolesRepo; this.rolesRepo = rolesRepo;
this.passwordEncoder = passwordEncoder; this.passwordEncoder = passwordEncoder;
this.request = request; this.request = request;
this.applicationSettings = applicationSettings;
} }
@ModelAttribute(name = "registrationForm") @ModelAttribute(name = "registrationForm")
@ -42,11 +48,15 @@ public class RegistrationController {
@GetMapping @GetMapping
public String registerForm() { public String registerForm() {
return "registration"; if (applicationSettings.isRegistrationAllowed())
return "registration";
return "registration_forbidden";
} }
@PostMapping @PostMapping
public String postMethodName(@Valid RegistrationForm form, Errors errors, Model model) { public String postMethodName(@Valid RegistrationForm form, Errors errors, Model model) {
if (!applicationSettings.isRegistrationAllowed())
return "redirect:/";
if (form.isPasswordsNotEqual()) { if (form.isPasswordsNotEqual()) {
model.addAttribute("passwordsMismatch", "Passwords must be the same."); model.addAttribute("passwordsMismatch", "Passwords must be the same.");
return "registration"; return "registration";

View file

@ -54,8 +54,8 @@ public class SecurityConfig {
.requestMatchers(mvc.pattern("/login")).anonymous() .requestMatchers(mvc.pattern("/login")).anonymous()
.requestMatchers(mvc.pattern("/error")).permitAll() .requestMatchers(mvc.pattern("/error")).permitAll()
.requestMatchers(PathRequest.toH2Console()).permitAll() .requestMatchers(PathRequest.toH2Console()).permitAll()
.requestMatchers(mvc.pattern("/")).hasAnyRole("ADMIN", "USER") .requestMatchers(mvc.pattern("/")).authenticated()
.requestMatchers(mvc.pattern("/profile/**")).hasAnyRole("ADMIN", "USER") .requestMatchers(mvc.pattern("/profile/**")).authenticated()//.hasAnyRole("ADMIN", "USER")
//.requestMatchers(mvc.pattern("/design/**")).hasRole("USER") //.requestMatchers(mvc.pattern("/design/**")).hasRole("USER")
.anyRequest().authenticated()) .anyRequest().authenticated())
//.anyRequest().permitAll()) //.anyRequest().permitAll())

View file

@ -0,0 +1,37 @@
package ru.redrise.marinesco.settings;
import org.springframework.stereotype.Component;
@Component
public class ApplicationSettings {
private static final String ALLOW_REGISTRATION = "allow_registration";
private KeyValueRepository keyValueRepository;
private boolean registrationAllowed;
public ApplicationSettings(KeyValueRepository keyValueRepository) {
this.keyValueRepository = keyValueRepository;
initAllowRegistraionValue();
}
private void initAllowRegistraionValue() {
try{
this.registrationAllowed = keyValueRepository.findById(ApplicationSettings.ALLOW_REGISTRATION).get().getM_value();
}
catch (Exception e){
// Application first run, thus no data on the DB
registrationAllowed = true;
}
}
public synchronized void setAllowRegistraion(boolean value) {
keyValueRepository.save(new KeyValue(ApplicationSettings.ALLOW_REGISTRATION, value));
this.registrationAllowed = value;
}
public synchronized boolean isRegistrationAllowed() {
return registrationAllowed;
}
}

View file

@ -0,0 +1,19 @@
package ru.redrise.marinesco.settings;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
public class KeyValue {
@Id
private String m_key;
private Boolean m_value;
}

View file

@ -0,0 +1,11 @@
package ru.redrise.marinesco.settings;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface KeyValueRepository extends CrudRepository<KeyValue, String>{
}

View file

@ -0,0 +1,42 @@
package ru.redrise.marinesco.settings;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
//@Slf4j
@Controller
@RequestMapping("/settings")
@PreAuthorize("hasRole('ADMIN')")
public class SettingsController {
private KeyValueRepository keyValueRepository;
private ApplicationSettings applicationSettings;
public SettingsController(KeyValueRepository keyValueRepository, ApplicationSettings applicationSettings){
this.keyValueRepository = keyValueRepository;
this.applicationSettings = applicationSettings;
}
@GetMapping
public String getPage() {
return "settings";
}
@ModelAttribute(name = "allowRegistration")
public Boolean setRegistrationSetting(){
return applicationSettings.isRegistrationAllowed();
//return keyValueRepository.findById(ApplicationSettings.ALLOW_REGISTRATION).get().getM_value();
}
@GetMapping("/allow_registration/{sw}")
public String switchRegistration(@PathVariable("sw") Boolean sw){
//log.info("{}", sw);
//keyValueRepository.save(new KeyValue(ApplicationSettings.ALLOW_REGISTRATION, sw));
applicationSettings.setAllowRegistraion(sw);
return "redirect:/settings";
}
}

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Marinesco - registration form</title>
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="alternate icon" href="/favicon.png" type="image/png">
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
<script src="/jquery.js"></script>
</head>
<body>
<div class="page">
<div th:replace="~{fragments/header :: 'header'}"></div>
<div class="container base">
<h1>Currently we're close to new registrations</h1>
</div>
</div>
<div th:replace="~{fragments/footer :: 'footer'}"></div>
</body>
</html>

View file

@ -15,6 +15,7 @@
<br /><a href="/login">Login</a> <br /><a href="/login">Login</a>
<br /><a href="/profile">/profile</a> <br /><a href="/profile">/profile</a>
<br /><a href="/manage_users">/manage_users</a> <br /><a href="/manage_users">/manage_users</a>
<br /><a href="/settings">/settings</a>
<br /><a href="/h2">H2</a> <br /><a href="/h2">H2</a>
</div> </div>
</div> </div>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Marinesco - Application settings</title>
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="alternate icon" href="/favicon.png" type="image/png">
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
</head>
<body>
<div class="page">
<div th:replace="~{fragments/header :: 'header'}"></div>
<div class="container base">
<span th:text="${'New users registration is now ' + (allowRegistration ? 'enabled. ' : 'disabled. ' )}"></span>
<a th:href="${'/settings/allow_registration/' + !allowRegistration }" th:text="${'Click here to ' + (allowRegistration ? 'disable' : 'enable' )}"></a>
</div>
</div>
<div th:replace="~{fragments/footer :: 'footer'}"></div>
</body>
</html>