Add basic roles support

This commit is contained in:
Dmitry Isaenko 2023-10-05 02:55:39 +03:00
parent 932d3643de
commit 147f590410
38 changed files with 641 additions and 35 deletions

View file

@ -0,0 +1,62 @@
package ru.redrise.marinesco;
import java.util.Arrays;
import java.util.List;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import lombok.extern.slf4j.Slf4j;
import ru.redrise.marinesco.data.RolesRepository;
import ru.redrise.marinesco.data.UserRepository;
import ru.redrise.marinesco.security.UserRole;
@Slf4j
@Configuration
public class ShinyApplicationRunner {
private UserRepository users;
private RolesRepository roles;
public ShinyApplicationRunner(UserRepository users, RolesRepository roles) {
this.users = users;
this.roles = roles;
}
@Bean
public ApplicationRunner appRunner() {
return args -> {
if (isFirstRun()) {
setRoles();
setAdmin(args);
} else
log.info("NOT FIRST APPLICATION RUN; DB Already set up");
};
}
private boolean isFirstRun() {
return (roles.count() <= 0);
}
private void setRoles() {
roles.saveAll(Arrays.asList(
new UserRole(null, "Admin", UserRole.Type.ADMIN),
new UserRole(null, "User", UserRole.Type.USER)));
}
private void setAdmin(ApplicationArguments args) {
List<String> login = args.getOptionValues("admin_login");
List<String> password = args.getOptionValues("admin_password");
List<UserRole> adminRoleOnlyAthority = roles.findByType(UserRole.Type.ADMIN);
if (login == null || login.size() == 0 || password == null || password.size() == 0) {
log.warn("No administrator credentials provided, using defaults:\n * Login: root\n * Password: root\n Expected: --admin_login LOGIN --admin_password PASSWORD "); // TODO: Move into properties i18n
var adminUser = new User("root", "root", "SuperAdmin", adminRoleOnlyAthority);
users.save(adminUser);
return;
}
users.save(new User(login.get(0), password.get(0), "SuperAdmin", adminRoleOnlyAthority));
}
}

View file

