From 2c6a1b1ed1d7cc09c073d3b5dc5f9fe163539761 Mon Sep 17 00:00:00 2001
From: Eduard Frankford <e.frankford@student.uibk.ac.at>
Date: Thu, 13 May 2021 14:44:07 +0200
Subject: [PATCH] achievements now working with first and lastname

---
 .../repository/search/MetaDataRepository.java | 24 +++++
 .../search/SearchRepositoryConstants.java     |  1 +
 .../uibk/gitsearch/service/GitlabService.java | 20 ++++
 .../uibk/gitsearch/service/SearchService.java | 17 ++++
 .../gitsearch/service/dto/SearchInputDTO.java |  4 +
 .../gitsearch/web/rest/SearchResource.java    | 95 +++++++++++++------
 .../web/rest/StatisticsResource.java          |  2 +
 .../app/account/achievements.component.html   | 20 ++--
 .../app/account/achievements.component.ts     | 19 +++-
 .../app/core/icons/font-awesome-icons.ts      |  4 +
 .../app/search/service/search-service.ts      |  4 +
 11 files changed, 169 insertions(+), 41 deletions(-)

diff --git a/src/main/java/at/ac/uibk/gitsearch/repository/search/MetaDataRepository.java b/src/main/java/at/ac/uibk/gitsearch/repository/search/MetaDataRepository.java
index 7f9345afd..3fdd4502a 100644
--- a/src/main/java/at/ac/uibk/gitsearch/repository/search/MetaDataRepository.java
+++ b/src/main/java/at/ac/uibk/gitsearch/repository/search/MetaDataRepository.java
@@ -292,6 +292,30 @@ public class MetaDataRepository {
 		return result;
 	}
 
