From 8998173e6fed32f08bb0f1bf66b35c8985c6cce2 Mon Sep 17 00:00:00 2001 From: Beyzanur Bektan <123978913+beyzabektan@users.noreply.github.com> Date: Tue, 26 Dec 2023 01:18:04 +0300 Subject: [PATCH] Frontend/enhancement/follow unfollow 654 (#671) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tested and works well * homepage will show the realted objects according to recommendation * if no recommendation show all * add follow/unfollow and other fixes --------- Co-authored-by: Halis Ayberk Erdem Co-authored-by: Ömer Talip Akalın Co-authored-by: Ömer Talip Akalın <56600661+omertalib42@users.noreply.github.com> --- app/annotation-service/README.md | 0 .../AnnotationServiceApplication.kt | 19 +- .../controller/AnnotationController.kt | 7 +- app/backend/README.md | 1 + .../gamelounge/backend/BackendApplication.kt | 2 +- .../backend/controller/AccessController.kt | 2 + .../src/main/resources/application.properties | 2 +- .../gamelounge/backend/CommentServiceTest.kt | 33 +- .../com/gamelounge/backend/GameServiceTest.kt | 482 +++--------------- .../com/gamelounge/backend/PostServiceTest.kt | 31 +- .../com/gamelounge/backend/UserServiceTest.kt | 25 +- app/backend/test.txt | 1 + app/frontend/README.md | 1 + app/frontend/src/App.js | 8 +- app/frontend/src/components/CommentCard.js | 19 +- app/frontend/src/components/PostCard.js | 3 +- app/frontend/src/components/navbar/Navbar.js | 38 +- .../src/pages/ForumPage/SelectTags.js | 16 +- app/frontend/src/pages/HomePage/Group.js | 54 +- app/frontend/src/pages/HomePage/HomePage.js | 31 +- app/frontend/src/pages/HomePage/Post.js | 5 +- app/frontend/src/pages/HomePage/profile.jpg | Bin 0 -> 13229 bytes app/frontend/src/pages/LfgPage/EditLfg.js | 2 +- app/frontend/src/pages/LfgPage/Lfg.js | 32 +- app/frontend/src/pages/LfgPage/LfgCard.js | 8 +- app/frontend/src/pages/LfgPage/LfgPage.js | 2 + app/frontend/src/pages/PostPage/PostPage.js | 6 +- app/frontend/src/pages/Profile/ProfileMenu.js | 6 +- app/frontend/src/pages/Profile/ProfilePage.js | 108 +++- app/frontend/src/pages/Profile/profile.jpg | Bin 0 -> 13229 bytes app/frontend/src/pages/Search/Search.js | 127 ----- app/frontend/src/pages/Search/index.js | 1 - app/frontend/src/services/searchService.js | 14 - app/frontend/src/services/userService.js | 18 + .../lib/constants/network_constants.dart | 2 - .../lib/data/models/annotation_model.dart | 169 ++---- .../lib/data/models/character_model.dart | 4 +- app/mobile/lib/data/models/content_model.dart | 14 +- .../models/dto/annotation/annotation_dto.dart | 4 +- .../annotation/get_annotation_request.dart | 26 - .../dto/annotation/multiple_annotation.dart | 4 +- .../dto/content/post_create_dto_request.dart | 4 +- .../dto/game/character_create_request.dart | 37 -- .../dto/lfg/lfg_create_dto_request.dart | 61 --- .../lib/data/models/dto/lfg/lfg_response.dart | 25 - .../dto/lfg/mutliple_lfg_dto_request.dart | 33 -- .../dto/search/search_all_response.dart | 39 -- app/mobile/lib/data/models/game_model.dart | 3 +- app/mobile/lib/data/models/lfg_model.dart | 45 +- app/mobile/lib/data/models/post_model.dart | 38 +- .../lib/data/services/annotation_service.dart | 103 +++- .../lib/data/services/base_service.dart | 10 +- .../lib/data/services/game_service.dart | 145 +----- app/mobile/lib/data/services/lfg_service.dart | 255 +++------ .../lib/data/services/post_service.dart | 31 +- .../lib/data/services/search_service.dart | 111 ---- app/mobile/lib/main.dart | 2 +- .../lib/presentation/pages/forum_page.dart | 143 ++---- .../lib/presentation/pages/game_page.dart | 16 +- .../presentation/pages/game_page_create.dart | 269 +++++----- .../presentation/pages/game_wiki_page.dart | 195 +------ .../lib/presentation/pages/group_page.dart | 52 +- .../lib/presentation/pages/home_page.dart | 54 +- .../lib/presentation/pages/lfg_page.dart | 15 +- .../presentation/pages/lfg_page_create.dart | 99 +--- .../lib/presentation/pages/navigator.dart | 12 +- .../lib/presentation/pages/opening_page.dart | 7 +- .../pages/post/content_card_widget.dart | 69 +-- .../presentation/pages/post/post_page.dart | 19 +- .../pages/post/report_widget.dart | 90 ---- .../states/game_list_grid_view_state.dart | 20 +- .../states/lfg_list_grid_view_state.dart | 71 +-- .../widgets/annotatable_image_widget.dart | 94 ++-- .../widgets/annotatable_text_widget.dart | 73 +-- .../presentation/widgets/lfg_card_widget.dart | 2 +- .../widgets/post_card_widget.dart | 70 +-- .../widgets/searchbar_widget.dart | 246 --------- app/mobile/pubspec.lock | 32 -- app/mobile/pubspec.yaml | 3 - 79 files changed, 958 insertions(+), 2962 deletions(-) delete mode 100644 app/annotation-service/README.md create mode 100644 app/backend/test.txt create mode 100644 app/frontend/src/pages/HomePage/profile.jpg create mode 100644 app/frontend/src/pages/Profile/profile.jpg delete mode 100644 app/frontend/src/pages/Search/Search.js delete mode 100644 app/frontend/src/pages/Search/index.js delete mode 100644 app/frontend/src/services/searchService.js delete mode 100644 app/mobile/lib/data/models/dto/annotation/get_annotation_request.dart delete mode 100644 app/mobile/lib/data/models/dto/game/character_create_request.dart delete mode 100644 app/mobile/lib/data/models/dto/lfg/lfg_create_dto_request.dart delete mode 100644 app/mobile/lib/data/models/dto/lfg/lfg_response.dart delete mode 100644 app/mobile/lib/data/models/dto/lfg/mutliple_lfg_dto_request.dart delete mode 100644 app/mobile/lib/data/models/dto/search/search_all_response.dart delete mode 100644 app/mobile/lib/data/services/search_service.dart delete mode 100644 app/mobile/lib/presentation/widgets/searchbar_widget.dart diff --git a/app/annotation-service/README.md b/app/annotation-service/README.md deleted file mode 100644 index e69de29b..00000000 diff --git a/app/annotation-service/src/main/kotlin/com/group6/annotationservice/AnnotationServiceApplication.kt b/app/annotation-service/src/main/kotlin/com/group6/annotationservice/AnnotationServiceApplication.kt index 7369e1a4..8e096f64 100644 --- a/app/annotation-service/src/main/kotlin/com/group6/annotationservice/AnnotationServiceApplication.kt +++ b/app/annotation-service/src/main/kotlin/com/group6/annotationservice/AnnotationServiceApplication.kt @@ -2,26 +2,9 @@ package com.group6.annotationservice import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication -import org.springframework.context.annotation.Bean -import org.springframework.web.servlet.config.annotation.CorsRegistry -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer @SpringBootApplication -class AnnotationServiceApplication { - @Bean - fun corsFilter(): WebMvcConfigurer { - return object : WebMvcConfigurer { - override fun addCorsMappings(registry: CorsRegistry) { - registry.addMapping("/**") - .allowedOrigins("http://localhost:3000", "http://game-lounge.com") - .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") - .allowCredentials(true) - .allowedHeaders("*") - .exposedHeaders("Access-Control-Allow-Origin", "Cookie", "Set-Cookie") - } - } - } -} +class AnnotationServiceApplication fun main(args: Array) { runApplication(*args) diff --git a/app/annotation-service/src/main/kotlin/com/group6/annotationservice/controller/AnnotationController.kt b/app/annotation-service/src/main/kotlin/com/group6/annotationservice/controller/AnnotationController.kt index 42f9c2b2..8fcc8148 100644 --- a/app/annotation-service/src/main/kotlin/com/group6/annotationservice/controller/AnnotationController.kt +++ b/app/annotation-service/src/main/kotlin/com/group6/annotationservice/controller/AnnotationController.kt @@ -15,13 +15,11 @@ class AnnotationController( private val annotationService: AnnotationService ) { @PostMapping("parse-selector") - @CrossOrigin(origins = ["http://localhost:3000", "http://game-lounge.com"]) fun parseSelector(@RequestBody selector: SelectorDto): ResponseEntity { return ResponseEntity.ok("test") } @PostMapping("/create") - @CrossOrigin(origins = ["http://localhost:3000", "http://game-lounge.com"]) fun createAnnotation(@RequestBody annotationDto: AnnotationDto): ResponseEntity { val responseAnnotation = DtoConverter @@ -30,7 +28,6 @@ class AnnotationController( } @GetMapping("/{id}") - @CrossOrigin(origins = ["http://localhost:3000", "http://game-lounge.com"]) fun getAnnotation(@PathVariable id: String): ResponseEntity { val annotation = annotationService.getAnnotation(id) ?: return ResponseEntity(HttpStatus.NOT_FOUND) @@ -40,7 +37,6 @@ class AnnotationController( } @PostMapping("/get-annotations-by-target") - @CrossOrigin(origins = ["http://localhost:3000", "http://game-lounge.com"]) fun getAnnotationsByTarget(@RequestBody request: GetAnnotationsByTargetIdRequest): ResponseEntity> { val annotations = annotationService.getAnnotationsByTarget(request.targetId) val responseAnnotationList = annotations.map { DtoConverter.convertAnnotationToAnnotationDto(it) } @@ -48,7 +44,6 @@ class AnnotationController( } @DeleteMapping("/{id}") - @CrossOrigin(origins = ["http://localhost:3000", "http://game-lounge.com"]) fun deleteAnnotation(@PathVariable id: String): ResponseEntity { return if (annotationService.deleteAnnotation(id)) { ResponseEntity(HttpStatus.NO_CONTENT) @@ -56,4 +51,4 @@ class AnnotationController( ResponseEntity(HttpStatus.NOT_FOUND) } } -} +} \ No newline at end of file diff --git a/app/backend/README.md b/app/backend/README.md index 4f67095c..ebb969bb 100644 --- a/app/backend/README.md +++ b/app/backend/README.md @@ -53,3 +53,4 @@ docker run --detach -p 8080:8080 -e SPRING_DATASOURCE_URL="jdbc:postgresql:// invocation.arguments[0] as Game } - `when`(s3Service.uploadGamePictureAndReturnURL(any(MultipartFile::class.java), anyLong())).thenReturn("image-url.jpg") - // Act - val result = gameService.createGame(sessionId, createGameRequest, image) - - // Assert - assertEquals(createGameRequest.title, result.title) - assertEquals(createGameRequest.description, result.description) - assertEquals(createGameRequest.genres, result.genres) - assertEquals(createGameRequest.platforms, result.platforms) - assertEquals(createGameRequest.playerNumber, result.playerNumber) - assertEquals(createGameRequest.releaseYear, result.releaseYear) - assertEquals(createGameRequest.universe, result.universe) - assertEquals(createGameRequest.mechanics, result.mechanics) - assertEquals(createGameRequest.playtime, result.playtime) - assertEquals(createGameRequest.totalRating, result.totalRating) - assertEquals(createGameRequest.countRating, result.countRating) - assertEquals(createGameRequest.averageRating, result.averageRating) - } - - @Test - fun `createEditingRequest should create and return a new editing request`() { - // Arrange - val sessionId = UUID.randomUUID() - val userId = 123L - val gameId = 1L - val createEditingRequest = CreateEditingRequest( - title = "Updated Title", - description = "Updated Description", - genres = listOf("ACTION"), - platforms = listOf("PC"), - playerNumber = NumberOfPlayers.Single, - releaseYear = 2023, - universe = UniverseInfo.Historical, - mechanics = GameMechanics.TurnBased, - playtime = "15 hours", - totalRating = 0, - countRating = 0, - averageRating = 0.0 - ) - val editedImage: MultipartFile? = mock() val user = User(userId = userId) - val game = Game(gameId = gameId, user = user, status = GameStatus.APPROVED) - `when`(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(userId) - `when`(userRepository.findById(userId)).thenReturn(Optional.of(user)) - `when`(gameRepository.findById(gameId)).thenReturn(Optional.of(game)) - `when`(editedGameRepository.findByGameId(gameId)).thenReturn(emptyList()) - `when`(editedGameRepository.save(any(RequestedEditingGame::class.java))).thenAnswer { invocation -> invocation.arguments[0] as RequestedEditingGame } - `when`(s3Service.uploadEditedGamePictureAndReturnURL(any(MultipartFile::class.java), anyLong())).thenReturn("edited-image-url.jpg") + whenever(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(userId) + whenever(userRepository.findById(userId)).thenReturn(Optional.of(user)) + whenever(gameRepository.save(any())).thenAnswer { invocation -> invocation.arguments[0] as Game } - // Act - gameService.createEditingRequest(sessionId, createEditingRequest, editedImage, gameId) + val result = gameService.createGame(sessionId, gameRequest, null) - // Assert - verify(editedGameRepository).save(any(RequestedEditingGame::class.java)) + assertNotNull(result) + assertEquals(gameRequest.title, result.title) + assertEquals(gameRequest.description, result.description) + assertEquals(gameRequest.genre, result.genre) + assertEquals(gameRequest.platform, result.platform) + assertEquals(gameRequest.playerNumber, result.playerNumber) + assertEquals(gameRequest.releaseYear, result.releaseYear) + assertEquals(gameRequest.universe, result.universe) + assertEquals(gameRequest.mechanics, result.mechanics) + assertEquals(gameRequest.playtime, result.playtime) + assertEquals(gameRequest.totalRating, result.totalRating) + assertEquals(gameRequest.countRating, result.countRating) + assertEquals(gameRequest.averageRating, result.averageRating) + assertEquals(user, result.user) } @Test - fun `deleteGame should mark the game as deleted`() { - // Arrange + fun `createGame should create and save game with image`() { val sessionId = UUID.randomUUID() val userId = 123L - val gameId = 1L - val user = User(userId = userId) - val game = Game(gameId = gameId, user = user, status = GameStatus.APPROVED) - - `when`(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(userId) - `when`(userRepository.findById(userId)).thenReturn(Optional.of(user)) - `when`(gameRepository.findById(gameId)).thenReturn(Optional.of(game)) - `when`(gameRepository.save(any(Game::class.java))).thenAnswer { invocation -> invocation.arguments[0] as Game } - - // Act - gameService.deleteGame(sessionId, gameId) - - // Assert - assertTrue(game.isDeleted) - } - - @Test - fun `getAllGames should return a list of approved and non-deleted games`() { - // Arrange - val games = listOf( - Game(title = "Game1", status = GameStatus.APPROVED), - Game(title = "Game2", status = GameStatus.PENDING_APPROVAL), - Game(title = "Game3", status = GameStatus.APPROVED, isDeleted = true), - Game(title = "Game4", status = GameStatus.APPROVED) + val gameRequest = CreateGameRequest( + title = "Game Title", + description = "Description", + genre = GameGenre.FIGHTING, + platform = GamePlatform.COMPUTER, + playerNumber = NumberOfPlayers.MULTIPLE, + releaseYear = 2020, + universe = UniverseInfo.FANTASY, + mechanics = GameMechanics.CHANCE_BASED, + playtime = "100", + totalRating = 0, + countRating = 0, + averageRating = 0.0, ) - `when`(gameRepository.findAll()).thenReturn(games) - - // Act - val result = gameService.getAllGames() - - // Assert - assertEquals(2, result.size) - assertEquals("Game1", result[0].title) - assertEquals("Game4", result[1].title) - // Add more assertions based on your requirements - } - - @Test - fun `rateGame should update the game's rating and return the modified game`() { - // Arrange - val sessionId = UUID.randomUUID() - val userId = 123L - val gameId = 1L - val score = 4L - val user = User(userId = userId) - val game = Game(gameId = gameId, user = user, status = GameStatus.APPROVED, totalRating = 10, countRating = 2) - - `when`(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(userId) - `when`(userRepository.findById(userId)).thenReturn(Optional.of(user)) - `when`(gameRepository.findById(gameId)).thenReturn(Optional.of(game)) - `when`(gameRepository.save(any(Game::class.java))).thenAnswer { invocation -> invocation.arguments[0] as Game } - `when`(userGameRatingRepository.findByUserAndGame(user, game)).thenReturn(emptyList()) - - // Act - val result = gameService.rateGame(sessionId, gameId, score) - - // Assert - assertEquals(score.toDouble(), result.averageRating) - assertEquals(12, result.totalRating) - assertEquals(3, result.countRating) - } - - @Test - fun `rateGame should update the user's rating for the game if already rated`() { - // Arrange - val sessionId = UUID.randomUUID() - val userId = 123L - val gameId = 1L - val score = 4L - val user = User(userId = userId) - val game = Game(gameId = gameId, user = user, status = GameStatus.APPROVED, totalRating = 10, countRating = 2) - val userGameRating = UserGameRating(user = user, game = game, score = 3) - - `when`(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(userId) - `when`(userRepository.findById(userId)).thenReturn(Optional.of(user)) - `when`(gameRepository.findById(gameId)).thenReturn(Optional.of(game)) - `when`(gameRepository.save(any(Game::class.java))).thenAnswer { invocation -> invocation.arguments[0] as Game } - `when`(userGameRatingRepository.findByUserAndGame(user, game)).thenReturn(listOf(userGameRating)) - - // Act - val result = gameService.rateGame(sessionId, gameId, score) - - // Assert - assertEquals(score.toDouble(), result.averageRating) - assertEquals(11, result.totalRating) - assertEquals(2, result.countRating) - } - - @Test - fun `rateGame should throw WrongRatingGameException for an invalid rating score`() { - // Arrange - val sessionId = UUID.randomUUID() - val userId = 123L - val gameId = 1L - val invalidScore = 6L - val user = User(userId = userId) - val game = Game(gameId = gameId, user = user, status = GameStatus.APPROVED) - - `when`(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(userId) - `when`(userRepository.findById(userId)).thenReturn(Optional.of(user)) - `when`(gameRepository.findById(gameId)).thenReturn(Optional.of(game)) - - // Act and Assert - assertThrows { - gameService.rateGame(sessionId, gameId, invalidScore) - } - } - - @Test - fun `deleteGame should throw UnauthorizedGameAccessException if the user is not the owner`() { - // Arrange - val sessionId = UUID.randomUUID() - val userId = 123L - val gameId = 1L - val ownerUserId = 456L - val user = User(userId = userId) - val owner = User(userId = ownerUserId) - val game = Game(gameId = gameId, user = owner, status = GameStatus.APPROVED) - - `when`(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(userId) - `when`(userRepository.findById(userId)).thenReturn(Optional.of(user)) - `when`(gameRepository.findById(gameId)).thenReturn(Optional.of(game)) - - // Act and Assert - assertThrows { - gameService.deleteGame(sessionId, gameId) - } - } - - @Test - fun `deleteGame should throw DeletedGameException if the game is already deleted`() { - // Arrange - val sessionId = UUID.randomUUID() - val userId = 123L - val gameId = 1L - val user = User(userId = userId) - val game = Game(gameId = gameId, user = user, status = GameStatus.APPROVED, isDeleted = true) - - `when`(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(userId) - `when`(userRepository.findById(userId)).thenReturn(Optional.of(user)) - `when`(gameRepository.findById(gameId)).thenReturn(Optional.of(game)) - - // Act and Assert - assertThrows { - gameService.deleteGame(sessionId, gameId) - } - } - - @Test - fun `rateGame should update the rating of the game and create a UserGameRating`() { - // Arrange - val sessionId = UUID.randomUUID() - val userId = 123L - val gameId = 1L - val score = 4L - val user = User(userId = userId) - val game = Game(gameId = gameId, user = user, status = GameStatus.APPROVED) - val userGameRating = UserGameRating(user = user, game = game, score = 0) - - `when`(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(userId) - `when`(userRepository.findById(userId)).thenReturn(Optional.of(user)) - `when`(gameRepository.findById(gameId)).thenReturn(Optional.of(game)) - `when`(userGameRatingRepository.findByUserAndGame(user, game)).thenReturn(emptyList()) - `when`(userGameRatingRepository.save(any(UserGameRating::class.java))).thenAnswer { invocation -> invocation.arguments[0] as UserGameRating } - `when`(gameRepository.save(any(Game::class.java))).thenAnswer { invocation -> invocation.arguments[0] as Game } - - // Act - val result = gameService.rateGame(sessionId, gameId, score) - - // Assert - assertEquals(score, result.averageRating) - verify(userGameRatingRepository).save(any(UserGameRating::class.java)) - } - - @Test - fun `rateGame should update the rating of the game and update the UserGameRating`() { - // Arrange - val sessionId = UUID.randomUUID() - val userId = 123L - val gameId = 1L - val score = 4L - val user = User(userId = userId) - val game = Game(gameId = gameId, user = user, status = GameStatus.APPROVED) - val existingUserGameRating = UserGameRating(user = user, game = game, score = 3) - - `when`(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(userId) - `when`(userRepository.findById(userId)).thenReturn(Optional.of(user)) - `when`(gameRepository.findById(gameId)).thenReturn(Optional.of(game)) - `when`(userGameRatingRepository.findByUserAndGame(user, game)).thenReturn(listOf(existingUserGameRating)) - `when`(userGameRatingRepository.save(any(UserGameRating::class.java))).thenAnswer { invocation -> invocation.arguments[0] as UserGameRating } - `when`(gameRepository.save(any(Game::class.java))).thenAnswer { invocation -> invocation.arguments[0] as Game } - - // Act - val result = gameService.rateGame(sessionId, gameId, score) - - // Assert - assertEquals(score, result.averageRating) - verify(userGameRatingRepository).save(any(UserGameRating::class.java)) - // Add more assertions based on your requirements - } - - @Test - fun `rateGame should throw DeletedGameException if the game is already deleted`() { - // Arrange - val sessionId = UUID.randomUUID() - val userId = 123L - val gameId = 1L - val score = 4L - val user = User(userId = userId) - val game = Game(gameId = gameId, user = user, status = GameStatus.APPROVED, isDeleted = true) - - `when`(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(userId) - `when`(userRepository.findById(userId)).thenReturn(Optional.of(user)) - `when`(gameRepository.findById(gameId)).thenReturn(Optional.of(game)) - - // Act and Assert - assertThrows { - gameService.rateGame(sessionId, gameId, score) - } - } - - @Test - fun `getGame should throw GameNotFoundException if the game does not exist`() { - // Arrange - val sessionId = UUID.randomUUID() - val gameId = 1L - - `when`(gameRepository.findById(gameId)).thenReturn(Optional.empty()) - - // Act and Assert - assertThrows { - gameService.getGame(gameId) - } - } - - @Test - fun `getEditingGame should throw GameNotFoundException if the editing game does not exist`() { - // Arrange - val sessionId = UUID.randomUUID() - val editingGameId = 1L + val image: MultipartFile = mock() - `when`(editedGameRepository.findByGameId(editingGameId)).thenReturn(emptyList()) - - // Act and Assert - assertThrows { - gameService.getEditingGame(editingGameId) + whenever(s3Service.uploadProfilePictureAndReturnURL(image, userId)).thenReturn("imageUrl") + whenever(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(userId) + whenever(userRepository.findById(userId)).thenReturn(Optional.of(User(userId = userId))) + whenever(gameRepository.save(any())).thenAnswer { invocation -> + (invocation.arguments[0] as Game).apply { gamePicture = "imageUrl" } } - } - - @Test - fun `createGame should update game similarity`() { - // Arrange - val sessionId = UUID.randomUUID() - // Provide necessary details for creating a game - val createGameRequest = CreateGameRequest( - title = "New Game", - description = "Game description", - genres = listOf("ACTION", "ADVENTURE"), - platforms = listOf("PC", "XBOX"), - playerNumber = NumberOfPlayers.Multiplayer, - releaseYear = 2022, - universe = UniverseInfo.Fantasy, - mechanics = GameMechanics.RealTime, - playtime = "10 hours", - totalRating = 0, - countRating = 0, - averageRating = 0.0 - ) - val image: MultipartFile? = mock() - - val user = User(userId = 123L) - - `when`(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(user.userId) - `when`(userRepository.findById(user.userId)).thenReturn(Optional.of(user)) - `when`(gameRepository.save(any(Game::class.java))).thenAnswer { invocation -> invocation.arguments[0] as Game } - `when`(s3Service.uploadGamePictureAndReturnURL(any(MultipartFile::class.java), anyLong())).thenReturn("image-url.jpg") - // Act - gameService.createGame(sessionId, createGameRequest, image) + val result = gameService.createGame(sessionId, gameRequest, image) - // Assert - verify(gameSimilarityService).updateSimilarGamesField(any(Game::class.java)) - verify(gameRepository).save(any(Game::class.java)) + assertNotNull(result) + assertEquals("imageUrl", result.gamePicture) } - // Add other tests related to game similarity as needed - @Test - fun `rateGame should update the game's rating and game similarity`() { - // Arrange - val sessionId = UUID.randomUUID() - val userId = 123L - val gameId = 1L - val score = 4L - val user = User(userId = userId) - val game = Game(gameId = gameId, user = user, status = GameStatus.APPROVED, totalRating = 10, countRating = 2) - `when`(sessionAuth.getUserIdFromSession(sessionId)).thenReturn(userId) - `when`(userRepository.findById(userId)).thenReturn(Optional.of(user)) - `when`(gameRepository.findById(gameId)).thenReturn(Optional.of(game)) - `when`(gameRepository.save(any(Game::class.java))).thenAnswer { invocation -> invocation.arguments[0] as Game } - `when`(userGameRatingRepository.findByUserAndGame(user, game)).thenReturn(emptyList()) - // Act - val result = gameService.rateGame(sessionId, gameId, score) - - // Assert - assertEquals(score.toDouble(), result.averageRating) - assertEquals(12, result.totalRating) - assertEquals(3, result.countRating) - - verify(gameSimilarityService).updateSimilarGamesField(any(Game::class.java)) - verify(userGameRatingRepository).save(any(UserGameRating::class.java)) - } -} +} \ No newline at end of file diff --git a/app/backend/src/test/kotlin/com/gamelounge/backend/PostServiceTest.kt b/app/backend/src/test/kotlin/com/gamelounge/backend/PostServiceTest.kt index eebe1229..d192a413 100644 --- a/app/backend/src/test/kotlin/com/gamelounge/backend/PostServiceTest.kt +++ b/app/backend/src/test/kotlin/com/gamelounge/backend/PostServiceTest.kt @@ -24,18 +24,17 @@ class PostServiceTest { private val reportRepository: ReportRepository = mock() private val objectMapper: ObjectMapper = mock() private val tagService: TagService = mock() - private val recommendationService: RecommendationService = mock() + private val converterDto : ConverterDTO = mock() private val gameService: GameService = mock() private val postService = PostService( - postRepository, - sessionAuth, - userRepository, - reportRepository, - objectMapper, - tagService, - recommendationService, - gameService + postRepository, + sessionAuth, + userRepository, + reportRepository, + objectMapper, + tagService, + gameService ) @Test @@ -76,9 +75,7 @@ class PostServiceTest { assertEquals(user, result.user) assertTrue(result.postTags.containsAll(postTags)) } - - //problamatic for GameServiceTest - /*@Test + @Test fun `updatePost should update and return post when user is authorized`() { val sessionId = UUID.randomUUID() val postId = 1L @@ -113,10 +110,8 @@ class PostServiceTest { assertEquals(updatedPostRequest.content, result.content) assertEquals(updatedPostRequest.category, result.category) assertTrue(result.postTags.containsAll(updatedTags)) - }*/ + } - //problematic for GameServiceTest - /* @Test fun `updatePost should throw UnauthorizedPostAccessException when user is not authorized`() { val sessionId = UUID.randomUUID() @@ -133,10 +128,8 @@ class PostServiceTest { assertThrows { postService.updatePost(sessionId, postId, updatedPostRequest) } - }*/ + } - //problematic for GameServiceTest - /* @Test fun `deletePost should successfully delete post when user is authorized`() { val sessionId = UUID.randomUUID() @@ -155,7 +148,7 @@ class PostServiceTest { postService.deletePost(sessionId, postId) verify(postRepository).delete(post) - }*/ + } @Test fun `deletePost should throw UnauthorizedPostAccessException when user is not authorized`() { val sessionId = UUID.randomUUID() diff --git a/app/backend/src/test/kotlin/com/gamelounge/backend/UserServiceTest.kt b/app/backend/src/test/kotlin/com/gamelounge/backend/UserServiceTest.kt index 1999a2d4..06d6515f 100644 --- a/app/backend/src/test/kotlin/com/gamelounge/backend/UserServiceTest.kt +++ b/app/backend/src/test/kotlin/com/gamelounge/backend/UserServiceTest.kt @@ -5,7 +5,10 @@ import com.gamelounge.backend.entity.User import com.gamelounge.backend.exception.UsernameNotFoundException import com.gamelounge.backend.middleware.SessionAuth import com.gamelounge.backend.model.request.UpdateUserRequest -import com.gamelounge.backend.repository.* +import com.gamelounge.backend.repository.GameRepository +import com.gamelounge.backend.repository.PostRepository +import com.gamelounge.backend.repository.SessionRepository +import com.gamelounge.backend.repository.UserRepository import com.gamelounge.backend.service.AccessService import com.gamelounge.backend.service.S3Service import com.gamelounge.backend.service.TagService @@ -25,22 +28,20 @@ class UserServiceTest { private val userRepository: UserRepository = mock() private val postRepository: PostRepository = mock() private val gameRepository: GameRepository = mock() - private val sessionAuth: SessionAuth = mock() private val s3Service: S3Service = mock() private val tagService: TagService = mock() + private val sessionAuth: SessionAuth = mock() private val accessService: AccessService = mock() - private val reportRepository: ReportRepository = mock() private val userService = UserService( - sessionRepository, - userRepository, - postRepository, - gameRepository, - sessionAuth, - s3Service, - tagService, - accessService, - reportRepository + sessionRepository, + userRepository, + postRepository, + gameRepository, + sessionAuth, + s3Service, + tagService, + accessService ) @Test fun `updateUser should update all fields when provided`() { diff --git a/app/backend/test.txt b/app/backend/test.txt new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/app/backend/test.txt @@ -0,0 +1 @@ + diff --git a/app/frontend/README.md b/app/frontend/README.md index 80737f14..3a8cced0 100644 --- a/app/frontend/README.md +++ b/app/frontend/README.md @@ -55,3 +55,4 @@ The command "docker run -p 3000:3000 -d game-lounge" starts a Docker container f Please note that one needs to setup a simple .env file before running it as the the backend url is defined by it. It's enough to define REACT_APP_API_URL (either localhost:8080 or some remote url). + diff --git a/app/frontend/src/App.js b/app/frontend/src/App.js index f3add35b..d48e4abf 100644 --- a/app/frontend/src/App.js +++ b/app/frontend/src/App.js @@ -8,16 +8,15 @@ import { ForumPage } from './pages/ForumPage' import { PostPage } from './pages/PostPage' import { NextUIProvider } from '@nextui-org/react' import { GameForum } from './pages/GameForum' -import { LfgPage } from './pages/LfgPage' -import Lfg from './pages/LfgPage/Lfg' +import { LfgPage } from "./pages/LfgPage"; +import Lfg from "./pages/LfgPage/Lfg"; import { AdminPanel } from './pages/AdminPanel' -import Search from './pages/Search/Search' + const App = () => ( } /> - } /> } /> } /> } /> @@ -37,3 +36,4 @@ const App = () => ( ) export default App + diff --git a/app/frontend/src/components/CommentCard.js b/app/frontend/src/components/CommentCard.js index 647eeb6c..9dba4318 100644 --- a/app/frontend/src/components/CommentCard.js +++ b/app/frontend/src/components/CommentCard.js @@ -1,16 +1,31 @@ import React from 'react' import userlogo from '../user.jpg' import ReportIcon from '@mui/icons-material/Report' +import DeleteIcon from '@mui/icons-material/Delete' +import { deleteComment } from '../services/commentService' const CommentCard = ({ comment, onUpvote, onDownvote, currentUser }) => { const isCurrentUserCreator = comment.creatorUser.username === currentUser.username + const handleDeleteComment = async (commentId) => { + try { + await deleteComment(commentId) + window.location.reload() + } catch (error) { + console.error('Error deleting post:', error) + } + } + return ( -
+

{comment.content}

- {isCurrentUserCreator ? null : ( + {isCurrentUserCreator ? ( + + ) : ( diff --git a/app/frontend/src/components/PostCard.js b/app/frontend/src/components/PostCard.js index c10e9609..97070faa 100644 --- a/app/frontend/src/components/PostCard.js +++ b/app/frontend/src/components/PostCard.js @@ -4,6 +4,7 @@ import EditPost from '../pages/ForumPage/EditPost' import { deletePost } from '../services/postService' import { useNavigate } from 'react-router-dom' import { useParams } from 'react-router-dom' +import DeleteIcon from '@mui/icons-material/Delete' const PostCard = ({ post, currentUser, onUpvote, onDownvote }) => { const isCurrentUserCreator = currentUser && post.creatorUser.username === currentUser.username ? true : false @@ -31,7 +32,7 @@ const PostCard = ({ post, currentUser, onUpvote, onDownvote }) => { className='btn btn-sm bg-neutral-200 border-none hover:bg-neutral-300' title='Delete Post' > - 🗑️ + )} diff --git a/app/frontend/src/components/navbar/Navbar.js b/app/frontend/src/components/navbar/Navbar.js index 3e6c2817..04148d4f 100644 --- a/app/frontend/src/components/navbar/Navbar.js +++ b/app/frontend/src/components/navbar/Navbar.js @@ -19,7 +19,6 @@ import { useState, useEffect } from 'react' import axios from 'axios' import { useNavigate } from 'react-router-dom' import logo from '../../gamelounge.png' -import { getAllSearch } from '../../services/searchService.js' import {getUserInfoBySessionId} from "../../services/userService"; const Navbarx = () => { const api_url = process.env.REACT_APP_API_URL @@ -98,31 +97,7 @@ const Navbarx = () => { if (isAdmin) { setIsAdmin(true) } - }, []) - const [searchResults, setSearchResults] = useState([]) - const [searchQuery, setSearchQuery] = useState('') - const navigateToSearch = (result) => { - // Use the 'navigate' function from 'react-router-dom' to navigate to the Search component - navigate('/search', { state: { searchData: result } }) - } - const handleSearch = async () => { - try { - const response = await getAllSearch(searchQuery) - - if (response.status === 200) { - setSearchResults(response.data) - console.log(searchResults) - navigateToSearch(response.data) - } - } catch (error) { - console.error(error) - } - } - - const handleInputChange = (e) => { - setSearchQuery(e.target.value) - // Trigger search when the user stops typing for 300 milliseconds - } + }, []) useEffect(() => { const fetchUserInfo = async () => { @@ -186,12 +161,6 @@ const Navbarx = () => { size='sm' startContent={} type='search' - onChange={handleInputChange} - onKeyDown={(e) => { - if (e.key === 'Enter') { - handleSearch() - } - }} /> {isLoggedIn ? ( @@ -225,11 +194,6 @@ const Navbarx = () => { size='sm' startContent={} type='search' - onKeyDown={(e) => { - if (e.key === 'Enter') { - handleSearch() - } - }} /> ) : null} diff --git a/app/frontend/src/pages/ForumPage/SelectTags.js b/app/frontend/src/pages/ForumPage/SelectTags.js index 3a53321f..dcb666a7 100644 --- a/app/frontend/src/pages/ForumPage/SelectTags.js +++ b/app/frontend/src/pages/ForumPage/SelectTags.js @@ -1,4 +1,4 @@ -import * as React from 'react'; +import React, { useState } from 'react'; import Box from '@mui/material/Box'; import FormLabel from '@mui/material/FormLabel'; import FormControl from '@mui/material/FormControl'; @@ -8,6 +8,9 @@ import Checkbox from '@mui/material/Checkbox'; import { grey } from '@mui/material/colors'; const TagSelection = ({ tags, selectedTags, handleTagChange }) => { + const [showMore, setShowMore] = useState(false); + const maxTagsToShow = 5; + const handleCheckboxChange = (event, tag) => { const updatedTags = event.target.checked ? [...selectedTags, tag] @@ -16,7 +19,9 @@ const TagSelection = ({ tags, selectedTags, handleTagChange }) => { handleTagChange(updatedTags); }; - const tagCheckboxes = tags.map((tag) => ( + const visibleTags = showMore ? tags : tags.slice(0, maxTagsToShow); + + const tagCheckboxes = visibleTags.map((tag) => ( { /> )); + const showMoreButton = tags.length > maxTagsToShow && ( + + ); + return ( @@ -39,6 +50,7 @@ const TagSelection = ({ tags, selectedTags, handleTagChange }) => { {tagCheckboxes} + {showMoreButton} ); diff --git a/app/frontend/src/pages/HomePage/Group.js b/app/frontend/src/pages/HomePage/Group.js index f2d27b52..7a10f3c0 100644 --- a/app/frontend/src/pages/HomePage/Group.js +++ b/app/frontend/src/pages/HomePage/Group.js @@ -1,28 +1,30 @@ -import React from 'react' -import {Link} from "react-router-dom"; +import React from 'react'; +import { Link } from 'react-router-dom'; +import profileIcon from "./profile.jpg"; -const Group = ({ item }) => { - return ( -
-
- Group -
-
-

{item.title}

-

{item.text}

-
- - Players: {item.totalMembers}/{item.memberCapacity} - - -
-
-
- ) -} +const Group = ({ group }) => { + return ( +
+
+ Post { + e.target.src = profileIcon; + }}/> +
+
+

+ + {group.title} + +

+

Game: {group.relatedGame}

+

Language: {group.requiredLanguage}

+

Platform: {group.requiredPlatform}

+
+ +
+
+
+ ); + } -export default Group + export default Group; diff --git a/app/frontend/src/pages/HomePage/HomePage.js b/app/frontend/src/pages/HomePage/HomePage.js index 7fe8e8d5..2fb58d2c 100644 --- a/app/frontend/src/pages/HomePage/HomePage.js +++ b/app/frontend/src/pages/HomePage/HomePage.js @@ -14,9 +14,10 @@ import alikasap from './alikasap.jpg' import { getRecommendedGroups, getAllGroups } from '../../services/lfgService' export default function HomePage() { - const [gamesData, setGamesData] = useState([]) - const [postData, setPostData] = useState([]) - const [groupData, setGroupData] = useState([]) + const [gamesData, setGamesData] = useState([]); + const [postData, setPostData] = useState([]); + const [groupData, setGroupData] = useState([]); + useEffect(() => { const fetchGames = async () => { try { @@ -85,30 +86,6 @@ export default function HomePage() { } ] - // const postData = [ - // { - // image: `https://primefaces.org/cdn/primereact/images/product/game-controller.jpg}`, - // header: 'Resident Evil 4 Remake', - // content: - // "Looking for someone to join me in my Resident Evil 4 adventure! Let's team up and face the horrors together.️ #ResidentEvil4 #GamingBuddyWanted", - // date: '29.10.2023 00.00' - // }, - // { - // image: 'https://primefaces.org/cdn/primereact/images/product/game-controller.jpg', - // header: 'Fifa', - // content: - // 'FIFA is one of the most popular football simulation games developed by EA Sports. It offers an immersive gaming experience with realistic graphics, player mechanics, and stadiums.', - // date: '29.10.2023 00.00' - // }, - // { - // image: `https://primefaces.org/cdn/primereact/images/product/game-controller.jpg}`, - // header: 'The Witcher 3: Wild Hunt', - // content: - // "The Witcher 3 is an unforgettable gaming experience. Its open world, rich storytelling, and captivating characters make it a must-play RPG. If you love epic adventures, this one's a masterpiece.", - // date: '29.10.2023 00.00' - // } - // ] - console.log(postData) return ( diff --git a/app/frontend/src/pages/HomePage/Post.js b/app/frontend/src/pages/HomePage/Post.js index 14122bc0..f0b017be 100644 --- a/app/frontend/src/pages/HomePage/Post.js +++ b/app/frontend/src/pages/HomePage/Post.js @@ -1,11 +1,14 @@ import React from 'react'; import { Link } from 'react-router-dom'; +import profileIcon from "./profile.jpg"; const Post = ({ post }) => { return (
- Post + Post { + e.target.src = profileIcon; + }}/>

diff --git a/app/frontend/src/pages/HomePage/profile.jpg b/app/frontend/src/pages/HomePage/profile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..245d9bfebc62e9221fe08816ffc9fe765464140b GIT binary patch literal 13229 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 UK8^Za+W${-h5twT!pZOc2X}5$RR910 literal 0 HcmV?d00001 diff --git a/app/frontend/src/pages/LfgPage/EditLfg.js b/app/frontend/src/pages/LfgPage/EditLfg.js index 8432da7b..2ba8692b 100644 --- a/app/frontend/src/pages/LfgPage/EditLfg.js +++ b/app/frontend/src/pages/LfgPage/EditLfg.js @@ -130,7 +130,7 @@ export default function EditLfg(props) { - Edit Lfg + Create Lfg diff --git a/app/frontend/src/pages/LfgPage/Lfg.js b/app/frontend/src/pages/LfgPage/Lfg.js index 7009c044..9ee4af8f 100644 --- a/app/frontend/src/pages/LfgPage/Lfg.js +++ b/app/frontend/src/pages/LfgPage/Lfg.js @@ -80,33 +80,6 @@ const Lfg = () => { } }; - const [isMember, setIsMember] = React.useState(true); - - const isUserGroupMember = async (user, group) => { - try { - const userId = user?.userId; - const members = group?.members; - - if (!userId || !members) { - return false; - } - - const isMember = members.some(member => member.userId === userId); - return isMember; - } catch (error) { - return false; - } - }; - - useEffect(() => { - const fetchIsMember = async () => { - const result = await isUserGroupMember(currentUser, lfg); - setIsMember(result); - }; - - fetchIsMember(); - }, [currentUser, lfg]); - return ( <> @@ -126,21 +99,18 @@ const Lfg = () => { /> ))}

- {isMember && } - {isMember && + >
- }
diff --git a/app/frontend/src/pages/LfgPage/LfgCard.js b/app/frontend/src/pages/LfgPage/LfgCard.js index e96dd823..3495aec6 100644 --- a/app/frontend/src/pages/LfgPage/LfgCard.js +++ b/app/frontend/src/pages/LfgPage/LfgCard.js @@ -150,16 +150,14 @@ const LfgCard = ({ group, currentUser }) => {

{group.description}

-
-
-

Platform: {group.requiredPlatform}

-
+
+

Game: {group.relatedGame}

Language: {group.requiredLanguage}

+

Platform: {group.requiredPlatform}

Mic/Cam: {group.micCamRequirement ? "yes" : "no"}

- {false &&

Game: {group.relatedGame}

}
diff --git a/app/frontend/src/pages/LfgPage/LfgPage.js b/app/frontend/src/pages/LfgPage/LfgPage.js index 4cecaf91..7d6cb365 100644 --- a/app/frontend/src/pages/LfgPage/LfgPage.js +++ b/app/frontend/src/pages/LfgPage/LfgPage.js @@ -1,5 +1,6 @@ import React, { useState, useEffect } from 'react'; import Navbarx from '../../components/navbar/Navbar'; +// import { getAllPosts } from '../../services/postService'; import LfgCard from "./LfgCard"; import {getUserInfoBySessionId} from "../../services/userService"; import {getAllGroups} from "../../services/lfgService"; @@ -9,6 +10,7 @@ export default function LfgPage() { const [groups, setGroups] = useState([]); const [isLoading, setIsLoading] = useState(true); +// const [filteredPosts, setFilteredPosts] = useState([]); const [currentUser, setCurrentUser] = useState(null); diff --git a/app/frontend/src/pages/PostPage/PostPage.js b/app/frontend/src/pages/PostPage/PostPage.js index cbafa544..f4230cad 100644 --- a/app/frontend/src/pages/PostPage/PostPage.js +++ b/app/frontend/src/pages/PostPage/PostPage.js @@ -118,8 +118,9 @@ const PostPage = () => { /> ))}
-