initial commit

This commit is contained in:
2021-10-03 17:07:01 +02:00
commit 456332f24e
246 changed files with 24590 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-main</artifactId>
<version>${revision}</version>
</parent>
<name>minetest</name>
<artifactId>webstly-minetest</artifactId>
<dependencies>
<dependency>
<groupId>de.bstly.we</groupId>
<artifactId>webstly-core</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,173 @@
/**
*
*/
package de.bstly.we.minetest.businesslogic;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.google.common.collect.Lists;
import de.bstly.we.businesslogic.QuotaManager;
import de.bstly.we.businesslogic.UserDataProvider;
import de.bstly.we.minetest.model.MinetestAccount;
import de.bstly.we.minetest.model.QMinetestAccount;
import de.bstly.we.minetest.repository.MinetestAccountRepository;
import de.bstly.we.model.Quota;
import de.bstly.we.model.UserData;
/**
* @author _bastler@bstly.de
*
*/
@Component
public class MinetestAccountManager implements UserDataProvider {
@Autowired
private QuotaManager quotaManager;
@Autowired
private MinetestAccountRepository minetestAccountRepository;
private QMinetestAccount qMinetestAccount = QMinetestAccount.minetestAccount;
/**
*
* @param name
* @return
*/
public MinetestAccount get(String name) {
return minetestAccountRepository.findById(name).orElse(null);
}
/**
*
* @param userId
* @return
*/
public List<MinetestAccount> getAllByOwner(Long userId) {
return Lists
.newArrayList(minetestAccountRepository.findAll(qMinetestAccount.owner.eq(userId)));
}
/**
*
* @param page
* @param size
* @param sortBy
* @param descending
* @return
*/
public Page<MinetestAccount> get(int page, int size, String sortBy, boolean descending) {
return minetestAccountRepository.findAll(PageRequest.of(page, size,
descending ? Sort.by(sortBy).descending() : Sort.by(sortBy).ascending()));
}
/**
*
* @param owner
* @param name
* @param quota
* @return
*/
public MinetestAccount create(Long owner, String name, boolean quota) {
MinetestAccount minetestAccount = new MinetestAccount();
minetestAccount.setOwner(owner);
Assert.isTrue(!minetestAccountRepository.existsById(name), "Given name already exists!");
minetestAccount.setName(name);
minetestAccount = minetestAccountRepository.save(minetestAccount);
if (quota) {
Quota minetestAccountsQuota = quotaManager.get(minetestAccount.getOwner(),
MinetestQuotas.MINETEST_ACCOUNTS);
if (minetestAccountsQuota != null) {
minetestAccountsQuota.setValue(minetestAccountsQuota.getValue() - 1);
quotaManager.update(minetestAccountsQuota);
}
}
return minetestAccount;
}
/**
*
* @param minetestAccount
* @return
*/
public MinetestAccount save(MinetestAccount minetestAccount) {
return minetestAccountRepository.save(minetestAccount);
}
/**
*
* @param minetestAccount
* @param quota
*/
public void delete(MinetestAccount minetestAccount, boolean quota) {
if (quota) {
Quota minetestAccountsQuota = quotaManager.get(minetestAccount.getOwner(),
MinetestQuotas.MINETEST_ACCOUNTS);
if (minetestAccountsQuota == null) {
minetestAccountsQuota = quotaManager.create(minetestAccount.getOwner(),
MinetestQuotas.MINETEST_ACCOUNTS, 0, "#", true);
}
minetestAccountsQuota.setValue(minetestAccountsQuota.getValue() + 1);
quotaManager.update(minetestAccountsQuota);
}
minetestAccountRepository.delete(minetestAccount);
}
/**
*
* @param owner
* @param quota
*/
public void deleteAll(Long owner, boolean quota) {
List<MinetestAccount> minetestAccounts = Lists
.newArrayList(minetestAccountRepository.findAll(qMinetestAccount.owner.eq(owner)));
for (MinetestAccount minetestAccount : minetestAccounts) {
delete(minetestAccount, quota);
}
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getId()
*/
@Override
public String getId() {
return "minetest-accounts";
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#getUserData(java.lang.Long)
*/
@Override
public List<UserData> getUserData(Long userId) {
List<UserData> result = Lists.newArrayList();
for (MinetestAccount minetestAccount : getAllByOwner(userId)) {
result.add(minetestAccount);
}
return result;
}
/*
* @see de.bstly.we.businesslogic.UserDataProvider#purgeUserData(java.lang.Long)
*/
@Override
public void purgeUserData(Long userId) {
for (MinetestAccount minetestAccount : getAllByOwner(userId)) {
minetestAccountRepository.delete(minetestAccount);
}
}
}
@@ -0,0 +1,13 @@
/**
*
*/
package de.bstly.we.minetest.businesslogic;
/**
* @author _bastler@bstly.de
*
*/
public interface MinetestPermissions {
public static final String MINETEST = "minetest";
}
@@ -0,0 +1,13 @@
/**
*
*/
package de.bstly.we.minetest.businesslogic;
/**
* @author _bastler@bstly.de
*
*/
public interface MinetestQuotas {
public static final String MINETEST_ACCOUNTS = "minetest_accounts";
}
@@ -0,0 +1,113 @@
/**
*
*/
package de.bstly.we.minetest.controller;
import java.util.List;
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.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.RestController;
import de.bstly.we.businesslogic.PermissionManager;
import de.bstly.we.businesslogic.QuotaManager;
import de.bstly.we.controller.BaseController;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.controller.support.RequestBodyErrors;
import de.bstly.we.minetest.businesslogic.MinetestAccountManager;
import de.bstly.we.minetest.businesslogic.MinetestPermissions;
import de.bstly.we.minetest.businesslogic.MinetestQuotas;
import de.bstly.we.minetest.controller.validation.MinetestAccountValidator;
import de.bstly.we.minetest.model.MinetestAccount;
import de.bstly.we.model.Quota;
/**
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/minetest/accounts")
public class MinetestAccountController extends BaseController {
@Autowired
private MinetestAccountManager minetestAccountManager;
@Autowired
private PermissionManager permissionManager;
@Autowired
private QuotaManager quotaManager;
@Autowired
private MinetestAccountValidator minetestAccountModelValidator;
/**
*
* @return
*/
@PreAuthorize("isAuthenticated()")
@GetMapping
public List<MinetestAccount> getMinetestAccounts() {
if (!permissionManager.hasPermission(getCurrentUserId(), MinetestPermissions.MINETEST)) {
minetestAccountManager.deleteAll(getCurrentUserId(), true);
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
return minetestAccountManager.getAllByOwner(getCurrentUserId());
}
/**
*
* @param minetestAccountModel
* @return
*/
@PreAuthorize("isAuthenticated()")
@PostMapping
public MinetestAccount createMinetestAccount(@RequestBody MinetestAccount minetestAccount) {
if (!permissionManager.hasPermission(getCurrentUserId(), MinetestPermissions.MINETEST)
|| !permissionManager.isFullUser(getCurrentUserId())) {
minetestAccountManager.deleteAll(getCurrentUserId(), true);
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
Quota minetestAccountsQuota = quotaManager.get(getCurrentUserId(),
MinetestQuotas.MINETEST_ACCOUNTS);
if (minetestAccountsQuota == null || minetestAccountsQuota.getValue() < 1) {
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
Errors errors = new RequestBodyErrors(minetestAccount);
minetestAccountModelValidator.validate(minetestAccount, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
return minetestAccountManager.create(getCurrentUserId(), minetestAccount.getName(), true);
}
/**
*
* @param id
*/
@PreAuthorize("isAuthenticated()")
@DeleteMapping("/{name}")
public void deleteMinetestAccount(@PathVariable("name") String name) {
if (!permissionManager.hasPermission(getCurrentUserId(), MinetestPermissions.MINETEST)) {
minetestAccountManager.deleteAll(getCurrentUserId(), true);
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
MinetestAccount minetestAccount = minetestAccountManager.get(name);
if (minetestAccount == null || !minetestAccount.getOwner().equals(getCurrentUserId())) {
throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
}
minetestAccountManager.delete(minetestAccount, true);
}
}
@@ -0,0 +1,104 @@
/**
*
*/
package de.bstly.we.minetest.controller;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
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.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.bstly.we.controller.BaseController;
import de.bstly.we.controller.support.EntityResponseStatusException;
import de.bstly.we.controller.support.RequestBodyErrors;
import de.bstly.we.minetest.businesslogic.MinetestAccountManager;
import de.bstly.we.minetest.controller.validation.MinetestAccountValidator;
import de.bstly.we.minetest.model.MinetestAccount;
/**
* @author _bastler@bstly.de
*
*/
@RestController
@RequestMapping("/minetest/accounts/manage")
public class MinetestAccountManagementController extends BaseController {
@Autowired
private MinetestAccountManager minetestAccountManager;
@Autowired
private MinetestAccountValidator minetestAccountModelValidator;
/**
*
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping
public Page<MinetestAccount> getMinetestAccounts(
@RequestParam("page") Optional<Integer> pageParameter,
@RequestParam("size") Optional<Integer> sizeParameter) {
return minetestAccountManager.get(pageParameter.orElse(0), sizeParameter.orElse(10), "name",
true);
}
/**
*
* @param minetestAccount
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping
public MinetestAccount createOrUpdateMinetestAccount(
@RequestBody MinetestAccount minetestAccount) {
Errors errors = new RequestBodyErrors(minetestAccount);
minetestAccountModelValidator.validateMinetestName(minetestAccount, errors);
if (errors.hasErrors()) {
throw new EntityResponseStatusException(errors.getAllErrors(), HttpStatus.CONFLICT);
}
return minetestAccountManager.save(minetestAccount);
}
/**
*
* @param id
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/{name}")
public void deleteMinetestAccount(@PathVariable("name") String name,
@RequestParam("quota") Optional<Boolean> quota) {
MinetestAccount minetestAccount = minetestAccountManager.get(name);
if (minetestAccount == null) {
throw new EntityResponseStatusException(HttpStatus.CONFLICT);
}
minetestAccountManager.delete(minetestAccount,
quota.isPresent() && quota.get().booleanValue());
}
/**
*
* @param owner
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/all/{owner}")
public void deleteAll(@PathVariable("owner") Long owner,
@RequestParam("quota") Optional<Boolean> quota) {
minetestAccountManager.deleteAll(owner, quota.isPresent() && quota.get().booleanValue());
}
}
@@ -0,0 +1,94 @@
/**
*
*/
package de.bstly.we.minetest.controller.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.bstly.we.businesslogic.SystemPropertyManager;
import de.bstly.we.controller.validation.UserModelValidator;
import de.bstly.we.minetest.businesslogic.MinetestAccountManager;
import de.bstly.we.minetest.model.MinetestAccount;
/**
* @author _bastler@bstly.de
*
*/
@Component
public class MinetestAccountValidator implements Validator {
@Autowired
private MinetestAccountManager minetestAccountManager;
@Autowired
private SystemPropertyManager systemPropertyManager;
protected static final String NAME_REGEX = "^([-_a-zA-Z0-9]+)$";
/*
* @see org.springframework.validation.Validator#supports(java.lang.Class)
*/
@Override
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(MinetestAccount.class);
}
/*
* @see org.springframework.validation.Validator#validate(java.lang.Object,
* org.springframework.validation.Errors)
*/
@Override
public void validate(Object target, Errors errors) {
validateMinetestName(target, errors);
if (!errors.hasErrors()) {
validateReservedNames(target, errors);
}
}
/**
*
* @param target
* @param errors
*/
public void validateMinetestName(Object target, Errors errors) {
MinetestAccount minetestAccount = (MinetestAccount) target;
if (!StringUtils.hasText(minetestAccount.getName())) {
errors.rejectValue("name", "REQUIRED");
return;
}
MinetestAccount existing = minetestAccountManager.get(minetestAccount.getName());
if (existing != null && !existing.getOwner().equals(minetestAccount.getOwner())) {
errors.rejectValue("name", "NOT_VALID");
return;
}
if (!minetestAccount.getName().matches(NAME_REGEX)) {
errors.rejectValue("name", "NOT_VALID");
return;
}
}
/**
*
* @param target
* @param errors
*/
public void validateReservedNames(Object target, Errors errors) {
MinetestAccount minetestAccount = (MinetestAccount) target;
if (StringUtils.hasText(minetestAccount.getName())) {
for (String systemUsername : systemPropertyManager
.get(UserModelValidator.RESERVED_USERNAMES, "").split(",")) {
if (StringUtils.hasText(systemUsername) && (minetestAccount.getName().toLowerCase()
.equals(systemUsername)
|| minetestAccount.getName().toLowerCase().matches(systemUsername))) {
errors.rejectValue("name", "NOT_VALID");
break;
}
}
}
}
}
@@ -0,0 +1,73 @@
/**
*
*/
package de.bstly.we.minetest.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import de.bstly.we.model.UserData;
/**
* @author _bastler@bstly.de
*
*/
@Entity
@Table(name = "minetest_accounts")
public class MinetestAccount implements UserData {
@Id
@Column(name = "name")
private String name;
@Column(name = "owner")
private Long owner;
@Lob
@Column(name = "skin")
private String skin;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the owner
*/
public Long getOwner() {
return owner;
}
/**
* @param owner the owner to set
*/
public void setOwner(Long owner) {
this.owner = owner;
}
/**
* @return the skin
*/
public String getSkin() {
return skin;
}
/**
* @param skin the skin to set
*/
public void setSkin(String skin) {
this.skin = skin;
}
}
@@ -0,0 +1,20 @@
/**
*
*/
package de.bstly.we.minetest.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
import de.bstly.we.minetest.model.MinetestAccount;
/**
*
* @author _bastler@bstly.de
*
*/
@Repository
public interface MinetestAccountRepository
extends JpaRepository<MinetestAccount, String>, QuerydslPredicateExecutor<MinetestAccount> {
}