+
+	public SearchResultsDTO searchByEmail(String email, int pageSize, Optional<User> user) throws IOException {
+		
+		SearchRequest searchRequest = new SearchRequest(SearchRepositoryConstants.INDEX_METADATA);
+
+		BoolQueryBuilder emailQuery = QueryBuilders.boolQuery();
+		
+		emailQuery
+		.must(QueryBuilders.prefixQuery(SearchRepositoryConstants.METADATA_CREATOR_EMAIL, email));
+
+		//addAuthorizationQuery(user, emailQuery);
+
+
+		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
+		sourceBuilder.query(emailQuery).size(pageSize)
+				.from(0);
+
+		searchRequest.source(sourceBuilder);
+
+		SearchResponse searchResponse = elasticsearchClient.search(searchRequest, RequestOptions.DEFAULT);
+
+		return parseSearchResponse(searchResponse);
+	}
+
 	/**
 	 * returns the hits from the meta data search index for the input query parameters.
 	 * @param searchInputDTO the query parameters.
diff --git a/src/main/java/at/ac/uibk/gitsearch/repository/search/SearchRepositoryConstants.java b/src/main/java/at/ac/uibk/gitsearch/repository/search/SearchRepositoryConstants.java
index e06ff8e90..d2cee8b3a 100644
--- a/src/main/java/at/ac/uibk/gitsearch/repository/search/SearchRepositoryConstants.java
+++ b/src/main/java/at/ac/uibk/gitsearch/repository/search/SearchRepositoryConstants.java
@@ -22,6 +22,7 @@ public final class SearchRepositoryConstants {
     public static final String METADATA_PROGRAMMING_LANGUAGES = "metadata.programmingLanguage";
     public static final String METADATA_PROJECT_ID = "project.project_id";
     public static final String METADATA_CREATOR = "metadata.creator.name";
+    public static final String METADATA_CREATOR_EMAIL = "metadata.creator.email";
     public static final String METADATA_CONTRIBUTOR = "metadata.contributor.name";
     public static final String METADATA_PUBLISHER = "metadata.publisher.name";
     public static final String METADATA_LICENSE = "metadata.license";
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 7833a917b..451f0a5a9 100644
--- a/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java
+++ b/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java
@@ -6,6 +6,8 @@ import java.io.InputStream;
 import java.io.PipedInputStream;
 import java.io.PipedOutputStream;
 import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
@@ -13,7 +15,12 @@ import java.util.zip.ZipOutputStream;
 import org.gitlab4j.api.GitLabApi;
 import org.gitlab4j.api.GitLabApiException;
 import org.gitlab4j.api.ProjectApi;
+import org.gitlab4j.api.Constants.ProjectOrderBy;
+import org.gitlab4j.api.Constants.SortOrder;
+import org.gitlab4j.api.models.Project;
 import org.gitlab4j.api.models.RepositoryFile;
+import org.gitlab4j.api.models.Visibility;
+import org.gitlab4j.api.models.Note.OrderBy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -53,6 +60,19 @@ public class GitlabService {
 			return false;
 		}
     }
+
+	public void getAllProjectIdsForUser() {
+		try{
+			final GitLabApi gitLabApi = gitLabRepository.getGitLabApi(tokenProvider.getGitLabAccessInfo());
+			final ProjectApi gitLabProjectApi = gitLabApi.getProjectApi();
+			final List<Project> projects =  gitLabProjectApi.getProjects(false, null, ProjectOrderBy.UPDATED_AT, SortOrder.ASC, "", true, true, true, false, true);
+
+			log.info("Got all projects {}" , projects.size());}
+		catch(GitLabApiException e){
+			log.error("Failed to load projects\n" + e.getMessage(), e);
+		}
+	}
+    
     
 	
 	public InputStream getRepositoryZip(String exerciseID) throws GitLabApiException, IOException {
diff --git a/src/main/java/at/ac/uibk/gitsearch/service/SearchService.java b/src/main/java/at/ac/uibk/gitsearch/service/SearchService.java
index d2969c64e..63d19d3f5 100644
--- a/src/main/java/at/ac/uibk/gitsearch/service/SearchService.java
+++ b/src/main/java/at/ac/uibk/gitsearch/service/SearchService.java
@@ -133,6 +133,23 @@ public class SearchService {
 		// return readTestResults(searchInput.getFulltextQuery(), first, length);
 	}
 
+	public SearchResultsDTO searchResultForAuthorEmail(String searchInput, int length) throws IOException {
+		log.debug("Searchrequest for {} ", searchInput);
+
+		final SearchResultsDTO pageDetails = metaDataRepository.searchByEmail(searchInput, length,
+				tokenProvider.getCurrentPrincipal());
+
+		pageDetails.getSearchResult().stream()
+				.forEach(hit -> pluginManagementService.getRegisteredPluginConfigs().stream()
+						.forEach(config -> config.getActions().values().stream()
+								.filter(action -> action.isApplicable(hit))
+								.forEach(action -> hit.getSupportedActions().add(action.getPluginActionInfo()))));
+		pageDetails.getSearchResult().stream().forEach(this::fixImageURL);
+
+		return pageDetails;
+		// return readTestResults(searchInput.getFulltextQuery(), first, length);
+	}
+
 	private void fixImageURL(SearchResultDTO metaData) {
 
 		String image = metaData.getMetadata().getImage();
diff --git a/src/main/java/at/ac/uibk/gitsearch/service/dto/SearchInputDTO.java b/src/main/java/at/ac/uibk/gitsearch/service/dto/SearchInputDTO.java
index 86d4ff266..dec65c4f7 100644
--- a/src/main/java/at/ac/uibk/gitsearch/service/dto/SearchInputDTO.java
+++ b/src/main/java/at/ac/uibk/gitsearch/service/dto/SearchInputDTO.java
@@ -38,6 +38,10 @@ public class SearchInputDTO {
         return metadata;
     }
 
+    public void setMetadata(SearchInputMetadataDTO metadata){
+        this.metadata = metadata;
+    }
+
     public List<String> getSelectedRepository() {
         return selectedRepository;
     }
diff --git a/src/main/java/at/ac/uibk/gitsearch/web/rest/SearchResource.java b/src/main/java/at/ac/uibk/gitsearch/web/rest/SearchResource.java
index a7870da4f..ae57e2c0e 100644
--- a/src/main/java/at/ac/uibk/gitsearch/web/rest/SearchResource.java
+++ b/src/main/java/at/ac/uibk/gitsearch/web/rest/SearchResource.java
@@ -14,6 +14,7 @@ import org.springframework.core.io.InputStreamResource;
 import org.springframework.core.io.Resource;
 import org.springframework.http.MediaType;
 import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -28,10 +29,14 @@ import at.ac.uibk.gitsearch.service.SearchService;
 import at.ac.uibk.gitsearch.service.StatisticsService;
 import at.ac.uibk.gitsearch.service.dto.AutoCompleteEntry;
 import at.ac.uibk.gitsearch.service.dto.SearchInputDTO;
+import at.ac.uibk.gitsearch.service.dto.SearchInputMetadataDTO;
+import at.ac.uibk.gitsearch.service.dto.SearchResultDTO;
 import at.ac.uibk.gitsearch.service.dto.SearchResultsDTO;
 import at.ac.uibk.gitsearch.service.dto.StatisticsDTO;
 import at.ac.uibk.gitsearch.web.util.HeaderUtil;
 
+import org.springframework.http.HttpStatus;
+
 /**
  * REST controller for managing {@link DocumentInfo}.
  */