@ -1,23 +1,25 @@
package ru.redrise.marinesco; package ru.redrise.marinesco;
import java.util.Arrays; import java.util.ArrayList;
import java.util.Collection; import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue; import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType; import jakarta.persistence.GenerationType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import ru.redrise.marinesco.security.UserRole;
@Data @Data
@Entity(name = "\"user\"") @Entity
@Table(name = "\"USER\"")
@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true) @NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
@RequiredArgsConstructor @RequiredArgsConstructor
public class User implements UserDetails{ public class User implements UserDetails{
@ -32,10 +34,8 @@ public class User implements UserDetails{
private final String password; private final String password;
private final String displayname; private final String displayname;
@Override @ManyToMany
public Collection<? extends GrantedAuthority> getAuthorities() { private final List<UserRole> authorities;
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
}
@Override @Override
public boolean isAccountNonExpired() { public boolean isAccountNonExpired() {
@ -56,4 +56,8 @@ public class User implements UserDetails{
public boolean isEnabled() { public boolean isEnabled() {
return true; return true;
} }
public void setRole(UserRole role){
this.authorities.add(role);
}
} }

View file

@ -0,0 +1,15 @@
package ru.redrise.marinesco.data;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import ru.redrise.marinesco.security.UserRole;
import ru.redrise.marinesco.security.UserRole.Type;
@Repository
public interface RolesRepository extends CrudRepository<UserRole, Long>{
public List<UserRole> findByType(Type type);
}

View file

@ -7,5 +7,5 @@ import ru.redrise.marinesco.User;
@Repository @Repository
public interface UserRepository extends CrudRepository<User, Long>{ public interface UserRepository extends CrudRepository<User, Long>{
User findByUsername(String username); public User findByUsername(String username);
} }

View file

@ -0,0 +1,21 @@
package ru.redrise.marinesco.security;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import ru.redrise.marinesco.data.RolesRepository;
@Component
public class AthorityByIdConverter implements Converter<Long, UserRole>{
private RolesRepository rolesRepo;
public AthorityByIdConverter(RolesRepository rolesRepo){
this.rolesRepo = rolesRepo;
}
@Override
public UserRole convert(Long id) {
return rolesRepo.findById(id).orElse(null);
}
}

View file

@ -6,16 +6,19 @@ import org.springframework.web.bind.annotation.GetMapping;
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 ru.redrise.marinesco.data.RolesRepository;
import ru.redrise.marinesco.data.UserRepository; import ru.redrise.marinesco.data.UserRepository;
@Controller @Controller
@RequestMapping("/register") @RequestMapping("/register")
public class RegistrationController { public class RegistrationController {
private UserRepository userRepo; private UserRepository userRepo;
private RolesRepository rolesRepo;
private PasswordEncoder passwordEncoder; private PasswordEncoder passwordEncoder;
public RegistrationController(UserRepository userRepo, PasswordEncoder passwordEncoder){ public RegistrationController(UserRepository userRepo, RolesRepository rolesRepo, PasswordEncoder passwordEncoder){
this.userRepo = userRepo; this.userRepo = userRepo;
this.rolesRepo = rolesRepo;
this.passwordEncoder = passwordEncoder; this.passwordEncoder = passwordEncoder;
} }
@ -26,7 +29,7 @@ public class RegistrationController {
@PostMapping @PostMapping
public String postMethodName(RegistrationForm registrationForm) { public String postMethodName(RegistrationForm registrationForm) {
userRepo.save(registrationForm.toUser(passwordEncoder)); userRepo.save(registrationForm.toUser(passwordEncoder, rolesRepo));
return "redirect:/login"; return "redirect:/login";
} }
} }

View file

@ -2,20 +2,27 @@ package ru.redrise.marinesco.security;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import ru.redrise.marinesco.User; import ru.redrise.marinesco.User;
import ru.redrise.marinesco.data.RolesRepository;
@Data @Data
public class RegistrationForm { public class RegistrationForm {
@NotNull
private String username; private String username;
@NotNull
private String password; private String password;
@NotNull
private String fullname; private String fullname;
@NotNull
private String displayname; private String displayname;
public User toUser(PasswordEncoder passwordEncoder){ public User toUser(PasswordEncoder passwordEncoder, RolesRepository rolesRepo){
return new User( return new User(
username, username,
passwordEncoder.encode(password), passwordEncoder.encode(password),
displayname); displayname,
rolesRepo.findByType(UserRole.Type.USER));
} }
} }

View file

@ -1,11 +1,11 @@
package ru.redrise.marinesco.security; package ru.redrise.marinesco.security;
import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher; import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@ -18,7 +18,8 @@ import ru.redrise.marinesco.User;
import ru.redrise.marinesco.data.UserRepository; import ru.redrise.marinesco.data.UserRepository;
@Configuration @Configuration
@EnableWebSecurity //@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig { public class SecurityConfig {
@Bean @Bean
public UserDetailsService userDetailsService(UserRepository repository) { public UserDetailsService userDetailsService(UserRepository repository) {
@ -44,10 +45,30 @@ public class SecurityConfig {
public SecurityFilterChain filterChain(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception { public SecurityFilterChain filterChain(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
return http return http
.authorizeHttpRequests(autorize -> autorize .authorizeHttpRequests(autorize -> autorize
.requestMatchers(mvc.pattern("/register/**")).hasRole("USER") .requestMatchers(mvc.pattern("/styles/**")).permitAll()
//.requestMatchers(antMatcher("/register/**")).hasRole("USER") .requestMatchers(mvc.pattern("/images/*")).permitAll()
.anyRequest().permitAll()) .requestMatchers(mvc.pattern("/register")).permitAll()
.formLogin(formLoginConfigurer -> formLoginConfigurer.loginPage("/login")) .requestMatchers(mvc.pattern("/login")).permitAll()
.requestMatchers(PathRequest.toH2Console()).permitAll()
//.requestMatchers(mvc.pattern("/design/**")).hasRole("USER")
.anyRequest().denyAll())
.formLogin(formLoginConfigurer -> formLoginConfigurer
.loginPage("/login")
.loginProcessingUrl("/auth")
.usernameParameter("login")
.passwordParameter("pwd")
//.defaultSuccessUrl("/", true)
)
// .formLogin(Customizer.withDefaults())
//.oauth2Login(c -> c.loginPage("/login"))
.logout(Customizer.withDefaults())
/* Make temporary access to H2 infrastructure START*/
.csrf(csrf -> csrf
.ignoringRequestMatchers(PathRequest.toH2Console())
.disable()
)
.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.sameOrigin()))
/* Make temporary access to H2 infrastructure END*/
.build(); .build();
} }
} }

View file

@ -0,0 +1,16 @@
package ru.redrise.marinesco.security;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/usersmanagment")
public class UserManagment {
@GetMapping
public String getPage(){
return "/usersmanagment";
}
}

View file

@ -0,0 +1,45 @@
package ru.redrise.marinesco.security;
import org.springframework.security.core.GrantedAuthority;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
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 UserRole implements GrantedAuthority{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private Type type;
@Override
public String getAuthority() {
if (type == null)
throw new UnsupportedOperationException("Unimplemented method 'getAuthority'");
switch (type) {
case USER:
return "ROLE_USER";
case ADMIN:
return "ROLE_ADMIN";
default:
throw new UnsupportedOperationException("Unimplemented method 'getAuthority'");
}
}
public enum Type{
USER, ADMIN
}
}

View file

@ -1,6 +1,24 @@
spring: spring:
thymeleaf: thymeleaf:
cache: false cache: false
datasource: datasource:
driverClassName: org.h2.Driver
generate-unique-name: false generate-unique-name: false
name: tacocloud name: marinesco
url: jdbc:h2:mem:marinesco
username: sa
password:
jpa:
properties:
hibernate:
database-platform: org.hibernate.dialect.H2Dialect
hibernate:
ddl-auto: update
h2:
console:
enabled: true
path: /h2
settings:
web-allow-others: true
trace: false

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="133mm"
height="27.5mm"
viewBox="0 0 133 27.5"
version="1.1"
id="svg5"
sodipodi:docname="marinesco logo.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#a535aa"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="1"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="2.8284271"
inkscape:cx="181.54967"
inkscape:cy="106.59635"
inkscape:window-width="3755"
inkscape:window-height="2123"
inkscape:window-x="1165"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showguides="false"
inkscape:lockguides="true" />
<defs
id="defs2" />
<g
inkscape:label="Слой 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.659681;stroke-linejoin:round;paint-order:stroke fill markers"
id="rect15547"
width="133.10405"
height="27.5"
x="0"
y="0"
ry="2.6981504" />
<path
id="rect2054-3-56-9"
style="fill:#008fc9;fill-opacity:1;stroke:none;stroke-width:0.0797409;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 33.635107,9.1000736 c -4.069468,0.03255 -8.346161,1.0300024 -13.794501,3.2114974 L 6.5975531,17.865938 c -0.4935601,0.191788 -0.9838347,0.36379 -0.9838347,0.815727 v 0.186858 c 0,0.451936 0.4902658,0.427052 0.9838346,0.235263 l 14.749126,-6.106412 c 14.756957,-5.7066219 23.415737,-1.612883 43.946257,10.728165 0,0 0.841119,0.292668 1.285227,0.36734 0.362328,0.06092 1.106533,0.06266 1.106533,0.06266 -0.778699,-0.281365 -1.557399,-0.56273 -2.336098,-0.844095 C 57.175207,16.691742 43.992671,9.0685056 33.635107,9.1000736 Z"
sodipodi:nodetypes="cccsscccaccc" />
<path
id="rect2054-3"
style="fill:#008fc9;fill-opacity:1;stroke:none;stroke-width:0.0797409;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 33.540144,12.646976 c -4.069467,0.03255 -8.346161,1.030003 -13.7945,3.211499 L 5.4515333,21.412842 C 4.9579732,21.60463 4.4676988,21.776631 4.4676988,22.228568 v 0.186858 c 0,0.451937 0.4902656,0.427052 0.9838345,0.235263 L 19.745644,17.096323 c 12.462727,-4.737552 19.147927,-3.9543 30.338669,1.161303 l 15.113671,6.908906 c 0,0 0.83208,0.367605 1.28523,0.36734 0.451297,-2.65e-4 1.279347,-0.36734 1.279347,-0.36734 l -0.04804,-1.192447 c 0,0 -0.825909,-0.02592 -1.234472,-0.0893 -0.413897,-0.06421 -1.2264,-0.293797 -1.2264,-0.293797 L 50.262163,16.841173 C 43.662433,14.158308 38.772318,12.605125 33.540144,12.646976 Z"
sodipodi:nodetypes="sccssccccaccaccs" />
<path
id="rect2054-3-56"
style="fill:#008fc9;fill-opacity:1;stroke:none;stroke-width:0.0797409;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 33.635104,10.787441 c -4.069468,0.03255 -8.34616,1.030003 -13.7945,3.211498 L 6.1596884,19.553306 c -0.4935601,0.191788 -0.9838347,0.363789 -0.9838347,0.815726 v 0.186859 c 0,0.451936 0.4902658,0.427051 0.9838347,0.235262 L 19.840604,15.236787 c 18.023542,-6.8094217 20.310357,-2.664449 45.452329,8.43342 0,0 0.832078,0.367606 1.285228,0.36734 l -0.0067,-0.278863 C 66.145911,23.758666 65.9158,23.511571 65.9158,23.511571 56.610459,18.316164 43.926086,10.729521 33.635147,10.787441 Z"
sodipodi:nodetypes="cccssccccccc" />
<path
id="rect2054-3-56-9-0"
style="fill:#008fc9;fill-opacity:1;stroke:none;stroke-width:0.0797409;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 100.99714,9.1071356 c 4.96731,-0.02748 8.34616,1.0300024 13.79449,3.2114974 L 128.20972,17.873 c 0.49355,0.191788 0.98383,0.36379 0.98383,0.815727 v 0.186858 c 0,0.451936 -0.49027,0.427052 -0.98383,0.235263 L 114.79163,13.556481 C 99.40161,6.2280595 89.12455,11.252488 69.339305,23.732601 c 0,0 -0.837922,0.307169 -1.285221,0.36734 -0.319432,0.04297 -0.970777,-0.0083 -0.970777,-0.0083 l 0.955881,-0.301597 1.244491,-0.471564 C 78.094253,16.55472 90.234122,9.1476096 100.99718,9.1071356 Z"
sodipodi:nodetypes="cccsscccaccccc" />
<path
id="rect2054-3-9"
style="fill:#008fc9;fill-opacity:1;stroke:none;stroke-width:0.0797409;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 101.09209,12.654038 c 4.06947,0.03255 9.05576,1.138066 13.79451,3.211499 l 14.29411,5.554367 c 0.49356,0.191788 0.98384,0.363789 0.98384,0.815726 v 0.186858 c 0,0.451937 -0.49027,0.427052 -0.98384,0.235263 L 114.8866,17.103385 c -12.46273,-4.737552 -19.147926,-3.9543 -30.338675,1.161303 L 69.43426,25.173594 c 0,0 -0.832083,0.367605 -1.285229,0.36734 -0.451299,-2.65e-4 -1.279345,-0.36734 -1.279345,-0.36734 l 1.282538,-1.281748 c 0.425526,-1.7e-5 1.226407,-0.293796 1.226407,-0.293796 l 14.991482,-6.749815 c 6.599732,-2.682865 11.489844,-4.236048 16.722017,-4.194197 z"
sodipodi:nodetypes="sccssccccaccccss" />
<path
id="rect2054-3-56-3"
style="fill:#008fc9;fill-opacity:1;stroke:none;stroke-width:0.0797409;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 100.99714,10.794503 c 4.06947,0.03255 8.34617,1.030003 13.79449,3.211498 l 13.68081,5.554367 c 0.49357,0.191788 0.98384,0.363789 0.98384,0.815726 v 0.186859 c 0,0.451936 -0.49027,0.427051 -0.98384,0.235262 l -13.68081,-5.554366 c -18.412603,-6.8141094 -22.492137,-1.640278 -45.452316,8.43342 -2.776303,0.05915 -2.9055,0.657477 -0.540756,-0.155942 9.537019,-5.771739 21.907671,-12.784744 32.198622,-12.726824 z"
sodipodi:nodetypes="cccsscccccc" />
<path
id="rect2054-3-5"
style="display:none;fill:#008fc9;fill-opacity:1;stroke:#ffffff;stroke-width:0.0852133;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 96.191624,12.357583 -18.87288,10.854929 c -0.929065,0.389453 -1.978574,0.37484 -2.864572,0.07241 L 55.123883,13.083327 C 47.577069,8.0785026 34.406788,7.0985105 22.485163,11.195846 l -16.523354,5.48195 c 0.0038,-0.0013 -1.1235037,0.363789 -1.1235037,0.815726 v 0.9857 c 0,0.451937 0.5573606,1.003563 1.1235037,0.815726 L 22.485163,13.812999 C 37.587703,8.6538836 43.906467,8.6882677 57.130824,15.70048 l 17.322925,9.185477 c 1.286762,0.379894 1.557099,0.369131 2.864572,-0.07241 l 17.323253,-9.8388 C 106.13569,8.4466193 115.0552,9.0758126 129.28722,13.813374 l 16.32336,5.554366 c 0.56364,0.191791 1.1235,-0.363789 1.1235,-0.815725 v -0.9857 c 0,-0.451937 -0.55987,-0.623939 -1.1235,-0.815727 L 129.28722,11.196222 C 106.86095,5.3664259 103.00828,10.013448 96.191624,12.357583 Z"
sodipodi:nodetypes="ccccccssccsccscsssccc" />
<path
id="rect2350"
style="opacity:1;fill:#a82b17;fill-opacity:1;stroke:none;stroke-width:0.0786222;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="M 130.27489,23.682275 75.159916,23.68264 H 72.438446 72.370115 60.772868 1.9729981 c -0.5184215,0 -0.9358165,0.336467 -0.9358165,0.754372 v 0.628522 c 0,0.417905 0.417395,0.754007 0.9358165,0.754007 H 60.772868 c 0.518421,0 1.023153,-0.336102 1.023153,-0.754007 v -0.0197 -0.0197 c 0,-0.0464 0.0547,-0.07075 0.09865,-0.07077 0.04394,-1.3e-5 0.09865,0.02714 0.09865,0.07077 v 0.05435 0.05472 c 0,0.438975 0.525657,0.79231 1.070216,0.79231 h 5.447919 0.405912 1.162078 c 0.544558,0 1.070216,-0.353335 1.070216,-0.79231 v -0.05472 -0.05435 c 0,-0.04363 0.0547,-0.07078 0.09865,-0.07077 0.04394,1.3e-5 0.0982,0.02437 0.0982,0.07077 v 0.0197 0.0197 c 0,0.417905 0.505185,0.754007 1.023606,0.754007 h 0.06833 58.731532 c 0.51842,0 0.93582,-0.336102 0.93582,-0.754007 v -0.628522 c 0,-0.417905 -0.4174,-0.754372 -0.93582,-0.754372 h -0.89056 c -0.002,-6e-6 -0.003,-3.65e-4 -0.004,-3.65e-4 z" />
<path
id="rect2675"
style="opacity:1;fill:#00b185;fill-opacity:1;stroke:#ffffff;stroke-width:0.917842;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
d="m 75.960365,18.022748 8.686193,-5.283117 c 0.04346,-0.02643 0.08973,0.04381 0.08973,0.09821 v 11.75165 c 0,0.0544 -0.04003,0.09821 -0.08973,0.09821 0,0 -4.343128,-2.045323 -4.343128,-3.840942 0,-0.06402 0,-0.06402 0,0 0,1.794641 -4.343065,3.840942 -4.343065,3.840942 -0.03835,0.03461 -0.08973,-0.04381 -0.08973,-0.09821 V 18.12096 c 0,-0.05441 0.04629,-0.07179 0.08973,-0.09821 z"
sodipodi:nodetypes="sssssssssss" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

View file

@ -0,0 +1,48 @@
@font-face{
font-family: "Terminus";
src: url('/styles/TerminusBold.ttf');
}
body {
margin-top: 0;
margin-bottom: 0;
margin-right: 1%;
margin-left: 1%;
font-family: Terminus;
background-color: #212121;
color: #cfcfcf;
}
.validationError {
color: red;
}
.header-container {
text-align: left;
position: relative;
color: white;
}
.header-container .header-bar {
position: absolute;
right: 10px;
}
table, th, td {
border: 1px solid;
border-collapse: collapse;
}
a {
color: #cfcfcf;
text-align: center;
}
a:link {
color: #cfcfcf;
}
a:hover {
color: white;
}
a:visited {
color: #949494;
}

View file

@ -3,10 +3,28 @@
<head> <head>
<title>Marinesco</title> <title>Marinesco</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
</head> </head>
<body> <body>
<h1>Welcome to LOGIN PAGE</h1> <h1>FUCKING BRILLIANT LOGIN PAGE</h1>
<img th:src="@{/images/logo.svg}" />
</body> </body>
<div class="container">
<br /> New here? <a href="/register">REGISTER NOW!</a>
<br /><a href="/h2">H2</a>
<form class="form-signin" method="post" action="/login">
<h2 class="form-signin-heading">Please sign in</h2>
<p>
<label for="username" class="sr-only">Username</label>
<input type="text" id="username" name="login" class="form-control" placeholder="Username" required autofocus>
</p>
<p>
<label for="password" class="sr-only">Password</label>
<input type="password" id="password" name="pwd" class="form-control" placeholder="Password" required>
</p>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div>
</html> </html>

View file

@ -3,19 +3,23 @@
<head> <head>
<title>Marinesco - registration form</title> <title>Marinesco - registration form</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
</head> </head>
<body> <body>
<h1>Register</h1> <h1>Register</h1>
<img th:src="@{/images/logo.svg}" />
<form method="POST" th:action="@{/register}" id="registerForm"> <form method="POST" th:action="@{/register}" id="registerForm">
<label for="username">Username: </label> <label for="username">Username: </label>
<input type="text" name="username" /><br /> <input type="text" name="login" /><br />
<label for="password">Password: </label> <label for="password">Password: </label>
<input type="password" name="password" /><br /> <input type="password" name="pwd" /><br />
<label for="confirm">Confirm password: </label> <label for="confirm">Confirm password: </label>
<input type="password" name="confirm" /><br /> <input type="password" name="confirm" /><br />
<label for="displayname">Displayed name: </label> <label for="displayname">Displayed name: </label>
<input type="text" name="fullname" /><br /> <input type="text" name="fullname" /><br />
<input type="submit" value="Register" />
</form> </form>
</body> </body>

View file

@ -3,10 +3,14 @@
<head> <head>
<title>Marinesco</title> <title>Marinesco</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
</head> </head>
<body> <body>
<h1>Welcome to Marinesco</h1> <h1>Welcome to Marinesco</h1>
<img th:src="@{/images/logo.svg}" />
<br /><a href="/login">Login</a>
</body> </body>
</html> </html>

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>User managment</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
</head>
<body>
<h1>User managment</h1>
<img th:src="@{/images/logo.svg}" />
<br /><a href="/logout">Log out</a>
</body>
</html>

View file

@ -1,6 +1,24 @@
spring: spring:
thymeleaf: thymeleaf:
cache: false cache: false
datasource: datasource:
driverClassName: org.h2.Driver
generate-unique-name: false generate-unique-name: false
name: tacocloud name: marinesco
url: jdbc:h2:mem:marinesco
username: sa
password:
jpa:
properties:
hibernate:
database-platform: org.hibernate.dialect.H2Dialect
hibernate:
ddl-auto: update
h2:
console:
enabled: true
path: /h2
settings:
web-allow-others: true
trace: false

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="133mm"
height="27.5mm"
viewBox="0 0 133 27.5"
version="1.1"
id="svg5"
sodipodi:docname="marinesco logo.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#a535aa"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="1"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="2.8284271"
inkscape:cx="181.54967"
inkscape:cy="106.59635"
inkscape:window-width="3755"
inkscape:window-height="2123"
inkscape:window-x="1165"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showguides="false"
inkscape:lockguides="true" />
<defs
id="defs2" />
<g
inkscape:label="Слой 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.659681;stroke-linejoin:round;paint-order:stroke fill markers"
id="rect15547"
width="133.10405"
height="27.5"
x="0"
y="0"
ry="2.6981504" />
<path
id="rect2054-3-56-9"
style="fill:#008fc9;fill-opacity:1;stroke:none;stroke-width:0.0797409;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 33.635107,9.1000736 c -4.069468,0.03255 -8.346161,1.0300024 -13.794501,3.2114974 L 6.5975531,17.865938 c -0.4935601,0.191788 -0.9838347,0.36379 -0.9838347,0.815727 v 0.186858 c 0,0.451936 0.4902658,0.427052 0.9838346,0.235263 l 14.749126,-6.106412 c 14.756957,-5.7066219 23.415737,-1.612883 43.946257,10.728165 0,0 0.841119,0.292668 1.285227,0.36734 0.362328,0.06092 1.106533,0.06266 1.106533,0.06266 -0.778699,-0.281365 -1.557399,-0.56273 -2.336098,-0.844095 C 57.175207,16.691742 43.992671,9.0685056 33.635107,9.1000736 Z"
sodipodi:nodetypes="cccsscccaccc" />
<path
id="rect2054-3"
style="fill:#008fc9;fill-opacity:1;stroke:none;stroke-width:0.0797409;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 33.540144,12.646976 c -4.069467,0.03255 -8.346161,1.030003 -13.7945,3.211499 L 5.4515333,21.412842 C 4.9579732,21.60463 4.4676988,21.776631 4.4676988,22.228568 v 0.186858 c 0,0.451937 0.4902656,0.427052 0.9838345,0.235263 L 19.745644,17.096323 c 12.462727,-4.737552 19.147927,-3.9543 30.338669,1.161303 l 15.113671,6.908906 c 0,0 0.83208,0.367605 1.28523,0.36734 0.451297,-2.65e-4 1.279347,-0.36734 1.279347,-0.36734 l -0.04804,-1.192447 c 0,0 -0.825909,-0.02592 -1.234472,-0.0893 -0.413897,-0.06421 -1.2264,-0.293797 -1.2264,-0.293797 L 50.262163,16.841173 C 43.662433,14.158308 38.772318,12.605125 33.540144,12.646976 Z"
sodipodi:nodetypes="sccssccccaccaccs" />
<path
id="rect2054-3-56"
style="fill:#008fc9;fill-opacity:1;stroke:none;stroke-width:0.0797409;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 33.635104,10.787441 c -4.069468,0.03255 -8.34616,1.030003 -13.7945,3.211498 L 6.1596884,19.553306 c -0.4935601,0.191788 -0.9838347,0.363789 -0.9838347,0.815726 v 0.186859 c 0,0.451936 0.4902658,0.427051 0.9838347,0.235262 L 19.840604,15.236787 c 18.023542,-6.8094217 20.310357,-2.664449 45.452329,8.43342 0,0 0.832078,0.367606 1.285228,0.36734 l -0.0067,-0.278863 C 66.145911,23.758666 65.9158,23.511571 65.9158,23.511571 56.610459,18.316164 43.926086,10.729521 33.635147,10.787441 Z"
sodipodi:nodetypes="cccssccccccc" />
<path
id="rect2054-3-56-9-0"
style="fill:#008fc9;fill-opacity:1;stroke:none;stroke-width:0.0797409;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 100.99714,9.1071356 c 4.96731,-0.02748 8.34616,1.0300024 13.79449,3.2114974 L 128.20972,17.873 c 0.49355,0.191788 0.98383,0.36379 0.98383,0.815727 v 0.186858 c 0,0.451936 -0.49027,0.427052 -0.98383,0.235263 L 114.79163,13.556481 C 99.40161,6.2280595 89.12455,11.252488 69.339305,23.732601 c 0,0 -0.837922,0.307169 -1.285221,0.36734 -0.319432,0.04297 -0.970777,-0.0083 -0.970777,-0.0083 l 0.955881,-0.301597 1.244491,-0.471564 C 78.094253,16.55472 90.234122,9.1476096 100.99718,9.1071356 Z"
sodipodi:nodetypes="cccsscccaccccc" />
<path
id="rect2054-3-9"
style="fill:#008fc9;fill-opacity:1;stroke:none;stroke-width:0.0797409;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 101.09209,12.654038 c 4.06947,0.03255 9.05576,1.138066 13.79451,3.211499 l 14.29411,5.554367 c 0.49356,0.191788 0.98384,0.363789 0.98384,0.815726 v 0.186858 c 0,0.451937 -0.49027,0.427052 -0.98384,0.235263 L 114.8866,17.103385 c -12.46273,-4.737552 -19.147926,-3.9543 -30.338675,1.161303 L 69.43426,25.173594 c 0,0 -0.832083,0.367605 -1.285229,0.36734 -0.451299,-2.65e-4 -1.279345,-0.36734 -1.279345,-0.36734 l 1.282538,-1.281748 c 0.425526,-1.7e-5 1.226407,-0.293796 1.226407,-0.293796 l 14.991482,-6.749815 c 6.599732,-2.682865 11.489844,-4.236048 16.722017,-4.194197 z"
sodipodi:nodetypes="sccssccccaccccss" />
<path
id="rect2054-3-56-3"
style="fill:#008fc9;fill-opacity:1;stroke:none;stroke-width:0.0797409;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 100.99714,10.794503 c 4.06947,0.03255 8.34617,1.030003 13.79449,3.211498 l 13.68081,5.554367 c 0.49357,0.191788 0.98384,0.363789 0.98384,0.815726 v 0.186859 c 0,0.451936 -0.49027,0.427051 -0.98384,0.235262 l -13.68081,-5.554366 c -18.412603,-6.8141094 -22.492137,-1.640278 -45.452316,8.43342 -2.776303,0.05915 -2.9055,0.657477 -0.540756,-0.155942 9.537019,-5.771739 21.907671,-12.784744 32.198622,-12.726824 z"
sodipodi:nodetypes="cccsscccccc" />
<path
id="rect2054-3-5"
style="display:none;fill:#008fc9;fill-opacity:1;stroke:#ffffff;stroke-width:0.0852133;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="m 96.191624,12.357583 -18.87288,10.854929 c -0.929065,0.389453 -1.978574,0.37484 -2.864572,0.07241 L 55.123883,13.083327 C 47.577069,8.0785026 34.406788,7.0985105 22.485163,11.195846 l -16.523354,5.48195 c 0.0038,-0.0013 -1.1235037,0.363789 -1.1235037,0.815726 v 0.9857 c 0,0.451937 0.5573606,1.003563 1.1235037,0.815726 L 22.485163,13.812999 C 37.587703,8.6538836 43.906467,8.6882677 57.130824,15.70048 l 17.322925,9.185477 c 1.286762,0.379894 1.557099,0.369131 2.864572,-0.07241 l 17.323253,-9.8388 C 106.13569,8.4466193 115.0552,9.0758126 129.28722,13.813374 l 16.32336,5.554366 c 0.56364,0.191791 1.1235,-0.363789 1.1235,-0.815725 v -0.9857 c 0,-0.451937 -0.55987,-0.623939 -1.1235,-0.815727 L 129.28722,11.196222 C 106.86095,5.3664259 103.00828,10.013448 96.191624,12.357583 Z"
sodipodi:nodetypes="ccccccssccsccscsssccc" />
<path
id="rect2350"
style="opacity:1;fill:#a82b17;fill-opacity:1;stroke:none;stroke-width:0.0786222;stroke-linejoin:round;stroke-opacity:0.624036;paint-order:stroke fill markers"
d="M 130.27489,23.682275 75.159916,23.68264 H 72.438446 72.370115 60.772868 1.9729981 c -0.5184215,0 -0.9358165,0.336467 -0.9358165,0.754372 v 0.628522 c 0,0.417905 0.417395,0.754007 0.9358165,0.754007 H 60.772868 c 0.518421,0 1.023153,-0.336102 1.023153,-0.754007 v -0.0197 -0.0197 c 0,-0.0464 0.0547,-0.07075 0.09865,-0.07077 0.04394,-1.3e-5 0.09865,0.02714 0.09865,0.07077 v 0.05435 0.05472 c 0,0.438975 0.525657,0.79231 1.070216,0.79231 h 5.447919 0.405912 1.162078 c 0.544558,0 1.070216,-0.353335 1.070216,-0.79231 v -0.05472 -0.05435 c 0,-0.04363 0.0547,-0.07078 0.09865,-0.07077 0.04394,1.3e-5 0.0982,0.02437 0.0982,0.07077 v 0.0197 0.0197 c 0,0.417905 0.505185,0.754007 1.023606,0.754007 h 0.06833 58.731532 c 0.51842,0 0.93582,-0.336102 0.93582,-0.754007 v -0.628522 c 0,-0.417905 -0.4174,-0.754372 -0.93582,-0.754372 h -0.89056 c -0.002,-6e-6 -0.003,-3.65e-4 -0.004,-3.65e-4 z" />
<path
id="rect2675"
style="opacity:1;fill:#00b185;fill-opacity:1;stroke:#ffffff;stroke-width:0.917842;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
d="m 75.960365,18.022748 8.686193,-5.283117 c 0.04346,-0.02643 0.08973,0.04381 0.08973,0.09821 v 11.75165 c 0,0.0544 -0.04003,0.09821 -0.08973,0.09821 0,0 -4.343128,-2.045323 -4.343128,-3.840942 0,-0.06402 0,-0.06402 0,0 0,1.794641 -4.343065,3.840942 -4.343065,3.840942 -0.03835,0.03461 -0.08973,-0.04381 -0.08973,-0.09821 V 18.12096 c 0,-0.05441 0.04629,-0.07179 0.08973,-0.09821 z"
sodipodi:nodetypes="sssssssssss" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

View file

@ -0,0 +1,48 @@
@font-face{
font-family: "Terminus";
src: url('/styles/TerminusBold.ttf');
}
body {
margin-top: 0;
margin-bottom: 0;
margin-right: 1%;
margin-left: 1%;
font-family: Terminus;
background-color: #212121;
color: #cfcfcf;
}
.validationError {
color: red;
}
.header-container {
text-align: left;
position: relative;
color: white;
}
.header-container .header-bar {
position: absolute;
right: 10px;
}
table, th, td {
border: 1px solid;
border-collapse: collapse;
}
a {
color: #cfcfcf;
text-align: center;
}
a:link {
color: #cfcfcf;
}
a:hover {
color: white;
}
a:visited {
color: #949494;
}

View file

@ -3,10 +3,28 @@
<head> <head>
<title>Marinesco</title> <title>Marinesco</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
</head> </head>
<body> <body>
<h1>Welcome to LOGIN PAGE</h1> <h1>FUCKING BRILLIANT LOGIN PAGE</h1>
<img th:src="@{/images/logo.svg}" />
</body> </body>
<div class="container">
<br /> New here? <a href="/register">REGISTER NOW!</a>
<br /><a href="/h2">H2</a>
<form class="form-signin" method="post" action="/login">
<h2 class="form-signin-heading">Please sign in</h2>
<p>
<label for="username" class="sr-only">Username</label>
<input type="text" id="username" name="login" class="form-control" placeholder="Username" required autofocus>
</p>
<p>
<label for="password" class="sr-only">Password</label>
<input type="password" id="password" name="pwd" class="form-control" placeholder="Password" required>
</p>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div>
</html> </html>

View file

@ -3,19 +3,23 @@
<head> <head>
<title>Marinesco - registration form</title> <title>Marinesco - registration form</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
</head> </head>
<body> <body>
<h1>Register</h1> <h1>Register</h1>
<img th:src="@{/images/logo.svg}" />
<form method="POST" th:action="@{/register}" id="registerForm"> <form method="POST" th:action="@{/register}" id="registerForm">
<label for="username">Username: </label> <label for="username">Username: </label>
<input type="text" name="username" /><br /> <input type="text" name="login" /><br />
<label for="password">Password: </label> <label for="password">Password: </label>
<input type="password" name="password" /><br /> <input type="password" name="pwd" /><br />
<label for="confirm">Confirm password: </label> <label for="confirm">Confirm password: </label>
<input type="password" name="confirm" /><br /> <input type="password" name="confirm" /><br />
<label for="displayname">Displayed name: </label> <label for="displayname">Displayed name: </label>
<input type="text" name="fullname" /><br /> <input type="text" name="fullname" /><br />
<input type="submit" value="Register" />
</form> </form>
</body> </body>

View file

@ -3,10 +3,14 @@
<head> <head>
<title>Marinesco</title> <title>Marinesco</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
</head> </head>
<body> <body>
<h1>Welcome to Marinesco</h1> <h1>Welcome to Marinesco</h1>
<img th:src="@{/images/logo.svg}" />
<br /><a href="/login">Login</a>
</body> </body>
</html> </html>

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>User managment</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
</head>
<body>
<h1>User managment</h1>
<img th:src="@{/images/logo.svg}" />
<br /><a href="/logout">Log out</a>
</body>
</html>