diff --git a/db/1.0.0/5. createGame.sql b/db/1.0.0/5. createGame.sql new file mode 100644 index 0000000..2285216 --- /dev/null +++ b/db/1.0.0/5. createGame.sql @@ -0,0 +1,11 @@ +CREATE TABLE IF NOT EXISTS raid_builder.game( + game_id uuid PRIMARY KEY, + game_name text UNIQUE NOT NULL, + game_icon text, + modified_by uuid, + modified_date timestamptz, + created_by uuid NOT NULL, + created_date timestamptz NOT NULL +); + +GRANT ALL ON TABLE raid_builder.game TO raid_builder; diff --git a/db/1.0.0/6. createGamePermission.sql b/db/1.0.0/6. createGamePermission.sql new file mode 100644 index 0000000..298b0fe --- /dev/null +++ b/db/1.0.0/6. createGamePermission.sql @@ -0,0 +1,17 @@ +CREATE TYPE raid_builder.game_permission_type AS ENUM ( 'ADMIN' ); + + +CREATE TABLE IF NOT EXISTS raid_builder.game_permission( + game_permission_id uuid PRIMARY KEY, + account_id uuid REFERENCES raid_builder.account(account_id) NOT NULL, + game_id uuid REFERENCES raid_builder.game(game_id) NOT NULL, + game_permission_type raid_builder.game_permission_type NOT NULL, + + --Auditing + modified_by uuid REFERENCES raid_builder.account(account_id) NOT NULL, + modified_date timestamptz NOT NULL, + created_by uuid REFERENCES raid_builder.account(account_id) NOT NULL, + created_date timestamptz NOT NULL +); + +GRANT ALL ON TABLE raid_builder.game_permission TO raid_builder; diff --git a/src/main/java/com/mattrixwv/raidbuilder/annotation/GameAuthorization.java b/src/main/java/com/mattrixwv/raidbuilder/annotation/GameAuthorization.java new file mode 100644 index 0000000..5602ca8 --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/annotation/GameAuthorization.java @@ -0,0 +1,16 @@ +package com.mattrixwv.raidbuilder.annotation; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.GamePermissionType; + + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface GameAuthorization{ + public GamePermissionType[] permissions(); +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/aspect/GameAuthorizationAspect.java b/src/main/java/com/mattrixwv/raidbuilder/aspect/GameAuthorizationAspect.java new file mode 100644 index 0000000..ac29ad9 --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/aspect/GameAuthorizationAspect.java @@ -0,0 +1,95 @@ +package com.mattrixwv.raidbuilder.aspect; + + +import java.util.List; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authorization.AuthorizationDeniedException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.jwt.Jwt; + +import com.mattrixwv.raidbuilder.annotation.GameAuthorization; +import com.mattrixwv.raidbuilder.entity.Account; +import com.mattrixwv.raidbuilder.entity.AccountPermission; +import com.mattrixwv.raidbuilder.entity.GamePermission; +import com.mattrixwv.raidbuilder.service.AccountPermissionService; +import com.mattrixwv.raidbuilder.service.AccountService; +import com.mattrixwv.raidbuilder.service.GamePermissionService; +import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.AccountPermissionType; +import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.AccountStatus; +import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.GamePermissionType; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +@Aspect +@Configuration +@RequiredArgsConstructor +public class GameAuthorizationAspect{ + private final AccountService accountService; + private final AccountPermissionService accountPermissionService; + private final GamePermissionService gamePermissionService; + + + @Pointcut("@annotation(com.mattrixwv.raidbuilder.annotation.GameAuthorizationAspect)") + public void gameAuthorizationAnnotation(){ + //Intentionally blank + } + + + @Before("gameAuthorizationAnnotation()") + public void authorizeGame(JoinPoint joinPoint){ + log.debug("Authorizing game"); + + + //Get the annotation + GameAuthorization gameAuthorization = ((MethodSignature)joinPoint.getSignature()).getMethod().getAnnotation(GameAuthorization.class); + //Return if there are no required permissions + if(gameAuthorization.permissions().length == 0){ + log.debug("No required permissions"); + return; + } + + //Get the account + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + String username = ((Jwt)auth.getPrincipal()).getClaimAsString("sub"); + Account account = accountService.getByUsername(username); + if(account.getAccountStatus() != AccountStatus.ACTIVE){ + throw new AuthorizationDeniedException("Account is not active", () -> false); + } + + //Return if the user is a site admin + List accountPermissions = accountPermissionService.getByAccountId(account.getAccountId()); + for(AccountPermission permission : accountPermissions){ + if(permission.getAccountPermissionType() == AccountPermissionType.ADMIN){ + log.debug("User is a site admin"); + return; + } + } + + //Return if the account has a matching permission + List gamePermissions = gamePermissionService.getByAccountId(account.getAccountId()); + for(GamePermission permission : gamePermissions){ + for(GamePermissionType permissionType : gameAuthorization.permissions()){ + if(permission.getGamePermissionType() == permissionType){ + log.debug("User is authorized"); + return; + } + } + } + + + log.debug("User is not authorized"); + + //If the user doesn't have a matching permission, throw an authorization exception + throw new AuthorizationDeniedException("User is not authorized to perform this action", () -> false); + } +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/config/SecurityConfig.java b/src/main/java/com/mattrixwv/raidbuilder/config/SecurityConfig.java index f98c1b6..b924272 100644 --- a/src/main/java/com/mattrixwv/raidbuilder/config/SecurityConfig.java +++ b/src/main/java/com/mattrixwv/raidbuilder/config/SecurityConfig.java @@ -44,6 +44,7 @@ public class SecurityConfig{ .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> { auth.requestMatchers(HttpMethod.OPTIONS).permitAll() + .requestMatchers("/icons/**").permitAll() .requestMatchers("/auth/refresh", "/auth/test").permitAll() //Permit refresh tokens .requestMatchers(HttpMethod.POST, "/auth/signup", "/auth/confirm").permitAll() //Permit signup operations .requestMatchers("/auth/forgot", "/auth/forgot/*").permitAll() //Permit forgot password operations diff --git a/src/main/java/com/mattrixwv/raidbuilder/config/TokenService.java b/src/main/java/com/mattrixwv/raidbuilder/config/TokenService.java index 2bd4b23..52dca96 100644 --- a/src/main/java/com/mattrixwv/raidbuilder/config/TokenService.java +++ b/src/main/java/com/mattrixwv/raidbuilder/config/TokenService.java @@ -43,6 +43,9 @@ public class TokenService{ .expiresAt(now.plus(accessTokenDuration)) .subject(account.getUsername()) .claim("scope", scope) + .claim("accountId", account.getAccountId().toString()) + //Game Permissions + //Raid Group Permissions .build(); return encoder.encode(JwtEncoderParameters.from(claims)).getTokenValue(); diff --git a/src/main/java/com/mattrixwv/raidbuilder/controller/AccountController.java b/src/main/java/com/mattrixwv/raidbuilder/controller/AccountController.java index 45648eb..3bbc4ec 100644 --- a/src/main/java/com/mattrixwv/raidbuilder/controller/AccountController.java +++ b/src/main/java/com/mattrixwv/raidbuilder/controller/AccountController.java @@ -186,6 +186,7 @@ public class AccountController{ log.info("Updating account {}", accountId); + //TODO: Existing account verification Account oldAccount = accountService.getByAccountId(accountId); ObjectNode returnNode = mapper.createObjectNode(); if(oldAccount == null){ diff --git a/src/main/java/com/mattrixwv/raidbuilder/controller/GameController.java b/src/main/java/com/mattrixwv/raidbuilder/controller/GameController.java new file mode 100644 index 0000000..30eaf5d --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/controller/GameController.java @@ -0,0 +1,137 @@ +package com.mattrixwv.raidbuilder.controller; + + +import java.util.List; +import java.util.UUID; + +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.mattrixwv.raidbuilder.annotation.AccountAuthorization; +import com.mattrixwv.raidbuilder.annotation.GameAuthorization; +import com.mattrixwv.raidbuilder.entity.Game; +import com.mattrixwv.raidbuilder.service.GameService; +import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.AccountPermissionType; +import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.GamePermissionType; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +@RestController +@RequestMapping("/game") +@RequiredArgsConstructor +public class GameController{ + private final ObjectMapper mapper; + private final GameService gameService; + + + @GetMapping + @AccountAuthorization(permissions = {AccountPermissionType.ADMIN, AccountPermissionType.USER}) + public List getGames(@RequestParam("page") int page, @RequestParam("pageSize") int pageSize, @RequestParam(value = "searchTerm", required = false) String searchTerm){ + log.info("Getting games page {} of size {} with search term {}", page, pageSize, searchTerm); + + + List games; + if((searchTerm == null) || (searchTerm.isBlank())){ + games = gameService.getGames(page, pageSize); + } + else{ + games = gameService.getGames(page, pageSize, searchTerm); + } + + + return games; + } + + + @GetMapping("/count") + @AccountAuthorization(permissions = {AccountPermissionType.ADMIN, AccountPermissionType.USER}) + public ObjectNode getGamesCount(@RequestParam(value = "searchTerm", required = false) String searchTerm){ + log.info("Getting games count"); + + + Long gamesCount; + if((searchTerm == null) || (searchTerm.isBlank())){ + gamesCount = gameService.getGamesCount(); + } + else{ + gamesCount = gameService.getGamesCount(searchTerm); + } + + ObjectNode countNode = mapper.createObjectNode(); + countNode.put("count", gamesCount); + countNode.put("status", "success"); + + + return countNode; + } + + + @PostMapping + @AccountAuthorization(permissions = {AccountPermissionType.ADMIN, AccountPermissionType.USER}) + @GameAuthorization(permissions = {GamePermissionType.ADMIN}) + public ObjectNode createGame(@RequestParam(value = "iconFile", required = false) MultipartFile file, @RequestParam("gameName") String gameName){ + log.info("Creating game {}", gameName); + + + //TODO: New game verification + ObjectNode returnNode = mapper.createObjectNode(); + Game game = new Game(); + game.setGameName(gameName); + game = gameService.createGame(game, file); + returnNode.put("gameId", game.getGameId().toString()); + returnNode.put("status", "success"); + + log.info("Successfully created game: {}", game.getGameId()); + + return returnNode; + } + + @PutMapping("/{gameId}") + @AccountAuthorization(permissions = {AccountPermissionType.ADMIN, AccountPermissionType.USER}) + @GameAuthorization(permissions = {GamePermissionType.ADMIN}) + public ObjectNode updateGame(@PathVariable("gameId") UUID gameId, @RequestParam(value = "iconFile", required = false) MultipartFile file, @RequestParam("gameName") String gameName, @RequestParam(name = "gameIcon", required = false) String gameIcon){ + log.info("Updating game {}", gameName); + + + ObjectNode returnNode = mapper.createObjectNode(); + Game game = new Game(); + game.setGameId(gameId); + game.setGameName(gameName); + game.setGameIcon(gameIcon); + game = gameService.updateGame(game, file); + returnNode.put("gameId", game.getGameId().toString()); + returnNode.put("status", "success"); + + log.info("Successfully updated game: {}", game.getGameId()); + + return returnNode; + } + + @DeleteMapping("/{gameId}") + @AccountAuthorization(permissions = {AccountPermissionType.ADMIN, AccountPermissionType.USER}) + @GameAuthorization(permissions = {GamePermissionType.ADMIN}) + public ObjectNode deleteGame(@PathVariable("gameId") UUID gameId){ + log.info("Deleting game {}", gameId); + + + ObjectNode returnNode = mapper.createObjectNode(); + gameService.deleteById(gameId); + returnNode.put("status", "success"); + + log.info("Successfully deleted game: {}", gameId); + + return returnNode; + } +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/controller/IconController.java b/src/main/java/com/mattrixwv/raidbuilder/controller/IconController.java new file mode 100644 index 0000000..8a5683a --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/controller/IconController.java @@ -0,0 +1,39 @@ +package com.mattrixwv.raidbuilder.controller; + + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.mattrixwv.raidbuilder.annotation.AccountAuthorization; + +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +@RestController +@RequestMapping("/icons") +public class IconController{ + @Value("${uploadFileDirectory}") + private String uploadFileDirectory; + + + @GetMapping("/gameIcons/{gameIconName}") + @AccountAuthorization(permissions = {}) + public ResponseEntity getGameClassIcons(@PathVariable("gameIconName") String gameIconName) throws IOException{ + log.info("Getting game icon {}", gameIconName); + + + byte[] resource = Files.readAllBytes(Path.of(uploadFileDirectory + "/gameIcons/" + gameIconName)); + + + return ResponseEntity.ok().body(resource); + } +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/entity/AuditableEntity.java b/src/main/java/com/mattrixwv/raidbuilder/entity/AuditableEntity.java index 2774c46..e1b9d0b 100644 --- a/src/main/java/com/mattrixwv/raidbuilder/entity/AuditableEntity.java +++ b/src/main/java/com/mattrixwv/raidbuilder/entity/AuditableEntity.java @@ -4,33 +4,26 @@ package com.mattrixwv.raidbuilder.entity; import java.time.ZonedDateTime; import java.util.UUID; -import org.springframework.data.annotation.CreatedBy; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedBy; -import org.springframework.data.annotation.LastModifiedDate; - import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.Column; +import jakarta.persistence.MappedSuperclass; import lombok.Data; @Data +@MappedSuperclass public abstract class AuditableEntity{ @JsonIgnore - @LastModifiedBy @Column(name = "modified_by") protected UUID modifiedBy; @JsonIgnore - @LastModifiedDate @Column(name = "modified_date") protected ZonedDateTime modifiedDate; @JsonIgnore - @CreatedBy @Column(name = "created_by", updatable = false) protected UUID createdBy; @JsonIgnore - @CreatedDate @Column(name = "created_date", updatable = false) protected ZonedDateTime createdDate; } diff --git a/src/main/java/com/mattrixwv/raidbuilder/entity/AuditableEntityListener.java b/src/main/java/com/mattrixwv/raidbuilder/entity/AuditableEntityListener.java index dc78207..76d78fa 100644 --- a/src/main/java/com/mattrixwv/raidbuilder/entity/AuditableEntityListener.java +++ b/src/main/java/com/mattrixwv/raidbuilder/entity/AuditableEntityListener.java @@ -4,12 +4,11 @@ package com.mattrixwv.raidbuilder.entity; import java.time.ZonedDateTime; import java.util.UUID; +import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.stereotype.Component; -import com.mattrixwv.raidbuilder.service.AccountService; - import jakarta.persistence.PrePersist; import jakarta.persistence.PreUpdate; import lombok.RequiredArgsConstructor; @@ -20,19 +19,16 @@ import lombok.extern.slf4j.Slf4j; @Component @RequiredArgsConstructor public class AuditableEntityListener{ - private final AccountService accountService; - - @PrePersist - public void prePersist(AuditableEntity entity){ - entity.setCreatedBy(getCurrentUserId()); - entity.setCreatedDate(ZonedDateTime.now()); + public void prePersist(AuditableEntity entity) throws NoSuchFieldException, IllegalAccessException{ + entity.createdBy = getCurrentUserId(); + entity.createdDate = ZonedDateTime.now(); } @PreUpdate public void preUpdate(AuditableEntity entity){ - entity.setModifiedBy(getCurrentUserId()); - entity.setModifiedDate(ZonedDateTime.now()); + entity.modifiedBy = getCurrentUserId(); + entity.modifiedDate = ZonedDateTime.now(); } @@ -43,11 +39,11 @@ public class AuditableEntityListener{ UUID returnUUID; try{ - UserDetails userDetails = (UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - returnUUID = accountService.getByUsername(userDetails.getUsername()).getAccountId(); + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + returnUUID = UUID.fromString(((Jwt)auth.getPrincipal()).getClaimAsString("accountId")); } catch(Exception e){ - returnUUID = UUID.fromString("382b1ed8-7d5a-4683-a25d-1f462e9cd921"); + returnUUID = new UUID(0, 0); log.debug("No user logged in: {}", returnUUID); } diff --git a/src/main/java/com/mattrixwv/raidbuilder/entity/Game.java b/src/main/java/com/mattrixwv/raidbuilder/entity/Game.java new file mode 100644 index 0000000..efe925c --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/entity/Game.java @@ -0,0 +1,35 @@ +package com.mattrixwv.raidbuilder.entity; + + +import java.util.UUID; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; + + +@Entity +@Table(name = "game", schema = "raid_builder") +@EntityListeners(AuditableEntityListener.class) +@Data +@EqualsAndHashCode(callSuper = false) +@ToString(callSuper = true) +@NoArgsConstructor +public class Game extends AuditableEntity{ + @Id + @GeneratedValue(strategy = GenerationType.UUID) + @Column(name = "game_id") + private UUID gameId; + @Column(name = "game_name") + private String gameName; + @Column(name = "game_icon") + private String gameIcon; +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/entity/GamePermission.java b/src/main/java/com/mattrixwv/raidbuilder/entity/GamePermission.java new file mode 100644 index 0000000..703e4b4 --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/entity/GamePermission.java @@ -0,0 +1,40 @@ +package com.mattrixwv.raidbuilder.entity; + + +import java.util.UUID; + +import com.mattrixwv.raidbuilder.util.DatabaseTypeUtil.GamePermissionType; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + + +@Entity +@Table(name = "game_permission", schema = "raid_builder") +@EntityListeners(AuditableEntityListener.class) +@Data +@EqualsAndHashCode(callSuper = false) +@NoArgsConstructor +public class GamePermission extends AuditableEntity{ + @Id + @Column(name = "game_permission_id") + @GeneratedValue(strategy = GenerationType.UUID) + private UUID gamePermissionId; + @Column(name = "account_id") + private UUID accountId; + @Column(name = "game_id") + private UUID gameId; + @Enumerated(EnumType.STRING) + @Column(name = "game_permission_type") + private GamePermissionType gamePermissionType; +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/repository/game/GameCustomRepository.java b/src/main/java/com/mattrixwv/raidbuilder/repository/game/GameCustomRepository.java new file mode 100644 index 0000000..addfbdb --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/repository/game/GameCustomRepository.java @@ -0,0 +1,5 @@ +package com.mattrixwv.raidbuilder.repository.game; + + +public interface GameCustomRepository{ +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/repository/game/GameRepository.java b/src/main/java/com/mattrixwv/raidbuilder/repository/game/GameRepository.java new file mode 100644 index 0000000..60463d7 --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/repository/game/GameRepository.java @@ -0,0 +1,16 @@ +package com.mattrixwv.raidbuilder.repository.game; + + +import java.util.List; +import java.util.UUID; + +import org.springframework.data.domain.PageRequest; +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mattrixwv.raidbuilder.entity.Game; + + +public interface GameRepository extends GameCustomRepository, JpaRepository{ + public List findAllByGameNameContainingIgnoreCase(String searchTerm, PageRequest pageRequest); + public long countAllByGameNameContainingIgnoreCase(String searchTerm); +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/repository/game/GameRepositoryImpl.java b/src/main/java/com/mattrixwv/raidbuilder/repository/game/GameRepositoryImpl.java new file mode 100644 index 0000000..7fbc155 --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/repository/game/GameRepositoryImpl.java @@ -0,0 +1,9 @@ +package com.mattrixwv.raidbuilder.repository.game; + + +import org.springframework.stereotype.Repository; + + +@Repository +public class GameRepositoryImpl implements GameCustomRepository{ +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/repository/game_permission/GamePermissionCustomRepository.java b/src/main/java/com/mattrixwv/raidbuilder/repository/game_permission/GamePermissionCustomRepository.java new file mode 100644 index 0000000..bf2a76c --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/repository/game_permission/GamePermissionCustomRepository.java @@ -0,0 +1,5 @@ +package com.mattrixwv.raidbuilder.repository.game_permission; + + +public interface GamePermissionCustomRepository{ +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/repository/game_permission/GamePermissionRepository.java b/src/main/java/com/mattrixwv/raidbuilder/repository/game_permission/GamePermissionRepository.java new file mode 100644 index 0000000..0d3c772 --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/repository/game_permission/GamePermissionRepository.java @@ -0,0 +1,14 @@ +package com.mattrixwv.raidbuilder.repository.game_permission; + + +import java.util.List; +import java.util.UUID; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mattrixwv.raidbuilder.entity.GamePermission; + + +public interface GamePermissionRepository extends GamePermissionCustomRepository, JpaRepository{ + public List findAllByAccountId(UUID accountId); +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/repository/game_permission/GamePermissionRepositoryImpl.java b/src/main/java/com/mattrixwv/raidbuilder/repository/game_permission/GamePermissionRepositoryImpl.java new file mode 100644 index 0000000..d2989ea --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/repository/game_permission/GamePermissionRepositoryImpl.java @@ -0,0 +1,9 @@ +package com.mattrixwv.raidbuilder.repository.game_permission; + + +import org.springframework.stereotype.Repository; + + +@Repository +public class GamePermissionRepositoryImpl implements GamePermissionCustomRepository{ +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/service/AccountService.java b/src/main/java/com/mattrixwv/raidbuilder/service/AccountService.java index c263336..56b1e9d 100644 --- a/src/main/java/com/mattrixwv/raidbuilder/service/AccountService.java +++ b/src/main/java/com/mattrixwv/raidbuilder/service/AccountService.java @@ -127,7 +127,10 @@ public class AccountService implements UserDetailsService{ } public List getAccounts(int page, int pageSize, String searchTerm){ - return accountRepository.findAllByUsernameContainingIgnoreCase(searchTerm, PageRequest.of(page, pageSize, Sort.by("username").ascending())); + return accountRepository.findAllByUsernameContainingIgnoreCase( + searchTerm, + PageRequest.of(page, pageSize, Sort.by("username").ascending()) + ); } public long getAccountsCount(){ diff --git a/src/main/java/com/mattrixwv/raidbuilder/service/GamePermissionService.java b/src/main/java/com/mattrixwv/raidbuilder/service/GamePermissionService.java new file mode 100644 index 0000000..1f1ed58 --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/service/GamePermissionService.java @@ -0,0 +1,41 @@ +package com.mattrixwv.raidbuilder.service; + + +import java.util.List; +import java.util.UUID; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.mattrixwv.raidbuilder.entity.GamePermission; +import com.mattrixwv.raidbuilder.repository.game_permission.GamePermissionRepository; + +import lombok.RequiredArgsConstructor; + + +@Service +@Transactional(rollbackFor = Exception.class) +@RequiredArgsConstructor +public class GamePermissionService{ + private final GamePermissionRepository gamePermissionRepository; + + + //Write + public GamePermission createGamePermission(GamePermission gamePermission){ + return gamePermissionRepository.save(gamePermission); + } + + public GamePermission updateGamePermission(GamePermission gamePermission){ + return gamePermissionRepository.save(gamePermission); + } + + public void deleteGamePermission(GamePermission gamePermission){ + gamePermissionRepository.delete(gamePermission); + } + + + //Read + public List getByAccountId(UUID accountId){ + return gamePermissionRepository.findAllByAccountId(accountId); + } +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/service/GameService.java b/src/main/java/com/mattrixwv/raidbuilder/service/GameService.java new file mode 100644 index 0000000..9c5b329 --- /dev/null +++ b/src/main/java/com/mattrixwv/raidbuilder/service/GameService.java @@ -0,0 +1,113 @@ +package com.mattrixwv.raidbuilder.service; + + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.UUID; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import com.mattrixwv.raidbuilder.entity.Game; +import com.mattrixwv.raidbuilder.repository.game.GameRepository; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + + +@Slf4j +@Service +@Transactional(rollbackFor = Exception.class) +@RequiredArgsConstructor +public class GameService{ + private final GameRepository gameRepository; + @Value("${uploadFileDirectory}") + private String uploadFileDirectory; + + + //Write + public Game createGame(Game game, MultipartFile file){ + if(file != null){ + String fileName = UUID.randomUUID().toString() + "--" + file.getOriginalFilename(); + Path filePath = Paths.get(uploadFileDirectory + "/gameIcons").resolve(fileName); + try{ + file.transferTo(filePath); + game.setGameIcon(fileName); + } + catch(Exception error){ + log.error("Error uploading file: " + error.getMessage(), error); + throw new RuntimeException("Error uploading file: " + error.getMessage(), error); + } + } + return gameRepository.save(game); + } + + public Game updateGame(Game game, MultipartFile file){ + Game existingGame = gameRepository.findById(game.getGameId()).orElse(null); + + //Delete the old file if one exists + if((existingGame != null) && (existingGame.getGameIcon() != null) && (game.getGameIcon() == null)){ + log.debug("Deleting old file: {}", existingGame.getGameIcon()); + File existingFile = new File(uploadFileDirectory + "/gameIcons/" + existingGame.getGameIcon()); + if(existingFile.exists()){ + existingFile.delete(); + } + } + + if(file != null){ + //Upload the new file + String fileName = UUID.randomUUID().toString() + "--" + file.getOriginalFilename(); + Path filePath = Paths.get(uploadFileDirectory + "/gameIcons").resolve(fileName); + try{ + file.transferTo(filePath); + game.setGameIcon(fileName); + } + catch(Exception error){ + log.error("Error uploading file: " + error.getMessage(), error); + throw new RuntimeException("Error uploading file: " + error.getMessage(), error); + } + } + + return gameRepository.save(game); + } + + public void deleteById(UUID gameId){ + Game game = gameRepository.findById(gameId).orElse(null); + if(game != null){ + if(game.getGameIcon() != null){ + File existingFile = new File(uploadFileDirectory + "/gameIcons/" + game.getGameIcon()); + if(existingFile.exists()){ + existingFile.delete(); + } + } + gameRepository.deleteById(gameId); + } + } + + + //Read + public List getGames(int page, int pageSize){ + return gameRepository.findAll(PageRequest.of(page, pageSize, Sort.by("gameName").ascending())).getContent(); + } + + public List getGames(int page, int pageSize, String searchTerm){ + return gameRepository.findAllByGameNameContainingIgnoreCase( + searchTerm, + PageRequest.of(page, pageSize, Sort.by("gameName").ascending()) + ); + } + + public long getGamesCount(){ + return gameRepository.count(); + } + + public long getGamesCount(String searchTerm){ + return gameRepository.countAllByGameNameContainingIgnoreCase(searchTerm); + } +} diff --git a/src/main/java/com/mattrixwv/raidbuilder/util/DatabaseTypeUtil.java b/src/main/java/com/mattrixwv/raidbuilder/util/DatabaseTypeUtil.java index 5ab6956..7f8cd8b 100644 --- a/src/main/java/com/mattrixwv/raidbuilder/util/DatabaseTypeUtil.java +++ b/src/main/java/com/mattrixwv/raidbuilder/util/DatabaseTypeUtil.java @@ -17,7 +17,11 @@ public class DatabaseTypeUtil{ public static enum AccountPermissionType { ADMIN, USER - } + }; + + public static enum GamePermissionType { + ADMIN + }; public static enum TutorialStatus { COMPLETED, diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b3962c6..31128cc 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -19,3 +19,6 @@ rsa.privateKey=classpath:certs/private.pem rsa.publicKey=classpath:certs/public.pem jwt.accessTokenDuration=15m jwt.refreshTokenDuration=30d + +#Files +uploadFileDirectory=../raidBuilderIcons diff --git a/temp/raidBuilderIcons/gameIcons/070d1ad3-48bb-438e-af01-0559e9169149--Screenshot 2024-10-19 162110.png b/temp/raidBuilderIcons/gameIcons/070d1ad3-48bb-438e-af01-0559e9169149--Screenshot 2024-10-19 162110.png new file mode 100644 index 0000000..304e847 Binary files /dev/null and b/temp/raidBuilderIcons/gameIcons/070d1ad3-48bb-438e-af01-0559e9169149--Screenshot 2024-10-19 162110.png differ