@@ -45,7 +50,6 @@ public class SearchResource {
 
     private static final String ENTITY_NAME = "SearchResource";
 
-
     private final Logger log = LoggerFactory.getLogger(SearchResource.class);
 
     private final SearchService searchService;
@@ -58,17 +62,42 @@ public class SearchResource {
     }
 
     /**
-     * {@code SEARCH  /search/page-details} : search for the searchResults corresponding
-     * to the query.
+     * {@code SEARCH  /search/page-details} : search for the searchResults
+     * corresponding to the query.
      *
      * @param query the query of the searchResult search.
      * @return the result of the search.
      */
     @PostMapping("/search/page-details")
-    public SearchResultsDTO
-    searchPageDetails(@RequestBody SearchInputDTO query) throws IOException {
+    public SearchResultsDTO searchPageDetails(@RequestBody SearchInputDTO query) throws IOException {
         log.debug("REST request to search  {}", query);
-        return searchService.searchResultPage(query, (long) SearchInputDTO.PAGE_SIZE * (long) query.getPage(), SearchInputDTO.PAGE_SIZE);
+        return searchService.searchResultPage(query, (long) SearchInputDTO.PAGE_SIZE * (long) query.getPage(),
+                SearchInputDTO.PAGE_SIZE);
+    }
+
+    @GetMapping("/user/{login}/statistics/views")
+    @PreAuthorize("hasAnyRole('USER')")
+    public ResponseEntity<StatisticsDTO> searchUserStatistics(@PathVariable String login) throws IOException {
+        log.debug("REST request to search statistics for user {}", login);
+        SearchInputDTO search = new SearchInputDTO();
+        SearchInputMetadataDTO metadata = new SearchInputMetadataDTO();
+        metadata.setAuthor(login);
+        search.setMetadata(metadata);
+        SearchResultsDTO results = searchService.searchResultForAuthorEmail("Michael.Breu@uibk.ac.at", 1000);
+        int totalAmountOfViews = 0;
+        int totalAmountOfDownloads = 0;
+        for (SearchResultDTO result : results.getSearchResult()) {
+            Optional<StatisticsDTO> statisticsDTO = statisticsService.findOneByExerciseID((Long.parseLong(result.getExerciseId())));
+            if (statisticsDTO.isPresent()) {
+                StatisticsDTO newStats = statisticsDTO.get();
+                totalAmountOfViews += newStats.getViews();
+                totalAmountOfDownloads += newStats.getDownloads();
+            }
+        }
+        StatisticsDTO toReturn = new StatisticsDTO();
+        toReturn.setViews(totalAmountOfViews);
+        toReturn.setDownloads(totalAmountOfDownloads);
+        return new ResponseEntity<StatisticsDTO>(toReturn, HttpStatus.OK);
     }
 
     /**
@@ -103,21 +132,22 @@ public class SearchResource {
      * @throws IOException
      */
     @GetMapping("/search/contributorAutoComplete")
-    public List<AutoCompleteEntry> getContributorAutoComplete(@RequestParam String contributorPrefix) throws IOException {
+    public List<AutoCompleteEntry> getContributorAutoComplete(@RequestParam String contributorPrefix)
+            throws IOException {
         return searchService.getContributorAutoComplete(contributorPrefix);
     }
 
-	/**
-	 * returns all contributor and author autocompletes
-	 *
-	 * @param contributorPrefix
-	 * @return
-	 * @throws IOException
-	 */
+    /**
+     * returns all contributor and author autocompletes
+     *
+     * @param contributorPrefix
+     * @return
+     * @throws IOException
+     */
     @GetMapping("/search/contributorCreatorAutoComplete")
-	public List<AutoCompleteEntry> getContributorCreatorAutoComplete(String contributorPrefix) throws IOException {
-		return searchService.getContributorCreatorAutoComplete(contributorPrefix);
-	}
+    public List<AutoCompleteEntry> getContributorCreatorAutoComplete(String contributorPrefix) throws IOException {
+        return searchService.getContributorCreatorAutoComplete(contributorPrefix);
+    }
 
     /**
      * returns all programmingLanguage autocompletes for keyWord
@@ -127,31 +157,34 @@ public class SearchResource {
      * @throws IOException
      */
     @GetMapping("/search/programmingLanguageAutoComplete")
-    public List<AutoCompleteEntry> getProgrammingLanguageAutoComplete(@RequestParam String programmingLanguagePrefix) throws IOException {
+    public List<AutoCompleteEntry> getProgrammingLanguageAutoComplete(@RequestParam String programmingLanguagePrefix)
+            throws IOException {
         return searchService.getProgrammingLanguageAutoComplete(programmingLanguagePrefix);
     }
 
-
     /**
-     * POST /programming-exercises/:exerciseId/export-programmingExercise : sends all repositories and details of the programming exercise as zip
-     * TODO projectId and ExerciseId are mixed up here. Please clarify!
+     * POST /programming-exercises/:exerciseId/export-programmingExercise : sends
+     * all repositories and details of the programming exercise as zip TODO
+     * projectId and ExerciseId are mixed up here. Please clarify!
      * 
-     * @param projectId the id of the exercise to get the repos from
-     * ResponseEntity with status
+     * @param projectId the id of the exercise to get the repos from ResponseEntity
+     *                  with status
      * @throws IOException if something during the zip process went wrong
      */
     @PostMapping("/programming-exercises/{projectId}/export-programming-exercise")
     public ResponseEntity<Resource> exportProgrammingExercise(@PathVariable long projectId) throws IOException {
 
         File zipFile = searchService.exportExercise(projectId);
-        
+
         if (zipFile == null) {
-            return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, ENTITY_NAME, "internalServerError",
-                    "There was an error on the server and the zip file could not be created.")).body(null);
+            return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(applicationName, true, ENTITY_NAME,
+                    "internalServerError", "There was an error on the server and the zip file could not be created."))
+                    .body(null);
         }
 
         /*
-         * Customized FileInputStream to delete and therefore clean up the returned files
+         * Customized FileInputStream to delete and therefore clean up the returned
+         * files
          */
         class NewFileInputStream extends FileInputStream {
 
@@ -172,13 +205,13 @@ public class SearchResource {
 
         log.debug("REST request to get Statistics for ExerciseID : {}", projectId);
         Optional<StatisticsDTO> statisticsDTO = statisticsService.findOneByExerciseID(projectId);
-        if(statisticsDTO.isPresent()){
+        if (statisticsDTO.isPresent()) {
             StatisticsDTO newStats = statisticsDTO.get();
             newStats.setDownloads(newStats.getDownloads() + 1);
             statisticsService.save(newStats);
             log.debug("REST increased number of downloads for ExerciseID : {}", projectId);
         }
-        if(!statisticsDTO.isPresent()){
+        if (!statisticsDTO.isPresent()) {
             StatisticsDTO newStats = new StatisticsDTO();
             newStats.setDownloads(1);
             newStats.setViews(1);
@@ -187,8 +220,8 @@ public class SearchResource {
             log.debug("Created new statistics entry for exerciseID: {}", projectId);
         }
 
-        return ResponseEntity.ok().contentLength(zipFile.length()).contentType(MediaType.APPLICATION_OCTET_STREAM).header("filename", zipFile.getName()).body(resource);
+        return ResponseEntity.ok().contentLength(zipFile.length()).contentType(MediaType.APPLICATION_OCTET_STREAM)
+                .header("filename", zipFile.getName()).body(resource);
     }
 
-
 }
diff --git a/src/main/java/at/ac/uibk/gitsearch/web/rest/StatisticsResource.java b/src/main/java/at/ac/uibk/gitsearch/web/rest/StatisticsResource.java
index c1013a9f4..a6f3dbf65 100644
--- a/src/main/java/at/ac/uibk/gitsearch/web/rest/StatisticsResource.java
+++ b/src/main/java/at/ac/uibk/gitsearch/web/rest/StatisticsResource.java
@@ -27,7 +27,9 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import javax.validation.Valid;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.stream.StreamSupport;
 
diff --git a/src/main/webapp/app/account/achievements.component.html b/src/main/webapp/app/account/achievements.component.html
index 952248d98..eda41b4d7 100644
--- a/src/main/webapp/app/account/achievements.component.html
+++ b/src/main/webapp/app/account/achievements.component.html
@@ -4,29 +4,35 @@
     <ul class="list-group">
         <li class="list-group-item d-flex justify-content-between align-items-center">
             More than 500 views
-            <span class="badge badge-primary badge-pill">14</span>
+            <span *ngIf="statistics.views <= 500" class="badge badge-primary badge-pill">{{statistics.views}}</span>
+            <fa-icon icon="check" *ngIf="statistics.views > 500" class="greeniconcolor"></fa-icon>
         </li>
         <li class="list-group-item d-flex justify-content-between align-items-center">
             More than 100 views
-            <span class="badge badge-primary badge-pill">2</span>
+            <span *ngIf="statistics.views <= 100" class="badge badge-primary badge-pill">{{statistics.views}}</span>
+            <fa-icon icon="check" *ngIf="statistics.views > 100" class="greeniconcolor"></fa-icon>
         </li>
         <li class="list-group-item d-flex justify-content-between align-items-center">
             More than 10 views
-            <span class="badge badge-primary badge-pill">1</span>
+            <span *ngIf="statistics.views <= 10" class="badge badge-primary badge-pill">{{statistics.views}}</span>
+            <fa-icon icon="check" *ngIf="statistics.views > 10" class="greeniconcolor"></fa-icon>
         </li>
         <li class="list-group-item d-flex justify-content-between align-items-center">
             More than 500 downloads
-            <span class="badge badge-primary badge-pill">14</span>
+            <span *ngIf="statistics.downloads <= 500" class="badge badge-primary badge-pill">{{statistics.downloads}}</span>
+            <fa-icon icon="check" *ngIf="statistics.downloads > 500" class="greeniconcolor"></fa-icon>
         </li>
         <li class="list-group-item d-flex justify-content-between align-items-center">
             More than 100 downloads
-            <fa-icon icon="check" class="greeniconcolor"></fa-icon>
+            <span *ngIf="statistics.downloads <= 100" class="badge badge-primary badge-pill">{{statistics.downloads}}</span>
+            <fa-icon icon="check" *ngIf="statistics.downloads > 100" class="greeniconcolor"></fa-icon>
         </li>
         <li class="list-group-item d-flex justify-content-between align-items-center">
             More than 10 downloads
-            <fa-icon icon="times-circle" class="rediconcolor"></fa-icon>
+            <span *ngIf="statistics.downloads <= 10" class="badge badge-primary badge-pill">{{statistics.downloads}}</span>
+            <fa-icon icon="check" *ngIf="statistics.downloads > 10" class="greeniconcolor"></fa-icon>
         </li>
     </ul>
 
-    <button (click) = "getTotalNumberOfViews()" class="btn btn-primary"> Get number of views </button>
+    <!-- <button (click) = "getTotalNumberOfViews()" class="btn btn-primary"> Get number of views </button> -->
 
diff --git a/src/main/webapp/app/account/achievements.component.ts b/src/main/webapp/app/account/achievements.component.ts
index 6a4f9e568..8996dad85 100644
--- a/src/main/webapp/app/account/achievements.component.ts
+++ b/src/main/webapp/app/account/achievements.component.ts
@@ -4,6 +4,7 @@ import { SearchService } from 'app/search/service/search-service';
 
 import { AccountService } from 'app/core/auth/account.service';
 import { Account } from 'app/core/user/account.model';
+import { Statistics } from 'app/shared/model/statistics.model';
 
 @Component({
   selector: 'jhi-achievements',
@@ -13,16 +14,27 @@ import { Account } from 'app/core/user/account.model';
 @Injectable({ providedIn: 'root' })
 export class AchievementsComponent implements OnInit {
   account!: Account;
+  statistics!: Statistics;
 
   constructor(private accountService: AccountService, protected searchService: SearchService) {}
 
   public getTotalNumberOfViews(): void {
     // eslint-disable-next-line no-console
     console.log('I have been called');
-    this.searchService.getStatisticsForUser(this.account.login).subscribe(
-      (data: number) => {
+    this.searchService.getStatisticsForUser(this.account.firstName + ' ' + this.account.lastName).subscribe(
+      (data: Statistics) => {
+        this.statistics = data;
         // eslint-disable-next-line no-console
-        console.log('Data: ' + data + ' for account ' + this.account.login);
+        console.log(
+          'Data: Number of Downloads: ' +
+            data.downloads +
+            ' Number of views: ' +
+            data.views +
+            ' for account ' +
+            this.account.firstName +
+            ' ' +
+            this.account.lastName
+        );
       },
       () => alert('Could not load statistics for User')
     );
@@ -34,5 +46,6 @@ export class AchievementsComponent implements OnInit {
         this.account = account;
       }
     });
+    this.getTotalNumberOfViews();
   }
 }
diff --git a/src/main/webapp/app/core/icons/font-awesome-icons.ts b/src/main/webapp/app/core/icons/font-awesome-icons.ts
index 46617c114..f8b7c0afd 100644
--- a/src/main/webapp/app/core/icons/font-awesome-icons.ts
+++ b/src/main/webapp/app/core/icons/font-awesome-icons.ts
@@ -35,6 +35,8 @@ import {
   faHome,
   faLanguage,
   faDownload,
+  faCheck,
+  faTimesCircle,
   // jhipster-needle-add-icon-import
 } from '@fortawesome/free-solid-svg-icons';
 
@@ -76,5 +78,7 @@ export const fontAwesomeIcons = [
   faLanguage,
   faBook,
   faDownload,
+  faCheck,
+  faTimesCircle,
   // jhipster-needle-add-icon-import
 ];
diff --git a/src/main/webapp/app/search/service/search-service.ts b/src/main/webapp/app/search/service/search-service.ts
index 094c73a48..6579bd09a 100644
--- a/src/main/webapp/app/search/service/search-service.ts
+++ b/src/main/webapp/app/search/service/search-service.ts
@@ -28,6 +28,10 @@ export class SearchService {
     return this.http.get<Statistics>(this.resourceSearchUrlStatisticsForExercise + exerciseID);
   }
 
+  getStatisticsForUser(login: string): Observable<Statistics> {
+    return this.http.get<Statistics>('api/user/' + login + '/statistics/views');
+  }
+
   /**
    * Used to export an exercise as a compressed zip file
    * The file will contain all the three repositories as well as the exercise text and further metadata
-- 
GitLab