From 9a2524fd2a6b30b1bfc904cabedc454f6a55785d Mon Sep 17 00:00:00 2001
From: Philipp Gritsch <philipp.gritsch@uibk.ac.at>
Date: Thu, 25 Jan 2024 10:53:41 +0100
Subject: [PATCH] closes #469

introduce check to only make button clickable if user has access to git repository
---
 .../uibk/gitsearch/service/GitlabService.java | 21 +++++++++++++++---
 .../gitsearch/web/rest/ExerciseResource.java  | 19 ++++++----------
 .../exercise-details.component.ts             | 10 +++++----
 .../exercise-body.component.html              |  2 +-
 .../app/exercise/service/exercise.service.ts  | 22 ++-----------------
 5 files changed, 34 insertions(+), 40 deletions(-)

diff --git a/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java b/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java
index 8b2d5f048..4d3576ff7 100644
--- a/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java
+++ b/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java
@@ -32,7 +32,6 @@ import org.gitlab4j.api.GroupApi;
 import org.gitlab4j.api.ProjectApi;
 import org.gitlab4j.api.UserApi;
 import org.gitlab4j.api.models.Group;
-import org.gitlab4j.api.models.Member;
 import org.gitlab4j.api.models.Project;
 import org.gitlab4j.api.models.RepositoryFile;
 import org.gitlab4j.api.models.Visibility;
@@ -377,8 +376,24 @@ public class GitlabService {
         return groupApi.getSubGroups(groupId);
     }
 
