diff --git a/pom.xml b/pom.xml
index 3dab06f..5700481 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.boot
spring-boot-starter-parent
- 2.5.6
+ 2.6.3
com.imjustdoom
@@ -30,13 +30,20 @@
- org.thymeleaf.extras
- thymeleaf-extras-springsecurity5
+ org.springframework.boot
+ spring-boot-starter-data-jpa
- org.springframework.boot
- spring-boot-starter-data-jpa
+ com.querydsl
+ querydsl-apt
+ 5.0.0
+
+
+
+ com.querydsl
+ querydsl-jpa
+ 5.0.0
@@ -68,11 +75,6 @@
test
-
- org.springframework.boot
- spring-boot-starter-thymeleaf
-
-
org.springframework.boot
spring-boot-configuration-processor
@@ -104,12 +106,6 @@
provided
-
- org.commonmark
- commonmark
- 0.18.1
-
-
com.google.code.gson
gson
@@ -117,12 +113,6 @@
compile
-
- me.xdrop
- fuzzywuzzy
- 1.3.1
-
-
@@ -154,6 +144,22 @@
17
+
+ com.mysema.maven
+ apt-maven-plugin
+ 1.1.3
+
+
+
+ process
+
+
+ target/generated-sources/java
+ com.querydsl.apt.jpa.JPAAnnotationProcessor
+
+
+
+
org.springframework.boot
spring-boot-maven-plugin
diff --git a/src/main/java/com/imjustdoom/pluginsite/PluginSiteApplication.java b/src/main/java/com/imjustdoom/pluginsite/PluginSiteApplication.java
index 69a4116..f66b3e2 100644
--- a/src/main/java/com/imjustdoom/pluginsite/PluginSiteApplication.java
+++ b/src/main/java/com/imjustdoom/pluginsite/PluginSiteApplication.java
@@ -3,8 +3,10 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
+import org.springframework.data.web.config.EnableSpringDataWebSupport;
@SpringBootApplication
+@EnableSpringDataWebSupport
@ConfigurationPropertiesScan
public class PluginSiteApplication {
diff --git a/src/main/java/com/imjustdoom/pluginsite/config/SecurityConfig.java b/src/main/java/com/imjustdoom/pluginsite/config/SecurityConfig.java
deleted file mode 100644
index 1626fde..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/config/SecurityConfig.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.imjustdoom.pluginsite.config;
-
-import lombok.AllArgsConstructor;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
-import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-import org.springframework.security.crypto.password.PasswordEncoder;
-
-@Configuration
-@EnableWebSecurity
-@AllArgsConstructor
-public class SecurityConfig extends WebSecurityConfigurerAdapter {
-
- @Bean
- public PasswordEncoder encoder() {
- return new BCryptPasswordEncoder();
- }
-
- private final UserDetailsService userDetailsService;
-
- @Bean
- public DaoAuthenticationProvider authProvider() {
- DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
- authProvider.setUserDetailsService(userDetailsService);
- authProvider.setPasswordEncoder(encoder());
- return authProvider;
- }
-
- @Override
- protected void configure(AuthenticationManagerBuilder auth) {
- auth.authenticationProvider(authProvider());
- }
-
- @Override
- public void configure(HttpSecurity http) throws Exception {
- http
- .csrf().disable()
-
- .authorizeRequests()
- .antMatchers("/admin", "/admin/roles").hasRole("ADMIN")
- .antMatchers("/resources/create", "/account/details").authenticated()
- .antMatchers("/signup", "/login").not().authenticated()
-
- .anyRequest().permitAll()
-
- .and()
- .formLogin().loginPage("/login");
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/imjustdoom/pluginsite/config/exception/RestErrorCode.java b/src/main/java/com/imjustdoom/pluginsite/config/exception/RestErrorCode.java
new file mode 100644
index 0000000..bc57527
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/config/exception/RestErrorCode.java
@@ -0,0 +1,54 @@
+package com.imjustdoom.pluginsite.config.exception;
+
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.springframework.http.HttpStatus;
+
+public enum RestErrorCode {
+ INVALID_USERNAME(HttpStatus.BAD_REQUEST, "auth", 1),
+ INVALID_EMAIL(HttpStatus.BAD_REQUEST, "auth", 2),
+ USERNAME_NOT_AVAILABLE(HttpStatus.BAD_REQUEST, "auth", 3),
+ EMAIL_NOT_AVAILABLE(HttpStatus.BAD_REQUEST, "auth", 4),
+
+ UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "auth", 100),
+ FORBIDDEN(HttpStatus.FORBIDDEN, "auth", 101),
+
+ ACCOUNT_NOT_FOUND(HttpStatus.NOT_FOUND, "data", 100),
+ REPORT_NOT_FOUND(HttpStatus.NOT_FOUND, "data", 101),
+ RESOURCE_NOT_FOUND(HttpStatus.NOT_FOUND, "data", 102),
+ RESOURCE_UPDATE_NOT_FOUND(HttpStatus.NOT_FOUND, "data", 103),
+ DOWNLOAD_NOT_FOUND(HttpStatus.NOT_FOUND, "data", 104),
+ MESSAGE_GROUP_NOT_FOUND(HttpStatus.NOT_FOUND, "data", 105),
+
+ WRONG_FILE_TYPE(HttpStatus.BAD_REQUEST, "data", 2),
+ FILE_TOO_LARGE(HttpStatus.BAD_REQUEST, "data", 3),
+ PAGE_SIZE_TOO_LARGE(HttpStatus.BAD_REQUEST, "data", 4),
+ REQUIRED_ARGUMENTS_MISSING(HttpStatus.BAD_REQUEST, "data", 5),
+
+ TOO_MANY_RESOURCE_CREATIONS(HttpStatus.TOO_MANY_REQUESTS, "resource", 1),
+ TOO_MANY_RESOURCE_UPDATES(HttpStatus.TOO_MANY_REQUESTS, "resource", 2),
+ RESOURCE_NAME_NOT_AVAILABLE(HttpStatus.BAD_REQUEST, "resource", 3);
+
+ private final HttpStatus httpStatus;
+ private final String module;
+ private final int errorCode;
+
+ RestErrorCode(HttpStatus httpStatus, String module, int errorCode) {
+ this.httpStatus = httpStatus;
+ this.module = module;
+ this.errorCode = errorCode;
+ }
+
+ @JsonIgnore
+ public HttpStatus getHttpStatus() {
+ return this.httpStatus;
+ }
+
+ public String getModule() {
+ return this.module;
+ }
+
+ public int getErrorCode() {
+ return this.errorCode;
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/config/exception/RestException.java b/src/main/java/com/imjustdoom/pluginsite/config/exception/RestException.java
new file mode 100644
index 0000000..ad1a745
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/config/exception/RestException.java
@@ -0,0 +1,20 @@
+package com.imjustdoom.pluginsite.config.exception;
+
+import lombok.Getter;
+import org.springframework.lang.Nullable;
+
+@Getter
+public class RestException extends Exception {
+ private final RestErrorCode errorCode;
+ private final @Nullable String message;
+
+ public RestException(RestErrorCode errorCode, String message, Object... params) {
+ this.errorCode = errorCode;
+ this.message = String.format(message, params);
+ }
+
+ public RestException(RestErrorCode errorCode) {
+ this.errorCode = errorCode;
+ this.message = null;
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/config/exception/RestExceptionResponseHandler.java b/src/main/java/com/imjustdoom/pluginsite/config/exception/RestExceptionResponseHandler.java
new file mode 100644
index 0000000..ae6a226
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/config/exception/RestExceptionResponseHandler.java
@@ -0,0 +1,27 @@
+package com.imjustdoom.pluginsite.config.exception;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@RestControllerAdvice
+@RequiredArgsConstructor
+public class RestExceptionResponseHandler extends ResponseEntityExceptionHandler {
+
+ private final ObjectMapper mapper;
+
+ @ExceptionHandler(RestException.class)
+ public void handle(HttpServletResponse response, RestException exception) throws IOException {
+ if (!response.isCommitted()) {
+ response.setStatus(exception.getErrorCode().getHttpStatus().value());
+ this.mapper.writeValue(response.getWriter(), exception);
+ }
+ }
+
+ // Could add an error ticketing system for unknown errors (5xx) thrown
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/config/security/AuthenticationProvider.java b/src/main/java/com/imjustdoom/pluginsite/config/security/AuthenticationProvider.java
new file mode 100644
index 0000000..2855b85
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/config/security/AuthenticationProvider.java
@@ -0,0 +1,23 @@
+package com.imjustdoom.pluginsite.config.security;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+@Configuration
+@RequiredArgsConstructor
+public class AuthenticationProvider {
+ private final UserDetailsService userDetailsService;
+ private final PasswordEncoder passwordEncoder;
+
+ @Bean
+ public DaoAuthenticationProvider authProvider() {
+ DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
+ authProvider.setUserDetailsService(this.userDetailsService);
+ authProvider.setPasswordEncoder(this.passwordEncoder);
+ return authProvider;
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/config/security/PasswordEncoderConfig.java b/src/main/java/com/imjustdoom/pluginsite/config/security/PasswordEncoderConfig.java
new file mode 100644
index 0000000..f884831
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/config/security/PasswordEncoderConfig.java
@@ -0,0 +1,15 @@
+package com.imjustdoom.pluginsite.config.security;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+@Configuration
+public class PasswordEncoderConfig {
+
+ @Bean
+ public PasswordEncoder encoder() {
+ return new BCryptPasswordEncoder();
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/config/security/SecurityConfig.java b/src/main/java/com/imjustdoom/pluginsite/config/security/SecurityConfig.java
new file mode 100644
index 0000000..ff26b3f
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/config/security/SecurityConfig.java
@@ -0,0 +1,37 @@
+package com.imjustdoom.pluginsite.config.security;
+
+import lombok.AllArgsConstructor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@EnableWebSecurity
+@AllArgsConstructor
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+ private final DaoAuthenticationProvider authProvider;
+
+ @Override
+ protected void configure(AuthenticationManagerBuilder auth) {
+ auth.authenticationProvider(this.authProvider);
+ }
+
+ @Override
+ public void configure(HttpSecurity http) throws Exception {
+ http
+ .csrf().disable()
+
+ .authorizeRequests()
+ .antMatchers("/admin", "/admin/roles").hasRole("ADMIN")
+ .antMatchers("/resources/create", "/account/details").authenticated()
+ .antMatchers("/register", "/login").not().authenticated()
+
+ .anyRequest().permitAll()
+
+ .and()
+ .formLogin().loginProcessingUrl("/login");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/AccountController.java b/src/main/java/com/imjustdoom/pluginsite/controller/AccountController.java
index 8e5f67a..882e50b 100644
--- a/src/main/java/com/imjustdoom/pluginsite/controller/AccountController.java
+++ b/src/main/java/com/imjustdoom/pluginsite/controller/AccountController.java
@@ -1,119 +1,67 @@
package com.imjustdoom.pluginsite.controller;
-import com.imjustdoom.pluginsite.config.custom.SiteConfig;
-import com.imjustdoom.pluginsite.dtos.in.CreateAccountRequest;
+import com.imjustdoom.pluginsite.config.exception.RestErrorCode;
+import com.imjustdoom.pluginsite.config.exception.RestException;
+import com.imjustdoom.pluginsite.dtos.in.account.CreateAccountRequest;
+import com.imjustdoom.pluginsite.dtos.in.account.UpdateAccountRequest;
+import com.imjustdoom.pluginsite.dtos.out.account.AccountDto;
+import com.imjustdoom.pluginsite.dtos.out.account.SelfAccountDto;
+import com.imjustdoom.pluginsite.dtos.out.message.MessageGroupDto;
import com.imjustdoom.pluginsite.model.Account;
-import com.imjustdoom.pluginsite.repositories.AccountRepository;
-import com.imjustdoom.pluginsite.util.ImageUtil;
-import com.imjustdoom.pluginsite.util.ValidationHelper;
+import com.imjustdoom.pluginsite.service.AccountService;
+import com.imjustdoom.pluginsite.service.MessageService;
import lombok.RequiredArgsConstructor;
-import org.springframework.security.crypto.bcrypt.BCrypt;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.web.PageableDefault;
+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 org.springframework.web.multipart.MultipartFile;
-import org.springframework.web.servlet.view.RedirectView;
-import java.util.Optional;
-
-@Controller
+@RestController
+@RequestMapping("/account")
@RequiredArgsConstructor
public class AccountController {
+ private final AccountService accountService;
+ private final MessageService messageService;
- private final PasswordEncoder passwordEncoder;
- private final AccountRepository accountRepository;
- private final SiteConfig siteConfig;
-
- @GetMapping("/signup")
- public String signup(Model model, @RequestParam(name = "error", required = false) String error, Account account) {
- model.addAttribute("createAccount", new CreateAccountRequest());
- model.addAttribute("account", account);
- model.addAttribute("error", error);
- return "account/signup";
- }
+ @PostMapping("/register")
+ public String signupSubmit(@RequestBody CreateAccountRequest accountRequest) throws RestException {
+ Account account = this.accountService.register(accountRequest);
- @GetMapping("/logout")
- public RedirectView logout() {
- return new RedirectView("/");
+ return ""; // todo return a registration DTO of some sort, probably with a session token
}
- @PostMapping("/signup")
- public String signupSubmit(@ModelAttribute CreateAccountRequest accountRequest) {
- if (!ValidationHelper.isUsernameValid(accountRequest.getUsername())) return "redirect:/signup?error=invalidcharacter";
-
- String emailAddress = accountRequest.getEmail();
-
- if (!ValidationHelper.isEmailValid(emailAddress)) return "redirect:/signup?error=invalidemail";
-
- if (accountRepository.existsByUsernameEqualsIgnoreCase(accountRequest.getUsername()))
- return "redirect:/signup?error=usernametaken";
-
- if (accountRepository.existsByEmailEqualsIgnoreCase(emailAddress)) return "redirect:/signup?error=emailtaken";
-
- Account account = new Account(accountRequest.getUsername(), emailAddress, passwordEncoder.encode(accountRequest.getPassword()));
- accountRepository.save(account);
-
- return "redirect:/profile/" + account.getId();
- }
+ // todo login with JWT
- @GetMapping("/login")
- public String login(Model model, @RequestParam(name = "error", required = false) String error, Account account) {
- model.addAttribute("error", error);
- model.addAttribute("createAccount", new CreateAccountRequest());
- model.addAttribute("account", account);
- return "account/login";
+ @GetMapping("/details")
+ public SelfAccountDto getSelfAccountDetails(Account account) {
+ return SelfAccountDto.fromAccount(account);
}
- @PostMapping("/login")
- public String loginSubmit(@ModelAttribute CreateAccountRequest accountRequest) {
-
- if (accountRepository.existsByUsernameEqualsIgnoreCaseOrEmailEqualsIgnoreCase(accountRequest.getUsername(), "")) { // todo change
- Optional account = accountRepository.findByUsernameEqualsIgnoreCase(accountRequest.getUsername());
- if (BCrypt.checkpw(accountRequest.getPassword(), account.get().getPassword())) {
-
- return "redirect:/profile/" + account.get().getId();
- }
- return "redirect:/login?error=incorrectpassword";
- }
-
- return "redirect:/login?error=notfound";
+ @PatchMapping("/details")
+ public SelfAccountDto updateAccountDetails(Account account, @RequestBody UpdateAccountRequest request,
+ @RequestParam(value = "profilePicture", required = false) MultipartFile file) throws RestException {
+ return SelfAccountDto.fromAccount(this.accountService.updateAccountDetails(account, request, file));
}
- @GetMapping("/account/details")
- public String accountDetails(Model model, Account account, @RequestParam(name = "error", required = false) String error) {
- model.addAttribute("account", account);
- model.addAttribute("url", this.siteConfig.getDomain());
- model.addAttribute("error", error);
- return "account/details";
+ @GetMapping("/{id}/details")
+ public AccountDto getAccountDetails(@PathVariable int id) throws RestException {
+ return AccountDto.fromAccount(this.accountService.getAccount(id));
}
- @PostMapping("/account/details")
- public String postAccountDetails(Account account, @RequestParam String username, @RequestParam String email,
- @RequestParam String password, @RequestParam("logo") MultipartFile file) {
- if (!ValidationHelper.isUsernameValid(username)) return "redirect:/account/details?error=invalidcharacter";
- if (!ValidationHelper.isEmailValid(email)) return "redirect:/account/details?error=invalidemail";
-
- if (!file.isEmpty()) {
- if (!file.getContentType().contains("image")) {
- return "redirect:/account/details?error=logotype";
- }
-
- if (file.getSize() > 1024000) {
- return "redirect:/account/details?error=filesize";
- }
-
- accountRepository.updateProfilePictureById(account.getId(), ImageUtil.handleImage(file));
- }
-
- if (accountRepository.existsByUsernameEqualsIgnoreCase(username))
- return "redirect:/account/details?error=usernametaken";
-
- if (accountRepository.existsByEmailEqualsIgnoreCase(email)) return "redirect:/account/details?error=emailtaken";
+ @GetMapping("/groups")
+ public Page getMessageGroups(Account account,
+ @PageableDefault(size = 25) Pageable pageable) throws RestException {
+ if (pageable.getPageSize() > 50) throw new RestException(RestErrorCode.PAGE_SIZE_TOO_LARGE, "Page size is too large (%s > %s)", pageable.getPageSize(), 50);
- accountRepository.setUsernameById(account.getId(), username);
- accountRepository.setEmailById(account.getId(), email);
- accountRepository.setPasswordById(account.getId(), passwordEncoder.encode(password));
- return "redirect:/profile/" + account.getId();
+ return this.messageService.getGroups(account, pageable)
+ .map(MessageGroupDto::fromMessageGroup);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/AdminController.java b/src/main/java/com/imjustdoom/pluginsite/controller/AdminController.java
index 19b72b2..c20a8e6 100644
--- a/src/main/java/com/imjustdoom/pluginsite/controller/AdminController.java
+++ b/src/main/java/com/imjustdoom/pluginsite/controller/AdminController.java
@@ -1,83 +1,52 @@
package com.imjustdoom.pluginsite.controller;
-import com.imjustdoom.pluginsite.model.Account;
+import com.imjustdoom.pluginsite.config.exception.RestErrorCode;
+import com.imjustdoom.pluginsite.config.exception.RestException;
import com.imjustdoom.pluginsite.model.Report;
-import com.imjustdoom.pluginsite.repositories.AccountRepository;
-import com.imjustdoom.pluginsite.repositories.ReportRepository;
-import com.imjustdoom.pluginsite.util.UrlUtil;
-import lombok.AllArgsConstructor;
-import org.commonmark.node.Node;
-import org.commonmark.parser.Parser;
-import org.commonmark.renderer.html.HtmlRenderer;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
+import com.imjustdoom.pluginsite.service.ReportService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.web.PageableDefault;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
-import java.util.Optional;
-
-@Controller
-@AllArgsConstructor
+@RestController
+@RequestMapping("/admin")
+@RequiredArgsConstructor
public class AdminController {
- private final AccountRepository accountRepository;
- private final ReportRepository reportRepository;
-
- private final UrlUtil urlUtil;
-
- @GetMapping("/admin")
- public String admin(Model model, Account account) {
- model.addAttribute("account", account);
- return "admin/admin";
- }
-
- @GetMapping("/admin/reports")
- public String reports(Model model, Account account) {
- model.addAttribute("account", account);
- model.addAttribute("reports", reportRepository.findAll());
- return "admin/reports";
- }
+ private final ReportService reportService;
- @GetMapping("/admin/report/{id}")
- public String report(Model model, Account account, @PathVariable("id") int id) {
-
- Report report = reportRepository.findById(id).get();
- String description = urlUtil.encode(report.getReport());
-
- description.replaceAll("script", "error style=\"display:none;\"");
- Parser parser = Parser.builder().build();
- Node document = parser.parse(description);
- HtmlRenderer renderer = HtmlRenderer.builder().build();
- String html = renderer.render(document);
-
- report.setReport(html);
-
- model.addAttribute("account", account);
- model.addAttribute("report", report);
- return "admin/report";
+ @GetMapping("/report")
+ public Page listReports(@PageableDefault(sort = "reportedDate", direction = Sort.Direction.DESC) Pageable pageable) throws RestException {
+ if (pageable.getPageSize() > 50) throw new RestException(RestErrorCode.PAGE_SIZE_TOO_LARGE, "Page size too large (%s > %s)", pageable.getPageSize(), 50);
+ return this.reportService.getReportPage(pageable);
}
- @PostMapping("/admin/report/{id}")
- public String report(@PathVariable("id") int id, @RequestParam String action) {
- reportRepository.updateActionTakenById(id, action);
- return "redirect:/admin/reports";
+ @GetMapping("/report/{id}")
+ public Report getReport(@PathVariable int id) throws RestException {
+ return this.reportService.getReport(id);
}
- @GetMapping("/admin/roles")
- public String roles(Model model, Account account) {
- model.addAttribute("account", account);
- return "admin/account/roles";
+ @PatchMapping("/report/{id}")
+ public Report updateActionTaken(@PathVariable int id, @RequestParam String actionTaken) {
+ return this.reportService.updateActionTaken(id, actionTaken);
}
- @PostMapping("/admin/roles")
- public void setRole(@RequestParam String username, @RequestParam String role, Account account, Model model) {
- model.addAttribute("account", account);
-
- Optional optionalAccount = accountRepository.findByUsernameEqualsIgnoreCase(username);
- if (optionalAccount.isEmpty()) return;
- role = role.toUpperCase();
- optionalAccount.get().setRole("ROLE_" + role);
- accountRepository.setRoleById(optionalAccount.get().getId(), "ROLE_" + role);
- }
-}
\ No newline at end of file
+ // todo didnt add roles since this system should be reworked. The code below is the old code.
+// @PostMapping("/admin/roles")
+// public void setRole(@RequestParam String username, @RequestParam String role, Account account, Model model) {
+// model.addAttribute("account", account);
+//
+// Optional optionalAccount = accountRepository.findByUsernameEqualsIgnoreCase(username);
+// if (optionalAccount.isEmpty()) return;
+// role = role.toUpperCase();
+// optionalAccount.get().setRole("ROLE_" + role);
+// accountRepository.setRoleById(optionalAccount.get().getId(), "ROLE_" + role);
+// }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/ErrorController.java b/src/main/java/com/imjustdoom/pluginsite/controller/ErrorController.java
deleted file mode 100644
index 37a82a4..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/controller/ErrorController.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.imjustdoom.pluginsite.controller;
-
-import com.imjustdoom.pluginsite.model.Account;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.ControllerAdvice;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.servlet.NoHandlerFoundException;
-
-@ControllerAdvice
-public class ErrorController {
- /* idk what an Exception error is */
-// @ExceptionHandler(Exception.class)
-// public String handleException() {
-// return "error/error";
-// }
-
- @ExceptionHandler(NoHandlerFoundException.class)
- public String handle404(Model model, Account account) {
- model.addAttribute("account", account);
- return "error/404";
- }
-}
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/ExternalUrlController.java b/src/main/java/com/imjustdoom/pluginsite/controller/ExternalUrlController.java
deleted file mode 100644
index 008c05b..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/controller/ExternalUrlController.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.imjustdoom.pluginsite.controller;
-
-import com.imjustdoom.pluginsite.model.Account;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
-
-@Controller
-public class ExternalUrlController {
- @GetMapping("/redirect")
- public String redirect(Model model, HttpServletResponse response, @RequestParam(name = "url", required = false, value = "") String url, Account account) {
- // do you know how to remove the url from the parameters?
-
- url.replaceAll("%2F", "/");
-
- Cookie cookie = new Cookie("url", url);
-
- response.addCookie(cookie);
-
- model.addAttribute("account", account);
-
- return "redirect/redirect";
- }
-}
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/FileController.java b/src/main/java/com/imjustdoom/pluginsite/controller/FileController.java
deleted file mode 100644
index e9591db..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/controller/FileController.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.imjustdoom.pluginsite.controller;
-
-import com.imjustdoom.pluginsite.model.Account;
-import com.imjustdoom.pluginsite.model.Update;
-import com.imjustdoom.pluginsite.repositories.ResourceRepository;
-import com.imjustdoom.pluginsite.repositories.UpdateRepository;
-import com.imjustdoom.pluginsite.service.LogoService;
-import com.imjustdoom.pluginsite.service.ProfilePictureService;
-import lombok.AllArgsConstructor;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.UrlResource;
-import org.springframework.http.*;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-import java.net.MalformedURLException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Optional;
-
-@Controller
-@AllArgsConstructor
-public class FileController {
-
- private final LogoService logoService;
- private final ProfilePictureService profilePictureService;
- private final UpdateRepository updateRepository;
- private final ResourceRepository resourceRepository;
-
- @GetMapping("/logo/{id}")
- @ResponseBody
- public HttpEntity serveLogo(@PathVariable("id") int id) {
-
- byte[] image = logoService.serverLogo(id);
-
- HttpHeaders headers = new HttpHeaders();
- headers.setContentType(MediaType.IMAGE_JPEG);
- headers.setContentLength(image.length);
-
- return new HttpEntity<>(image, headers);
- }
-
- @GetMapping("/profile-picture/{id}")
- @ResponseBody
- public HttpEntity serveProfilePicture(@PathVariable("id") int id) {
-
- byte[] image = profilePictureService.serverProfilePicture(id);
-
- HttpHeaders headers = new HttpHeaders();
- headers.setContentType(MediaType.IMAGE_JPEG);
- headers.setContentLength(image.length);
-
- return new HttpEntity<>(image, headers);
- }
-
- @GetMapping("/files/{id}/download/{fileId}")
- @ResponseBody
- public ResponseEntity serveFile(Account account, @PathVariable("fileId") int fileId) throws MalformedURLException {
-
- Optional optional = updateRepository.findById(fileId);
- Update update = optional.get();
-
- if(!update.getStatus().equalsIgnoreCase("public")
- && account.getId() != update.getResource().getAuthor().getId()) {
- return ResponseEntity.notFound().build();
- }
-
- Path path = Paths.get("resources/plugins/" + fileId + "/");
- Resource file = new UrlResource(path.resolve(update.getFilename()).toUri());
-
- updateRepository.addDownload(fileId);
-
- if(!update.getExternal().equalsIgnoreCase("")) {
- HttpHeaders headers = new HttpHeaders();
- headers.add("Location", update.getExternal());
- return new ResponseEntity(headers, HttpStatus.FOUND);
- }
-
- return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
- "attachment; filename=\"" + file.getFilename() + "\"").body(file);
- }
-}
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/HomeController.java b/src/main/java/com/imjustdoom/pluginsite/controller/HomeController.java
deleted file mode 100644
index d1cb0bb..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/controller/HomeController.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.imjustdoom.pluginsite.controller;
-
-import com.imjustdoom.pluginsite.model.Account;
-import com.imjustdoom.pluginsite.model.Blog;
-import com.imjustdoom.pluginsite.repositories.AccountRepository;
-import com.imjustdoom.pluginsite.repositories.BlogRepository;
-import lombok.AllArgsConstructor;
-import org.commonmark.node.Node;
-import org.commonmark.parser.Parser;
-import org.commonmark.renderer.html.HtmlRenderer;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.GetMapping;
-
-import java.time.LocalDateTime;
-import java.util.Collections;
-import java.util.List;
-
-@Controller
-@AllArgsConstructor
-public class HomeController {
-
- private final BlogRepository blogRepository;
- private final AccountRepository accountRepository;
-
- @GetMapping("/")
- public String home(Model model, Account account) {
- for (Blog blog : blogRepository.findAll()) {
- int authorId = blog.getAuthorId();
- Account author = accountRepository.findById(authorId).get();
- blog.setAuthorName(author.getUsername());
-
- LocalDateTime date = blog.getCreatedDate();
- String dateString = date.getDayOfMonth() + "/" + date.getMonthValue() + "/" + date.getYear() + ", " + date.getHour() + ":" + date.getMinute();
- blog.setDateString(dateString);
-
- String md_body = blog.getPost();
- md_body = md_body.replaceAll("script", "error style=\"display:none;\"");
- Parser parser = Parser.builder().build();
-
- Node document = parser.parse(md_body);
- HtmlRenderer renderer = HtmlRenderer.builder().build();
- blog.setPost(renderer.render(document));
- }
-
- model.addAttribute("account", account);
-
- List blogs = blogRepository.findAll();
- Collections.reverse(blogs);
- model.addAttribute("blogs", blogs);
- return "home";
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/MessageController.java b/src/main/java/com/imjustdoom/pluginsite/controller/MessageController.java
new file mode 100644
index 0000000..05c835a
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/controller/MessageController.java
@@ -0,0 +1,22 @@
+package com.imjustdoom.pluginsite.controller;
+
+import com.imjustdoom.pluginsite.config.exception.RestException;
+import com.imjustdoom.pluginsite.model.Account;
+import com.imjustdoom.pluginsite.service.MessageService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/message")
+@RequiredArgsConstructor
+public class MessageController {
+ private final MessageService messageService;
+
+ @PostMapping
+ public void sendMessage(Account account, @RequestParam int groupId, @RequestParam String content) throws RestException {
+ this.messageService.sendMessage(account, groupId, content);
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/MessageGroupController.java b/src/main/java/com/imjustdoom/pluginsite/controller/MessageGroupController.java
new file mode 100644
index 0000000..78058b6
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/controller/MessageGroupController.java
@@ -0,0 +1,63 @@
+package com.imjustdoom.pluginsite.controller;
+
+import com.imjustdoom.pluginsite.config.exception.RestException;
+import com.imjustdoom.pluginsite.dtos.out.message.MessageDto;
+import com.imjustdoom.pluginsite.dtos.out.message.MessageGroupDto;
+import com.imjustdoom.pluginsite.model.Account;
+import com.imjustdoom.pluginsite.service.MessageService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.web.PageableDefault;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/message/group")
+@RequiredArgsConstructor
+public class MessageGroupController {
+ private final MessageService messageService;
+
+ @PostMapping
+ public void createGroup(Account sender, @RequestParam int targetId) throws RestException {
+ this.messageService.createGroup(sender, targetId);
+ }
+
+ @GetMapping("/{groupId}")
+ public MessageGroupDto getGroup(Account account, @PathVariable int groupId) throws RestException {
+ return MessageGroupDto.fromMessageGroup(this.messageService.getGroup(account, groupId));
+ }
+
+ @GetMapping("/{groupId}/messages")
+ public Page getMessages(Account account, @PathVariable int groupId, @PageableDefault(size = 25) Pageable pageable) throws RestException {
+ return this.messageService.getMessages(account, groupId, pageable)
+ .map(MessageDto::fromMessage);
+ }
+
+ @DeleteMapping("/{groupId}")
+ public void deleteGroup(Account account, @PathVariable int groupId) throws RestException {
+ this.messageService.deleteGroup(account, groupId);
+ }
+
+ @PostMapping("/{groupId}/addUser")
+ public void addUserToGroup(Account account, @PathVariable int groupId, @RequestParam int targetId) throws RestException {
+ this.messageService.addUserToGroup(account, groupId, targetId);
+ }
+
+ @PostMapping("/{groupId}/leave")
+ public void leaveGroup(Account account, @PathVariable int groupId) throws RestException {
+ this.messageService.leaveGroup(account, groupId);
+ }
+
+ @PatchMapping("/{groupId}/name")
+ public MessageGroupDto editGroupName(Account account, @PathVariable int groupId, @RequestParam String name) throws RestException {
+ return MessageGroupDto.fromMessageGroup(this.messageService.editGroupName(account, groupId, name));
+ }
+
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/MessagesController.java b/src/main/java/com/imjustdoom/pluginsite/controller/MessagesController.java
deleted file mode 100644
index c8734c6..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/controller/MessagesController.java
+++ /dev/null
@@ -1,236 +0,0 @@
-package com.imjustdoom.pluginsite.controller;
-
-import com.google.gson.Gson;
-import com.imjustdoom.pluginsite.model.Account;
-import com.imjustdoom.pluginsite.model.Message;
-import com.imjustdoom.pluginsite.model.MessageGroup;
-import com.imjustdoom.pluginsite.repositories.AccountRepository;
-import com.imjustdoom.pluginsite.repositories.MessageGroupRepository;
-import com.imjustdoom.pluginsite.repositories.MessageRepository;
-import com.imjustdoom.pluginsite.util.RequestUtil;
-import lombok.AllArgsConstructor;
-import me.xdrop.fuzzywuzzy.FuzzySearch;
-import me.xdrop.fuzzywuzzy.model.BoundExtractedResult;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-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 java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.nio.charset.StandardCharsets;
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Optional;
-
-@Controller
-@AllArgsConstructor
-public class MessagesController {
-
- private final MessageRepository messageRepository;
- private final MessageGroupRepository messageGroupRepository;
- private final AccountRepository accountRepository;
-
- private void sendSystemMessage(String message, int groupId){
-// Account systemAccount = new Account("System", "a@a.a", "a@a.a");
-// accountRepository.save(systemAccount);
- Account systemAccount = accountRepository.findByUsernameEqualsIgnoreCase("System").get();
- MessageGroup messageGroup = messageGroupRepository.findById(groupId).get();
- Message systemMessage = new Message(message, systemAccount, messageGroup);
- messageRepository.save(systemMessage);
- }
-
- @GetMapping("/message")
- public String message(Model model, Account account){
- if (account == null) {
- return "redirect:/login";
- }
- model.addAttribute("account", account);
- return "message/message";
- }
-
- @GetMapping("/message/new/{id}")
- public String newMessage(Model model, Account account, @PathVariable("id") int id){
- List users = new ArrayList<>();
- Optional adding = accountRepository.findById(id);
- // TODO: add an error message
- if(adding.isEmpty() || adding.get().getId() == account.getId()) return "redirect:/message";
- users.add(adding.get());
- users.add(account);
- String name = "Generic Group #" + (int) (Math.random() * 100);
- MessageGroup messageGroup = new MessageGroup(name, LocalDateTime.now(), users);
- messageGroupRepository.save(messageGroup);
-
- return "redirect:/message";
- }
-
- @PostMapping(value = "/message/api/get_groups", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
- public ResponseEntity> getConversations(Account account){
- List messageGroups;
- if(account == null) {
- return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
- }
- messageGroups = account.getGroups();
- HashMap response = new HashMap<>();
- for (MessageGroup messageGroup : messageGroups) {
- HashMap group = new HashMap<>();
- group.put("GroupId", String.valueOf(messageGroup.getId()));
- group.put("GroupName", messageGroup.getName());
- group.put("GroupMembers", String.valueOf(messageGroup.getMembers().size()));
- response.put("Group." + response.size(), new Gson().toJson(group));
- }
- return new ResponseEntity<>(response, HttpStatus.OK);
- }
-
- @PostMapping(value = "/message/api/get_group", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
- public ResponseEntity> getGroup(@RequestBody String request) {
- HashMap params = RequestUtil.getParams(request);
- String groupId = params.get("groupId");
- MessageGroup messageGroup = messageGroupRepository.findById(Integer.parseInt(groupId)).get();
- HashMap response = new HashMap<>();
- for (Account account : messageGroup.getMembers()) {
- response.put("Username." + response.size(), account.getUsername());
- }
- response.put("GroupName", messageGroup.getName());
- return new ResponseEntity<>(response, HttpStatus.OK);
- }
-
- @PostMapping(value = "/message/api/get_messages", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
- public ResponseEntity> getMessages(@RequestBody String request, Account account) {
- HashMap params = RequestUtil.getParams(request);
- String groupId = params.get("groupId");
- MessageGroup messageGroup = messageGroupRepository.findById(Integer.parseInt(groupId)).get();
- List messages = messageGroup.getMessages();
- HashMap response = new HashMap<>();
- for (Message message : messages) {
- HashMap messageMap = new HashMap<>();
- messageMap.put("MessageId", String.valueOf(message.getId()));
- if(message.getAuthor().getUsername().equalsIgnoreCase("System")) {
- messageMap.put("MessageAuthor", "system");
- }else{
- messageMap.put("MessageAuthor", (message.getAuthor().getId() == account.getId()) ? "self" : "other");
- }
- messageMap.put("MessageAuthorId", String.valueOf(message.getAuthor().getId()));
- messageMap.put("MessageAuthorName", message.getAuthor().getUsername());
- messageMap.put("MessageContent", message.getContent());
-
- response.put("Message." + response.size(), new Gson().toJson(messageMap));
- }
- return new ResponseEntity<>(response, HttpStatus.OK);
- }
-
- @PostMapping("/message/api/send_message")
- public ResponseEntity> sendMessage(@RequestBody String request, Account account) {
- // send message to that conversation
- // return json
- HashMap params = RequestUtil.getParams(request);
- String groupId = params.get("groupId");
- String content = params.get("content");
- MessageGroup messageGroup = messageGroupRepository.findById(Integer.parseInt(groupId)).get();
- Message message = new Message(content, account, messageGroup);
- messageRepository.save(message);
- HashMap response = new HashMap<>();
- response.put("MessageId", String.valueOf(message.getId()));
- response.put("MessageAuthor", String.valueOf(message.getAuthor().getId()));
- response.put("MessageContent", message.getContent());
- return new ResponseEntity<>(response, HttpStatus.OK);
- }
-
- @PostMapping(value = "/message/api/create_group", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
- public ResponseEntity> getGroups(@RequestBody String request, Account account) {
- HashMap params = RequestUtil.getParams(request);
- String userIds = params.get("userIds");
- String name = "Generic Group #" + (int) (Math.random() * 100);
- String[] userIdsList = userIds.split("%2C");
- List users = new ArrayList();
- for (String userId : userIdsList) {
- users.add(accountRepository.findById(Integer.parseInt(userId)).get());
- }
-
- users.add(account);
-
- MessageGroup messageGroup = new MessageGroup(name, LocalDateTime.now(), users);
- messageGroupRepository.save(messageGroup);
-
- HashMap response = new HashMap<>();
- response.put("groupId", String.valueOf(messageGroup.getId()));
- response.put("name", messageGroup.getName());
- return new ResponseEntity<>(response, HttpStatus.OK);
- }
-
- @PostMapping(value = "message/api/add_member", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
- public ResponseEntity> addMember(@RequestBody String request, Account account) {
- HashMap params = RequestUtil.getParams(request);
- String groupId = params.get("groupId");
- String userId = params.get("userId");
- MessageGroup messageGroup = messageGroupRepository.findById(Integer.parseInt(groupId)).get();
- Account user = accountRepository.findByUsernameEqualsIgnoreCase(userId).get();
- messageGroup.getMembers().add(user);
- messageGroupRepository.save(messageGroup);
- HashMap response = new HashMap<>();
- response.put("groupId", groupId);
- sendSystemMessage("User " + user.getUsername() + " has been added to the group.", messageGroup.getId());
- return new ResponseEntity<>(response, HttpStatus.OK);
- }
-
- @PostMapping(value = "message/api/leave", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
- public ResponseEntity> leave(@RequestBody String request, Account account) {
- HashMap params = RequestUtil.getParams(request);
- String groupId = params.get("groupId");
- MessageGroup messageGroup = messageGroupRepository.findById(Integer.parseInt(groupId)).get();
- messageGroup.getMembers().remove(account);
- messageGroupRepository.save(messageGroup);
- HashMap response = new HashMap<>();
- response.put("groupId", groupId);
- sendSystemMessage("User " + account.getUsername() + " has left the group.", messageGroup.getId());
- return new ResponseEntity<>(response, HttpStatus.OK);
- }
-
- @PostMapping(value = "message/api/delete_group", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
- public ResponseEntity> deleteGroup(@RequestBody String request, Account account) {
- HashMap params = RequestUtil.getParams(request);
- String groupId = params.get("groupId");
- MessageGroup messageGroup = messageGroupRepository.findById(Integer.parseInt(groupId)).get();
- messageGroupRepository.delete(messageGroup);
- HashMap response = new HashMap<>();
- response.put("groupId", groupId);
- return new ResponseEntity<>(response, HttpStatus.OK);
- }
-
- @PostMapping(value = "message/api/edit_group_name", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
- public ResponseEntity> editGroupName(@RequestBody String request, Account account) throws UnsupportedEncodingException {
- HashMap params = RequestUtil.getParams(request);
- String groupId = params.get("groupId");
- String name = params.get("name");
- name = URLDecoder.decode(name, StandardCharsets.UTF_8);
- MessageGroup messageGroup = messageGroupRepository.findById(Integer.parseInt(groupId)).get();
- messageGroup.setName(name);
- messageGroupRepository.save(messageGroup);
- HashMap response = new HashMap<>();
- response.put("groupId", groupId);
- return new ResponseEntity<>(response, HttpStatus.OK);
- }
-
- @PostMapping(value = "message/api/fuzzy_search/users", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
- public ResponseEntity> searchUsers(@RequestBody String request, Account account) {
- HashMap params = RequestUtil.getParams(request);
- String searchTerm = params.get("searchTerm");
-
- List> searchResults = FuzzySearch.extractSorted(searchTerm, accountRepository.findAll(), Account::getUsername);
-
- HashMap response = new HashMap<>();
- List usernames = new ArrayList<>();
- for(BoundExtractedResult result : searchResults) {
- usernames.add(result.getString());
- }
- response.put("usernames", String.join(",", usernames));
- return new ResponseEntity<>(response, HttpStatus.OK);
- }
-}
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/OtherController.java b/src/main/java/com/imjustdoom/pluginsite/controller/OtherController.java
deleted file mode 100644
index e0e0c2e..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/controller/OtherController.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.imjustdoom.pluginsite.controller;
-
-import com.imjustdoom.pluginsite.model.Account;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.GetMapping;
-
-@Controller
-public class OtherController {
-
- @GetMapping("/privacy")
- public String privacy(Account account, Model model) {
- model.addAttribute("account", account);
- return "terms/privacy";
- }
-
- @GetMapping("/terms")
- public String terms(Account account, Model model) {
- model.addAttribute("account", account);
- return "terms/terms";
- }
-
- @GetMapping("/contact")
- public String contact(Account account, Model model) {
- model.addAttribute("account", account);
- return "terms/contact";
- }
-
- @GetMapping("/team")
- public String team(Account account, Model model) {
- model.addAttribute("account", account);
- return "team";
- }
-}
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/ProfileController.java b/src/main/java/com/imjustdoom/pluginsite/controller/ProfileController.java
index 377bf1a..a704eca 100644
--- a/src/main/java/com/imjustdoom/pluginsite/controller/ProfileController.java
+++ b/src/main/java/com/imjustdoom/pluginsite/controller/ProfileController.java
@@ -1,77 +1,22 @@
package com.imjustdoom.pluginsite.controller;
-import com.imjustdoom.pluginsite.dtos.out.SimpleResourceDto;
-import com.imjustdoom.pluginsite.model.Account;
-import com.imjustdoom.pluginsite.model.Resource;
-import com.imjustdoom.pluginsite.repositories.AccountRepository;
-import com.imjustdoom.pluginsite.repositories.ResourceRepository;
-import com.imjustdoom.pluginsite.repositories.UpdateRepository;
-import com.imjustdoom.pluginsite.util.DateUtil;
-import lombok.AllArgsConstructor;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
+import com.imjustdoom.pluginsite.config.exception.RestException;
+import com.imjustdoom.pluginsite.dtos.out.ProfileDto;
+import com.imjustdoom.pluginsite.service.ProfileService;
+import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-@Controller
-@AllArgsConstructor
+@RestController
+@RequestMapping("/profile")
+@RequiredArgsConstructor
public class ProfileController {
+ private final ProfileService profileService;
- private final ResourceRepository resourceRepository;
- private final AccountRepository accountRepository;
- private final UpdateRepository updateRepository;
-
- @GetMapping("/profile/{id}")
- public String profile(Account account, @RequestParam(name = "sort", required = false, defaultValue = "updated") String sort, @RequestParam(name = "page", required = false, defaultValue = "1") String page, @RequestParam(name = "field", required = false, defaultValue = "") String field, @PathVariable("id") int id, Model model) {
- model.addAttribute("account", account);
- model.addAttribute("page", Integer.parseInt(page));
-
- Optional optionalAccount = accountRepository.findById(id);
-
- if (optionalAccount.isEmpty()) return "error/404";
-
- Account profile = accountRepository.getById(id);
-
- int totalDownloads = 0;
- for (Resource resource : profile.getResources()) {
- totalDownloads += updateRepository.getTotalDownloads(resource.getId()) == null ? 0 : updateRepository.getTotalDownloads(resource.getId());
- }
-
- model.addAttribute("totalDownloads", totalDownloads);
- model.addAttribute("user", profile);
- model.addAttribute("joined", profile.getJoined().format(DateUtil.getDateFormatter()));
-
- switch (field.toLowerCase()) {
- case "resources":
- if (Integer.parseInt(page) < 1) return "redirect:/profile/1?page=1";
-
- Sort sort1 = Sort.by(sort).ascending();
- Pageable pageable = PageRequest.of(Integer.parseInt(page) - 1, 25, sort1);
- List resources = resourceRepository.findAllByAuthorId(id, pageable);
-
- List data = new ArrayList<>();
- int total = resources.size() / 25;
- int remainder = resources.size() % 25;
- if (remainder > 1) total++;
-
- for (Resource resource : resources) {
- Integer downloads = updateRepository.getTotalDownloads(resource.getId());
- data.add(SimpleResourceDto.create(resource, downloads == null ? 0 : downloads));
- }
-
- model.addAttribute("total", total);
- model.addAttribute("files", data);
- return "profile/resources";
- default:
- return "profile/profile";
- }
+ @GetMapping("/{id}")
+ public ProfileDto getProfile(@PathVariable int id) throws RestException {
+ return this.profileService.getProfileDto(id);
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/ReportController.java b/src/main/java/com/imjustdoom/pluginsite/controller/ReportController.java
index 12332e9..0e27017 100644
--- a/src/main/java/com/imjustdoom/pluginsite/controller/ReportController.java
+++ b/src/main/java/com/imjustdoom/pluginsite/controller/ReportController.java
@@ -2,35 +2,21 @@
import com.imjustdoom.pluginsite.dtos.in.CreateReportRequest;
import com.imjustdoom.pluginsite.model.Account;
-import com.imjustdoom.pluginsite.model.Report;
-import com.imjustdoom.pluginsite.repositories.ReportRepository;
-import lombok.AllArgsConstructor;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.ModelAttribute;
+import com.imjustdoom.pluginsite.service.ReportService;
+import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
-@Controller
-@AllArgsConstructor
+@RestController
+@RequestMapping("/report")
+@RequiredArgsConstructor
public class ReportController {
+ private final ReportService reportService;
- private final ReportRepository reportRepository;
-
- @GetMapping("/report")
- public String report(Account account, Model model, @RequestParam(name = "status", required = false) String status) {
- model.addAttribute("report", new CreateReportRequest());
- model.addAttribute("account", account);
- model.addAttribute("status", status);
- return "report";
- }
-
- @PostMapping("/report")
- public String sendReport(Account account, @ModelAttribute CreateReportRequest reportRequest) {
- Report report = new Report(account, reportRequest.getReportingObject(), reportRequest.getReportingId(),
- reportRequest.getReport(), reportRequest.getReason());
- reportRepository.save(report);
- return "redirect:/report?status=success";
+ @PostMapping
+ public void createReport(Account account, @RequestBody CreateReportRequest request) {
+ this.reportService.createReport(account, request);
}
}
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/ResourceController.java b/src/main/java/com/imjustdoom/pluginsite/controller/ResourceController.java
new file mode 100644
index 0000000..fab06d0
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/controller/ResourceController.java
@@ -0,0 +1,56 @@
+package com.imjustdoom.pluginsite.controller;
+
+import com.imjustdoom.pluginsite.config.exception.RestErrorCode;
+import com.imjustdoom.pluginsite.config.exception.RestException;
+import com.imjustdoom.pluginsite.dtos.in.CreateResourceRequest;
+import com.imjustdoom.pluginsite.dtos.out.SimpleResourceDto;
+import com.imjustdoom.pluginsite.model.Account;
+import com.imjustdoom.pluginsite.model.Resource;
+import com.imjustdoom.pluginsite.repositories.ResourceRepository;
+import com.imjustdoom.pluginsite.service.ResourceService;
+import com.querydsl.core.types.Predicate;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.querydsl.binding.QuerydslPredicate;
+import org.springframework.data.web.PageableDefault;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+@RestController
+@RequestMapping("/resource")
+@RequiredArgsConstructor
+public class ResourceController {
+ private final ResourceService resourceService;
+ private final ResourceRepository resourceRepository;
+
+ @GetMapping
+ public Page searchResources(@PageableDefault(size = 25, sort = "updated", direction = Sort.Direction.DESC) Pageable pageable,
+ @QuerydslPredicate(root = Resource.class) Predicate predicate) throws RestException {
+ if (pageable.getPageSize() > 50) throw new RestException(RestErrorCode.PAGE_SIZE_TOO_LARGE, "Page size is too large (%s > %s)", pageable.getPageSize(), 50);
+ return this.resourceService.searchResources(pageable, predicate);
+ }
+
+ @PostMapping
+ public void createResource(Account account, CreateResourceRequest request) throws RestException {
+ this.resourceService.createResource(account, request);
+ }
+
+ @PostMapping("/{resourceId}/edit")
+ public void updateResourceInfo(Account account, @PathVariable int resourceId, @RequestParam(value = "file", required = false) MultipartFile file, CreateResourceRequest request) throws RestException {
+ this.resourceService.updateResource(account, resourceId, file, request);
+ }
+
+ // todo properly delete
+ @DeleteMapping("/{resourceId}")
+ public void deleteResource(@PathVariable int resourceId) {
+ this.resourceRepository.updateStatusById(resourceId, "removed");
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/ResourceUpdateController.java b/src/main/java/com/imjustdoom/pluginsite/controller/ResourceUpdateController.java
new file mode 100644
index 0000000..385bfcd
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/controller/ResourceUpdateController.java
@@ -0,0 +1,59 @@
+package com.imjustdoom.pluginsite.controller;
+
+
+import com.imjustdoom.pluginsite.config.exception.RestException;
+import com.imjustdoom.pluginsite.dtos.in.CreateUpdateRequest;
+import com.imjustdoom.pluginsite.dtos.in.resource.EditResourceUpdateRequest;
+import com.imjustdoom.pluginsite.model.Account;
+import com.imjustdoom.pluginsite.model.Update;
+import com.imjustdoom.pluginsite.service.ResourceUpdateService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ContentDisposition;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+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 org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+
+@RestController
+@RequestMapping("/resource/update")
+@RequiredArgsConstructor
+public class ResourceUpdateController {
+ private final ResourceUpdateService resourceUpdateService;
+
+ @PatchMapping("/{updateId}/status")
+ public Update changeStatus(Account account, @PathVariable int updateId, @RequestParam String status) throws RestException {
+ return this.resourceUpdateService.changeStatus(account, updateId, status);
+ }
+
+ @PatchMapping("/{updateId}")
+ public Update editUpdate(Account account, @PathVariable int updateId, @RequestBody EditResourceUpdateRequest request) throws RestException {
+ return this.resourceUpdateService.editUpdate(account, updateId, request);
+ }
+
+ @PostMapping("/")
+ public void createUpdate(Account account, @RequestParam int resourceId,
+ @RequestParam MultipartFile file, @RequestBody CreateUpdateRequest updateRequest) throws RestException {
+ this.resourceUpdateService.createUpdate(account, resourceId, file, updateRequest);
+ }
+
+ @GetMapping(value = "/{updateId}/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
+ public ResponseEntity getFile(@PathVariable int updateId) throws RestException {
+ ResourceUpdateService.FileReturn fileReturn = this.resourceUpdateService.getDownload(updateId);
+ return ResponseEntity.ok()
+ .headers(httpHeaders -> httpHeaders.setContentDisposition(
+ ContentDisposition.attachment()
+ .filename(fileReturn.realName())
+ .build()
+ ))
+ .body(fileReturn.file());
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/controller/ResourcesController.java b/src/main/java/com/imjustdoom/pluginsite/controller/ResourcesController.java
deleted file mode 100644
index 2548334..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/controller/ResourcesController.java
+++ /dev/null
@@ -1,407 +0,0 @@
-package com.imjustdoom.pluginsite.controller;
-
-import com.imjustdoom.pluginsite.config.custom.SiteConfig;
-import com.imjustdoom.pluginsite.dtos.in.CreateResourceRequest;
-import com.imjustdoom.pluginsite.dtos.in.CreateUpdateRequest;
-import com.imjustdoom.pluginsite.dtos.out.SimpleResourceDto;
-import com.imjustdoom.pluginsite.model.Account;
-import com.imjustdoom.pluginsite.model.Resource;
-import com.imjustdoom.pluginsite.model.Update;
-import com.imjustdoom.pluginsite.repositories.AccountRepository;
-import com.imjustdoom.pluginsite.repositories.ResourceRepository;
-import com.imjustdoom.pluginsite.repositories.UpdateRepository;
-import com.imjustdoom.pluginsite.service.LogoService;
-import com.imjustdoom.pluginsite.service.ResourceService;
-import com.imjustdoom.pluginsite.util.*;
-import lombok.AllArgsConstructor;
-import me.xdrop.fuzzywuzzy.FuzzySearch;
-import org.commonmark.node.Node;
-import org.commonmark.parser.Parser;
-import org.commonmark.renderer.html.HtmlRenderer;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
-import org.springframework.web.servlet.mvc.support.RedirectAttributes;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.util.*;
-
-@Controller
-@AllArgsConstructor
-@RequestMapping("/resources")
-public class ResourcesController {
- private final LogoService logoService;
- private final ResourceService resourceService;
- private final ResourceRepository resourceRepository;
- private final AccountRepository accountRepository;
- private final UpdateRepository updateRepository;
-
- private final SiteConfig siteConfig;
- private final UrlUtil urlUtil;
-
- @GetMapping
- public String resources(Account account, @RequestParam(name = "category", required = false, defaultValue = "all") String category, @RequestParam(name = "search", required = false) String search, @RequestParam(name = "sort", required = false, defaultValue = "updated") String sort, @RequestParam(name = "page", required = false, defaultValue = "1") String page, Model model) {
-
- // TODO: clean up more and make it easier to read
- if (Integer.parseInt(page) < 1) return "redirect:/resources?page=1";
-
- List data;
-
- int resources, total, remainder;
-
- if (search != null && !search.equals("")) {
-
- data = resourceService.searchResources(search, sort, page);
- resources = FuzzySearch.extractSorted(search, resourceRepository.findAllByStatusEqualsIgnoreCase("public"), Resource::getName).size();
- total = resources / 25;
- remainder = resources % 25;
- if (remainder > 1) total++;
-
- model.addAttribute("results", resources);
- } else if (!category.equalsIgnoreCase("all")) {
- Sort sort1 = Sort.by(sort).descending();
- if (sort.equalsIgnoreCase("name")) sort1 = sort1.ascending();
- Pageable pageable = PageRequest.of(Integer.parseInt(page) - 1, 25, sort1);
-
- resources = resourceRepository.findAllByCategoryEqualsAndStatusEquals(category, "public", pageable).size();
- total = resources / 25;
- remainder = resources % 25;
- if (remainder > 1) total++;
-
- data = resourceService.getResourcesWithCategory(sort, page, category);
- } else {
-
- resources = resourceRepository.findAll().size();
- total = resources / 25;
- remainder = resources % 25;
- if (remainder > 1) total++;
-
- data = resourceService.getResources(sort, page);
- }
-
- model.addAttribute("total", total);
- model.addAttribute("files", data);
- model.addAttribute("account", account);
- model.addAttribute("page", Integer.parseInt(page));
-
- return "resource/resources";
- }
-
- @GetMapping("/{id_s}")
- public String resource(Account account, @RequestParam(name = "software", required = false, defaultValue = "all") String softwareParam, @RequestParam(name = "sort", required = false, defaultValue = "uploaded") String sort, @PathVariable("id_s") String id_s, @RequestParam(name = "field", required = false, defaultValue = "") String field, Model model) throws MalformedURLException {
- int id;
- try {
- id = Integer.parseInt(id_s);
- } catch (NumberFormatException e) {
- return "error/404";
- }
-
- Optional optionalResource = resourceRepository.findById(id);
-
- if (optionalResource.isEmpty()) return "error/404";
-
- Resource resource = resourceRepository.getById(id);
-
- if (!resource.getStatus().equalsIgnoreCase("public") && !account.getRole().equalsIgnoreCase("role_admin")) {
- model.addAttribute("account", account);
- return "error/resourceDeleted";
- }
-
- String description = urlUtil.encode(resource.getDescription());
-
- description.replaceAll("script", "error style=\"display:none;\"");
- Parser parser = Parser.builder().build();
- Node document = parser.parse(description);
- HtmlRenderer renderer = HtmlRenderer.builder().build();
- String html = renderer.render(document);
-
- resource.setDescription(html);
-
- List updates = updateRepository.findAllByResourceIdAndStatusEquals(id, "public", Sort.by("uploaded").descending());
-
- model.addAttribute("download", updates.size() > 0 ? updates.get(0).getDownload() : null);
- model.addAttribute("account", account);
- model.addAttribute("resource", resource);
- model.addAttribute("editUrl", "/resources/%s/edit".formatted(id));
- model.addAttribute("uploadUrl", "/resources/%s/upload/".formatted(id));
-
- Integer totalDownloads = updateRepository.getTotalDownloads(resource.getId());
- model.addAttribute("totalDownloads", totalDownloads == null ? 0 : totalDownloads);
- model.addAttribute("created", resource.getCreated().format(DateUtil.getDateFormatter()));
- model.addAttribute("updated", resource.getUpdated().format(DateUtil.getDateFormatter()));
-
- switch (field.toLowerCase()) {
- case "updates":
- Sort sort1 = Sort.by(sort).descending();
- if (sort.equalsIgnoreCase("name")) sort1 = sort1.ascending();
-
- // TODO: improve getting the versions and software. 100% not the best way to do this
- List data;
- if (!softwareParam.equals("all")) {
- data = updateRepository.findAllByResourceIdAndStatusEqualsAndSoftware(id, "public", softwareParam, sort1);
- //data = new ArrayList<>();
- } else {
- data = updateRepository.findAllByResourceIdAndStatusEquals(id, "public", sort1);
- }
- List> versions = new ArrayList<>();
- List versionLists = new ArrayList<>();
- List softwareLists = new ArrayList<>();
- for (Update update : data) {
- List versionList = new ArrayList<>();
-
- versionList.add(update.getVersions().get(0));
- boolean first = true;
- StringBuilder versionString = new StringBuilder();
- String splitter = "";
- for (String v : update.getVersions()) {
- if (first) {
- first = false;
- continue;
- }
- versionString.append(splitter);
- splitter = ", ";
- versionString.append(v);
- }
- versionLists.add(versionString.toString());
- versions.add(versionList);
-
- StringBuilder softwareString = new StringBuilder();
- splitter = "";
- for (String v : update.getSoftware()) {
- softwareString.append(splitter);
- splitter = ", ";
- softwareString.append(v);
- }
- softwareLists.add(softwareString.toString());
- }
-
- model.addAttribute("versions", versions);
- model.addAttribute("versionLists", versionLists);
- model.addAttribute("softwareLists", softwareLists);
- model.addAttribute("updates", data);
- return "resource/updates";
- default:
- return "resource/resource";
- }
- }
-
- @GetMapping("/{id}/edit/update/{fileId}")
- public String editResourceUpdate(@RequestParam(name = "error", required = false) String error, @PathVariable("id") int id, @PathVariable("fileId") int fileId, Model model, Account account) {
-
- Optional optionalResource = resourceRepository.findById(id);
- if (optionalResource.isEmpty()) return "error/404";
-
- Optional optionalUpdate = updateRepository.findById(fileId);
- if (optionalUpdate.isEmpty()) return "error/404";
- Update update = optionalUpdate.get();
-
- model.addAttribute("error", error);
- model.addAttribute("update", update);
- model.addAttribute("url", this.siteConfig.getDomain() + "/resources/" + id);
- model.addAttribute("account", account);
- model.addAttribute("resourceid", id);
-
- return "resource/editUpdate";
- }
-
- @PostMapping("/{id}/edit/update/{fileId}")
- public String editUpdateSubmit(@ModelAttribute Update update, @PathVariable("id") int id, @PathVariable("fileId") int fileId) {
-
- if (update.getName().equalsIgnoreCase("")
- || update.getVersion().equalsIgnoreCase("")
- || update.getDescription().equalsIgnoreCase(""))
- return "redirect:/resources/%s/edit/update/%s?error=invalidinput".formatted(id, fileId);
-
- //update.getId() doesnt actually return the id of the update for some reason
- // figure out why in the future
- updateRepository.setInfo(fileId, update.getName(), update.getDescription(), update.getVersion());
-
- return "redirect:/resources/%s".formatted(id);
- }
-
- @GetMapping("/{id}/edit")
- public String editResource(@RequestParam(name = "error", required = false) String error, @PathVariable("id") int id,
- Model model, Account account, @ModelAttribute(name = "resource") CreateResourceRequest resourceModel) {
- model.addAttribute("error", error);
- model.addAttribute("maxUploadSize", this.siteConfig.getMaxUploadSize().toBytes());
-
- Optional optionalResource = resourceRepository.findById(id);
- Resource resource = optionalResource.get();
-
- if (optionalResource.isEmpty()) return "error/404";
-
- model.addAttribute("id", id);
- model.addAttribute("authorid", resource.getAuthor().getId());
- model.addAttribute("resource", resourceModel.getName() == null ? resource : resourceModel);
- model.addAttribute("url", "/resources/" + id + "/edit");
- model.addAttribute("account", account);
-
- return "resource/edit";
- }
-
- @PostMapping("/{id}/edit")
- public String editSubmit(@RequestParam("logo") MultipartFile file, RedirectAttributes redirectAttributes,
- @ModelAttribute CreateResourceRequest resource, @PathVariable("id") int id) {
-
- redirectAttributes.addFlashAttribute("resource", resource);
- if (resourceRepository.existsByNameEqualsIgnoreCaseAndIdEqualsNot(id, resource.getName()))
- return "redirect:/resources/%s/edit?error=nametaken".formatted(id);
-
- if (resource.getName().equalsIgnoreCase("")
- || resource.getBlurb().equalsIgnoreCase("")
- || resource.getDescription().equalsIgnoreCase(""))
- return "redirect:/resources/%s/edit?error=invalidinput".formatted(id);
-
- if (!file.isEmpty()) {
- if (file.getSize() > 1024000) {
- return "redirect:/resources/%s/edit?error=filesize".formatted(id);
- }
-
- resourceRepository.updateLogoById(id, ImageUtil.handleImage(file));
- }
- // todo handle errors from ImageUtil
-
- resourceRepository.setInfo(id, resource.getName(), resource.getBlurb(), resource.getDescription(),
- resource.getDonation(), resource.getSource(), resource.getSupport(), resource.getCategory());
-
- return "redirect:/resources/%s".formatted(id);
- }
-
- //TODO: Do sanity checks
- @PostMapping("/create")
- public String createSubmit(@ModelAttribute CreateResourceRequest resourceRequest, Account account, RedirectAttributes redirectAttributes) {
- return resourceService.postCreateResource(resourceRequest, account, siteConfig, redirectAttributes);
- }
-
- @GetMapping("/create")
- public String create(Model model, Account account, @RequestParam(name = "error", required = false) String error, @ModelAttribute(name = "resourceRequest") CreateResourceRequest resourceRequest) {
- model.addAttribute("error", error);
- model.addAttribute("limit", this.siteConfig.getMaxCreationsPerHour());
- model.addAttribute("account", account);
- model.addAttribute("resource", resourceRequest.getName() == null ? new CreateResourceRequest() : resourceRequest);
- model.addAttribute("url", this.siteConfig.getDomain() + "/resources");
- return "resource/create";
- }
-
- @GetMapping("/{id}/upload")
- public String uploadFile(@RequestParam(name = "error", required = false) String error, @PathVariable("id") int id, Model model, Account account, @ModelAttribute(name = "updateRequest") CreateUpdateRequest updateRequest) {
-
- // TODO: make the checkboxing also save
-
- Optional optionalResource = resourceRepository.findById(id);
- Resource resource = optionalResource.get();
-
- if (optionalResource.isEmpty()) return "error/404";
-
- model.addAttribute("resource", resource);
- model.addAttribute("update", updateRequest.getName() == null ? new CreateUpdateRequest() : updateRequest);
- model.addAttribute("url", this.siteConfig.getDomain() + "/resources/%s/upload/".formatted(id));
- model.addAttribute("mainUrl", this.siteConfig.getDomain() + "/resources/%s".formatted(id));
- model.addAttribute("error", error);
- model.addAttribute("maxUploadSize", this.siteConfig.getMaxUploadSize().toBytes());
- model.addAttribute("account", account);
- model.addAttribute("limit", this.siteConfig.getMaxUpdatesPerHour());
-
- return "resource/upload";
- }
-
- @PostMapping("/{id}/upload")
- public String uploadFilePost(Account account, @RequestParam(name = "softwareCheckbox") List softwareBoxes,
- @RequestParam(name = "versionCheckbox") List versionBoxes,
- @PathVariable("id") int id, @RequestParam("file") MultipartFile file,
- @ModelAttribute CreateUpdateRequest updateRequest, RedirectAttributes redirectAttributes)
- throws IOException {
-
- redirectAttributes.addFlashAttribute("updateRequest", updateRequest);
- if (updateRepository.getUpdatesCreateLastHour(account.getId()) > this.siteConfig.getMaxUpdatesPerHour()) {
- return "redirect:/resources/%s/upload?error=uploadlimit".formatted(id);
- }
-
- if ((file.isEmpty() || file.getSize() > this.siteConfig.getMaxUploadSize().toBytes()) && updateRequest.getExternalLink().equals("")) {
- return "redirect:/resources/%s/upload?error=filesize".formatted(id);
- }
- if ((!file.getOriginalFilename().endsWith(".jar") && !file.getOriginalFilename().endsWith(".zip")) && updateRequest.getExternalLink().equals("")) {
- return "redirect:/resources/%s/upload?error=filetype".formatted(id);
- }
-
- if (updateRequest.getName().equalsIgnoreCase("")
- || updateRequest.getVersion().equalsIgnoreCase("")
- || updateRequest.getDescription().equalsIgnoreCase(""))
- return "redirect:/resources/%s/upload?error=invalidinput";
-
- Update update = new Update(updateRequest.getDescription(), file.getOriginalFilename(),
- updateRequest.getVersion(), "", updateRequest.getName(), versionBoxes, softwareBoxes,
- resourceRepository.findById(id).get(), updateRequest.getExternalLink());
- updateRepository.save(update);
-
- if (updateRequest.getExternalLink() == null || updateRequest.getExternalLink().equals("")) {
- if (!FileUtil.doesFileExist("./resources/plugins/" + update.getId())) {
- try {
- Files.createDirectory(Paths.get("./resources/plugins/" + update.getId()));
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- Path destinationFile = Path.of("./resources/plugins/" + update.getId() + "/" + file.getOriginalFilename()).normalize().toAbsolutePath();
-
- try (InputStream inputStream = file.getInputStream()) {
- Files.copy(inputStream, destinationFile,
- StandardCopyOption.REPLACE_EXISTING);
- }
- }
-
- String download = "%s/files/%s/download/%s".formatted(this.siteConfig.getDomain(), update.getResource().getId(), update.getId());
- resourceRepository.setDownload(id, download);
- updateRepository.setDownload(update.getId(), download);
-
- return "redirect:/resources/%s".formatted(id);
- }
-
- @GetMapping("/{id}/delete")
- public String delete(Account account, Model model, @PathVariable("id") int id) {
- model.addAttribute("account", account);
- model.addAttribute("resource", resourceRepository.findById(id).get());
- return "resource/delete";
- }
-
- @PostMapping("/{id}/delete")
- public String delete(@PathVariable("id") int id) {
- resourceRepository.updateStatusById(id, "removed");
- return "redirect:/";
- }
-
- @PostMapping("/{id}/update/{update}/status")
- public ResponseEntity> changeStatus(Account account, @PathVariable("id") int id,
- @PathVariable("update") int updateId,
- @RequestBody String request) {
-
- HashMap response = new HashMap<>();
-
- Optional optionalResource = resourceRepository.findById(id);
- Resource resource = optionalResource.get();
-
- if (account.getId() != resource.getAuthor().getId()) {
- return new ResponseEntity<>(response, HttpStatus.FORBIDDEN);
- }
-
- HashMap params = RequestUtil.getParams(request);
- String status = params.get("status");
-
- updateRepository.updateStatusById(updateId, status);
-
- return new ResponseEntity<>(response, HttpStatus.OK);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/imjustdoom/pluginsite/dtos/in/CreateUpdateRequest.java b/src/main/java/com/imjustdoom/pluginsite/dtos/in/CreateUpdateRequest.java
index f8368b5..9d67e68 100644
--- a/src/main/java/com/imjustdoom/pluginsite/dtos/in/CreateUpdateRequest.java
+++ b/src/main/java/com/imjustdoom/pluginsite/dtos/in/CreateUpdateRequest.java
@@ -4,6 +4,8 @@
import lombok.NoArgsConstructor;
import lombok.Setter;
+import java.util.List;
+
@Setter
@Getter
@NoArgsConstructor
@@ -13,4 +15,13 @@ public class CreateUpdateRequest {
private String version;
private String externalLink;
private String description;
+ private List versions;
+ private List software;
+
+ public boolean isMissingRequirements() {
+ return this.name == null || this.name.isEmpty()
+ || this.version == null || this.version.isEmpty()
+ || this.externalLink == null || this.externalLink.isEmpty()
+ || this.description == null || this.description.isEmpty();
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/imjustdoom/pluginsite/dtos/in/CreateAccountRequest.java b/src/main/java/com/imjustdoom/pluginsite/dtos/in/account/CreateAccountRequest.java
similarity index 65%
rename from src/main/java/com/imjustdoom/pluginsite/dtos/in/CreateAccountRequest.java
rename to src/main/java/com/imjustdoom/pluginsite/dtos/in/account/CreateAccountRequest.java
index f8e8a01..148ea91 100644
--- a/src/main/java/com/imjustdoom/pluginsite/dtos/in/CreateAccountRequest.java
+++ b/src/main/java/com/imjustdoom/pluginsite/dtos/in/account/CreateAccountRequest.java
@@ -1,12 +1,10 @@
-package com.imjustdoom.pluginsite.dtos.in;
+package com.imjustdoom.pluginsite.dtos.in.account;
import lombok.Getter;
-import lombok.NoArgsConstructor;
import lombok.Setter;
@Setter
@Getter
-@NoArgsConstructor
public class CreateAccountRequest {
private String username;
diff --git a/src/main/java/com/imjustdoom/pluginsite/dtos/in/account/UpdateAccountRequest.java b/src/main/java/com/imjustdoom/pluginsite/dtos/in/account/UpdateAccountRequest.java
new file mode 100644
index 0000000..3099ca2
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/dtos/in/account/UpdateAccountRequest.java
@@ -0,0 +1,11 @@
+package com.imjustdoom.pluginsite.dtos.in.account;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class UpdateAccountRequest {
+ private String username;
+ private String email;
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/dtos/in/resource/EditResourceUpdateRequest.java b/src/main/java/com/imjustdoom/pluginsite/dtos/in/resource/EditResourceUpdateRequest.java
new file mode 100644
index 0000000..2601b31
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/dtos/in/resource/EditResourceUpdateRequest.java
@@ -0,0 +1,12 @@
+package com.imjustdoom.pluginsite.dtos.in.resource;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class EditResourceUpdateRequest {
+ private String name;
+ private String version;
+ private String description;
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/dtos/out/ProfileDto.java b/src/main/java/com/imjustdoom/pluginsite/dtos/out/ProfileDto.java
new file mode 100644
index 0000000..fed62a7
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/dtos/out/ProfileDto.java
@@ -0,0 +1,8 @@
+package com.imjustdoom.pluginsite.dtos.out;
+
+import com.imjustdoom.pluginsite.dtos.out.account.AccountDto;
+
+public record ProfileDto(int id, int totalDownloads,
+ AccountDto accountDto) {
+
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/dtos/out/account/AccountDto.java b/src/main/java/com/imjustdoom/pluginsite/dtos/out/account/AccountDto.java
new file mode 100644
index 0000000..4fd2f86
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/dtos/out/account/AccountDto.java
@@ -0,0 +1,14 @@
+package com.imjustdoom.pluginsite.dtos.out.account;
+
+import com.imjustdoom.pluginsite.model.Account;
+
+import java.time.LocalDateTime;
+
+public record AccountDto(int id, String username,
+ byte[] profilePicture, LocalDateTime joined) {
+
+ public static AccountDto fromAccount(Account account) {
+ return new AccountDto(account.getId(), account.getUsername(),
+ account.getProfilePicture(), account.getJoined());
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/dtos/out/account/SelfAccountDto.java b/src/main/java/com/imjustdoom/pluginsite/dtos/out/account/SelfAccountDto.java
new file mode 100644
index 0000000..93725e2
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/dtos/out/account/SelfAccountDto.java
@@ -0,0 +1,16 @@
+package com.imjustdoom.pluginsite.dtos.out.account;
+
+import com.imjustdoom.pluginsite.model.Account;
+
+import java.time.LocalDateTime;
+
+public record SelfAccountDto(int id, String username,
+ String email, byte[] profilePicture,
+ LocalDateTime joined) {
+
+ public static SelfAccountDto fromAccount(Account account) {
+ return new SelfAccountDto(account.getId(), account.getUsername(),
+ account.getEmail(), account.getProfilePicture(),
+ account.getJoined());
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/dtos/out/message/MessageDto.java b/src/main/java/com/imjustdoom/pluginsite/dtos/out/message/MessageDto.java
new file mode 100644
index 0000000..01cdab9
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/dtos/out/message/MessageDto.java
@@ -0,0 +1,11 @@
+package com.imjustdoom.pluginsite.dtos.out.message;
+
+import com.imjustdoom.pluginsite.model.Message;
+
+public record MessageDto(int id, int authorId,
+ String content) {
+
+ public static MessageDto fromMessage(Message message) {
+ return new MessageDto(message.getId(), message.getAuthor().getId(), message.getContent());
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/dtos/out/message/MessageGroupDto.java b/src/main/java/com/imjustdoom/pluginsite/dtos/out/message/MessageGroupDto.java
new file mode 100644
index 0000000..2d7e9a8
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/dtos/out/message/MessageGroupDto.java
@@ -0,0 +1,12 @@
+package com.imjustdoom.pluginsite.dtos.out.message;
+
+import com.imjustdoom.pluginsite.model.MessageGroup;
+
+import java.time.LocalDateTime;
+
+public record MessageGroupDto(int id, String name, LocalDateTime createdTime) {
+
+ public static MessageGroupDto fromMessageGroup(MessageGroup group) {
+ return new MessageGroupDto(group.getId(), group.getName(), group.getCreatedTime());
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/model/Account.java b/src/main/java/com/imjustdoom/pluginsite/model/Account.java
index ff67d84..d0be555 100644
--- a/src/main/java/com/imjustdoom/pluginsite/model/Account.java
+++ b/src/main/java/com/imjustdoom/pluginsite/model/Account.java
@@ -1,6 +1,7 @@
package com.imjustdoom.pluginsite.model;
import lombok.Getter;
+import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -15,6 +16,7 @@
@Setter
@Getter
@Entity
+@NoArgsConstructor
public class Account implements UserDetails {
public Account(String username, String email, String password) {
@@ -30,10 +32,10 @@ public Account(String username, String email, String password) {
private int id;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "author")
- private List resources;
+ private List resources = new ArrayList<>();
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "reporter")
- private List reports;
+ private List reports = new ArrayList<>();
@Column(nullable = false, unique = true)
private String username;
@@ -56,14 +58,11 @@ public Account(String username, String email, String password) {
private List groups;
@Lob
- private byte[] profile_picture;
+ @Column(name = "profile_picture")
+ private byte[] profilePicture;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "author")
- private List messages;
-
- public Account() {
-
- }
+ private List messages = new ArrayList<>();
@Override
public Collection extends GrantedAuthority> getAuthorities() {
diff --git a/src/main/java/com/imjustdoom/pluginsite/model/Message.java b/src/main/java/com/imjustdoom/pluginsite/model/Message.java
index 08daee0..18a3883 100644
--- a/src/main/java/com/imjustdoom/pluginsite/model/Message.java
+++ b/src/main/java/com/imjustdoom/pluginsite/model/Message.java
@@ -3,9 +3,14 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
-import javax.persistence.Id;
-import javax.persistence.*;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
@Setter
@Getter
@@ -13,7 +18,7 @@
@NoArgsConstructor
public class Message {
- public Message(String content, Account author, MessageGroup group){
+ public Message(String content, Account author, MessageGroup group) {
this.content = content;
this.author = author;
this.group = group;
diff --git a/src/main/java/com/imjustdoom/pluginsite/model/MessageGroup.java b/src/main/java/com/imjustdoom/pluginsite/model/MessageGroup.java
index 6a0838a..7a02d3c 100644
--- a/src/main/java/com/imjustdoom/pluginsite/model/MessageGroup.java
+++ b/src/main/java/com/imjustdoom/pluginsite/model/MessageGroup.java
@@ -3,9 +3,16 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
-import javax.persistence.Id;
-import javax.persistence.*;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.OneToMany;
import java.time.LocalDateTime;
import java.util.List;
@@ -15,9 +22,9 @@
@NoArgsConstructor
public class MessageGroup {
- public MessageGroup(String name, LocalDateTime createdDate, List members){
+ public MessageGroup(String name, LocalDateTime createdTime, List members) {
this.name = name;
- this.createdDate = createdDate;
+ this.createdTime = createdTime;
this.members = members;
System.out.println(members.toString());
}
@@ -34,7 +41,7 @@ public MessageGroup(String name, LocalDateTime createdDate, List member
private String name;
@Column(nullable = false)
- private LocalDateTime createdDate;
+ private LocalDateTime createdTime;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "group")
private List messages;
diff --git a/src/main/java/com/imjustdoom/pluginsite/model/Resource.java b/src/main/java/com/imjustdoom/pluginsite/model/Resource.java
index 1dfcf2a..5ae163b 100644
--- a/src/main/java/com/imjustdoom/pluginsite/model/Resource.java
+++ b/src/main/java/com/imjustdoom/pluginsite/model/Resource.java
@@ -14,14 +14,13 @@
@NoArgsConstructor
public class Resource {
- public Resource(String name, String description, String blurb, String donation, String source, String download,
+ public Resource(String name, String description, String blurb, String donation, String source,
Account author, String support, String category) {
this.name = name;
this.description = description;
this.blurb = blurb;
this.donation = donation;
this.source = source;
- this.download = download;
this.author = author;
this.support = support;
this.created = LocalDateTime.now();
@@ -49,15 +48,13 @@ public Resource(String name, String description, String blurb, String donation,
@Column(nullable = false)
private LocalDateTime updated;
+ // todo if we are making these optional, they should also be nullable??
@Column(nullable = false)
private String donation;
@Column(nullable = false)
private String source;
- @Column(nullable = false)
- private String download;
-
@ManyToOne(fetch = FetchType.LAZY)
private Account author;
diff --git a/src/main/java/com/imjustdoom/pluginsite/model/Update.java b/src/main/java/com/imjustdoom/pluginsite/model/Update.java
index 89a836a..4f37e91 100644
--- a/src/main/java/com/imjustdoom/pluginsite/model/Update.java
+++ b/src/main/java/com/imjustdoom/pluginsite/model/Update.java
@@ -2,6 +2,7 @@
import lombok.Getter;
import lombok.Setter;
+import org.springframework.lang.Nullable;
import javax.persistence.*;
import java.time.LocalDateTime;
@@ -14,18 +15,17 @@
public class Update {
public Update(String description, String filename, String version, String download, String name,
- List versions, List software, Resource resource, String external) {
+ List versions, List software, Resource resource) {
this.downloads = 0;
this.description = description;
this.filename = filename;
this.version = version;
- this.download = download;
+ this.downloadLink = download;
this.name = name;
this.uploaded = LocalDateTime.now();
this.versions = versions;
this.software = software;
this.resource = resource;
- this.external = external;
this.status = "public";
}
@@ -33,6 +33,9 @@ public Update(String description, String filename, String version, String downlo
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
+ @ManyToOne(fetch = FetchType.LAZY)
+ private Resource resource;
+
@Column(nullable = false)
private String description;
@@ -45,8 +48,7 @@ public Update(String description, String filename, String version, String downlo
@ElementCollection
private List software;
- @Column(nullable = false)
- private String download;
+ private @Nullable String downloadLink;
@Column(nullable = false)
private String name;
@@ -60,12 +62,6 @@ public Update(String description, String filename, String version, String downlo
@Column(nullable = false)
private int downloads;
- @Column(nullable = false)
- private String external;
-
- @ManyToOne(fetch = FetchType.LAZY)
- private Resource resource;
-
@Column(nullable = false)
private String status;
diff --git a/src/main/java/com/imjustdoom/pluginsite/repositories/AccountRepository.java b/src/main/java/com/imjustdoom/pluginsite/repositories/AccountRepository.java
index fa870ef..bc5143d 100644
--- a/src/main/java/com/imjustdoom/pluginsite/repositories/AccountRepository.java
+++ b/src/main/java/com/imjustdoom/pluginsite/repositories/AccountRepository.java
@@ -42,9 +42,9 @@ public interface AccountRepository extends JpaRepository {
@Modifying
@Transactional
- @Query("UPDATE Account account SET account.profile_picture = ?2 WHERE account.id = ?1")
- void updateProfilePictureById(int id, byte[] profile_picture);
+ @Query("UPDATE Account account SET account.profilePicture = ?2 WHERE account.id = ?1")
+ void updateProfilePictureById(int id, byte[] profilePicture);
- @Query("SELECT profile_picture FROM Account WHERE id = ?1")
+ @Query("SELECT profilePicture FROM Account WHERE id = ?1")
byte[] findAccountProfilePicture(int id);
}
\ No newline at end of file
diff --git a/src/main/java/com/imjustdoom/pluginsite/repositories/MessageGroupRepository.java b/src/main/java/com/imjustdoom/pluginsite/repositories/MessageGroupRepository.java
index 0c1dc56..5f874d0 100644
--- a/src/main/java/com/imjustdoom/pluginsite/repositories/MessageGroupRepository.java
+++ b/src/main/java/com/imjustdoom/pluginsite/repositories/MessageGroupRepository.java
@@ -1,12 +1,13 @@
package com.imjustdoom.pluginsite.repositories;
+import com.imjustdoom.pluginsite.model.Account;
import com.imjustdoom.pluginsite.model.MessageGroup;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.repository.PagingAndSortingRepository;
-public interface MessageGroupRepository extends JpaRepository {
+public interface MessageGroupRepository extends PagingAndSortingRepository {
+
+ Page findAllByMembersContains(Account account, Pageable pageable);
- // get all message groups that an account is in
-// @Query("select mg from MessageGroup mg where mg.account.id = ?1")
-// Iterable findAllByAccountId(int accountId);
}
diff --git a/src/main/java/com/imjustdoom/pluginsite/repositories/MessageRepository.java b/src/main/java/com/imjustdoom/pluginsite/repositories/MessageRepository.java
index 1e3cba6..7730c1e 100644
--- a/src/main/java/com/imjustdoom/pluginsite/repositories/MessageRepository.java
+++ b/src/main/java/com/imjustdoom/pluginsite/repositories/MessageRepository.java
@@ -1,8 +1,12 @@
package com.imjustdoom.pluginsite.repositories;
import com.imjustdoom.pluginsite.model.Message;
+import com.imjustdoom.pluginsite.model.MessageGroup;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.Query;
public interface MessageRepository extends JpaRepository {
+
+ Page findByGroup(MessageGroup group, Pageable pageable);
}
diff --git a/src/main/java/com/imjustdoom/pluginsite/repositories/ReportRepository.java b/src/main/java/com/imjustdoom/pluginsite/repositories/ReportRepository.java
index c6baccc..3e432f8 100644
--- a/src/main/java/com/imjustdoom/pluginsite/repositories/ReportRepository.java
+++ b/src/main/java/com/imjustdoom/pluginsite/repositories/ReportRepository.java
@@ -1,18 +1,18 @@
package com.imjustdoom.pluginsite.repositories;
import com.imjustdoom.pluginsite.model.Report;
-import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
@Repository
-public interface ReportRepository extends JpaRepository {
+public interface ReportRepository extends PagingAndSortingRepository {
@Modifying
@Transactional
@Query("UPDATE Report report SET report.actionTaken = ?2 WHERE report.id = ?1")
- void updateActionTakenById(int id, String actionTaken);
+ Report updateActionTakenById(int id, String actionTaken);
}
diff --git a/src/main/java/com/imjustdoom/pluginsite/repositories/ResourceRepository.java b/src/main/java/com/imjustdoom/pluginsite/repositories/ResourceRepository.java
index a448534..850aff1 100644
--- a/src/main/java/com/imjustdoom/pluginsite/repositories/ResourceRepository.java
+++ b/src/main/java/com/imjustdoom/pluginsite/repositories/ResourceRepository.java
@@ -1,11 +1,15 @@
package com.imjustdoom.pluginsite.repositories;
+import com.imjustdoom.pluginsite.model.QResource;
import com.imjustdoom.pluginsite.model.Resource;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.querydsl.QuerydslPredicateExecutor;
+import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
+import org.springframework.data.querydsl.binding.QuerydslBindings;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
@@ -13,7 +17,18 @@
import java.util.Optional;
@Repository
-public interface ResourceRepository extends JpaRepository {
+public interface ResourceRepository extends JpaRepository, QuerydslPredicateExecutor, QuerydslBinderCustomizer {
+
+ @Override
+ default void customize(QuerydslBindings bindings, QResource root) {
+ bindings.including(
+ root.name,
+ root.category,
+ root.author.username,
+ root.author.id
+ );
+ bindings.excludeUnlistedProperties(true);
+ }
boolean existsByNameEqualsIgnoreCase(String name);
@@ -26,11 +41,6 @@ public interface ResourceRepository extends JpaRepository {
List findAllByStatusEqualsIgnoreCase(String status);
- @Modifying
- @Transactional
- @Query("UPDATE Resource resource SET resource.download = ?2 WHERE resource.id = ?1")
- void setDownload(int id, String download);
-
@Modifying
@Transactional
@Query("UPDATE Resource resource SET resource.name = ?2, resource.blurb = ?3, resource.description = ?4, " +
diff --git a/src/main/java/com/imjustdoom/pluginsite/repositories/UpdateRepository.java b/src/main/java/com/imjustdoom/pluginsite/repositories/UpdateRepository.java
index adf759d..0e7e7ce 100644
--- a/src/main/java/com/imjustdoom/pluginsite/repositories/UpdateRepository.java
+++ b/src/main/java/com/imjustdoom/pluginsite/repositories/UpdateRepository.java
@@ -8,8 +8,8 @@
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
-import java.util.Collection;
import java.util.List;
+import java.util.Optional;
@Repository
public interface UpdateRepository extends JpaRepository {
@@ -18,22 +18,16 @@ public interface UpdateRepository extends JpaRepository {
List findAllByResourceIdAndStatusEquals(int resourceId, String status, Sort sort);
- // TODO: get this to actually work at some point
- @Query("SELECT updates FROM Update updates WHERE ?3 in(updates.software)")
- List findAllByResourceIdAndStatusEqualsAndSoftware(int resourceId, String status, String software, Sort sort);
-
- @Modifying
- @Transactional
- @Query("UPDATE Update updates SET updates.download = ?2 WHERE updates.id = ?1")
- void setDownload(int id, String download);
-
@Modifying
@Transactional
@Query("UPDATE Update updates SET updates.downloads = updates.downloads + 1 WHERE updates.id = ?1")
void addDownload(int id);
@Query("SELECT SUM(updates.downloads) FROM Update updates WHERE updates.resource.id = ?1")
- Integer getTotalDownloads(int id);
+ Optional getTotalDownloads(int id);
+
+ @Query("SELECT SUM(updates.downloads) FROM Update updates WHERE updates.resource.author.id = ?1")
+ Optional getTotalAccountDownloads(int userId);
@Modifying
@Transactional
@@ -46,5 +40,5 @@ public interface UpdateRepository extends JpaRepository {
@Modifying
@Transactional
@Query("UPDATE Update updates SET updates.status = ?2 WHERE updates.id = ?1")
- void updateStatusById(int id, String status);
+ Optional updateStatusById(int id, String status);
}
\ No newline at end of file
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/AccountService.java b/src/main/java/com/imjustdoom/pluginsite/service/AccountService.java
new file mode 100644
index 0000000..895c965
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/service/AccountService.java
@@ -0,0 +1,76 @@
+package com.imjustdoom.pluginsite.service;
+
+import com.imjustdoom.pluginsite.config.custom.SiteConfig;
+import com.imjustdoom.pluginsite.config.exception.RestErrorCode;
+import com.imjustdoom.pluginsite.config.exception.RestException;
+import com.imjustdoom.pluginsite.dtos.in.account.CreateAccountRequest;
+import com.imjustdoom.pluginsite.dtos.in.account.UpdateAccountRequest;
+import com.imjustdoom.pluginsite.model.Account;
+import com.imjustdoom.pluginsite.repositories.AccountRepository;
+import com.imjustdoom.pluginsite.util.ImageUtil;
+import com.imjustdoom.pluginsite.util.ValidationHelper;
+import lombok.RequiredArgsConstructor;
+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.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+@Service
+@RequiredArgsConstructor
+public class AccountService implements UserDetailsService {
+ private final AccountRepository accountRepository;
+ private final PasswordEncoder passwordEncoder;
+
+ private final SiteConfig siteConfig;
+
+ @Override
+ public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
+ return accountRepository.findByUsernameEqualsIgnoreCase(s).orElseThrow(() -> new UsernameNotFoundException("User not found"));
+ }
+
+ public Account register(CreateAccountRequest request) throws RestException {
+ String username = request.getUsername();
+ if (!ValidationHelper.isUsernameValid(username)) throw new RestException(RestErrorCode.INVALID_USERNAME);
+
+ String email = request.getEmail();
+ if (!ValidationHelper.isEmailValid(email)) throw new RestException(RestErrorCode.INVALID_EMAIL);
+
+ if (this.accountRepository.existsByUsernameEqualsIgnoreCase(username)) throw new RestException(RestErrorCode.USERNAME_NOT_AVAILABLE);
+ if (this.accountRepository.existsByEmailEqualsIgnoreCase(email)) throw new RestException(RestErrorCode.EMAIL_NOT_AVAILABLE);
+
+ Account account = new Account(username, email, this.passwordEncoder.encode(request.getPassword()));
+ this.accountRepository.save(account);
+
+ return account;
+ }
+
+ public Account getAccount(int id) throws RestException {
+ return this.accountRepository.findById(id).orElseThrow(() -> new RestException(RestErrorCode.ACCOUNT_NOT_FOUND));
+ }
+
+ // todo will there be concurrency issues with performing this all in one update?
+ public Account updateAccountDetails(Account account, UpdateAccountRequest request, MultipartFile file) throws RestException {
+ if (file != null) {
+ if (file.getContentType() == null || !file.getContentType().contains("image")) throw new RestException(RestErrorCode.WRONG_FILE_TYPE);
+ if (file.getSize() > this.siteConfig.getMaxUploadSize().toBytes()) throw new RestException(RestErrorCode.FILE_TOO_LARGE);
+
+ account.setProfilePicture(ImageUtil.handleImage(file));
+ }
+ if (request.getEmail() != null) {
+ String email = request.getEmail();
+ if (!ValidationHelper.isEmailValid(email)) throw new RestException(RestErrorCode.INVALID_EMAIL);
+ if (this.accountRepository.existsByEmailEqualsIgnoreCase(email)) throw new RestException(RestErrorCode.EMAIL_NOT_AVAILABLE);
+ account.setEmail(email);
+ }
+ if (request.getUsername() != null) {
+ String username = request.getUsername();
+ if (!ValidationHelper.isUsernameValid(username)) throw new RestException(RestErrorCode.INVALID_USERNAME);
+ if (this.accountRepository.existsByUsernameEqualsIgnoreCase(username)) throw new RestException(RestErrorCode.USERNAME_NOT_AVAILABLE);
+ account.setUsername(username);
+ }
+ this.accountRepository.save(account);
+ return account;
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/AdminService.java b/src/main/java/com/imjustdoom/pluginsite/service/AdminService.java
new file mode 100644
index 0000000..b296d77
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/service/AdminService.java
@@ -0,0 +1,11 @@
+package com.imjustdoom.pluginsite.service;
+
+import com.imjustdoom.pluginsite.repositories.ReportRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class AdminService {
+ private final ReportRepository reportRepository;
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/LogoService.java b/src/main/java/com/imjustdoom/pluginsite/service/LogoService.java
deleted file mode 100644
index 495e2a4..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/service/LogoService.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.imjustdoom.pluginsite.service;
-
-import org.springframework.web.multipart.MultipartFile;
-
-public interface LogoService {
-
- void updateLogo(int id, MultipartFile logo);
-
- boolean logoExists(int id);
-
- byte[] serveDefaultLogo();
-
- byte[] serverLogo(int id);
-}
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/MessageService.java b/src/main/java/com/imjustdoom/pluginsite/service/MessageService.java
new file mode 100644
index 0000000..50c5fc6
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/service/MessageService.java
@@ -0,0 +1,117 @@
+package com.imjustdoom.pluginsite.service;
+
+import com.imjustdoom.pluginsite.config.exception.RestErrorCode;
+import com.imjustdoom.pluginsite.config.exception.RestException;
+import com.imjustdoom.pluginsite.model.Account;
+import com.imjustdoom.pluginsite.model.Message;
+import com.imjustdoom.pluginsite.model.MessageGroup;
+import com.imjustdoom.pluginsite.repositories.AccountRepository;
+import com.imjustdoom.pluginsite.repositories.MessageGroupRepository;
+import com.imjustdoom.pluginsite.repositories.MessageRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+@Service
+@RequiredArgsConstructor
+public class MessageService {
+
+ private final MessageRepository messageRepository;
+ private final MessageGroupRepository messageGroupRepository;
+ private final AccountRepository accountRepository;
+ private final PasswordEncoder passwordEncoder;
+
+ private Account systemAccount;
+
+ @PostConstruct
+ public void setup() {
+ this.systemAccount = this.accountRepository.findByUsernameEqualsIgnoreCase("system").orElseGet(() -> {
+ Account account = new Account("system", "system@example.com", this.passwordEncoder.encode(UUID.randomUUID().toString())); // todo in the future, let's just lock the account
+ return this.accountRepository.save(account);
+ });
+ }
+
+ private void sendSystemMessage(int groupId, String message) throws RestException {
+ MessageGroup messageGroup = this.messageGroupRepository.findById(groupId).orElseThrow(() -> new RestException(RestErrorCode.MESSAGE_GROUP_NOT_FOUND));
+ Message systemMessage = new Message(message, this.systemAccount, messageGroup);
+ this.messageRepository.save(systemMessage);
+ }
+
+ public void sendMessage(Account sender, int groupId, String content) throws RestException {
+ MessageGroup group = this.messageGroupRepository.findById(groupId).orElseThrow(() -> new RestException(RestErrorCode.MESSAGE_GROUP_NOT_FOUND));
+ if (!group.getMembers().contains(sender)) throw new RestException(RestErrorCode.FORBIDDEN);
+
+ Message message = new Message(content, sender, group);
+ this.messageRepository.save(message);
+ }
+
+ public void createGroup(Account sender, int targetId) throws RestException {
+ Account targetAccount = this.accountRepository.findById(targetId).orElseThrow(() -> new RestException(RestErrorCode.ACCOUNT_NOT_FOUND, "Target user not found"));
+
+ List users = new ArrayList<>() {{
+ add(sender);
+ add(targetAccount);
+ }};
+ String name = "Generic Group #" + (int) (Math.random() * 100);
+ MessageGroup messageGroup = new MessageGroup(name, LocalDateTime.now(), users);
+ this.messageGroupRepository.save(messageGroup);
+ }
+
+ public Page getGroups(Account account, Pageable pageable) {
+ return this.messageGroupRepository.findAllByMembersContains(account, pageable);
+ }
+
+ public MessageGroup getGroup(Account account, int groupId) throws RestException {
+ MessageGroup group = this.messageGroupRepository.findById(groupId).orElseThrow(() -> new RestException(RestErrorCode.MESSAGE_GROUP_NOT_FOUND));
+ if (!group.getMembers().contains(account)) throw new RestException(RestErrorCode.FORBIDDEN);
+
+ return group;
+ }
+
+ public void addUserToGroup(Account sender, int groupId, int targetId) throws RestException {
+ MessageGroup group = this.messageGroupRepository.findById(groupId).orElseThrow(() -> new RestException(RestErrorCode.MESSAGE_GROUP_NOT_FOUND));
+ if (!group.getMembers().contains(sender)) throw new RestException(RestErrorCode.FORBIDDEN);
+
+ Account target = this.accountRepository.findById(targetId).orElseThrow(() -> new RestException(RestErrorCode.ACCOUNT_NOT_FOUND, "Target user not found"));
+ group.getMembers().add(target);
+ this.messageGroupRepository.save(group);
+ }
+
+ public void leaveGroup(Account sender, int groupId) throws RestException {
+ MessageGroup group = this.messageGroupRepository.findById(groupId).orElseThrow(() -> new RestException(RestErrorCode.MESSAGE_GROUP_NOT_FOUND));
+ if (!group.getMembers().contains(sender)) throw new RestException(RestErrorCode.FORBIDDEN);
+
+ group.getMembers().remove(sender);
+ this.messageGroupRepository.save(group);
+ }
+
+ public void deleteGroup(Account sender, int groupId) throws RestException {
+ MessageGroup group = this.messageGroupRepository.findById(groupId).orElseThrow(() -> new RestException(RestErrorCode.MESSAGE_GROUP_NOT_FOUND));
+ if (!group.getMembers().contains(sender)) throw new RestException(RestErrorCode.FORBIDDEN);
+
+ this.messageGroupRepository.delete(group);
+ }
+
+ public MessageGroup editGroupName(Account sender, int groupId, String newName) throws RestException {
+ MessageGroup group = this.messageGroupRepository.findById(groupId).orElseThrow(() -> new RestException(RestErrorCode.MESSAGE_GROUP_NOT_FOUND));
+ if (!group.getMembers().contains(sender)) throw new RestException(RestErrorCode.FORBIDDEN);
+
+ group.setName(newName);
+ return this.messageGroupRepository.save(group);
+ }
+
+ public Page getMessages(Account account, int groupId, Pageable pageable) throws RestException {
+ MessageGroup group = this.messageGroupRepository.findById(groupId).orElseThrow(() -> new RestException(RestErrorCode.MESSAGE_GROUP_NOT_FOUND));
+ if (!group.getMembers().contains(account)) throw new RestException(RestErrorCode.FORBIDDEN);
+
+ return this.messageRepository.findByGroup(group, pageable);
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/ProfilePictureService.java b/src/main/java/com/imjustdoom/pluginsite/service/ProfilePictureService.java
deleted file mode 100644
index 95c02ed..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/service/ProfilePictureService.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.imjustdoom.pluginsite.service;
-
-import org.springframework.web.multipart.MultipartFile;
-
-public interface ProfilePictureService {
-
- void updateProfilePicture(int id, MultipartFile logo);
-
- boolean logoExists(int id);
-
- byte[] serveDefaultProfilePicture();
-
- byte[] serverProfilePicture(int id);
-}
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/ProfileService.java b/src/main/java/com/imjustdoom/pluginsite/service/ProfileService.java
new file mode 100644
index 0000000..fc47193
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/service/ProfileService.java
@@ -0,0 +1,23 @@
+package com.imjustdoom.pluginsite.service;
+
+import com.imjustdoom.pluginsite.config.exception.RestException;
+import com.imjustdoom.pluginsite.dtos.out.ProfileDto;
+import com.imjustdoom.pluginsite.dtos.out.account.AccountDto;
+import com.imjustdoom.pluginsite.model.Account;
+import com.imjustdoom.pluginsite.repositories.UpdateRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class ProfileService {
+ private final UpdateRepository updateRepository;
+ private final AccountService accountService;
+
+ public ProfileDto getProfileDto(int userId) throws RestException {
+ Account account = this.accountService.getAccount(userId);
+ int totalDownloads = this.updateRepository.getTotalAccountDownloads(userId).orElse(0);
+
+ return new ProfileDto(account.getId(), totalDownloads, AccountDto.fromAccount(account));
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/ReportService.java b/src/main/java/com/imjustdoom/pluginsite/service/ReportService.java
new file mode 100644
index 0000000..d6dfcf1
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/service/ReportService.java
@@ -0,0 +1,35 @@
+package com.imjustdoom.pluginsite.service;
+
+import com.imjustdoom.pluginsite.config.exception.RestErrorCode;
+import com.imjustdoom.pluginsite.config.exception.RestException;
+import com.imjustdoom.pluginsite.dtos.in.CreateReportRequest;
+import com.imjustdoom.pluginsite.model.Account;
+import com.imjustdoom.pluginsite.model.Report;
+import com.imjustdoom.pluginsite.repositories.ReportRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class ReportService {
+ private final ReportRepository reportRepository;
+
+ public void createReport(Account reporter, CreateReportRequest request) {
+ Report report = new Report(reporter, request.getReportingObject(), request.getReportingId(), request.getReport(), request.getReason());
+ this.reportRepository.save(report);
+ }
+
+ public Page getReportPage(Pageable pageable) {
+ return this.reportRepository.findAll(pageable);
+ }
+
+ public Report getReport(int id) throws RestException {
+ return this.reportRepository.findById(id).orElseThrow(() -> new RestException(RestErrorCode.REPORT_NOT_FOUND));
+ }
+
+ public Report updateActionTaken(int id, String actionTaken) {
+ return this.reportRepository.updateActionTakenById(id, actionTaken);
+ }
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/ResourceService.java b/src/main/java/com/imjustdoom/pluginsite/service/ResourceService.java
index e5b8b7c..5eed884 100644
--- a/src/main/java/com/imjustdoom/pluginsite/service/ResourceService.java
+++ b/src/main/java/com/imjustdoom/pluginsite/service/ResourceService.java
@@ -1,20 +1,94 @@
package com.imjustdoom.pluginsite.service;
import com.imjustdoom.pluginsite.config.custom.SiteConfig;
+import com.imjustdoom.pluginsite.config.exception.RestErrorCode;
+import com.imjustdoom.pluginsite.config.exception.RestException;
import com.imjustdoom.pluginsite.dtos.in.CreateResourceRequest;
import com.imjustdoom.pluginsite.dtos.out.SimpleResourceDto;
import com.imjustdoom.pluginsite.model.Account;
-import org.springframework.web.servlet.mvc.support.RedirectAttributes;
+import com.imjustdoom.pluginsite.model.Resource;
+import com.imjustdoom.pluginsite.repositories.ResourceRepository;
+import com.imjustdoom.pluginsite.repositories.UpdateRepository;
+import com.imjustdoom.pluginsite.util.ImageUtil;
+import com.querydsl.core.types.Predicate;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
-import java.util.List;
+@Service
+@RequiredArgsConstructor
+public class ResourceService {
+ private final ResourceRepository resourceRepository;
+ private final UpdateRepository updateRepository;
+ private final SiteConfig siteConfig;
-public interface ResourceService {
+ public Page searchResources(Pageable pageable, Predicate query) throws RestException {
+ return this.resourceRepository.findAll(query, pageable)
+ .map(resource -> {
+ int totalDownloads = this.updateRepository.getTotalDownloads(resource.getId()).orElse(0);
+ return SimpleResourceDto.create(resource, totalDownloads);
+ });
+ }
- String postCreateResource(CreateResourceRequest resourceRequest, Account account, SiteConfig siteConfig, RedirectAttributes redirectAttributes);
+ //TODO: More sanity checks
+ public Resource createResource(Account account, CreateResourceRequest request) throws RestException {
+ if (this.resourceRepository.getResourcesCreateLastHour(account.getId()) > this.siteConfig.getMaxCreationsPerHour())
+ throw new RestException(RestErrorCode.TOO_MANY_RESOURCE_CREATIONS);
+ if (this.resourceRepository.existsByNameEqualsIgnoreCase(request.getName()))
+ throw new RestException(RestErrorCode.RESOURCE_NAME_NOT_AVAILABLE);
+ if (request.getName().isEmpty() || request.getBlurb().isEmpty() || request.getDescription().isEmpty())
+ throw new RestException(RestErrorCode.REQUIRED_ARGUMENTS_MISSING);
- List searchResources(String search, String sortBy, String page);
+ Resource resource = new Resource(request.getName(), request.getDescription(),
+ request.getBlurb(), request.getDonation(), request.getSource(),
+ account, request.getSupport(), request.getCategory());
- List getResourcesWithCategory(String sort, String page, String category);
+ return this.resourceRepository.save(resource);
+ }
- List getResources(String sort, String page);
+ // TODO: More sanity checks
+ // todo: also this is horrible, can we just use querydsl?
+ public Resource updateResource(Account account, int resourceId, MultipartFile file, CreateResourceRequest request) throws RestException {
+ Resource resource = this.resourceRepository.findById(resourceId).orElseThrow(() -> new RestException(RestErrorCode.RESOURCE_NOT_FOUND));
+ if (resource.getAuthor().getId() != account.getId()) throw new RestException(RestErrorCode.FORBIDDEN);
+
+ String name = request.getName();
+ if (name != null && !name.isEmpty())
+ resource.setName(name);
+
+ String description = request.getDescription();
+ if (description != null && !description.isEmpty())
+ resource.setDescription(description);
+
+ String blurb = request.getBlurb();
+ if (blurb != null && !blurb.isEmpty())
+ resource.setBlurb(blurb);
+
+ String category = request.getCategory();
+ if (category != null && !category.isEmpty())
+ resource.setCategory(category);
+
+ String donation = request.getDonation();
+ if (donation != null && !donation.isEmpty())
+ resource.setDonation(donation);
+
+ String support = request.getSupport();
+ if (support != null && !support.isEmpty())
+ resource.setSupport(support);
+
+ String source = request.getSource();
+ if (source != null && !source.isEmpty())
+ resource.setSource(source);
+
+ if (file != null && !file.isEmpty()) {
+ if (file.getSize() > this.siteConfig.getMaxUploadSize().toBytes()) throw new RestException(RestErrorCode.FILE_TOO_LARGE);
+ if (file.getContentType() == null || !file.getContentType().contains("image")) throw new RestException(RestErrorCode.WRONG_FILE_TYPE);
+
+ resource.setLogo(ImageUtil.handleImage(file));
+ }
+
+ return this.resourceRepository.save(resource);
+ }
}
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/ResourceUpdateService.java b/src/main/java/com/imjustdoom/pluginsite/service/ResourceUpdateService.java
new file mode 100644
index 0000000..69846fb
--- /dev/null
+++ b/src/main/java/com/imjustdoom/pluginsite/service/ResourceUpdateService.java
@@ -0,0 +1,100 @@
+package com.imjustdoom.pluginsite.service;
+
+import com.imjustdoom.pluginsite.config.custom.SiteConfig;
+import com.imjustdoom.pluginsite.config.exception.RestErrorCode;
+import com.imjustdoom.pluginsite.config.exception.RestException;
+import com.imjustdoom.pluginsite.dtos.in.CreateUpdateRequest;
+import com.imjustdoom.pluginsite.dtos.in.resource.EditResourceUpdateRequest;
+import com.imjustdoom.pluginsite.model.Account;
+import com.imjustdoom.pluginsite.model.Resource;
+import com.imjustdoom.pluginsite.model.Update;
+import com.imjustdoom.pluginsite.repositories.ResourceRepository;
+import com.imjustdoom.pluginsite.repositories.UpdateRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.PostConstruct;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+@Service
+@RequiredArgsConstructor
+public class ResourceUpdateService {
+ private static final Path BASE_PATH = Path.of("./resources/plugins/");
+
+ private final UpdateRepository updateRepository;
+ private final ResourceRepository resourceRepository;
+ private final SiteConfig siteConfig;
+
+ @PostConstruct
+ public void setup() {
+ if (Files.notExists(BASE_PATH))
+ BASE_PATH.toFile().mkdirs();
+ }
+
+ public Update changeStatus(Account account, int updateId, String status) throws RestException {
+ Update update = this.updateRepository.findById(updateId).orElseThrow(() -> new RestException(RestErrorCode.RESOURCE_UPDATE_NOT_FOUND));
+ if (update.getResource().getAuthor().getId() != account.getId()) throw new RestException(RestErrorCode.FORBIDDEN);
+ update.setStatus(status);
+ return this.updateRepository.save(update);
+ }
+
+ public Update editUpdate(Account account, int updateId, EditResourceUpdateRequest request) throws RestException {
+ Update update = this.updateRepository.findById(updateId).orElseThrow(() -> new RestException(RestErrorCode.RESOURCE_UPDATE_NOT_FOUND));
+ if (update.getResource().getAuthor().getId() != account.getId()) throw new RestException(RestErrorCode.FORBIDDEN);
+
+ String name = request.getName();
+ if (name != null && !name.isEmpty())
+ update.setName(name);
+
+ String version = request.getVersion();
+ if (version != null && !version.isEmpty())
+ update.setVersion(version);
+
+ String description = request.getDescription();
+ if (description != null && !description.isEmpty())
+ update.setDescription(description);
+
+ return this.updateRepository.save(update);
+ }
+
+ public void createUpdate(Account account, int resourceId,
+ MultipartFile file, CreateUpdateRequest request) throws RestException {
+
+ if (this.updateRepository.getUpdatesCreateLastHour(account.getId()) > this.siteConfig.getMaxUpdatesPerHour()) throw new RestException(RestErrorCode.TOO_MANY_RESOURCE_UPDATES);
+
+ if ((file.isEmpty() || file.getSize() > this.siteConfig.getMaxUploadSize().toBytes()) && (request.getExternalLink() == null || request.getExternalLink().isEmpty())) throw new RestException(RestErrorCode.REQUIRED_ARGUMENTS_MISSING, "Missing File");
+ if ((!file.getOriginalFilename().endsWith(".jar") && !file.getOriginalFilename().endsWith(".zip")) && request.getExternalLink().equals("")) throw new RestException(RestErrorCode.WRONG_FILE_TYPE);
+ if (request.isMissingRequirements()) throw new RestException(RestErrorCode.REQUIRED_ARGUMENTS_MISSING, "Missing name, version or description.");
+
+ Resource resource = this.resourceRepository.findById(resourceId).orElseThrow(() -> new RestException(RestErrorCode.RESOURCE_NOT_FOUND));
+ Update update;
+ if (file.isEmpty()) {
+ update = new Update(request.getDescription(), null, request.getVersion(), request.getExternalLink(), request.getName(), request.getVersions(), request.getSoftware(), resource);
+ } else {
+ update = new Update(request.getDescription(), file.getOriginalFilename(), request.getVersion(), null, request.getName(), request.getVersions(), request.getSoftware(), resource);
+ Path resourcePath = BASE_PATH.resolve(update.getId() + ".jar");
+ try (InputStream inputStream = file.getInputStream()) {
+ Files.copy(inputStream, resourcePath);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ this.updateRepository.save(update);
+ }
+
+ public FileReturn getDownload(int updateId) throws RestException {
+ Path path = BASE_PATH.resolve(updateId + ".jar");
+ if (!Files.exists(path)) throw new RestException(RestErrorCode.DOWNLOAD_NOT_FOUND, "File not found");
+ Update update = this.updateRepository.findById(updateId).orElseThrow(() -> new RestException(RestErrorCode.RESOURCE_UPDATE_NOT_FOUND));
+ if (update.getDownloadLink() != null) throw new RestException(RestErrorCode.WRONG_FILE_TYPE, "File is provided via an external URL");
+
+ return new FileReturn(path.toFile(), update.getFilename());
+ }
+
+ public record FileReturn(File file, String realName) {}
+}
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/UpdateService.java b/src/main/java/com/imjustdoom/pluginsite/service/UpdateService.java
deleted file mode 100644
index f5b9f0f..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/service/UpdateService.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.imjustdoom.pluginsite.service;
-
-import com.imjustdoom.pluginsite.dtos.in.CreateResourceRequest;
-import com.imjustdoom.pluginsite.dtos.in.CreateUpdateRequest;
-import com.imjustdoom.pluginsite.dtos.out.SimpleResourceDto;
-import com.imjustdoom.pluginsite.model.Account;
-import com.imjustdoom.pluginsite.model.Resource;
-import com.imjustdoom.pluginsite.model.Update;
-
-import java.util.List;
-
-public interface UpdateService {
-
- Update createUpdate(CreateUpdateRequest updateRequest, Account account);
-}
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/impl/AccountServiceImpl.java b/src/main/java/com/imjustdoom/pluginsite/service/impl/AccountServiceImpl.java
deleted file mode 100644
index d7502cc..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/service/impl/AccountServiceImpl.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.imjustdoom.pluginsite.service.impl;
-
-import com.imjustdoom.pluginsite.repositories.AccountRepository;
-import lombok.AllArgsConstructor;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.stereotype.Service;
-
-@Service
-@AllArgsConstructor
-public class AccountServiceImpl implements UserDetailsService {
-
- private final AccountRepository accountRepository;
-
- @Override
- public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
- return accountRepository.findByUsernameEqualsIgnoreCase(s).orElseThrow(() -> new UsernameNotFoundException("User not found"));
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/impl/LogoServiceImpl.java b/src/main/java/com/imjustdoom/pluginsite/service/impl/LogoServiceImpl.java
deleted file mode 100644
index 788084b..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/service/impl/LogoServiceImpl.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.imjustdoom.pluginsite.service.impl;
-
-import com.imjustdoom.pluginsite.PluginSiteApplication;
-import com.imjustdoom.pluginsite.repositories.ResourceRepository;
-import com.imjustdoom.pluginsite.service.LogoService;
-import com.imjustdoom.pluginsite.util.ImageUtil;
-import lombok.AllArgsConstructor;
-import org.springframework.stereotype.Service;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.io.IOException;
-import java.nio.file.Paths;
-
-@Service
-@AllArgsConstructor
-public class LogoServiceImpl implements LogoService {
-
- private final ResourceRepository resourceRepository;
-
- @Override
- public void updateLogo(int id, MultipartFile logo) {
-
- byte[] image = ImageUtil.handleImage(logo);
-
- resourceRepository.updateLogoById(id, image);
-
- //if (image.getHeight() != image.getWidth())
- //return "redirect:/resources/%s/edit?error=logosize".formatted(id);
- }
-
- @Override
- public boolean logoExists(int id) {
- return Paths.get("resources/logos/%s".formatted(id)).toFile().exists();
- }
-
- @Override
- public byte[] serveDefaultLogo() {
- try {
- return PluginSiteApplication.class.getResourceAsStream("/pictures/default.png").readAllBytes();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- @Override
- public byte[] serverLogo(int id) {
- byte[] image = resourceRepository.findResourceLogo(id);
- if(image == null){
- return serveDefaultLogo();
- }
- return resourceRepository.findResourceLogo(id);
- }
-}
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/impl/ProfilePictureServiceImpl.java b/src/main/java/com/imjustdoom/pluginsite/service/impl/ProfilePictureServiceImpl.java
deleted file mode 100644
index 2c31280..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/service/impl/ProfilePictureServiceImpl.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.imjustdoom.pluginsite.service.impl;
-
-import com.imjustdoom.pluginsite.PluginSiteApplication;
-import com.imjustdoom.pluginsite.repositories.AccountRepository;
-import com.imjustdoom.pluginsite.service.ProfilePictureService;
-import com.imjustdoom.pluginsite.util.ImageUtil;
-import lombok.AllArgsConstructor;
-import org.springframework.stereotype.Service;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.io.IOException;
-import java.nio.file.Paths;
-
-@Service
-@AllArgsConstructor
-public class ProfilePictureServiceImpl implements ProfilePictureService {
-
- private final AccountRepository accountRepository;
-
- @Override
- public void updateProfilePicture(int id, MultipartFile profilePicture) {
-
- byte[] image = ImageUtil.handleImage(profilePicture);
-
- accountRepository.updateProfilePictureById(id, image);
-
- //if (image.getHeight() != image.getWidth())
- //return "redirect:/resources/%s/edit?error=logosize".formatted(id);
- }
-
- @Override
- public boolean logoExists(int id) {
- return Paths.get("resources/logos/%s".formatted(id)).toFile().exists();
- }
-
- @Override
- public byte[] serveDefaultProfilePicture() {
- try {
- return PluginSiteApplication.class.getResourceAsStream("/pictures/default.png").readAllBytes();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
-
- @Override
- public byte[] serverProfilePicture(int id) {
- byte[] image = accountRepository.findAccountProfilePicture(id);
- if(image == null){
- return serveDefaultProfilePicture();
- }
- return accountRepository.findAccountProfilePicture(id);
- }
-}
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/impl/ResourceServiceImpl.java b/src/main/java/com/imjustdoom/pluginsite/service/impl/ResourceServiceImpl.java
deleted file mode 100644
index d1ab48a..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/service/impl/ResourceServiceImpl.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package com.imjustdoom.pluginsite.service.impl;
-
-import com.imjustdoom.pluginsite.config.custom.SiteConfig;
-import com.imjustdoom.pluginsite.dtos.in.CreateResourceRequest;
-import com.imjustdoom.pluginsite.dtos.out.SimpleResourceDto;
-import com.imjustdoom.pluginsite.model.Account;
-import com.imjustdoom.pluginsite.model.Resource;
-import com.imjustdoom.pluginsite.repositories.ResourceRepository;
-import com.imjustdoom.pluginsite.repositories.UpdateRepository;
-import com.imjustdoom.pluginsite.service.ResourceService;
-import lombok.AllArgsConstructor;
-import me.xdrop.fuzzywuzzy.FuzzySearch;
-import me.xdrop.fuzzywuzzy.model.BoundExtractedResult;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
-import org.springframework.data.domain.Sort;
-import org.springframework.stereotype.Service;
-import org.springframework.web.servlet.mvc.support.RedirectAttributes;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-@Service
-@AllArgsConstructor
-public class ResourceServiceImpl implements ResourceService {
-
- private final UpdateRepository updateRepository;
- private final ResourceRepository resourceRepository;
-
- @Override
- public String postCreateResource(CreateResourceRequest resourceRequest, Account account, SiteConfig siteConfig,
- RedirectAttributes redirectAttributes) {
-
- redirectAttributes.addFlashAttribute("resourceRequest", resourceRequest);
- if (resourceRepository.getResourcesCreateLastHour(account.getId()) > siteConfig.getMaxCreationsPerHour())
- return "redirect:/resources/create?error=createlimit";
-
- if (resourceRepository.existsByNameEqualsIgnoreCase(resourceRequest.getName()))
- return "redirect:/resources/create?error=nametaken";
-
- if (resourceRequest.getName().equalsIgnoreCase("")
- || resourceRequest.getBlurb().equalsIgnoreCase("")
- || resourceRequest.getDescription().equalsIgnoreCase(""))
- return "redirect:/resources/create?error=invalidinput";
-
- Resource resource = new Resource(resourceRequest.getName(), resourceRequest.getDescription(),
- resourceRequest.getBlurb(), resourceRequest.getDonation(), resourceRequest.getSource(),
- "", account, resourceRequest.getSupport(), resourceRequest.getCategory());
-
- resourceRepository.save(resource);
-
- return "redirect:/resources/%s".formatted(resource.getId());
- }
-
- @Override
- public List searchResources(String search, String sortBy, String page) {
- List> searchResults;
- List data = new ArrayList<>();
-
- Sort sort = Sort.by(sortBy).descending();
- if(sortBy.equalsIgnoreCase("name")) sort = sort.ascending();
- Pageable pageable = PageRequest.of(Integer.parseInt(page) - 1, 25, sort);
-
- searchResults = FuzzySearch.extractSorted(search, resourceRepository.findAllByStatusEqualsIgnoreCase("public", pageable), Resource::getName);
-
- for (BoundExtractedResult extractedResult : searchResults) {
- if (extractedResult.getScore() < 40) continue;
-
- //TODO: use getReferent
- Optional optionalResource = resourceRepository.findByNameEqualsIgnoreCase(extractedResult.getString());
- Resource resource = optionalResource.get();
-
- Integer downloads = updateRepository.getTotalDownloads(resource.getId());
- data.add(SimpleResourceDto.create(resource, downloads == null ? 0 : downloads));
-
- }
-
- return data;
- }
-
- @Override
- public List getResourcesWithCategory(String sortBy, String page, String category) {
- List data = new ArrayList<>();
- Sort sort = Sort.by(sortBy).descending();
- if(sortBy.equalsIgnoreCase("name")) sort = sort.ascending();
- Pageable pageable = PageRequest.of(Integer.parseInt(page) - 1, 25, sort);
-
- for (Resource resource : resourceRepository.findAllByCategoryEqualsAndStatusEquals(category, "public", pageable)) {
- Integer downloads = updateRepository.getTotalDownloads(resource.getId());
- data.add(SimpleResourceDto.create(resource, downloads == null ? 0 : downloads));
- }
-
- return data;
- }
-
- @Override
- public List getResources(String sortBy, String page) {
- List data = new ArrayList<>();
- Sort sort = Sort.by(sortBy).descending();
- if(sortBy.equalsIgnoreCase("name")) sort = sort.ascending();
- Pageable pageable = PageRequest.of(Integer.parseInt(page) - 1, 25, sort);
-
- for (Resource resource : resourceRepository.findAllByStatusEqualsIgnoreCase("public", pageable)) {
- Integer downloads = updateRepository.getTotalDownloads(resource.getId());
- data.add(SimpleResourceDto.create(resource, downloads == null ? 0 : downloads));
- }
-
- return data;
- }
-}
diff --git a/src/main/java/com/imjustdoom/pluginsite/service/impl/UpdateServiceImpl.java b/src/main/java/com/imjustdoom/pluginsite/service/impl/UpdateServiceImpl.java
deleted file mode 100644
index 525ce49..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/service/impl/UpdateServiceImpl.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.imjustdoom.pluginsite.service.impl;
-
-import com.imjustdoom.pluginsite.dtos.in.CreateUpdateRequest;
-import com.imjustdoom.pluginsite.model.Account;
-import com.imjustdoom.pluginsite.model.Resource;
-import com.imjustdoom.pluginsite.model.Update;
-import com.imjustdoom.pluginsite.repositories.UpdateRepository;
-import com.imjustdoom.pluginsite.service.UpdateService;
-import lombok.AllArgsConstructor;
-import org.springframework.stereotype.Service;
-
-import java.util.ArrayList;
-
-@Service
-@AllArgsConstructor
-public class UpdateServiceImpl implements UpdateService {
-
- private final UpdateRepository updateRepository;
-
- @Override
- public Update createUpdate(CreateUpdateRequest updateRequest, Account account) {
- Update resource = new Update(updateRequest.getDescription(), "", "", "", "",
- new ArrayList<>(), new ArrayList<>(), new Resource(), updateRequest.getExternalLink());
-
- updateRepository.save(resource);
-
- return resource;
- }
-}
diff --git a/src/main/java/com/imjustdoom/pluginsite/util/DateUtil.java b/src/main/java/com/imjustdoom/pluginsite/util/DateUtil.java
index 90b06e1..30be21b 100644
--- a/src/main/java/com/imjustdoom/pluginsite/util/DateUtil.java
+++ b/src/main/java/com/imjustdoom/pluginsite/util/DateUtil.java
@@ -3,10 +3,9 @@
import java.time.format.DateTimeFormatter;
public class DateUtil {
-
- public static DateTimeFormatter format = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ssa");
+ private static final DateTimeFormatter FORMAT = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ssa");
public static DateTimeFormatter getDateFormatter() {
- return format;
+ return FORMAT;
}
}
diff --git a/src/main/java/com/imjustdoom/pluginsite/util/StringUtil.java b/src/main/java/com/imjustdoom/pluginsite/util/StringUtil.java
deleted file mode 100644
index 4462d8a..0000000
--- a/src/main/java/com/imjustdoom/pluginsite/util/StringUtil.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.imjustdoom.pluginsite.util;
-
-import org.commonmark.node.Node;
-import org.commonmark.parser.Parser;
-import org.commonmark.renderer.html.HtmlRenderer;
-
-public class StringUtil {
-
- public static String markdownToHtml(String markdown) {
- Parser parser = Parser.builder().build();
- Node document = parser.parse(markdown);
- HtmlRenderer renderer = HtmlRenderer.builder().build();
- return renderer.render(document);
- }
-}