rename folders
This commit is contained in:
@@ -1,11 +0,0 @@
|
||||
bin/
|
||||
target/
|
||||
.settings/
|
||||
.project
|
||||
.classpath
|
||||
hs_err*.log
|
||||
application.properties
|
||||
usernames.txt
|
||||
lucene
|
||||
|
||||
.vscode
|
||||
@@ -1,138 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>de.champonthis</groupId>
|
||||
<artifactId>buntspecht</artifactId>
|
||||
<version>${revision}</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>17</java.version>
|
||||
<maven.compiler.release></maven.compiler.release>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||
<querydsl.version>5.1.0</querydsl.version>
|
||||
<revision>0.4.0</revision>
|
||||
</properties>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.3.4</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-mail</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-oauth2-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Query DSL -->
|
||||
<dependency>
|
||||
<groupId>com.querydsl</groupId>
|
||||
<artifactId>querydsl-apt</artifactId>
|
||||
<version>${querydsl.version}</version>
|
||||
<classifier>jakarta</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.querydsl</groupId>
|
||||
<artifactId>querydsl-jpa</artifactId>
|
||||
<version>${querydsl.version}</version>
|
||||
<classifier>jakarta</classifier>
|
||||
</dependency>
|
||||
|
||||
<!-- Utils -->
|
||||
<dependency>
|
||||
<groupId>commons-validator</groupId>
|
||||
<artifactId>commons-validator</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk18on</artifactId>
|
||||
<version>1.78.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.passay</groupId>
|
||||
<artifactId>passay</artifactId>
|
||||
<version>1.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Datbase -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>de.champonthis.buntspecht.Application</mainClass>
|
||||
<finalName>buntspecht</finalName>
|
||||
<executable>true</executable>
|
||||
<layout>ZIP</layout>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>build-info</id>
|
||||
<goals>
|
||||
<goal>build-info</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,16 +0,0 @@
|
||||
package de.champonthis.buntspecht;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application extends SpringBootServletInitializer {
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package de.champonthis.buntspecht;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
@Configuration
|
||||
@EnableJpaAuditing
|
||||
public class JPAConfig {
|
||||
|
||||
@Autowired
|
||||
private EntityManager em;
|
||||
|
||||
@Bean
|
||||
public JPAQueryFactory jpaQueryFactory() {
|
||||
return new JPAQueryFactory(em);
|
||||
}
|
||||
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
package de.champonthis.buntspecht.businesslogic;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import de.champonthis.buntspecht.model.SystemProperty;
|
||||
import de.champonthis.buntspecht.repository.SystemPropertyRepository;
|
||||
|
||||
@Component
|
||||
public class SystemPropertyManager {
|
||||
|
||||
@Autowired
|
||||
private SystemPropertyRepository systemPropertyRepository;
|
||||
|
||||
public boolean has(String key) {
|
||||
return systemPropertyRepository.existsById(key);
|
||||
}
|
||||
|
||||
public String get(String key) {
|
||||
return systemPropertyRepository.findById(key).orElse(new SystemProperty()).getValue();
|
||||
}
|
||||
|
||||
public String get(String key, String defaultValue) {
|
||||
return systemPropertyRepository.findById(key).orElse(new SystemProperty(key, defaultValue)).getValue();
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key) {
|
||||
return getBoolean(key, false);
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
return Boolean.valueOf(get(key, String.valueOf(defaultValue)));
|
||||
}
|
||||
|
||||
public int getInteger(String key) {
|
||||
return getInteger(key, 0);
|
||||
}
|
||||
|
||||
public int getInteger(String key, int defaultValue) {
|
||||
return Integer.valueOf(get(key, String.valueOf(defaultValue)));
|
||||
}
|
||||
|
||||
public long getLong(String key) {
|
||||
return getLong(key, 0L);
|
||||
}
|
||||
|
||||
public long getLong(String key, long defaultValue) {
|
||||
return Long.valueOf(get(key, String.valueOf(defaultValue)));
|
||||
}
|
||||
|
||||
public void add(String key, String value) {
|
||||
Assert.isTrue(!systemPropertyRepository.existsById(key),
|
||||
"System Property already exists, use update method to change value!");
|
||||
systemPropertyRepository.save(new SystemProperty(key, value));
|
||||
}
|
||||
|
||||
public void update(String key, String value) {
|
||||
Assert.isTrue(systemPropertyRepository.existsById(key),
|
||||
"System Property does not exists, use add method to add new!");
|
||||
SystemProperty systemProperty = systemPropertyRepository.findById(key).get();
|
||||
systemProperty.setValue(value);
|
||||
systemPropertyRepository.save(systemProperty);
|
||||
}
|
||||
|
||||
public void set(String key, String value) {
|
||||
if (systemPropertyRepository.existsById(key)) {
|
||||
update(key, value);
|
||||
} else {
|
||||
add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-202
@@ -1,202 +0,0 @@
|
||||
package de.champonthis.buntspecht.businesslogic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.QueryResults;
|
||||
import com.querydsl.core.Tuple;
|
||||
import com.querydsl.core.types.Order;
|
||||
import com.querydsl.core.types.OrderSpecifier;
|
||||
import com.querydsl.core.types.Path;
|
||||
import com.querydsl.core.types.Predicate;
|
||||
import com.querydsl.jpa.impl.JPAQuery;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
|
||||
import de.champonthis.buntspecht.controller.model.TurnoverFilterModel;
|
||||
import de.champonthis.buntspecht.model.QTurnover;
|
||||
import de.champonthis.buntspecht.model.Turnover;
|
||||
import de.champonthis.buntspecht.repository.TurnoverRepository;
|
||||
|
||||
@Service
|
||||
public class TurnoverManager {
|
||||
|
||||
@Autowired
|
||||
private TurnoverRepository turnoverRepository;
|
||||
@Autowired
|
||||
private JPAQueryFactory jpaQueryFactory;
|
||||
|
||||
private QTurnover qTurnover = QTurnover.turnover;
|
||||
|
||||
public QueryResults<Turnover> fetch(long limit, long offset, String sortBy, boolean descending,
|
||||
TurnoverFilterModel filter) {
|
||||
return fetch(null, limit, offset, sortBy, descending, filter);
|
||||
}
|
||||
|
||||
public QueryResults<Turnover> fetch(String username, long limit, long offset, String sortBy, boolean descending,
|
||||
TurnoverFilterModel filter) {
|
||||
BooleanBuilder builder = new BooleanBuilder();
|
||||
|
||||
if (StringUtils.hasText(username)) {
|
||||
builder.and(qTurnover.username.eq(username));
|
||||
}
|
||||
|
||||
builder.and(buildFilter(filter));
|
||||
|
||||
JPAQuery<Turnover> query = jpaQueryFactory.from(qTurnover).where(builder.getValue()).select(qTurnover);
|
||||
Long total = query.clone().select(qTurnover.id.countDistinct()).fetchOne();
|
||||
|
||||
if (StringUtils.hasText(sortBy)) {
|
||||
Path<? extends Comparable<?>> path = null;
|
||||
switch (sortBy) {
|
||||
case "created":
|
||||
path = qTurnover.created;
|
||||
break;
|
||||
case "dueDate":
|
||||
path = qTurnover.dueDate;
|
||||
break;
|
||||
case "updated":
|
||||
path = qTurnover.updated;
|
||||
break;
|
||||
case "customer":
|
||||
path = qTurnover.customer;
|
||||
break;
|
||||
case "price":
|
||||
path = qTurnover.price;
|
||||
break;
|
||||
case "timeInvestment":
|
||||
path = qTurnover.timeInvestment;
|
||||
break;
|
||||
}
|
||||
if (path != null) {
|
||||
query.orderBy(new OrderSpecifier<>(descending ? Order.DESC : Order.ASC, path));
|
||||
}
|
||||
}
|
||||
|
||||
List<Turnover> result = query.limit(limit).offset(offset).fetch();
|
||||
return new QueryResults<Turnover>(result, limit, offset, total == null ? 0L : total);
|
||||
|
||||
}
|
||||
|
||||
protected Predicate buildFilter(TurnoverFilterModel filter) {
|
||||
BooleanBuilder builder = new BooleanBuilder();
|
||||
|
||||
if (filter != null) {
|
||||
if (filter.getCreated() != null) {
|
||||
if (filter.getCreated().getMin() != null) {
|
||||
builder.and(qTurnover.created.after(filter.getCreated().getMin()));
|
||||
}
|
||||
if (filter.getCreated().getMax() != null) {
|
||||
builder.and(qTurnover.created.before(filter.getCreated().getMax()));
|
||||
}
|
||||
}
|
||||
if (filter.getDueDate() != null) {
|
||||
if (filter.getDueDate().getMin() != null) {
|
||||
builder.and(qTurnover.dueDate.after(filter.getDueDate().getMin()));
|
||||
}
|
||||
if (filter.getDueDate().getMax() != null) {
|
||||
builder.and(qTurnover.dueDate.before(filter.getDueDate().getMax()));
|
||||
}
|
||||
}
|
||||
if (filter.getUpdated() != null) {
|
||||
if (filter.getUpdated().getMin() != null) {
|
||||
builder.and(qTurnover.updated.after(filter.getUpdated().getMin()));
|
||||
}
|
||||
if (filter.getUpdated().getMax() != null) {
|
||||
builder.and(qTurnover.updated.before(filter.getUpdated().getMax()));
|
||||
}
|
||||
}
|
||||
if (filter.getCustomer() != null) {
|
||||
builder.and(qTurnover.customer.contains(filter.getCustomer()));
|
||||
}
|
||||
if (filter.getMotif() != null) {
|
||||
builder.and(qTurnover.motif.contains(filter.getMotif()));
|
||||
}
|
||||
if (filter.getPrice() != null) {
|
||||
if (filter.getPrice().getMin() != null) {
|
||||
builder.and(qTurnover.price.goe(filter.getPrice().getMin()));
|
||||
}
|
||||
if (filter.getPrice().getMax() != null) {
|
||||
builder.and(qTurnover.price.loe(filter.getPrice().getMax()));
|
||||
}
|
||||
}
|
||||
if (filter.getTimeInvestment() != null) {
|
||||
if (filter.getTimeInvestment().getMin() != null) {
|
||||
builder.and(qTurnover.timeInvestment.goe(filter.getTimeInvestment().getMin()));
|
||||
}
|
||||
if (filter.getTimeInvestment().getMax() != null) {
|
||||
builder.and(qTurnover.timeInvestment.loe(filter.getTimeInvestment().getMax()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return builder.getValue();
|
||||
}
|
||||
|
||||
public Turnover get(Long id) {
|
||||
return turnoverRepository.findById(id).orElse(null);
|
||||
}
|
||||
|
||||
public Turnover save(Turnover turnover) {
|
||||
return turnoverRepository.save(turnover);
|
||||
}
|
||||
|
||||
public boolean exists(Long id) {
|
||||
return turnoverRepository.existsById(id);
|
||||
}
|
||||
|
||||
public void delete(Turnover turnover) {
|
||||
turnoverRepository.delete(turnover);
|
||||
}
|
||||
|
||||
public void deleteById(Long id) {
|
||||
turnoverRepository.deleteById(id);
|
||||
}
|
||||
|
||||
public void deleteByUsername(String username) {
|
||||
turnoverRepository.deleteAllInBatch(turnoverRepository.findAll(qTurnover.username.eq(username)));
|
||||
}
|
||||
|
||||
public QueryResults<Tuple> overview(String username, long limit, long offset, String sortBy, boolean descending,
|
||||
TurnoverFilterModel filter) {
|
||||
BooleanBuilder builder = new BooleanBuilder();
|
||||
|
||||
if (StringUtils.hasText(username)) {
|
||||
builder.and(qTurnover.username.eq(username));
|
||||
}
|
||||
|
||||
builder.and(buildFilter(filter));
|
||||
|
||||
JPAQuery<Tuple> query = jpaQueryFactory.from(qTurnover).where(builder.getValue()).groupBy(qTurnover.username)
|
||||
.select(qTurnover.username.as("username"), qTurnover.price.sum().as("price"),
|
||||
qTurnover.timeInvestment.sum().as("timeInvestment"));
|
||||
Long total = query.clone().select(qTurnover.username.countDistinct()).fetchOne();
|
||||
|
||||
if (StringUtils.hasText(sortBy)) {
|
||||
Path<? extends Comparable<?>> path = null;
|
||||
switch (sortBy) {
|
||||
case "username":
|
||||
path = qTurnover.username;
|
||||
break;
|
||||
case "price":
|
||||
path = qTurnover.price;
|
||||
break;
|
||||
case "timeInvestment":
|
||||
path = qTurnover.timeInvestment;
|
||||
break;
|
||||
}
|
||||
if (path != null) {
|
||||
query.orderBy(new OrderSpecifier<>(descending ? Order.DESC : Order.ASC, path));
|
||||
}
|
||||
}
|
||||
|
||||
List<Tuple> result = query.limit(limit).offset(offset)
|
||||
.fetch();
|
||||
|
||||
return new QueryResults<Tuple>(result, limit, offset, total == null ? 0L : total);
|
||||
}
|
||||
|
||||
}
|
||||
-211
@@ -1,211 +0,0 @@
|
||||
package de.champonthis.buntspecht.businesslogic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
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.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.QueryResults;
|
||||
import com.querydsl.core.types.Order;
|
||||
import com.querydsl.core.types.OrderSpecifier;
|
||||
import com.querydsl.core.types.Path;
|
||||
import com.querydsl.jpa.impl.JPAQuery;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
|
||||
import de.champonthis.buntspecht.model.QUser;
|
||||
import de.champonthis.buntspecht.model.User;
|
||||
import de.champonthis.buntspecht.repository.UserRepository;
|
||||
import de.champonthis.buntspecht.security.LocalUserDetails;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
@Service
|
||||
public class UserManager implements UserDetailsService, SmartInitializingSingleton {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(UserManager.class);
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
@Autowired
|
||||
private JPAQueryFactory jpaQueryFactory;
|
||||
@Autowired
|
||||
private TurnoverManager turnoverManager;
|
||||
private QUser qUser = QUser.user;
|
||||
|
||||
@Value("${admin.password:}")
|
||||
private String adminPassword;
|
||||
|
||||
public QueryResults<User> fetch(long limit, long offset, String sortBy, boolean descending, String usernameFilter) {
|
||||
BooleanBuilder builder = new BooleanBuilder();
|
||||
|
||||
if (StringUtils.hasText(usernameFilter)) {
|
||||
builder.and(qUser.username.contains(usernameFilter));
|
||||
}
|
||||
|
||||
JPAQuery<User> query = jpaQueryFactory.from(qUser).where(builder.getValue()).select(qUser);
|
||||
Long total = query.clone().select(qUser.username.countDistinct()).fetchOne();
|
||||
|
||||
if (StringUtils.hasText(sortBy)) {
|
||||
Path<? extends Comparable<?>> path = null;
|
||||
switch (sortBy) {
|
||||
case "username":
|
||||
path = qUser.username;
|
||||
break;
|
||||
case "name":
|
||||
path = qUser.name;
|
||||
break;
|
||||
}
|
||||
if (path != null) {
|
||||
query.orderBy(new OrderSpecifier<>(descending ? Order.DESC : Order.ASC, path));
|
||||
}
|
||||
}
|
||||
|
||||
List<User> result = query.limit(limit).offset(offset).fetch();
|
||||
return new QueryResults<User>(result, limit, offset, total == null ? 0L : total);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
User user = getByUsername(username);
|
||||
|
||||
if (user == null) {
|
||||
throw new UsernameNotFoundException(username);
|
||||
}
|
||||
|
||||
List<GrantedAuthority> authorities = new ArrayList<>();
|
||||
if (user.getRoles() != null) {
|
||||
for (String role : user.getRoles()) {
|
||||
authorities.add(new SimpleGrantedAuthority(role));
|
||||
}
|
||||
}
|
||||
|
||||
String passwordHash = user.getPasswordHash();
|
||||
|
||||
if (passwordHash == null) {
|
||||
passwordHash = "";
|
||||
}
|
||||
|
||||
LocalUserDetails userDetails = new LocalUserDetails(username, passwordHash, authorities);
|
||||
return userDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
if (!userRepository.exists(qUser.roles.contains("ROLE_ADMIN"))) {
|
||||
if (!StringUtils.hasText(adminPassword)) {
|
||||
adminPassword = RandomStringUtils.random(24, true, true);
|
||||
logger.error("password for 'admin': " + adminPassword);
|
||||
}
|
||||
User admin = new User();
|
||||
admin.setUsername("admin");
|
||||
admin.setRoles(List.of("ROLE_ADMIN", "ROLE_DEBUG"));
|
||||
admin.setPasswordHash(passwordEncoder.encode(adminPassword));
|
||||
admin.setLocale("de");
|
||||
userRepository.save(admin);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public User getByUsername(String username) {
|
||||
return userRepository.findOne(qUser.username.equalsIgnoreCase(username)).orElse(null);
|
||||
}
|
||||
|
||||
public User getByExternalId(String externalId) {
|
||||
return userRepository.findOne(qUser.externalId.eq(externalId)).orElse(null);
|
||||
}
|
||||
|
||||
public User getByAuth(Authentication authentication) {
|
||||
if (authentication != null) {
|
||||
if (authentication instanceof UsernamePasswordAuthenticationToken) {
|
||||
UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
|
||||
return getByUsername(token.getName());
|
||||
} else if (authentication instanceof OAuth2AuthenticationToken) {
|
||||
OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication;
|
||||
String externalId = token.getAuthorizedClientRegistrationId() + "-" +
|
||||
token.getName();
|
||||
User user = getByExternalId(externalId);
|
||||
if (user == null) {
|
||||
user = new User();
|
||||
user.setExternalId(externalId);
|
||||
String tmpUsername = token.getPrincipal().getAttribute("preferred_username");
|
||||
if (!StringUtils.hasText(tmpUsername)) {
|
||||
tmpUsername = token.getPrincipal().getAttribute("username");
|
||||
}
|
||||
if (!StringUtils.hasText(tmpUsername)) {
|
||||
tmpUsername = token.getPrincipal().getAttribute("name");
|
||||
} else {
|
||||
user.setName(token.getPrincipal().getAttribute("name"));
|
||||
}
|
||||
if (!StringUtils.hasText(tmpUsername)) {
|
||||
tmpUsername = token.getName();
|
||||
}
|
||||
if (!StringUtils.hasText(tmpUsername)) {
|
||||
tmpUsername = "user";
|
||||
}
|
||||
int count = 1;
|
||||
String username = tmpUsername;
|
||||
while (userRepository.exists(qUser.username.equalsIgnoreCase(username))) {
|
||||
username = tmpUsername + "-" + count;
|
||||
count++;
|
||||
}
|
||||
|
||||
user.setUsername(username);
|
||||
user.setEmail(token.getPrincipal().getAttribute("email"));
|
||||
user = userRepository.save(user);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public User save(User user) {
|
||||
if (exists(user.getUsername())) {
|
||||
user.setPasswordHash(this.getPasswordHash(user.getUsername()));
|
||||
}
|
||||
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
public boolean exists(String username) {
|
||||
return userRepository.exists(qUser.username.equalsIgnoreCase(username));
|
||||
}
|
||||
|
||||
public void delete(User user) {
|
||||
turnoverManager.deleteByUsername(user.getUsername());
|
||||
userRepository.delete(user);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public String getPasswordHash(String username) {
|
||||
Assert.isTrue(userRepository.existsById(username), "User with username '" + username + "' not exists!");
|
||||
return userRepository.findById(username).get().getPasswordHash();
|
||||
}
|
||||
|
||||
public User setPassword(String username, String password) {
|
||||
Assert.isTrue(userRepository.existsById(username), "User with username '" + username + "' not exists!");
|
||||
User user = userRepository.findById(username).get();
|
||||
user.setPasswordHash(passwordEncoder.encode(password));
|
||||
return userRepository.save(user);
|
||||
}
|
||||
}
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import de.champonthis.buntspecht.controller.support.EntityResponseStatusException;
|
||||
import de.champonthis.buntspecht.security.LocalUserDetails;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
public class AuthenticationController extends BaseController {
|
||||
|
||||
private static String authorizationRequestBaseUri = "oauth2/authorization";
|
||||
|
||||
@Autowired(required = false)
|
||||
private ClientRegistrationRepository clientRegistrationRepository;
|
||||
|
||||
@GetMapping
|
||||
public Object me() {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (auth != null && auth.getPrincipal() instanceof LocalUserDetails) {
|
||||
return (LocalUserDetails) auth.getPrincipal();
|
||||
}
|
||||
|
||||
throw new EntityResponseStatusException(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@GetMapping("external")
|
||||
public List<Client> getExternalLoginUrls() {
|
||||
List<Client> clients = new ArrayList<>();
|
||||
if (clientRegistrationRepository != null) {
|
||||
Iterable<ClientRegistration> clientRegistrations = null;
|
||||
ResolvableType type = ResolvableType.forInstance(clientRegistrationRepository).as(Iterable.class);
|
||||
if (type != ResolvableType.NONE && ClientRegistration.class.isAssignableFrom(type.resolveGenerics()[0])) {
|
||||
clientRegistrations = (Iterable<ClientRegistration>) clientRegistrationRepository;
|
||||
clientRegistrations.forEach(registration -> clients.add(new Client(registration.getRegistrationId(),
|
||||
authorizationRequestBaseUri + "/" + registration.getRegistrationId())));
|
||||
}
|
||||
}
|
||||
|
||||
return clients;
|
||||
}
|
||||
|
||||
protected static class Client {
|
||||
|
||||
private String id;
|
||||
|
||||
private String loginUrl;
|
||||
|
||||
public Client(String id, String loginUrl) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.loginUrl = loginUrl;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getLoginUrl() {
|
||||
return loginUrl;
|
||||
}
|
||||
|
||||
public void setLoginUrl(String loginUrl) {
|
||||
this.loginUrl = loginUrl;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
import de.champonthis.buntspecht.security.LocalUserDetails;
|
||||
|
||||
public class BaseController {
|
||||
|
||||
protected boolean authenticated() {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
return auth != null && auth.isAuthenticated();
|
||||
}
|
||||
|
||||
protected String getCurrentUsername() {
|
||||
LocalUserDetails userDetails = getLocalUserDetails();
|
||||
return userDetails != null ? userDetails.getUsername() : null;
|
||||
}
|
||||
|
||||
protected boolean hasRole(String role) {
|
||||
LocalUserDetails userDetails = getLocalUserDetails();
|
||||
return userDetails != null ? userDetails.getAuthorities().contains(new SimpleGrantedAuthority(role)) : false;
|
||||
}
|
||||
|
||||
protected LocalUserDetails getLocalUserDetails() {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
return (auth != null && auth.getPrincipal() instanceof LocalUserDetails)
|
||||
? (LocalUserDetails) auth.getPrincipal()
|
||||
: null;
|
||||
}
|
||||
}
|
||||
-174
@@ -1,174 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.querydsl.core.QueryResults;
|
||||
import com.querydsl.core.Tuple;
|
||||
|
||||
import de.champonthis.buntspecht.businesslogic.TurnoverManager;
|
||||
import de.champonthis.buntspecht.businesslogic.UserManager;
|
||||
import de.champonthis.buntspecht.controller.model.TurnoverFilterModel;
|
||||
import de.champonthis.buntspecht.controller.model.TurnoverFilterModel.MinMax;
|
||||
import de.champonthis.buntspecht.controller.support.EntityResponseStatusException;
|
||||
import de.champonthis.buntspecht.controller.support.RequestBodyErrors;
|
||||
import de.champonthis.buntspecht.controller.validation.TurnoverValidator;
|
||||
import de.champonthis.buntspecht.model.Turnover;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/turnovers")
|
||||
public class TurnoverController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private TurnoverManager turnoverManager;
|
||||
@Autowired
|
||||
private UserManager userManager;
|
||||
@Autowired
|
||||
private TurnoverValidator turnoverValidator;
|
||||
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@GetMapping
|
||||
@Transactional
|
||||
public QueryResults<Turnover> fetch(
|
||||
@RequestParam("limit") Optional<Long> limitParameter,
|
||||
@RequestParam("offset") Optional<Long> offsetParameter,
|
||||
@RequestParam("sort") Optional<String> sort,
|
||||
@RequestParam("descending") Optional<Boolean> descending,
|
||||
@RequestParam("from") Optional<Instant> from,
|
||||
@RequestParam("to") Optional<Instant> to,
|
||||
@RequestParam("created_from") Optional<Instant> fromCreated,
|
||||
@RequestParam("created_to") Optional<Instant> toCreated,
|
||||
@RequestParam("customer") Optional<String> customer,
|
||||
@RequestParam("motif") Optional<String> motif) {
|
||||
|
||||
TurnoverFilterModel filter = new TurnoverFilterModel();
|
||||
filter.setDueDate(new MinMax<Instant>(from.orElse(null), to.orElse(null)));
|
||||
filter.setCreated(new MinMax<Instant>(fromCreated.orElse(null), toCreated.orElse(null)));
|
||||
filter.setCustomer(customer.orElse(null));
|
||||
filter.setMotif(motif.orElse(null));
|
||||
|
||||
return turnoverManager.fetch(getCurrentUsername(), limitParameter.orElse(15L), offsetParameter.orElse(0L),
|
||||
sort.orElse("dueDate"), descending.orElse(false), filter);
|
||||
}
|
||||
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@GetMapping("/overview")
|
||||
@Transactional
|
||||
public Tuple overview(
|
||||
@RequestParam("limit") Optional<Long> limitParameter,
|
||||
@RequestParam("offset") Optional<Long> offsetParameter,
|
||||
@RequestParam("sort") Optional<String> sort,
|
||||
@RequestParam("descending") Optional<Boolean> descending,
|
||||
@RequestParam("from") Optional<Instant> from,
|
||||
@RequestParam("to") Optional<Instant> to,
|
||||
@RequestParam("created_from") Optional<Instant> fromCreated,
|
||||
@RequestParam("created_to") Optional<Instant> toCreated,
|
||||
@RequestParam("customer") Optional<String> customer,
|
||||
@RequestParam("motif") Optional<String> motif) {
|
||||
|
||||
TurnoverFilterModel filter = new TurnoverFilterModel();
|
||||
filter.setDueDate(new MinMax<Instant>(from.orElse(null), to.orElse(null)));
|
||||
filter.setCreated(new MinMax<Instant>(fromCreated.orElse(null), toCreated.orElse(null)));
|
||||
filter.setCustomer(customer.orElse(null));
|
||||
filter.setMotif(motif.orElse(null));
|
||||
|
||||
List<Tuple> result = turnoverManager.overview(getCurrentUsername(), limitParameter.orElse(15L),
|
||||
offsetParameter.orElse(0L), sort.orElse("username"),
|
||||
descending.orElse(false), filter).getResults();
|
||||
|
||||
if (result.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return result.get(0);
|
||||
}
|
||||
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@GetMapping("/{id}")
|
||||
@Transactional
|
||||
public Turnover get(@PathVariable("id") Long id) {
|
||||
Turnover turnover = turnoverManager.get(id);
|
||||
|
||||
if (turnover == null || !getCurrentUsername().equals(turnover.getUsername())) {
|
||||
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
return turnover;
|
||||
}
|
||||
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@PostMapping
|
||||
@Transactional
|
||||
public Turnover create(@RequestBody Turnover turnover) {
|
||||
Errors errors = new RequestBodyErrors(turnover);
|
||||
turnoverValidator.validate(turnover, errors);
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
|
||||
}
|
||||
|
||||
if (!hasRole("ROLE_ADMIN") || !StringUtils.hasText(turnover.getUsername())
|
||||
|| !userManager.exists(turnover.getUsername())) {
|
||||
turnover.setUsername(getCurrentUsername());
|
||||
}
|
||||
turnover.setCreated(Instant.now());
|
||||
turnover.setUpdated(turnover.getCreated());
|
||||
if (turnover.getDueDate() == null) {
|
||||
turnover.setDueDate(turnover.getCreated());
|
||||
}
|
||||
|
||||
return turnoverManager.save(turnover);
|
||||
}
|
||||
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@PatchMapping
|
||||
@Transactional
|
||||
public Turnover update(@RequestBody Turnover turnover) {
|
||||
Errors errors = new RequestBodyErrors(turnover);
|
||||
turnoverValidator.validate(turnover, errors);
|
||||
|
||||
if (errors.hasErrors() || turnover.getId() == null || turnover.getId() == 0L
|
||||
|| !turnoverManager.exists(turnover.getId())) {
|
||||
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
|
||||
}
|
||||
|
||||
if (!hasRole("ROLE_ADMIN")) {
|
||||
Turnover existing = turnoverManager.get(turnover.getId());
|
||||
if (!getCurrentUsername().equals(existing.getUsername())) {
|
||||
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
turnover.setUsername(getCurrentUsername());
|
||||
}
|
||||
|
||||
Turnover existing = turnoverManager.get(turnover.getId());
|
||||
|
||||
if (existing.equals(turnover)) {
|
||||
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
|
||||
}
|
||||
|
||||
if (turnover.getDueDate() == null) {
|
||||
turnover.setDueDate(turnover.getCreated());
|
||||
}
|
||||
|
||||
turnover.setUpdated(Instant.now());
|
||||
|
||||
return turnoverManager.save(turnover);
|
||||
}
|
||||
}
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import de.champonthis.buntspecht.businesslogic.UserManager;
|
||||
import de.champonthis.buntspecht.controller.model.UserPasswordModel;
|
||||
import de.champonthis.buntspecht.controller.support.EntityResponseStatusException;
|
||||
import de.champonthis.buntspecht.controller.support.RequestBodyErrors;
|
||||
import de.champonthis.buntspecht.controller.validation.PasswordModelValidator;
|
||||
import de.champonthis.buntspecht.model.User;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/users")
|
||||
public class UserController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private UserManager userManager;
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
@Autowired
|
||||
private PasswordModelValidator passwordModelValidator;
|
||||
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@GetMapping("/user")
|
||||
@Transactional
|
||||
public User get() {
|
||||
return userManager.getByUsername(getCurrentUsername());
|
||||
}
|
||||
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@PatchMapping("/user")
|
||||
@Transactional
|
||||
public User updateUser(@RequestBody User user) {
|
||||
if (!getCurrentUsername().equals(user.getUsername())) {
|
||||
throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
|
||||
}
|
||||
|
||||
User orgUser = userManager.getByUsername(user.getUsername());
|
||||
|
||||
orgUser.setName(user.getName());
|
||||
orgUser.setAbout(user.getAbout());
|
||||
orgUser.setDarkTheme(user.isDarkTheme());
|
||||
orgUser.setEmail(user.getEmail());
|
||||
orgUser.setLocale(user.getLocale());
|
||||
|
||||
user = userManager.save(orgUser);
|
||||
return user;
|
||||
}
|
||||
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@PostMapping("/password")
|
||||
public void changePassword(@RequestBody UserPasswordModel passwordModel) {
|
||||
|
||||
Errors errors = new RequestBodyErrors(passwordModel);
|
||||
|
||||
User user = userManager.getByUsername(getCurrentUsername());
|
||||
|
||||
if (!StringUtils.hasText(passwordModel.getOld())
|
||||
|| !passwordEncoder.matches(passwordModel.getOld(), userManager.getPasswordHash(user.getUsername()))) {
|
||||
errors.rejectValue("old", "UNAUTHORIZED");
|
||||
}
|
||||
|
||||
passwordModelValidator.validate(passwordModel, errors);
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
|
||||
}
|
||||
|
||||
userManager.setPassword(user.getUsername(), passwordModel.getPassword());
|
||||
}
|
||||
|
||||
}
|
||||
-118
@@ -1,118 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.admin;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.SplittableRandom;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import de.champonthis.buntspecht.model.QUser;
|
||||
import de.champonthis.buntspecht.model.Turnover;
|
||||
import de.champonthis.buntspecht.model.User;
|
||||
import de.champonthis.buntspecht.repository.TurnoverRepository;
|
||||
import de.champonthis.buntspecht.repository.UserRepository;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/debug")
|
||||
public class DebugController {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(DebugController.class);
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
@Autowired
|
||||
private TurnoverRepository turnoverRepository;
|
||||
|
||||
SplittableRandom splittableRandom = new SplittableRandom();
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_DEBUG')")
|
||||
@GetMapping("/random")
|
||||
public void random(
|
||||
@RequestParam("users") Optional<Integer> usersParameter,
|
||||
@RequestParam("minEntries") Optional<Integer> minEntriesParameter,
|
||||
@RequestParam("maxEntries") Optional<Integer> maxEntriesParameter,
|
||||
@RequestParam("days") Optional<Integer> daysParameter) {
|
||||
logger.warn("start random generation");
|
||||
|
||||
long userCount = userRepository.count(QUser.user.username.startsWith("Tätowier"));
|
||||
|
||||
List<String> newUser = new ArrayList<>();
|
||||
|
||||
for (long i = userCount + 1; i <= userCount + usersParameter.orElse(5); i++) {
|
||||
User user = new User();
|
||||
String username = (splittableRandom.nextBoolean() ? "Tätowiererin " : "Tätowierer ") + i;
|
||||
String name = "Random " + RandomStringUtils.randomAlphanumeric(splittableRandom.nextInt(4, 8));
|
||||
user.setUsername(username);
|
||||
user.setName(name);
|
||||
user.setPasswordHash(passwordEncoder.encode(username));
|
||||
user = userRepository.save(user);
|
||||
logger.trace("Created user: '" + username + "'");
|
||||
newUser.add(user.getUsername());
|
||||
}
|
||||
|
||||
logger.info("Created " + usersParameter.orElse(5) + " users");
|
||||
|
||||
Instant startInclusive = Instant.now().minus(daysParameter.orElse(350), ChronoUnit.DAYS);
|
||||
Instant endExclusive = Instant.now();
|
||||
|
||||
for (String username : newUser) {
|
||||
long numEntries = splittableRandom.nextLong(minEntriesParameter.orElse(3), maxEntriesParameter.orElse(20));
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
Turnover turnover = new Turnover();
|
||||
turnover.setUsername(username);
|
||||
turnover.setCreated(randomDate(startInclusive, endExclusive));
|
||||
turnover.setUpdated(splittableRandom.nextBoolean() ? turnover.getCreated()
|
||||
: randomDate(turnover.getCreated(), endExclusive));
|
||||
turnover.setDueDate(splittableRandom.nextBoolean() ? turnover.getCreated()
|
||||
: randomDate(startInclusive, turnover.getCreated()));
|
||||
turnover.setCustomer(RandomStringUtils.randomAlphabetic(splittableRandom.nextInt(3, 10)));
|
||||
|
||||
turnover.setMotif(RandomStringUtils.randomAlphabetic(splittableRandom.nextInt(5, 30)));
|
||||
|
||||
turnover.setPrice(Float.valueOf(String.format("%.2f", splittableRandom.nextFloat(0.01f, 2000f))));
|
||||
|
||||
if (splittableRandom.nextBoolean()) {
|
||||
turnover.setTimeInvestment(
|
||||
Float.valueOf(String.format("%.2f", splittableRandom.nextFloat(0.01f, 20f))));
|
||||
}
|
||||
|
||||
if (splittableRandom.nextBoolean()) {
|
||||
turnover.setRemark(RandomStringUtils.randomAlphabetic(splittableRandom.nextInt(10, 50)));
|
||||
}
|
||||
|
||||
if (splittableRandom.nextInt(5) < 3) {
|
||||
turnover.setMaterialConsumption(
|
||||
RandomStringUtils.randomAlphabetic(splittableRandom.nextInt(10, 250)));
|
||||
}
|
||||
|
||||
turnover = turnoverRepository.save(turnover);
|
||||
logger.trace("Created turnover: '" + turnover.getId() + "'");
|
||||
}
|
||||
logger.info("Created " + numEntries + " turnovers of '" + username + "'");
|
||||
}
|
||||
|
||||
logger.warn("finished random generation");
|
||||
}
|
||||
|
||||
protected Instant randomDate(Instant startInclusive, Instant endExclusive) {
|
||||
long startSeconds = startInclusive.getEpochSecond();
|
||||
long endSeconds = endExclusive.getEpochSecond();
|
||||
long random = splittableRandom.nextLong(startSeconds, endSeconds);
|
||||
|
||||
return Instant.ofEpochSecond(random);
|
||||
}
|
||||
}
|
||||
-78
@@ -1,78 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.admin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import de.champonthis.buntspecht.controller.BaseController;
|
||||
import de.champonthis.buntspecht.controller.support.EntityResponseStatusException;
|
||||
import de.champonthis.buntspecht.model.SystemProperty;
|
||||
import de.champonthis.buntspecht.repository.SystemPropertyRepository;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/system/properties")
|
||||
public class SystemPropertiesController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private SystemPropertyRepository systemPropertyRepository;
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@GetMapping()
|
||||
public List<SystemProperty> getProperties(@RequestParam("page") Optional<Integer> pageParameter,
|
||||
@RequestParam("size") Optional<Integer> sizeParameter) {
|
||||
Sort sort = Sort.by("key").ascending();
|
||||
return systemPropertyRepository.findAll(PageRequest.of(pageParameter.orElse(0), sizeParameter.orElse(10), sort))
|
||||
.getContent();
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@GetMapping("/{key}")
|
||||
public SystemProperty getProperty(@PathVariable("key") String key) {
|
||||
if (!systemPropertyRepository.existsById(key)) {
|
||||
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
return systemPropertyRepository.findById(key).get();
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@PostMapping("")
|
||||
public SystemProperty createOrUpdate(@RequestBody SystemProperty systemProperty) {
|
||||
return systemPropertyRepository.save(systemProperty);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@PostMapping("/list")
|
||||
public List<SystemProperty> createOrUpdateList(@RequestBody List<SystemProperty> systemProperties) {
|
||||
List<SystemProperty> result = new ArrayList<>();
|
||||
for (SystemProperty systemProperty : systemProperties) {
|
||||
result.add(
|
||||
systemPropertyRepository.save(systemProperty));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@DeleteMapping("/{key}")
|
||||
public void deleteProperty(@PathVariable("key") String key) {
|
||||
if (!systemPropertyRepository.existsById(key)) {
|
||||
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
|
||||
}
|
||||
|
||||
systemPropertyRepository.deleteById(key);
|
||||
}
|
||||
}
|
||||
-139
@@ -1,139 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.admin;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.querydsl.core.QueryResults;
|
||||
import com.querydsl.core.Tuple;
|
||||
|
||||
import de.champonthis.buntspecht.businesslogic.TurnoverManager;
|
||||
import de.champonthis.buntspecht.controller.BaseController;
|
||||
import de.champonthis.buntspecht.controller.model.TurnoverFilterModel;
|
||||
import de.champonthis.buntspecht.controller.model.TurnoverFilterModel.MinMax;
|
||||
import de.champonthis.buntspecht.controller.support.EntityResponseStatusException;
|
||||
import de.champonthis.buntspecht.controller.support.RequestBodyErrors;
|
||||
import de.champonthis.buntspecht.controller.validation.TurnoverValidator;
|
||||
import de.champonthis.buntspecht.model.Turnover;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/turnovers/manage")
|
||||
public class TurnoverManagementController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private TurnoverManager turnoverManager;
|
||||
@Autowired
|
||||
private TurnoverValidator turnoverValidator;
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@GetMapping
|
||||
@Transactional
|
||||
public QueryResults<Turnover> fetch(
|
||||
@RequestParam("username") Optional<String> usernameParameter,
|
||||
@RequestParam("limit") Optional<Long> limitParameter,
|
||||
@RequestParam("offset") Optional<Long> offsetParameter,
|
||||
@RequestParam("sort") Optional<String> sort,
|
||||
@RequestParam("descending") Optional<Boolean> descending,
|
||||
@RequestParam("from") Optional<Instant> from,
|
||||
@RequestParam("to") Optional<Instant> to,
|
||||
@RequestParam("created_from") Optional<Instant> fromCreated,
|
||||
@RequestParam("created_to") Optional<Instant> toCreated,
|
||||
@RequestParam("customer") Optional<String> customer,
|
||||
@RequestParam("motif") Optional<String> motif) {
|
||||
|
||||
TurnoverFilterModel filter = new TurnoverFilterModel();
|
||||
filter.setDueDate(new MinMax<Instant>(from.orElse(null), to.orElse(null)));
|
||||
filter.setCreated(new MinMax<Instant>(fromCreated.orElse(null), toCreated.orElse(null)));
|
||||
filter.setCustomer(customer.orElse(null));
|
||||
filter.setMotif(motif.orElse(null));
|
||||
|
||||
return turnoverManager.fetch(usernameParameter.orElse(null), limitParameter.orElse(15L),
|
||||
offsetParameter.orElse(0L), sort.orElse("dueDate"), descending.orElse(false), filter);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@GetMapping("/overview")
|
||||
@Transactional
|
||||
public QueryResults<Tuple> overview(
|
||||
@RequestParam("username") Optional<String> usernameParameter,
|
||||
@RequestParam("limit") Optional<Long> limitParameter,
|
||||
@RequestParam("offset") Optional<Long> offsetParameter,
|
||||
@RequestParam("sort") Optional<String> sort,
|
||||
@RequestParam("descending") Optional<Boolean> descending,
|
||||
@RequestParam("from") Optional<Instant> from,
|
||||
@RequestParam("to") Optional<Instant> to,
|
||||
@RequestParam("created_from") Optional<Instant> fromCreated,
|
||||
@RequestParam("created_to") Optional<Instant> toCreated,
|
||||
@RequestParam("customer") Optional<String> customer,
|
||||
@RequestParam("motif") Optional<String> motif) {
|
||||
|
||||
TurnoverFilterModel filter = new TurnoverFilterModel();
|
||||
filter.setDueDate(new MinMax<Instant>(from.orElse(null), to.orElse(null)));
|
||||
filter.setCreated(new MinMax<Instant>(fromCreated.orElse(null), toCreated.orElse(null)));
|
||||
filter.setCustomer(customer.orElse(null));
|
||||
filter.setMotif(motif.orElse(null));
|
||||
return turnoverManager.overview(usernameParameter.orElse(null), limitParameter.orElse(15L),
|
||||
offsetParameter.orElse(0L), sort.orElse("username"),
|
||||
descending.orElse(false), filter);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@GetMapping("/{id}")
|
||||
@Transactional
|
||||
public Turnover getById(@PathVariable("id") Long id) {
|
||||
if (!turnoverManager.exists(id)) {
|
||||
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
return turnoverManager.get(id);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@PatchMapping
|
||||
@Transactional
|
||||
public Turnover update(@RequestBody Turnover turnover) {
|
||||
Errors errors = new RequestBodyErrors(turnover);
|
||||
turnoverValidator.validate(turnover, errors);
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
|
||||
}
|
||||
|
||||
Turnover existing = turnoverManager.get(turnover.getId());
|
||||
if (existing.equals(turnover)) {
|
||||
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
|
||||
}
|
||||
|
||||
if (turnover.getDueDate() == null) {
|
||||
turnover.setDueDate(turnover.getCreated());
|
||||
}
|
||||
|
||||
turnover.setUpdated(Instant.now());
|
||||
|
||||
return turnoverManager.save(turnover);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@DeleteMapping("/{id}")
|
||||
@Transactional
|
||||
public void deleteById(@PathVariable("id") Long id) {
|
||||
if (!turnoverManager.exists(id)) {
|
||||
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
turnoverManager.deleteById(id);
|
||||
}
|
||||
}
|
||||
-148
@@ -1,148 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.admin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.querydsl.core.QueryResults;
|
||||
|
||||
import de.champonthis.buntspecht.businesslogic.UserManager;
|
||||
import de.champonthis.buntspecht.controller.BaseController;
|
||||
import de.champonthis.buntspecht.controller.admin.validation.UserValidator;
|
||||
import de.champonthis.buntspecht.controller.model.UserPasswordModel;
|
||||
import de.champonthis.buntspecht.controller.support.EntityResponseStatusException;
|
||||
import de.champonthis.buntspecht.controller.support.RequestBodyErrors;
|
||||
import de.champonthis.buntspecht.controller.validation.PasswordModelValidator;
|
||||
import de.champonthis.buntspecht.model.User;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/users/manage")
|
||||
public class UserManagementController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private UserManager userManager;
|
||||
@Autowired
|
||||
private UserValidator userValidator;
|
||||
@Autowired
|
||||
private PasswordModelValidator passwordModelValidator;
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@GetMapping
|
||||
@Transactional
|
||||
public QueryResults<User> fetch(
|
||||
@RequestParam("limit") Optional<Long> limitParameter,
|
||||
@RequestParam("offset") Optional<Long> offsetParameter,
|
||||
@RequestParam("sort") Optional<String> sort,
|
||||
@RequestParam("descending") Optional<Boolean> descending,
|
||||
@RequestParam("filter") Optional<String> search) {
|
||||
return userManager.fetch(limitParameter.orElse(15L), offsetParameter.orElse(0L), sort.orElse("username"),
|
||||
descending.orElse(false), search.orElse(""));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@GetMapping("/pick")
|
||||
@Transactional
|
||||
public List<User> pick(
|
||||
@RequestParam("filter") Optional<String> search) {
|
||||
return userManager.fetch(5L, 0L, "", false, search.orElse("")).getResults();
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@GetMapping("/{username}")
|
||||
@Transactional
|
||||
public User get(@PathVariable("username") String username) {
|
||||
User user = userManager.getByUsername(username);
|
||||
|
||||
if (user == null) {
|
||||
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@PostMapping
|
||||
@Transactional
|
||||
public User create(@RequestBody User user) {
|
||||
Errors errors = new RequestBodyErrors(user);
|
||||
userValidator.validateNew(user, errors);
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
|
||||
}
|
||||
|
||||
if (user.getLocale() == null) {
|
||||
user.setLocale("de");
|
||||
}
|
||||
|
||||
return userManager.save(user);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@PatchMapping
|
||||
@Transactional
|
||||
public User update(@RequestBody User user) {
|
||||
Errors errors = new RequestBodyErrors(user);
|
||||
userValidator.validate(user, errors);
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
|
||||
}
|
||||
|
||||
if (getCurrentUsername().equals(user.getUsername()) && user.getRoles().indexOf("ROLE_ADMIN") == -1) {
|
||||
user.getRoles().add("ROLE_ADMIN");
|
||||
}
|
||||
|
||||
return userManager.save(user);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@DeleteMapping("/{username}")
|
||||
@Transactional
|
||||
public void delete(@PathVariable("username") String username) {
|
||||
User user = userManager.getByUsername(username);
|
||||
|
||||
if (user == null || getCurrentUsername().equals(username)) {
|
||||
throw new EntityResponseStatusException(HttpStatus.NOT_MODIFIED);
|
||||
}
|
||||
|
||||
userManager.delete(user);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@PostMapping("/{username}/password")
|
||||
public void password(@PathVariable("username") String username,
|
||||
@RequestBody UserPasswordModel passwordModel) {
|
||||
|
||||
Errors errors = new RequestBodyErrors(passwordModel);
|
||||
|
||||
User user = userManager.getByUsername(username);
|
||||
|
||||
if (user == null) {
|
||||
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
passwordModelValidator.validate(passwordModel, errors);
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
|
||||
}
|
||||
|
||||
userManager.setPassword(user.getUsername(), passwordModel.getPassword());
|
||||
}
|
||||
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.admin.validation;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
import de.champonthis.buntspecht.businesslogic.UserManager;
|
||||
import de.champonthis.buntspecht.model.User;
|
||||
|
||||
@Component
|
||||
public class UserValidator implements Validator {
|
||||
|
||||
@Autowired
|
||||
private UserManager userManager;
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return clazz.isAssignableFrom(User.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object target, Errors errors) {
|
||||
User user = (User) target;
|
||||
if (!StringUtils.hasText(user.getUsername())) {
|
||||
errors.rejectValue("username", "REQUIRED");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void validateNew(Object target, Errors errors) {
|
||||
validate(target, errors);
|
||||
|
||||
if (errors.hasErrors()) {
|
||||
return;
|
||||
}
|
||||
|
||||
User user = (User) target;
|
||||
if (userManager.exists(user.getUsername())) {
|
||||
errors.rejectValue("username", "ALREADY_EXISTS");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.model;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.querydsl.core.Tuple;
|
||||
|
||||
@JsonComponent
|
||||
public class TupleSerializer extends JsonSerializer<Tuple> {
|
||||
|
||||
@Override
|
||||
public void serialize(Tuple value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
if (value.toArray().length > 1) {
|
||||
gen.writeStartArray();
|
||||
}
|
||||
for (Object object : value.toArray()) {
|
||||
gen.writeObject(object);
|
||||
}
|
||||
if (value.toArray().length > 1) {
|
||||
gen.writeEndArray();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.model;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
public class TurnoverFilterModel {
|
||||
|
||||
private MinMax<Instant> created;
|
||||
private MinMax<Instant> dueDate;
|
||||
private MinMax<Instant> updated;
|
||||
private String customer;
|
||||
private String motif;
|
||||
private MinMax<Float> price;
|
||||
private MinMax<Float> timeInvestment;
|
||||
|
||||
public MinMax<Instant> getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(MinMax<Instant> created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
public MinMax<Instant> getDueDate() {
|
||||
return dueDate;
|
||||
}
|
||||
|
||||
public void setDueDate(MinMax<Instant> dueDate) {
|
||||
this.dueDate = dueDate;
|
||||
}
|
||||
|
||||
public MinMax<Instant> getUpdated() {
|
||||
return updated;
|
||||
}
|
||||
|
||||
public void setUpdated(MinMax<Instant> updated) {
|
||||
this.updated = updated;
|
||||
}
|
||||
|
||||
public String getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(String customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public String getMotif() {
|
||||
return motif;
|
||||
}
|
||||
|
||||
public void setMotif(String motif) {
|
||||
this.motif = motif;
|
||||
}
|
||||
|
||||
public MinMax<Float> getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(MinMax<Float> price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public MinMax<Float> getTimeInvestment() {
|
||||
return timeInvestment;
|
||||
}
|
||||
|
||||
public void setTimeInvestment(MinMax<Float> timeInvestment) {
|
||||
this.timeInvestment = timeInvestment;
|
||||
}
|
||||
|
||||
public static class MinMax<T> {
|
||||
|
||||
private T min;
|
||||
private T max;
|
||||
|
||||
public MinMax(T min, T max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public T getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public void setMin(T min) {
|
||||
this.min = min;
|
||||
}
|
||||
|
||||
public T getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public void setMax(T max) {
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.model;
|
||||
|
||||
public class UserPasswordModel {
|
||||
|
||||
private String old;
|
||||
private String password;
|
||||
private String password2;
|
||||
|
||||
public String getOld() {
|
||||
return old;
|
||||
}
|
||||
|
||||
public void setOld(String old) {
|
||||
this.old = old;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getPassword2() {
|
||||
return password2;
|
||||
}
|
||||
|
||||
public void setPassword2(String password2) {
|
||||
this.password2 = password2;
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.support;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
|
||||
@ControllerAdvice
|
||||
public class ControllerExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
|
||||
|
||||
@ExceptionHandler(value = { EntityResponseStatusException.class })
|
||||
protected ResponseEntity<Object> handleResponseEntityStatusException(RuntimeException exception,
|
||||
WebRequest request) {
|
||||
EntityResponseStatusException entityResponseStatusException = (EntityResponseStatusException) exception;
|
||||
return handleExceptionInternal(exception, entityResponseStatusException.getBody(), new HttpHeaders(),
|
||||
entityResponseStatusException.getStatus(), request);
|
||||
}
|
||||
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.support;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
|
||||
|
||||
public class EntityResponseStatusException extends NestedRuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final HttpStatus status;
|
||||
|
||||
@Nullable
|
||||
private final Object body;
|
||||
|
||||
|
||||
public EntityResponseStatusException(HttpStatus status) {
|
||||
this(null, status);
|
||||
}
|
||||
|
||||
|
||||
public EntityResponseStatusException(@Nullable Object body, HttpStatus status) {
|
||||
this(body, status, null);
|
||||
}
|
||||
|
||||
|
||||
public EntityResponseStatusException(@Nullable Object body, HttpStatus status, @Nullable Throwable cause) {
|
||||
super(null, cause);
|
||||
Assert.notNull(status, "HttpStatus is required");
|
||||
this.status = status;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
|
||||
public HttpStatus getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public Object getBody() {
|
||||
return this.body;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.springframework.core.NestedRuntimeException#getMessage()
|
||||
*/
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return this.status + (this.body != null ? " \"" + this.body + "\"" : "");
|
||||
}
|
||||
|
||||
}
|
||||
-101
@@ -1,101 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
|
||||
@ControllerAdvice
|
||||
public class JsonStringBodyControllerAdvice implements RequestBodyAdvice, ResponseBodyAdvice<String> {
|
||||
|
||||
private Gson gson = new Gson();
|
||||
|
||||
/*
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice#
|
||||
* supports(org.springframework.core.MethodParameter, java.lang.reflect.Type,
|
||||
* java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(MethodParameter methodParameter, Type targetType,
|
||||
Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
return targetType instanceof Class && String.class.equals((Class<?>) targetType);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice#
|
||||
* beforeBodyRead(org.springframework.http.HttpInputMessage,
|
||||
* org.springframework.core.MethodParameter, java.lang.reflect.Type,
|
||||
* java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
|
||||
Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
|
||||
return inputMessage;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice#
|
||||
* afterBodyRead(java.lang.Object, org.springframework.http.HttpInputMessage,
|
||||
* org.springframework.core.MethodParameter, java.lang.reflect.Type,
|
||||
* java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
|
||||
Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
body = ((String) body).replaceAll("^\"|\"$", "");
|
||||
return body;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice#
|
||||
* handleEmptyBody(java.lang.Object, org.springframework.http.HttpInputMessage,
|
||||
* org.springframework.core.MethodParameter, java.lang.reflect.Type,
|
||||
* java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
|
||||
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
return body;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#
|
||||
* supports(org.springframework.core.MethodParameter, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
return converterType == StringHttpMessageConverter.class;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice#
|
||||
* beforeBodyWrite(java.lang.Object, org.springframework.core.MethodParameter,
|
||||
* org.springframework.http.MediaType, java.lang.Class,
|
||||
* org.springframework.http.server.ServerHttpRequest,
|
||||
* org.springframework.http.server.ServerHttpResponse)
|
||||
*/
|
||||
@Override
|
||||
public String beforeBodyWrite(String body, MethodParameter returnType, MediaType selectedContentType,
|
||||
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
|
||||
ServerHttpResponse response) {
|
||||
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||
return gson.toJson(new JsonPrimitive(body));
|
||||
}
|
||||
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.support;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.validation.AbstractBindingResult;
|
||||
|
||||
|
||||
public class RequestBodyErrors extends AbstractBindingResult {
|
||||
|
||||
@Nullable
|
||||
private final Object target;
|
||||
|
||||
|
||||
public RequestBodyErrors(@Nullable Object target) {
|
||||
super("request-body");
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.springframework.validation.AbstractBindingResult#getTarget()
|
||||
*/
|
||||
@Override
|
||||
public Object getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
/*
|
||||
* @see
|
||||
* org.springframework.validation.AbstractBindingResult#getActualFieldValue(java
|
||||
* .lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected Object getActualFieldValue(String field) {
|
||||
// Not necessary
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.validation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.passay.CharacterRule;
|
||||
import org.passay.EnglishCharacterData;
|
||||
import org.passay.LengthRule;
|
||||
import org.passay.PasswordData;
|
||||
import org.passay.PasswordValidator;
|
||||
import org.passay.Rule;
|
||||
import org.passay.RuleResult;
|
||||
import org.passay.RuleResultDetail;
|
||||
import org.passay.WhitespaceRule;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
import de.champonthis.buntspecht.businesslogic.SystemPropertyManager;
|
||||
import de.champonthis.buntspecht.controller.model.UserPasswordModel;
|
||||
|
||||
@Component
|
||||
public class PasswordModelValidator implements Validator {
|
||||
|
||||
@Autowired
|
||||
private SystemPropertyManager systemPropertyManager;
|
||||
|
||||
public static final String SYSTEM_PROPERTY_PASSWORD_RULE_WHITESPACE = "password.rule.whitespace";
|
||||
public static final String SYSTEM_PROPERTY_PASSWORD_RULE_LENGTH = "password.rule.length";
|
||||
public static final String SYSTEM_PROPERTY_PASSWORD_RULE_UPPERCASE = "password.rule.uppercase";
|
||||
public static final String SYSTEM_PROPERTY_PASSWORD_RULE_DIGIT = "password.rule.digit";
|
||||
public static final String SYSTEM_PROPERTY_PASSWORD_RULE_SPECIAL = "password.rule.special";
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return clazz.isAssignableFrom(UserPasswordModel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object target, Errors errors) {
|
||||
UserPasswordModel passwordModel = (UserPasswordModel) target;
|
||||
|
||||
List<Rule> rules = new ArrayList<Rule>();
|
||||
|
||||
if (systemPropertyManager.getBoolean(SYSTEM_PROPERTY_PASSWORD_RULE_WHITESPACE, true)) {
|
||||
rules.add(new WhitespaceRule());
|
||||
}
|
||||
|
||||
int length = systemPropertyManager.getInteger(SYSTEM_PROPERTY_PASSWORD_RULE_LENGTH, 8);
|
||||
if (length > 0) {
|
||||
rules.add(new LengthRule(length, 4096));
|
||||
}
|
||||
|
||||
int uppercase = systemPropertyManager.getInteger(SYSTEM_PROPERTY_PASSWORD_RULE_UPPERCASE, 1);
|
||||
if (uppercase > 0) {
|
||||
rules.add(new CharacterRule(EnglishCharacterData.UpperCase, uppercase));
|
||||
}
|
||||
|
||||
int digit = systemPropertyManager.getInteger(SYSTEM_PROPERTY_PASSWORD_RULE_DIGIT, 1);
|
||||
if (digit > 0) {
|
||||
rules.add(new CharacterRule(EnglishCharacterData.Digit, digit));
|
||||
}
|
||||
|
||||
int special = systemPropertyManager.getInteger(SYSTEM_PROPERTY_PASSWORD_RULE_SPECIAL, 1);
|
||||
if (special > 0) {
|
||||
rules.add(new CharacterRule(EnglishCharacterData.Special, special));
|
||||
}
|
||||
|
||||
PasswordValidator validator = new PasswordValidator(rules);
|
||||
PasswordData password = new PasswordData(passwordModel.getPassword());
|
||||
RuleResult result = validator.validate(password);
|
||||
|
||||
if (!result.isValid()) {
|
||||
for (RuleResultDetail ruleResultDetail : result.getDetails()) {
|
||||
errors.rejectValue("password", ruleResultDetail.getErrorCode());
|
||||
}
|
||||
}
|
||||
|
||||
if (!passwordModel.getPassword().equals(passwordModel.getPassword2())) {
|
||||
errors.rejectValue("password2", "NOT_MATCH");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
package de.champonthis.buntspecht.controller.validation;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
import de.champonthis.buntspecht.model.Turnover;
|
||||
|
||||
@Component
|
||||
public class TurnoverValidator implements Validator {
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return clazz.isAssignableFrom(Turnover.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object target, Errors errors) {
|
||||
Turnover turnover = (Turnover) target;
|
||||
|
||||
if (!StringUtils.hasText(turnover.getCustomer())) {
|
||||
errors.rejectValue("customer", "REQUIRED");
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(turnover.getMotif())) {
|
||||
errors.rejectValue("motif", "REQUIRED");
|
||||
}
|
||||
|
||||
if (turnover.getPrice() == 0) {
|
||||
errors.rejectValue("price", "REQUIRED");
|
||||
}
|
||||
|
||||
if (turnover.getPrice() < 0) {
|
||||
errors.rejectValue("price", "POSITIVE_VALUE");
|
||||
}
|
||||
}
|
||||
}
|
||||
-143
@@ -1,143 +0,0 @@
|
||||
package de.champonthis.buntspecht.i18n.businesslogic;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import de.champonthis.buntspecht.i18n.model.I18n;
|
||||
import de.champonthis.buntspecht.i18n.repository.I18nRepository;
|
||||
|
||||
|
||||
@Component
|
||||
public class I18nManager implements SmartInitializingSingleton {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(I18nManager.class);
|
||||
|
||||
@Autowired
|
||||
private I18nRepository i18nRepository;
|
||||
|
||||
@Autowired
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
private Gson gson = new Gson();
|
||||
|
||||
|
||||
public I18n get(String locale) {
|
||||
return i18nRepository.findById(locale).orElse(null);
|
||||
}
|
||||
|
||||
|
||||
public JsonObject getLabel(String locale) {
|
||||
I18n i18n = get(locale);
|
||||
if (i18n != null && StringUtils.hasText(i18n.getLabel())) {
|
||||
JsonElement element = JsonParser.parseString(i18n.getLabel());
|
||||
if (element != null && element.isJsonObject()) {
|
||||
return element.getAsJsonObject();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public List<String> getLocales() {
|
||||
return i18nRepository.findAll().stream().map(I18n::getLocale).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
protected void extendJsonObject(JsonObject dest, JsonObject src) {
|
||||
for (Entry<String, JsonElement> srcEntry : src.entrySet()) {
|
||||
String srcKey = srcEntry.getKey();
|
||||
JsonElement srcValue = srcEntry.getValue();
|
||||
if (dest.has(srcKey)) {
|
||||
JsonElement destValue = dest.get(srcKey);
|
||||
if (destValue.isJsonObject() && srcValue.isJsonObject()) {
|
||||
extendJsonObject(destValue.getAsJsonObject(), srcValue.getAsJsonObject());
|
||||
} else {
|
||||
dest.add(srcKey, srcValue);
|
||||
}
|
||||
} else {
|
||||
dest.add(srcKey, srcValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public I18n addLabel(String locale, JsonObject newLabel) {
|
||||
JsonObject label = getLabel(locale);
|
||||
|
||||
if (label == null || label.size() == 0 || label.entrySet().isEmpty()) {
|
||||
label = newLabel;
|
||||
} else {
|
||||
extendJsonObject(label, newLabel);
|
||||
}
|
||||
|
||||
I18n i18n = new I18n();
|
||||
i18n.setLocale(locale);
|
||||
i18n.setLabel(gson.toJson(label));
|
||||
|
||||
return i18nRepository.save(i18n);
|
||||
}
|
||||
|
||||
|
||||
public I18n setLabel(String locale, JsonObject label) {
|
||||
I18n i18n = new I18n();
|
||||
i18n.setLocale(locale);
|
||||
i18n.setLabel(gson.toJson(label));
|
||||
|
||||
return i18nRepository.save(i18n);
|
||||
}
|
||||
|
||||
|
||||
public void deleteLabel(String locale) {
|
||||
if (i18nRepository.existsById(locale)) {
|
||||
i18nRepository.deleteById(locale);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.springframework.beans.factory.SmartInitializingSingleton#
|
||||
* afterSingletonsInstantiated()
|
||||
*/
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
try {
|
||||
Resource resource = resourceLoader.getResource("classpath:label");
|
||||
|
||||
if (resource.exists()) {
|
||||
File labelFolder = resource.getFile();
|
||||
if (labelFolder.exists() && labelFolder.isDirectory()) {
|
||||
for (File labelFile : labelFolder.listFiles()) {
|
||||
JsonObject label = JsonParser.parseReader(new FileReader(labelFile, StandardCharsets.UTF_8))
|
||||
.getAsJsonObject();
|
||||
|
||||
String locale = labelFile.getName().replace(".json", "");
|
||||
addLabel(locale, label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
logger.warn("cannot read in label folder", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
package de.champonthis.buntspecht.i18n.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonIOException;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import de.champonthis.buntspecht.controller.BaseController;
|
||||
import de.champonthis.buntspecht.i18n.businesslogic.I18nManager;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/i18n")
|
||||
public class I18nController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
private I18nManager i18nManager;
|
||||
|
||||
private Gson gson = new Gson();
|
||||
|
||||
|
||||
@GetMapping
|
||||
public List<String> getLocales() {
|
||||
return i18nManager.getLocales();
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/{locale}")
|
||||
public void getLabel(@PathVariable("locale") String locale, HttpServletResponse response)
|
||||
throws JsonIOException, IOException {
|
||||
JsonObject label = i18nManager.getLabel(locale);
|
||||
if (label != null) {
|
||||
response.setCharacterEncoding("utf-8");
|
||||
gson.toJson(label, response.getWriter());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@PostMapping("/{locale}")
|
||||
public void setLabel(@PathVariable("locale") String locale, @RequestBody Object label) {
|
||||
JsonElement element = gson.toJsonTree(label);
|
||||
|
||||
if (element != null && element.isJsonObject()) {
|
||||
i18nManager.setLabel(locale, element.getAsJsonObject());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@PutMapping("/{locale}")
|
||||
public void addLabel(@PathVariable("locale") String locale, @RequestBody Object label) {
|
||||
JsonElement element = gson.toJsonTree(label);
|
||||
|
||||
if (element != null && element.isJsonObject()) {
|
||||
i18nManager.addLabel(locale, element.getAsJsonObject());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN')")
|
||||
@DeleteMapping("/{locale}")
|
||||
public void deleteLocale(@PathVariable("locale") String locale) {
|
||||
i18nManager.deleteLabel(locale);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package de.champonthis.buntspecht.i18n.model;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Lob;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name = "i18n", uniqueConstraints = @UniqueConstraint(columnNames = { "locale" }))
|
||||
public class I18n {
|
||||
|
||||
@Id
|
||||
@Column(name = "locale", unique = true, nullable = false)
|
||||
private String locale;
|
||||
|
||||
@Lob
|
||||
@Column(name = "label", length = 100000)
|
||||
private String label;
|
||||
|
||||
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
|
||||
public void setLocale(String locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
package de.champonthis.buntspecht.i18n.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import de.champonthis.buntspecht.i18n.model.I18n;
|
||||
|
||||
|
||||
@Repository
|
||||
public interface I18nRepository extends JpaRepository<I18n, String>, QuerydslPredicateExecutor<I18n> {
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package de.champonthis.buntspecht.model;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "persistent_logins")
|
||||
public class PersistentLogin {
|
||||
|
||||
@Column(name = "username", length = 64, nullable = false)
|
||||
private String username;
|
||||
@Id
|
||||
@Column(name = "series", length = 64)
|
||||
private String series;
|
||||
@Column(name = "token", length = 64, nullable = false)
|
||||
private String token;
|
||||
@Column(name = "last_used", nullable = false)
|
||||
private Instant last_used;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getSeries() {
|
||||
return series;
|
||||
}
|
||||
|
||||
public void setSeries(String series) {
|
||||
this.series = series;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public Instant getLast_used() {
|
||||
return last_used;
|
||||
}
|
||||
|
||||
public void setLast_used(Instant last_used) {
|
||||
this.last_used = last_used;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package de.champonthis.buntspecht.model;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Lob;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name = "system_properties")
|
||||
public class SystemProperty {
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
private String key;
|
||||
@Lob
|
||||
@Column(name = "value", length = 100000)
|
||||
private String value;
|
||||
|
||||
|
||||
public SystemProperty() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
public SystemProperty(String key, String value) {
|
||||
super();
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
package de.champonthis.buntspecht.model;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Lob;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "turnovers")
|
||||
public class Turnover {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", updatable = false, unique = true, nullable = false)
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "username", nullable = false)
|
||||
private String username;
|
||||
|
||||
@Column(name = "created", nullable = false, updatable = false)
|
||||
private Instant created;
|
||||
|
||||
@Column(name = "due_date", nullable = false)
|
||||
private Instant dueDate;
|
||||
|
||||
@Column(name = "updated", nullable = false)
|
||||
private Instant updated;
|
||||
|
||||
@Column(name = "customer", nullable = false)
|
||||
private String customer;
|
||||
|
||||
@Column(name = "motif", nullable = false)
|
||||
private String motif;
|
||||
|
||||
@Column(name = "price", nullable = false)
|
||||
private float price;
|
||||
|
||||
@Column(name = "time_investment", nullable = true)
|
||||
private float timeInvestment;
|
||||
|
||||
@Lob
|
||||
@Column(name = "remark", nullable = true, length = 5000)
|
||||
private String remark;
|
||||
|
||||
@Lob
|
||||
@Column(name = "material_consumption", nullable = true, length = 5000)
|
||||
private String materialConsumption;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public Instant getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(Instant created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
public Instant getDueDate() {
|
||||
return dueDate;
|
||||
}
|
||||
|
||||
public void setDueDate(Instant dueDate) {
|
||||
this.dueDate = dueDate;
|
||||
}
|
||||
|
||||
public Instant getUpdated() {
|
||||
return updated;
|
||||
}
|
||||
|
||||
public void setUpdated(Instant updated) {
|
||||
this.updated = updated;
|
||||
}
|
||||
|
||||
public String getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(String customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public String getMotif() {
|
||||
return motif;
|
||||
}
|
||||
|
||||
public void setMotif(String motif) {
|
||||
this.motif = motif;
|
||||
}
|
||||
|
||||
public float getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(float price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public float getTimeInvestment() {
|
||||
return timeInvestment;
|
||||
}
|
||||
|
||||
public void setTimeInvestment(float timeInvestment) {
|
||||
this.timeInvestment = timeInvestment;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
|
||||
public String getMaterialConsumption() {
|
||||
return materialConsumption;
|
||||
}
|
||||
|
||||
public void setMaterialConsumption(String materialConsumption) {
|
||||
this.materialConsumption = materialConsumption;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Turnover)) {
|
||||
return false;
|
||||
}
|
||||
Turnover turnover = (Turnover) obj;
|
||||
boolean equals = true;
|
||||
|
||||
equals &= dueDate.equals(turnover.getDueDate());
|
||||
|
||||
equals &= id == null && turnover.getId() == null || id.equals(turnover.getId());
|
||||
|
||||
equals &= username == null && turnover.getUsername() == null || username.equals(turnover.getUsername());
|
||||
|
||||
equals &= customer == null && turnover.getCustomer() == null || customer.equals(turnover.getCustomer());
|
||||
|
||||
equals &= motif == null && turnover.getMotif() == null || motif.equals(turnover.getMotif());
|
||||
|
||||
equals &= price == turnover.getPrice();
|
||||
|
||||
equals &= timeInvestment == turnover.getTimeInvestment();
|
||||
|
||||
equals &= remark == null && turnover.getRemark() == null || remark.equals(turnover.getRemark());
|
||||
|
||||
equals &= materialConsumption == null && turnover.getMaterialConsumption() == null
|
||||
|| materialConsumption.equals(turnover.getMaterialConsumption());
|
||||
|
||||
return equals;
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
package de.champonthis.buntspecht.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
import jakarta.persistence.CollectionTable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.ElementCollection;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Lob;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Transient;
|
||||
|
||||
@Entity
|
||||
@Table(name = "users")
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@Column(name = "username", nullable = false)
|
||||
private String username;
|
||||
@Column(name = "external_id", nullable = true)
|
||||
private String externalId;
|
||||
@Column(name = "name", nullable = true)
|
||||
private String name;
|
||||
@JsonIgnore
|
||||
@Column(name = "password_hash", nullable = true)
|
||||
private String passwordHash;
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "users_roles")
|
||||
private List<String> roles;
|
||||
@Lob
|
||||
@Column(name = "about", nullable = true, length = 100000)
|
||||
private String about;
|
||||
@Column(name = "email", nullable = true)
|
||||
private String email;
|
||||
@Column(name = "locale", nullable = true, columnDefinition = "varchar(255) default 'de'")
|
||||
private String locale;
|
||||
@Column(name = "dark_theme", nullable = true, columnDefinition = "boolean default false")
|
||||
private boolean darkTheme;
|
||||
@Transient
|
||||
private Map<String, Object> metadata;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getExternalId() {
|
||||
return externalId;
|
||||
}
|
||||
|
||||
public void setExternalId(String externalId) {
|
||||
this.externalId = externalId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPasswordHash() {
|
||||
return passwordHash;
|
||||
}
|
||||
|
||||
public void setPasswordHash(String passwordHash) {
|
||||
this.passwordHash = passwordHash;
|
||||
}
|
||||
|
||||
public List<String> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
public void setRoles(List<String> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
public String getAbout() {
|
||||
return about;
|
||||
}
|
||||
|
||||
public void setAbout(String about) {
|
||||
this.about = about;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
public void setLocale(String locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public boolean isDarkTheme() {
|
||||
return darkTheme;
|
||||
}
|
||||
|
||||
public void setDarkTheme(boolean darkTheme) {
|
||||
this.darkTheme = darkTheme;
|
||||
}
|
||||
|
||||
public Map<String, Object> getMetadata() {
|
||||
if (metadata == null) {
|
||||
metadata = Map.of();
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public void setMetadata(Map<String, Object> metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package de.champonthis.buntspecht.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import de.champonthis.buntspecht.model.SystemProperty;
|
||||
|
||||
|
||||
@Repository
|
||||
public interface SystemPropertyRepository
|
||||
extends JpaRepository<SystemProperty, String>, QuerydslPredicateExecutor<SystemProperty> {
|
||||
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
package de.champonthis.buntspecht.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import de.champonthis.buntspecht.model.Turnover;
|
||||
|
||||
@Repository
|
||||
public interface TurnoverRepository extends JpaRepository<Turnover, Long>, QuerydslPredicateExecutor<Turnover> {
|
||||
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
package de.champonthis.buntspecht.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import de.champonthis.buntspecht.model.User;
|
||||
|
||||
|
||||
@Repository
|
||||
public interface UserRepository extends JpaRepository<User, String>, QuerydslPredicateExecutor<User> {
|
||||
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
package de.champonthis.buntspecht.security;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
|
||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||
|
||||
|
||||
public class LocalRememberMeServices extends PersistentTokenBasedRememberMeServices {
|
||||
|
||||
|
||||
public LocalRememberMeServices(String key, UserDetailsService userDetailsService,
|
||||
PersistentTokenRepository tokenRepository) {
|
||||
super(key, userDetailsService, tokenRepository);
|
||||
}
|
||||
|
||||
/*
|
||||
* @see org.springframework.security.web.authentication.rememberme.
|
||||
* AbstractRememberMeServices#rememberMeRequested(javax.servlet.http.
|
||||
* HttpServletRequest, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected boolean rememberMeRequested(HttpServletRequest request, String parameter) {
|
||||
Object value = request.getAttribute(parameter);
|
||||
if (value != null) {
|
||||
String paramValue = value.toString();
|
||||
if (paramValue.equalsIgnoreCase("true") || paramValue.equalsIgnoreCase("on")
|
||||
|| paramValue.equalsIgnoreCase("yes") || paramValue.equals("1")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.rememberMeRequested(request, parameter);
|
||||
}
|
||||
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
package de.champonthis.buntspecht.security;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
|
||||
|
||||
public class LocalUserDetails extends User {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
public LocalUserDetails(String username, String password, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(username, password, authorities);
|
||||
}
|
||||
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
package de.champonthis.buntspecht.security;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
|
||||
|
||||
@Configuration
|
||||
public class PasswordEncoderConfig {
|
||||
|
||||
|
||||
@Bean(name = "passwordEncoder")
|
||||
public Argon2PasswordEncoder passwordEncoder() {
|
||||
return Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8();
|
||||
}
|
||||
}
|
||||
-113
@@ -1,113 +0,0 @@
|
||||
package de.champonthis.buntspecht.security;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
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.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
|
||||
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
|
||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
|
||||
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import de.champonthis.buntspecht.businesslogic.UserManager;
|
||||
import de.champonthis.buntspecht.security.handler.FormAuthenticationFailureHandler;
|
||||
import de.champonthis.buntspecht.security.handler.OAuth2AuthenticationSuccessHandler;
|
||||
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity(prePostEnabled = true)
|
||||
@Configuration
|
||||
public class SecurityConfig {
|
||||
|
||||
@Autowired
|
||||
private UserManager userManager;
|
||||
@Autowired
|
||||
private OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler;
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
@Value("${loginUrl:/login}")
|
||||
private String loginUrl;
|
||||
@Value("${loginTargetUrl:/}")
|
||||
private String loginTargetUrl;
|
||||
@Value("${spring.security.oauth2.client:false}")
|
||||
private boolean oauth2Enabled;
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
|
||||
if (oauth2Enabled) {
|
||||
oAuth2AuthenticationSuccessHandler.setDefaultTargetUrl(loginTargetUrl);
|
||||
oAuth2AuthenticationSuccessHandler.setRememberMeServices(rememberMeServices());
|
||||
}
|
||||
|
||||
http
|
||||
// crsf
|
||||
.csrf((csrf) -> csrf.disable())
|
||||
// cors
|
||||
// .cors().configurationSource(corsConfigurationSource()).and()
|
||||
// anonymous
|
||||
.anonymous((anonymous) -> anonymous.disable())
|
||||
// login
|
||||
.formLogin((formLogin) -> formLogin.loginPage("/login").defaultSuccessUrl(loginTargetUrl)
|
||||
.failureHandler(new FormAuthenticationFailureHandler(loginUrl)))
|
||||
// remember me
|
||||
.rememberMe((rememberMe) -> rememberMe.rememberMeServices(rememberMeServices()))
|
||||
// logout
|
||||
.logout((logout) -> logout.logoutUrl("/logout")
|
||||
.logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK)))
|
||||
// exception
|
||||
.exceptionHandling((exceptionHandling) -> exceptionHandling
|
||||
.defaultAuthenticationEntryPointFor(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED),
|
||||
new AntPathRequestMatcher("/api/**")));
|
||||
|
||||
if (oauth2Enabled) {
|
||||
http.oauth2Login((oauth2Login) -> oauth2Login.successHandler(oAuth2AuthenticationSuccessHandler)
|
||||
.failureHandler(new SimpleUrlAuthenticationFailureHandler(loginUrl + "?externalError"))
|
||||
.loginPage("/login"));
|
||||
}
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PersistentTokenRepository persistentTokenRepository() {
|
||||
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
|
||||
tokenRepository.setDataSource(dataSource);
|
||||
return tokenRepository;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RememberMeServices rememberMeServices() {
|
||||
PersistentTokenBasedRememberMeServices rememberMeServices = new LocalRememberMeServices("remember-me",
|
||||
userManager, persistentTokenRepository());
|
||||
return rememberMeServices;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
configuration.setAllowedOriginPatterns(List.of("*"));
|
||||
configuration.setAllowedMethods(Collections.singletonList("*"));
|
||||
configuration.setAllowCredentials(true);
|
||||
configuration.setAllowedHeaders(Collections.singletonList("*"));
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
return source;
|
||||
}
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package de.champonthis.buntspecht.security.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
public class FormAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
|
||||
|
||||
private String failureUrl;
|
||||
|
||||
public FormAuthenticationFailureHandler(String failureUrl) {
|
||||
super(failureUrl);
|
||||
this.failureUrl = failureUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException exception) throws IOException, ServletException {
|
||||
setDefaultFailureUrl(failureUrl + "?error&username=" + request.getParameter("username"));
|
||||
super.onAuthenticationFailure(request, response, exception);
|
||||
setDefaultFailureUrl(failureUrl);
|
||||
}
|
||||
}
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
package de.champonthis.buntspecht.security.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import de.champonthis.buntspecht.businesslogic.UserManager;
|
||||
import de.champonthis.buntspecht.model.User;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
@Component
|
||||
public class OAuth2AuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
|
||||
|
||||
@Autowired
|
||||
private UserManager userManager;
|
||||
|
||||
private RememberMeServices rememberMeServices;
|
||||
|
||||
/*
|
||||
* @see org.springframework.security.web.authentication.
|
||||
* SavedRequestAwareAuthenticationSuccessHandler#onAuthenticationSuccess(javax.
|
||||
* servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse,
|
||||
* org.springframework.security.core.Authentication)
|
||||
*/
|
||||
@Override
|
||||
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authentication) throws IOException, ServletException {
|
||||
User user = userManager.getByAuth(authentication);
|
||||
|
||||
UserDetails userDetails = userManager.loadUserByUsername(user.getUsername());
|
||||
|
||||
List<GrantedAuthority> authorities = new ArrayList<>();
|
||||
authorities.addAll(authentication.getAuthorities());
|
||||
authorities.addAll(userDetails.getAuthorities());
|
||||
|
||||
UsernamePasswordAuthenticationToken newAuthentication = new UsernamePasswordAuthenticationToken(userDetails,
|
||||
null, authorities);
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(newAuthentication);
|
||||
|
||||
if (rememberMeServices != null) {
|
||||
request.setAttribute("remember-me", "true");
|
||||
rememberMeServices.loginSuccess(request, response, newAuthentication);
|
||||
}
|
||||
|
||||
handle(request, response, newAuthentication);
|
||||
clearAuthenticationAttributes(request);
|
||||
}
|
||||
|
||||
|
||||
public void setRememberMeServices(RememberMeServices rememberMeServices) {
|
||||
this.rememberMeServices = rememberMeServices;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user