-    public List<Member> getMembers(long gitProjectId) throws GitLabApiException {
-        return gitLabRepository.getAdminGitLabApi().getProjectApi().getAllMembers(gitProjectId);
+    public boolean isMember(long gitProjectId, at.ac.uibk.gitsearch.domain.User user) throws GitLabApiException {
+        try {
+            org.gitlab4j.api.models.User gitUser = this.gitLabRepository.getAdminGitLabApi().getUserApi().getUserByEmail(user.getEmail());
+
+            if (gitUser == null) {
+                return false;
+            }
+
+            return gitLabRepository.getAdminGitLabApi().getProjectApi().getMember(gitProjectId, gitUser.getId(), true) != null;
+        } catch (final GitLabApiException e) {
+            if (e.getHttpStatus() == 404) {
+                return false;
+            }
+            throw e;
+        } catch (IllegalArgumentException e) {
+            // email of user invalid
+            return false;
+        }
     }
 
     /**
diff --git a/src/main/java/at/ac/uibk/gitsearch/web/rest/ExerciseResource.java b/src/main/java/at/ac/uibk/gitsearch/web/rest/ExerciseResource.java
index 5ea47db68..90535e691 100644
--- a/src/main/java/at/ac/uibk/gitsearch/web/rest/ExerciseResource.java
+++ b/src/main/java/at/ac/uibk/gitsearch/web/rest/ExerciseResource.java
@@ -32,7 +32,6 @@ import org.codeability.sharing.plugins.api.search.SearchResultDTO;
 import org.codeability.sharing.plugins.api.search.util.ExerciseId;
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.gitlab4j.api.GitLabApiException;
-import org.gitlab4j.api.models.Member;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -367,11 +366,11 @@ public class ExerciseResource {
 
     @GetMapping("/exercises/{id}/source-authorization")
     public ResponseEntity<?> getMembers(@PathVariable("id") String exerciseId) {
-        System.out.println("hi");
         try {
             if (SecurityUtils.getCurrentUserLogin().isEmpty()) {
-                ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+                ResponseEntity.status(HttpStatus.FORBIDDEN).build();
             }
+
             final Optional<SearchResultDTO> result = searchService.findExerciseById(ExerciseId.fromString(exerciseId));
             if (result.isEmpty()) {
                 return ResponseEntity.notFound().build();
@@ -379,18 +378,14 @@ public class ExerciseResource {
 
             Optional<User> user = this.userService.getUserByLogin(SecurityUtils.getCurrentUserLogin().get());
             if (user.isEmpty()) {
-                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+                return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
             }
 
             int gitProjectId = result.get().getProject().getProject_id();
-            boolean isMember =
-                this.gitlabService.getMembers(gitProjectId)
-                    .stream()
-                    .map(Member::getEmail)
-                    .filter(StringUtils::isNotEmpty)
-                    .anyMatch(email -> email.equals(user.get().getEmail()));
-
-            return isMember ? ResponseEntity.ok().build() : ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+
+            return this.gitLabService.isMember(gitProjectId, user.get())
+                ? ResponseEntity.ok().build()
+                : ResponseEntity.status(HttpStatus.FORBIDDEN).build();
         } catch (final Exception e) {
             log.error("Error while getting /source-authorization for exercise {}", exerciseId, e);
             return ResponseEntity.internalServerError().build();
diff --git a/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts b/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts
index 083a23fdd..4738648a1 100644
--- a/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts
+++ b/src/main/webapp/app/exercise/exercise-details/exercise-details.component.ts
@@ -74,9 +74,6 @@ export class ExerciseHeaderComponent {
 })
 export class ExerciseBodyComponent implements OnInit, OnDestroy {
   @Output() exerciseChangedEvent = new EventEmitter<SearchResultDTO>();
-  @Input() get referencedExercise(): SearchResultDTO | undefined {
-    return this.exercise;
-  }
   gitlabIsAccessible = false;
   exercise: ExtendedSearchResultDTO | undefined;
 
@@ -90,10 +87,15 @@ export class ExerciseBodyComponent implements OnInit, OnDestroy {
   likeSubscription?: Subscription;
   authenticated = false;
 
+  @Input() get referencedExercise(): SearchResultDTO | undefined {
+    return this.exercise;
+  }
   set referencedExercise(exercise: SearchResultDTO | undefined) {
     this.gitlabIsAccessible = false;
-    this.updateGitIsAccessibleForUser();
     this.exercise = exercise as ExtendedSearchResultDTO;
+    if (exercise) {
+      this.updateGitIsAccessibleForUser();
+    }
   }
 
   treeIcon = faFolder;
diff --git a/src/main/webapp/app/exercise/exercise-details/exerciseComponents/exercise-body.component.html b/src/main/webapp/app/exercise/exercise-details/exerciseComponents/exercise-body.component.html
index 5aad1c53b..f1582e368 100644
--- a/src/main/webapp/app/exercise/exercise-details/exerciseComponents/exercise-body.component.html
+++ b/src/main/webapp/app/exercise/exercise-details/exerciseComponents/exercise-body.component.html
@@ -168,7 +168,7 @@
         jhiTranslate="exercise.details.allExercises"
       ></button>
       <button
-        [disabled]="gitlabIsAccessible"
+        [disabled]="!this.gitlabIsAccessible"
         type="button"
         class="btn btn-outline-secondary"
         style="display: block"
diff --git a/src/main/webapp/app/exercise/service/exercise.service.ts b/src/main/webapp/app/exercise/service/exercise.service.ts
index 740d0a0b6..2d4a0a634 100644
--- a/src/main/webapp/app/exercise/service/exercise.service.ts
+++ b/src/main/webapp/app/exercise/service/exercise.service.ts
@@ -38,29 +38,11 @@ export class ExerciseService {
     const endpoint: string = this.applicationConfigService.getEndpointFor(
       SERVER_API_URL + 'api/exercises/' + encodeURIforExerciseId(exerciseId) + '/source-authorization'
     );
-    this.http
-      .get<any>(SERVER_API_URL + 'api/exercises/hi')
-      .pipe(
-        map((response: HttpResponse<any>) => {
-          console.log('here inside');
-          console.log(response);
-          return response.status === 200;
-        }),
-        catchError((error: any) => {
-          console.log('amak');
-          console.log(error);
-          return of(false);
-        })
-      )
-      .subscribe((x: any) => console.log(x));
-
-    return this.http.get<any>(endpoint).pipe(
+    return this.http.get<any>(endpoint, { observe: 'response' }).pipe(
       map((response: HttpResponse<any>) => {
-        console.log(response);
         return response.status === 200;
       }),
-      catchError((error: any) => {
-        console.log(error);
+      catchError(() => {
         return of(false);
       })
     );
-- 
GitLab