diff --git a/.classpath b/.classpath
index 1badeb561c4cbb328db13cd6bc617b79b310386a..6e0021feb305ffa1cda191a1eb3c4d28089b9cf0 100644
--- a/.classpath
+++ b/.classpath
@@ -6,12 +6,6 @@
 			<attribute name="maven.pomderived" value="true"/>
 		</attributes>
 	</classpathentry>
-	<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
-		<attributes>
-			<attribute name="test" value="true"/>
-		</attributes>
-	</classpathentry>
-	<classpathentry kind="src" path="target/generated-sources/annotations"/>
 	<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
 		<attributes>
 			<attribute name="maven.pomderived" value="true"/>
@@ -19,20 +13,19 @@
 	</classpathentry>
 	<classpathentry kind="src" output="target/test-classes" path="src/test/java">
 		<attributes>
-			<attribute name="test" value="true"/>
 			<attribute name="optional" value="true"/>
 			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="test" value="true"/>
 		</attributes>
 	</classpathentry>
 	<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
 		<attributes>
-			<attribute name="test" value="true"/>
 			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="test" value="true"/>
 		</attributes>
 	</classpathentry>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
 		<attributes>
-			<attribute name="module" value="true"/>
 			<attribute name="maven.pomderived" value="true"/>
 		</attributes>
 	</classpathentry>
@@ -41,5 +34,22 @@
 			<attribute name="maven.pomderived" value="true"/>
 		</attributes>
 	</classpathentry>
+	<classpathentry kind="src" path="target/generated-sources/annotations">
+		<attributes>
+			<attribute name="optional" value="true"/>
+			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="ignore_optional_problems" value="true"/>
+			<attribute name="m2e-apt" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
+		<attributes>
+			<attribute name="optional" value="true"/>
+			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="ignore_optional_problems" value="true"/>
+			<attribute name="m2e-apt" value="true"/>
+			<attribute name="test" value="true"/>
+		</attributes>
+	</classpathentry>
 	<classpathentry kind="output" path="target/classes"/>
 </classpath>
diff --git a/.gitignore b/.gitignore
index eb314f1436cf4862f5d1403630118baaf2a2470c..91274bca2c6044c28c5190fac42c907c9f906ba1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,7 @@ tmp/**/*
 local.properties
 .loadpath
 .factorypath
+.settings/org.eclipse.jdt.apt.core.prefs
 
 
 # CDT-specific
diff --git a/.project b/.project
index 6c9cf5fa2bbdf2f2bd2c600d1a4712e2ff3d8b93..53f18a33bd1b691236a6099e91dc8fda2930bf99 100644
--- a/.project
+++ b/.project
@@ -39,4 +39,15 @@
 		<nature>org.eclipse.jdt.core.javanature</nature>
 		<nature>org.eclipse.m2e.core.maven2Nature</nature>
 	</natures>
+	<filteredResources>
+		<filter>
+			<id>1617023900149</id>
+			<name></name>
+			<type>30</type>
+			<matcher>
+				<id>org.eclipse.core.resources.regexFilterMatcher</id>
+				<arguments>node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
+			</matcher>
+		</filter>
+	</filteredResources>
 </projectDescription>
diff --git a/.settings/org.eclipse.jdt.apt.core.prefs b/.settings/org.eclipse.jdt.apt.core.prefs
new file mode 100644
index 0000000000000000000000000000000000000000..dfa4f3adb289a4f7d73e0694f9045f99325604d7
--- /dev/null
+++ b/.settings/org.eclipse.jdt.apt.core.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.apt.aptEnabled=true
+org.eclipse.jdt.apt.genSrcDir=target/generated-sources/annotations
+org.eclipse.jdt.apt.genTestSrcDir=target/generated-test-sources/test-annotations
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
index 2bd4e77333c71a363a69f94617a46fdac942825d..93d8913371f1c8c83ccd5db57c650ef42e4dac72 100644
--- a/.settings/org.eclipse.jdt.core.prefs
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -12,5 +12,6 @@ org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
 org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
 org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
+org.eclipse.jdt.core.compiler.processAnnotations=enabled
 org.eclipse.jdt.core.compiler.release=disabled
 org.eclipse.jdt.core.compiler.source=11
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 efe0af09a277b9fcc099f22a9d31ebc9bccd990a..f6f27f359779f58c2ee81698b9b105e3944c792b 100644
--- a/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java
+++ b/src/main/java/at/ac/uibk/gitsearch/service/GitlabService.java
@@ -20,6 +20,7 @@ import org.springframework.util.StreamUtils;
 import org.springframework.util.StringUtils;
 
 import at.ac.uibk.gitsearch.repository.gitlab.GitLabRepository;
+import at.ac.uibk.gitsearch.security.jwt.TokenProvider;
 
 /**
  * Service for exercise/course search results
@@ -30,14 +31,16 @@ public class GitlabService {
 	
 	@Autowired
 	private GitLabRepository gitLabRepository;
+	@Autowired
+	protected TokenProvider tokenProvider;
 	
 	private final Logger log = LoggerFactory.getLogger(ShoppingBasketService.class);
 
 
     public Boolean repositoryExists(String projectID) {
-        final GitLabApi gitLabApi = gitLabRepository.getGitLabApi();
-		final ProjectApi gitLabProjectApi = gitLabApi.getProjectApi();
 		try{
+			final GitLabApi gitLabApi = gitLabRepository.getGitLabApi(tokenProvider.getGitLabAccessInfo());
+			final ProjectApi gitLabProjectApi = gitLabApi.getProjectApi();
 			return gitLabProjectApi.getProject(projectID) != null;}
 		catch(GitLabApiException e){
 			log.error(e.getMessage(), e);
@@ -48,7 +51,7 @@ public class GitlabService {
 	
 	public InputStream getRepositoryZip(String exerciseID) throws GitLabApiException, IOException {
 		
-        final GitLabApi gitLabApi = gitLabRepository.getGitLabApi(Optional.empty());
+        final GitLabApi gitLabApi = gitLabRepository.getGitLabApi(tokenProvider.getGitLabAccessInfo());
 		return rePackageGitLabProjectZip(new ZipInputStream(gitLabApi.getRepositoryApi().getRepositoryArchive(exerciseID, "HEAD", "zip")), "from project " + exerciseID);
 	}
 	
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 4e99536ca3d5c8d6f1b164255d505535b679796e..f00f1fdbb73f0c310156f1596f53a11d43444f14 100644
--- a/src/main/java/at/ac/uibk/gitsearch/service/SearchService.java
+++ b/src/main/java/at/ac/uibk/gitsearch/service/SearchService.java
@@ -244,8 +244,8 @@ public class SearchService {
 		return copyInputStreamToFile(inputFile, file);}
 		catch(GitLabApiException exception){
 			log.error(exception.getMessage());
+			return null;
 		}
-		return null;
 	}
 
 	private File copyInputStreamToFile(InputStream inputStream, File file) throws IOException {
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 aff0f6d515fd975a8b9cfbe8d218a3f34849686d..759cbad8d83b2c2a3cfc22290864e9cb16666b2f 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
@@ -163,7 +163,7 @@ public class StatisticsResource {
             return ResponseUtil.wrapOrNotFound(statisticsDTO);
         }
         else{
-            return null;
+            return ResponseUtil.wrapOrNotFound(statisticsDTO);
         }
     }
 
diff --git a/src/main/resources/config/application-prod.yml b/src/main/resources/config/application-prod.yml
index b5cf61124a4a7d950c7437b9bbea0141a2f1df8b..171d4e70b0a935593787d5d334a2b1194e04c597 100644
--- a/src/main/resources/config/application-prod.yml
+++ b/src/main/resources/config/application-prod.yml
@@ -74,7 +74,6 @@ spring:
             client-id: ${SECURITY_OAUTH2_CLIENT_REGISTRATION_GITLABOIDC_CLIENTID}
             client-secret: ${SECURITY_OAUTH2_CLIENT_REGISTRATION_GITLABOIDC_CLIENTSECRET}
 
-
 # ===================================================================
 # To enable TLS in production, generate a certificate using:
 # keytool -genkey -alias gitsearch -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650
@@ -154,7 +153,7 @@ jhipster:
 
 application:
   registeredPlugins:
-   - "https://artemis.codeability.uibk.ac.at/api/sharing/config" 
+    - 'https://artemis.codeability.uibk.ac.at/api/sharing/config'
   gitlab:
-   url: https://sharing-codeability.uibk.ac.at/
-   generalAccessToken: ${APPLICATION_GITLAB_GENERALACCESSTOKEN}
+    url: https://sharing-codeability.uibk.ac.at/
+    generalAccessToken: ${APPLICATION_GITLAB_GENERALACCESSTOKEN}
diff --git a/src/main/webapp/app/admin/health/health.component.ts b/src/main/webapp/app/admin/health/health.component.ts
index 509cc0b531f6e29d5de94f9ce0109211fa3fe400..3dd1a9c4f985cf0432450b4206b7da6627aedd6d 100644
--- a/src/main/webapp/app/admin/health/health.component.ts
+++ b/src/main/webapp/app/admin/health/health.component.ts
@@ -42,9 +42,9 @@ export class HealthComponent implements OnInit {
     const modalRef = this.modalService.open(HealthModalComponent);
     modalRef.componentInstance.health = health;
   }
-  
+
   translateKeys(key: string) {
-    if ( key.startsWith('health.indicator.http')) return key.substr(17);
+    if (key.startsWith('health.indicator.http')) return key.substr(17);
     return this.translateService.instant(key);
-}
+  }
 }
diff --git a/src/main/webapp/app/app.module.ts b/src/main/webapp/app/app.module.ts
index 90a55ad673d9537e9249b7af5ee8577c28ee39cb..f82548f29847e655fbc97ca611a1cd79bf714c7a 100644
--- a/src/main/webapp/app/app.module.ts
+++ b/src/main/webapp/app/app.module.ts
@@ -16,7 +16,7 @@ import { PageRibbonComponent } from './layouts/profiles/page-ribbon.component';
 import { ActiveMenuDirective } from './layouts/navbar/active-menu.directive';
 import { ErrorComponent } from './layouts/error/error.component';
 import { QueryParamModule } from '@ngqp/core';
-import { CacheService } from 'app/shared/service/cache.service'
+import { CacheService } from 'app/shared/service/cache.service';
 
 @NgModule({
   imports: [
@@ -30,17 +30,8 @@ import { CacheService } from 'app/shared/service/cache.service'
     GitSearchV2AppRoutingModule,
     QueryParamModule,
   ],
-  declarations: [
-	    MainComponent, 
-    NavbarComponent, 
-    ErrorComponent, 
-    PageRibbonComponent, 
-    ActiveMenuDirective, 
-    FooterComponent],
+  declarations: [MainComponent, NavbarComponent, ErrorComponent, PageRibbonComponent, ActiveMenuDirective, FooterComponent],
   bootstrap: [MainComponent],
-  providers:  [
-      CacheService,
-      ]
-
+  providers: [CacheService],
 })
 export class GitSearchV2AppModule {}
diff --git a/src/main/webapp/app/core/application/applicationInfo.service.ts b/src/main/webapp/app/core/application/applicationInfo.service.ts
index b235c0c19a8b610d160806bbe8d1c3d6bf12ab53..980a98ba4e173d495047513af89d6c412422442e 100644
--- a/src/main/webapp/app/core/application/applicationInfo.service.ts
+++ b/src/main/webapp/app/core/application/applicationInfo.service.ts
@@ -1,38 +1,33 @@
 import { Injectable } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
-import { Observable, } from 'rxjs';
+import { Observable } from 'rxjs';
 
 import { SERVER_API_URL } from 'app/app.constants';
 
 export class DeploymentInfo {
-    branch = "";
-    commitId = "";
+  branch = '';
+  commitId = '';
 }
 @Injectable({ providedIn: 'root' })
 export class ApplicationInfoService {
-
   cachedDeploymentInfo: DeploymentInfo;
   inLoading = false;
-  constructor(
-    private http: HttpClient,
-    ) {
-      this.cachedDeploymentInfo = {} as DeploymentInfo;
-    }
+  constructor(private http: HttpClient) {
+    this.cachedDeploymentInfo = {} as DeploymentInfo;
+  }
 
   private loadDeploymentInfo(): Observable<DeploymentInfo> {
     return this.http.get<DeploymentInfo>(SERVER_API_URL + 'api/applicationInfo/deploymentInfo');
   }
-  
+
   public getDeploymentInfo(): DeploymentInfo {
-    if(!this.cachedDeploymentInfo.branch && !this.inLoading) {
-        this.inLoading = true;
-        this.loadDeploymentInfo().subscribe((res) => {
-            this.cachedDeploymentInfo = res;
-            this.inLoading = false;
-        });
+    if (!this.cachedDeploymentInfo.branch && !this.inLoading) {
+      this.inLoading = true;
+      this.loadDeploymentInfo().subscribe(res => {
+        this.cachedDeploymentInfo = res;
+        this.inLoading = false;
+      });
     }
     return this.cachedDeploymentInfo;
-    }
-  
-
+  }
 }
diff --git a/src/main/webapp/app/exercise/exercise-card/exercise-card.component.ts b/src/main/webapp/app/exercise/exercise-card/exercise-card.component.ts
index 73c759ab444b6d3d1cdfe824387840cdb8ba5540..151f8ba9580d9534adef45391caad3f42a322679 100644
--- a/src/main/webapp/app/exercise/exercise-card/exercise-card.component.ts
+++ b/src/main/webapp/app/exercise/exercise-card/exercise-card.component.ts
@@ -26,7 +26,7 @@ export class ExerciseCardComponent implements OnInit {
           this.exercise!.views = data.views!;
           this.exercise!.downloads = data.downloads!;
         },
-        () => alert('Request failed')
+        () => alert('Could not load exercise statistics')
       );
     }
     this.exerciseSelectionEvent.emit(this.exercise);
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 109966ff106134e19841da8c02f99fca88e4b533..072b7434e434f6f6f355168e4d957dbc04cc8995 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
@@ -5,8 +5,6 @@ import { Subscription } from 'rxjs';
 import { PluginActionInfo } from 'app/shared/model/search/search-result-dto.model';
 import { PluginService } from 'app/shared/service/plugin-service';
 import { ShoppingBasketInfo, ShoppingBasketRedirectInfoDTO } from 'app/shared/model/basket/shopping-basket-info.model';
-import { HttpErrorResponse } from '@angular/common/http';
-
 import { AccountService } from 'app/core/auth/account.service';
 import { Account } from 'app/core/user/account.model';
 import { SearchService } from 'app/search/service/search-service.ts';
@@ -51,7 +49,7 @@ export class ExerciseDetailsComponent implements OnInit, OnDestroy {
   }
 
   public getPersonDetailsWithEmail(person: Person): string {
-    return "<a class='text-dark' href= 'mailto:'" + person.email + '>' + person.name + ', ' + person.affiliation + '</a>';
+    return "<a class='text-dark' href='mailto:" + person.email + "'>" + person.name + ', ' + person.affiliation + '</a>';
   }
 
   public arrayToString(array: string[]): string {
@@ -71,22 +69,21 @@ export class ExerciseDetailsComponent implements OnInit, OnDestroy {
     return result;
   }
 
-    public startAction(action: PluginActionInfo, exercise: Exercise): void {
-        const basketInfo: ShoppingBasketInfo = {
-            plugin: action.plugin,
-            action: action.action,
-            itemInfos: [
-                exercise.originalResult
-            ]
-        };
-        this.pluginService.getRedirectLink(basketInfo).subscribe(
-            (redirectInfo: ShoppingBasketRedirectInfoDTO) => {
-                // alert('redirecting to ' + redirectInfo.redirectURL);
-                // location.href = redirectInfo.redirectURL;
-                	window.open(redirectInfo.redirectURL, action.action);
-            },
-            () => alert('Search failed'))
-    }
+  public startAction(action: PluginActionInfo, exercise: Exercise): void {
+    const basketInfo: ShoppingBasketInfo = {
+      plugin: action.plugin,
+      action: action.action,
+      itemInfos: [exercise.originalResult],
+    };
+    this.pluginService.getRedirectLink(basketInfo).subscribe(
+      (redirectInfo: ShoppingBasketRedirectInfoDTO) => {
+        // alert('redirecting to ' + redirectInfo.redirectURL);
+        // location.href = redirectInfo.redirectURL;
+        window.open(redirectInfo.redirectURL, action.action);
+      },
+      () => alert('Search failed')
+    );
+  }
 
   public download(): void {
     this.exportExercise(Number(this.exercise!.originalResult.project.project_id));
@@ -107,7 +104,7 @@ export class ExerciseDetailsComponent implements OnInit, OnDestroy {
           window.URL.revokeObjectURL(url);
         }
       },
-      (error: HttpErrorResponse) => this.jhiAlertService.error('Unable to export exercise. Error: ' + error.message)
+      () => alert('Unable to export exercise. Please log in to export.')
     );
   }
 
diff --git a/src/main/webapp/app/layouts/main/main.component.ts b/src/main/webapp/app/layouts/main/main.component.ts
index 1c8a8fa17fec8834ef50ed8ca0852af3fece0c9a..81943c2ed5148cffb0b77858335510debb880f38 100644
--- a/src/main/webapp/app/layouts/main/main.component.ts
+++ b/src/main/webapp/app/layouts/main/main.component.ts
@@ -6,7 +6,7 @@ import { TranslateService, LangChangeEvent } from '@ngx-translate/core';
 import { AccountService } from 'app/core/auth/account.service';
 import { AuthServerProvider } from 'app/core/auth/auth-jwt.service';
 import { CookieService } from 'ngx-cookie-service';
-import { MessageService, BroadCastMessage} from 'app/shared/service/message-service'
+import { MessageService, BroadCastMessage } from 'app/shared/service/message-service';
 // import { AlertErrorComponent } from 'app/shared/alert/alert-error.component';
 
 @Component({
@@ -24,9 +24,8 @@ export class MainComponent implements OnInit {
     rootRenderer: RendererFactory2,
     private authServerProvider: AuthServerProvider,
     private cookieService: CookieService,
-    private messageService: MessageService,
-  ) //	private alertErrorComponent: AlertErrorComponent
-  {
+    private messageService: MessageService //	private alertErrorComponent: AlertErrorComponent
+  ) {
     this.renderer = rootRenderer.createRenderer(document.querySelector('html'), null);
   }
 
@@ -50,11 +49,10 @@ export class MainComponent implements OnInit {
       this.renderer.setAttribute(document.querySelector('html'), 'lang', langChangeEvent.lang);
     });
   }
-  
-      public getActiveMessages(): Array<BroadCastMessage> {
-        return this.messageService.getActiveMessages(); // 
-        }
 
+  public getActiveMessages(): Array<BroadCastMessage> {
+    return this.messageService.getActiveMessages(); //
+  }
 
   private checkRequestToken(): void {
     const tokenCookie = this.cookieService.get('tempRequestToken');
diff --git a/src/main/webapp/app/search/search-input/search-input.component.ts b/src/main/webapp/app/search/search-input/search-input.component.ts
index a3a5f469dabe812e717ca394135d0973dc741685..98a88b1e90aafd53ff9ce26008071d7af933c053 100644
--- a/src/main/webapp/app/search/search-input/search-input.component.ts
+++ b/src/main/webapp/app/search/search-input/search-input.component.ts
@@ -4,16 +4,16 @@ import { ActivatedRoute, Router } from '@angular/router';
 import { QueryParam, QueryParamBuilder, QueryParamGroup } from '@ngqp/core';
 import { takeUntil } from 'rxjs/operators';
 import { SearchInput } from 'app/shared/model/search/search-input.model';
-import { SearchService } from '../service/search-service'
+import { SearchService } from '../service/search-service';
 import { faQuestion } from '@fortawesome/free-solid-svg-icons';
 
-import {Observable} from 'rxjs';
-import {debounceTime, distinctUntilChanged, map, switchMap} from 'rxjs/operators';
+import { Observable } from 'rxjs';
+import { debounceTime, distinctUntilChanged, map, switchMap } from 'rxjs/operators';
 
-import {IExerciseType } from 'app/shared/model/exercise.model';
+import { IExerciseType } from 'app/shared/model/exercise.model';
 
 interface LooseObject {
-    [key: string]: any
+  [key: string]: any;
 }
 
 @Component({
@@ -26,9 +26,9 @@ export class SearchInputComponent implements OnInit, OnDestroy {
 
   @Output() searchInputEvent = new EventEmitter<SearchInput>();
   public pageSize = 4;
-  
+
   typeValues = Object.keys(IExerciseType);
-  
+
   questionIcon = faQuestion;
   public paramGroup: QueryParamGroup;
   private componentDestroyed$ = new Subject<void>();
@@ -37,15 +37,67 @@ export class SearchInputComponent implements OnInit, OnDestroy {
 
   public showSearchUsage = false;
 
-  private states = ['Alabama', 'Alaska', 'American Samoa', 'Arizona', 'Arkansas', 'California', 'Colorado',
-  'Connecticut', 'Delaware', 'District Of Columbia', 'Federated States Of Micronesia', 'Florida', 'Georgia',
-  'Guam', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine',
-  'Marshall Islands', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana',
-  'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'New York', 'North Carolina', 'North Dakota',
-  'Northern Mariana Islands', 'Ohio', 'Oklahoma', 'Oregon', 'Palau', 'Pennsylvania', 'Puerto Rico', 'Rhode Island',
-  'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virgin Islands', 'Virginia',
-  'Washington', 'West Virginia', 'Wisconsin', 'Wyoming'];
-
+  private states = [
+    'Alabama',
+    'Alaska',
+    'American Samoa',
+    'Arizona',
+    'Arkansas',
+    'California',
+    'Colorado',
+    'Connecticut',
+    'Delaware',
+    'District Of Columbia',
+    'Federated States Of Micronesia',
+    'Florida',
+    'Georgia',
+    'Guam',
+    'Hawaii',
+    'Idaho',
+    'Illinois',
+    'Indiana',
+    'Iowa',
+    'Kansas',
+    'Kentucky',
+    'Louisiana',
+    'Maine',
+    'Marshall Islands',
+    'Maryland',
+    'Massachusetts',
+    'Michigan',
+    'Minnesota',
+    'Mississippi',
+    'Missouri',
+    'Montana',
+    'Nebraska',
+    'Nevada',
+    'New Hampshire',
+    'New Jersey',
+    'New Mexico',
+    'New York',
+    'North Carolina',
+    'North Dakota',
+    'Northern Mariana Islands',
+    'Ohio',
+    'Oklahoma',
+    'Oregon',
+    'Palau',
+    'Pennsylvania',
+    'Puerto Rico',
+    'Rhode Island',
+    'South Carolina',
+    'South Dakota',
+    'Tennessee',
+    'Texas',
+    'Utah',
+    'Vermont',
+    'Virgin Islands',
+    'Virginia',
+    'Washington',
+    'West Virginia',
+    'Wisconsin',
+    'Wyoming',
+  ];
 
   constructor(
     protected activatedRoute: ActivatedRoute,
@@ -80,17 +132,15 @@ export class SearchInputComponent implements OnInit, OnDestroy {
         emptyOn: '',
       }),
     };
-    
+
     // add type checkbox support
-    this.typeValues.forEach(
-        function(type: string): void {
-            const typeName = type.toString();
-            groupDef[typeName] = qpb.stringParam(typeName, {
-                debounceTime: SearchInputComponent.DEBOUNCE_TIME,
-                emptyOn: '',
-              });
-        }
-    );
+    this.typeValues.forEach(function (type: string): void {
+      const typeName = type.toString();
+      groupDef[typeName] = qpb.stringParam(typeName, {
+        debounceTime: SearchInputComponent.DEBOUNCE_TIME,
+        emptyOn: '',
+      });
+    });
 
     this.paramGroup = qpb.group(groupDef);
 
@@ -98,19 +148,18 @@ export class SearchInputComponent implements OnInit, OnDestroy {
       this.searchInput.setValues(value);
       this.searchInputEvent.emit(this.searchInput);
     });
-
   }
-  
+
   getSelectedTypes(): string[] {
     const result: string[] = [];
-    this.typeValues.forEach(
-        type => {if(this.paramGroup.queryParams[type].value) result.push(type)});
+    this.typeValues.forEach(type => {
+      if (this.paramGroup.queryParams[type].value) result.push(type);
+    });
     return result;
-}
+  }
 
   ngOnInit(): void {}
 
-   
   ngOnDestroy(): void {
     this.componentDestroyed$.next();
     this.componentDestroyed$.complete();
@@ -123,39 +172,33 @@ export class SearchInputComponent implements OnInit, OnDestroy {
   public onPageChange(page: number): void {
     this.pageParam.setValue(page);
   }
-  
-/*
+
+  /*
   public itemSelected(): void {
           this.searchInputEvent.emit(this.searchInput);
   }
 */
-   autoCompleteContributorCreator = (text$: Observable<string>) =>
+  autoCompleteContributorCreator = (text$: Observable<string>) =>
     text$.pipe(
       debounceTime(200),
       distinctUntilChanged(),
-      switchMap((searchText) => {
-        if(searchText.length <= 2) return [];
-        return this.searchService.getContributorCreatorAutoComplete( searchText).pipe(map(
-            ace => (ace.map(ac => ac.target)) ) ); }
-            )
-     );
-      
-   autoCompleteKeyWords = (text$: Observable<string>) =>
+      switchMap(searchText => {
+        if (searchText.length <= 2) return [];
+        return this.searchService.getContributorCreatorAutoComplete(searchText).pipe(map(ace => ace.map(ac => ac.target)));
+      })
+    );
+
+  autoCompleteKeyWords = (text$: Observable<string>) =>
     text$.pipe(
       debounceTime(200),
       distinctUntilChanged(),
-      switchMap((searchText) => 
-        this.searchService.getKeywordsAutoComplete( searchText).pipe(map(
-            ace => (ace.map(ac => ac.target)) ) ))
-     );
+      switchMap(searchText => this.searchService.getKeywordsAutoComplete(searchText).pipe(map(ace => ace.map(ac => ac.target))))
+    );
 
-   autoCompleteProgrammingLanguage = (text$: Observable<string>) =>
+  autoCompleteProgrammingLanguage = (text$: Observable<string>) =>
     text$.pipe(
       debounceTime(200),
       distinctUntilChanged(),
-      switchMap((searchText) => 
-        this.searchService.getProgrammingLanguageAutoComplete( searchText).pipe(map(
-            ace => (ace.map(ac => ac.target)) ) ))
-     );
-     
+      switchMap(searchText => this.searchService.getProgrammingLanguageAutoComplete(searchText).pipe(map(ace => ace.map(ac => ac.target))))
+    );
 }
diff --git a/src/main/webapp/app/search/search.component.ts b/src/main/webapp/app/search/search.component.ts
index 2a70db9b233724329c5406d4563117eb7693d7b5..f69a68032f874cb464bb5b976f5aeaafecefc57c 100644
--- a/src/main/webapp/app/search/search.component.ts
+++ b/src/main/webapp/app/search/search.component.ts
@@ -57,11 +57,11 @@ export class SearchComponent implements OnInit {
     this.hitCount = searchResultsDTO.hitCount;
     // fix string to date conversion: unfortunatelly dates are not converted correctly :-()
     searchResultsDTO.searchResult.forEach(hit => {
-        // eslint-disable-next-line @typescript-eslint/camelcase
-        hit.project.last_activity_at = new Date(hit.project.last_activity_at);
-        // eslint-disable-next-line @typescript-eslint/camelcase
-        hit.file.indexing_date = new Date(hit.file.indexing_date);
-        });
+      // eslint-disable-next-line @typescript-eslint/camelcase
+      hit.project.last_activity_at = new Date(hit.project.last_activity_at);
+      // eslint-disable-next-line @typescript-eslint/camelcase
+      hit.file.indexing_date = new Date(hit.file.indexing_date);
+    });
     return searchResultsDTO.searchResult.map(this.searchResultToExercise);
   }
 
diff --git a/src/main/webapp/app/search/service/search-service.ts b/src/main/webapp/app/search/service/search-service.ts
index 64719cff3cbd53c344702dba2f22dec85c87260b..094c73a4872597d198037d7b6ceed1006ee2cc26 100644
--- a/src/main/webapp/app/search/service/search-service.ts
+++ b/src/main/webapp/app/search/service/search-service.ts
@@ -1,3 +1,4 @@
+/* eslint-disable */
 import { Injectable } from '@angular/core';
 import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';
 import { Observable } from 'rxjs';
@@ -69,8 +70,8 @@ export class SearchService {
       params: new HttpParams().set('contributorPrefix', prefix),
     });
   }
-  
-   getContributorCreatorAutoComplete(prefix: string): Observable<Array<AutoCompletionEntry>> {
+
+  getContributorCreatorAutoComplete(prefix: string): Observable<Array<AutoCompletionEntry>> {
     const options: HttpParams = new HttpParams();
     options.append('keyWordPrefix', prefix);
     return this.http.get<Array<AutoCompletionEntry>>(this.resourceContributorCreatorAutoCompleteDetails, {
@@ -85,7 +86,6 @@ export class SearchService {
       params: new HttpParams().set('contributorPrefix', prefix),
     });
   }
-
 }
 
 export class AutoCompletionEntry {
diff --git a/src/main/webapp/app/shared/service/cache.service.ts b/src/main/webapp/app/shared/service/cache.service.ts
index d7cc47f008389a999e53eac8c50aa03e285c519e..5873a9d8673084e2e58f6b22d8c7996a11282e9b 100644
--- a/src/main/webapp/app/shared/service/cache.service.ts
+++ b/src/main/webapp/app/shared/service/cache.service.ts
@@ -1,53 +1,53 @@
-import { Injectable } from '@angular/core'
+import { Injectable } from '@angular/core';
 
 /** provides a caching service, with a key, the data and a timeout ()
     Warning: Objects are stored as json-Strings. I.e. Dates objects (and others) may not be converted correctly */
 @Injectable()
 export class CacheService {
-    constructor() { }
-
-    save(options: LocalStorageSaveOptions) {
-        // Set default values for optionals
-        options.expirationMins = options.expirationMins || 0
-
-        // Set expiration date in miliseconds
-        const expirationMS = options.expirationMins !== 0 ? options.expirationMins * 60 * 1000 : 0
-
-        const record = {
-            value: typeof options.data === 'string' ? options.data : JSON.stringify(options.data),
-            expiration: expirationMS !== 0 ? new Date().getTime() + expirationMS : null,
-            hasExpiration: expirationMS !== 0 ? true : false
-        }
-        localStorage.setItem(options.key, JSON.stringify(record))
-    }
-
-    load(key: string) {
-        // Get cached data from localstorage
-        const item = localStorage.getItem(key)
-        if (item !== null) {
-            const record = JSON.parse(item)
-            const now = new Date().getTime()
-            // Expired data will return null
-            if (!record || (record.hasExpiration && record.expiration <= now)) {
-                return null
-            } else {
-                return JSON.parse(record.value)
-            }
-        }
-        return null
+  constructor() {}
+
+  save(options: LocalStorageSaveOptions) {
+    // Set default values for optionals
+    options.expirationMins = options.expirationMins || 0;
+
+    // Set expiration date in miliseconds
+    const expirationMS = options.expirationMins !== 0 ? options.expirationMins * 60 * 1000 : 0;
+
+    const record = {
+      value: typeof options.data === 'string' ? options.data : JSON.stringify(options.data),
+      expiration: expirationMS !== 0 ? new Date().getTime() + expirationMS : null,
+      hasExpiration: expirationMS !== 0 ? true : false,
+    };
+    localStorage.setItem(options.key, JSON.stringify(record));
+  }
+
+  load(key: string) {
+    // Get cached data from localstorage
+    const item = localStorage.getItem(key);
+    if (item !== null) {
+      const record = JSON.parse(item);
+      const now = new Date().getTime();
+      // Expired data will return null
+      if (!record || (record.hasExpiration && record.expiration <= now)) {
+        return null;
+      } else {
+        return JSON.parse(record.value);
+      }
     }
+    return null;
+  }
 
-    remove(key: string) {
-        localStorage.removeItem(key)
-    }
+  remove(key: string) {
+    localStorage.removeItem(key);
+  }
 
-    cleanLocalStorage() {
-        localStorage.clear()
-    }
+  cleanLocalStorage() {
+    localStorage.clear();
+  }
 }
 
 export class LocalStorageSaveOptions {
-    key = '';
-    data: any
-    expirationMins?: number
-}
\ No newline at end of file
+  key = '';
+  data: any;
+  expirationMins?: number;
+}
diff --git a/src/main/webapp/app/shared/service/message-service.ts b/src/main/webapp/app/shared/service/message-service.ts
index 478dcf03633feb1d0a2ab31aab23a72d77cd9f82..8efcf3d69d1c789f47630ab1c7308cf1f6b92b7f 100644
--- a/src/main/webapp/app/shared/service/message-service.ts
+++ b/src/main/webapp/app/shared/service/message-service.ts
@@ -3,19 +3,18 @@ import { HttpClient } from '@angular/common/http';
 
 import { SERVER_API_URL } from 'app/app.constants';
 
-
 export interface BroadCastMessage {
-    message: string;
-    starts_at: Date;
-    ends_at: Date;
-
-    color: string;
-    font: string;
-    id: number;
-    active: boolean; // false,
-    target_path: string; // "*/welcome",
-    broadcast_type: string; // "banner",
-    dismissable: boolean; // false
+  message: string;
+  starts_at: Date;
+  ends_at: Date;
+
+  color: string;
+  font: string;
+  id: number;
+  active: boolean; // false,
+  target_path: string; // "*/welcome",
+  broadcast_type: string; // "banner",
+  dismissable: boolean; // false
 }
 
 /**
@@ -23,53 +22,43 @@ export interface BroadCastMessage {
  */
 @Injectable({ providedIn: 'root' })
 export class MessageService {
+  public messageResourceURL = SERVER_API_URL + 'api/applicationInfo/broadcastMessages';
 
-    public messageResourceURL = SERVER_API_URL + 'api/applicationInfo/broadcastMessages';
-
-    private messages = new Array<BroadCastMessage>();;
-    private nextUpdate = 0;
-    
-    constructor(protected http: HttpClient,) {
-        
-    }
+  private messages = new Array<BroadCastMessage>();
+  private nextUpdate = 0;
 
-    public getActiveMessages(): Array<BroadCastMessage> {
-        const now = new Date();
-        return this.getMessages().filter(m => 
-            ((m.starts_at <= now) && (m.ends_at >= now) ) 
-            ); // 
-        }
+  constructor(protected http: HttpClient) {}
 
-    public getMessages(): Array<BroadCastMessage> {
+  public getActiveMessages(): Array<BroadCastMessage> {
+    const now = new Date();
+    return this.getMessages().filter(m => m.starts_at <= now && m.ends_at >= now); //
+  }
 
-        const now = new Date().getTime();
-        if (this.nextUpdate > now) {
-            return this.messages;
-            }
+  public getMessages(): Array<BroadCastMessage> {
+    const now = new Date().getTime();
+    if (this.nextUpdate > now) {
+      return this.messages;
+    }
 
-        this.nextUpdate = now + 60*1000; // wait at least 1 Minute for next try
-            
-        const resp = this.http.get<Array<BroadCastMessage>>(this.messageResourceURL);
+    this.nextUpdate = now + 60 * 1000; // wait at least 1 Minute for next try
 
+    const resp = this.http.get<Array<BroadCastMessage>>(this.messageResourceURL);
 
-        resp.subscribe(
-            response => {
-                // first convert dates correctly :-(
-                    
-                response.forEach( m =>  {
-                    // eslint-disable-next-line @typescript-eslint/camelcase
-                    m.starts_at = new Date(m.starts_at);
-                    // eslint-disable-next-line @typescript-eslint/camelcase
-                    m.ends_at = new Date(m.ends_at);})
-                // Data will be cached
-                this.messages = response;
-                this.nextUpdate = new Date().getTime() + 10*60*1000; // wait 10 Minute for next try
+    resp.subscribe(response => {
+      // first convert dates correctly :-(
 
-                return (response);
-            }
-        );
-        return this.messages;
-    }
+      response.forEach(m => {
+        // eslint-disable-next-line @typescript-eslint/camelcase
+        m.starts_at = new Date(m.starts_at);
+        // eslint-disable-next-line @typescript-eslint/camelcase
+        m.ends_at = new Date(m.ends_at);
+      });
+      // Data will be cached
+      this.messages = response;
+      this.nextUpdate = new Date().getTime() + 10 * 60 * 1000; // wait 10 Minute for next try
 
+      return response;
+    });
+    return this.messages;
+  }
 }
-
diff --git a/src/main/webapp/i18n/de/health.json b/src/main/webapp/i18n/de/health.json
index b8ddba445436dcbfdef3ef3cdbc7ff99c557cc17..d0acbac326286efb10a91cc6d0c2e43ecb4c8207 100644
--- a/src/main/webapp/i18n/de/health.json
+++ b/src/main/webapp/i18n/de/health.json
@@ -17,7 +17,7 @@
       "db": "Datenbank",
       "elasticsearch": "Elasticsearch",
       "elasticsearchRest": "Elasticsearch REST API",
-       "pluginHealthCheck": "Plugin Status"
+      "pluginHealthCheck": "Plugin Status"
     },
     "table": {
       "service": "Dienst Name",
diff --git a/src/main/webapp/i18n/en/health.json b/src/main/webapp/i18n/en/health.json
index 2f0a7fc1754a706fcd238d99ae0a16b05ebce497..8c030728fadbbf8d8d1e4e53417ec3b5115bd48d 100644
--- a/src/main/webapp/i18n/en/health.json
+++ b/src/main/webapp/i18n/en/health.json
@@ -17,8 +17,7 @@
       "db": "Database",
       "elasticsearch": "Elasticsearch",
       "elasticsearchRest": "Elasticsearch REST API",
-     "pluginHealthCheck": "State of plugins"
-
+      "pluginHealthCheck": "State of plugins"
     },
     "table": {
       "service": "Service name",
diff --git a/src/test/java/at/ac/uibk/gitsearch/web/rest/StatisticsResourceIT.java b/src/test/java/at/ac/uibk/gitsearch/web/rest/StatisticsResourceIT.java
index 552819c97c9b869a8a1968e5767fdb9f75591d83..b7b7b39be3052315034e5e54d07366b2d9ffd9e8 100644
--- a/src/test/java/at/ac/uibk/gitsearch/web/rest/StatisticsResourceIT.java
+++ b/src/test/java/at/ac/uibk/gitsearch/web/rest/StatisticsResourceIT.java
@@ -3,11 +3,15 @@ package at.ac.uibk.gitsearch.web.rest;
 import at.ac.uibk.gitsearch.GitsearchApp;
 import at.ac.uibk.gitsearch.domain.Statistics;
 import at.ac.uibk.gitsearch.repository.StatisticsRepository;
+import at.ac.uibk.gitsearch.repository.gitlab.GitLabRepository;
 import at.ac.uibk.gitsearch.repository.search.StatisticsSearchRepository;
+import at.ac.uibk.gitsearch.service.GitlabService;
 import at.ac.uibk.gitsearch.service.StatisticsService;
 import at.ac.uibk.gitsearch.service.dto.StatisticsDTO;
 import at.ac.uibk.gitsearch.service.mapper.StatisticsMapper;
 
+import org.gitlab4j.api.GitLabApi;
+import org.gitlab4j.api.ProjectApi;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mock;
@@ -25,12 +29,15 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.persistence.EntityManager;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 import at.ac.uibk.gitsearch.security.AuthoritiesConstants;
+import at.ac.uibk.gitsearch.security.jwt.TokenProvider.GitLabAccessInfo;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
 import static org.hamcrest.Matchers.hasItem;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.Mockito.*;
 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@@ -63,6 +70,10 @@ public class StatisticsResourceIT {
     @Autowired
     private StatisticsService statisticsService;
 
+    @Autowired
+    private GitLabRepository gitLabRepository;
+
+
     /**
      * This repository is mocked in the at.ac.uibk.gitsearch.repository.search test
      * package.
@@ -78,6 +89,9 @@ public class StatisticsResourceIT {
     @Autowired
     private MockMvc restStatisticsMockMvc;
 
+    @Autowired
+    private GitlabService gitlabService;
+
     private Statistics statistics;
 
     /**
@@ -289,4 +303,46 @@ public class StatisticsResourceIT {
                 .andExpect(jsonPath("$.[*].downloads").value(hasItem(DEFAULT_DOWNLOADS)))
                 .andExpect(jsonPath("$.[*].exerciseID").value(hasItem(DEFAULT_EXERCISE_ID.intValue())));
     }
+
+    @Test
+    @Transactional
+    @WithMockUser(authorities = AuthoritiesConstants.ADMIN)
+    public void getStatisticsByExerciseId() throws Exception {
+        // Initialize the database
+        statisticsRepository.saveAndFlush(statistics);
+
+        // Get the statistics and see if it coincides with the mock stats
+        assertEquals(statisticsService.findOneByExerciseID(statistics.getExerciseID()).get().getExerciseID(), statistics.getExerciseID());
+    }
+
+
+    @Test
+    @Transactional
+    @WithMockUser(authorities = AuthoritiesConstants.ADMIN)
+    public void createStatisticsByExerciseId() throws Exception {
+        // Initialize the database
+        statisticsRepository.saveAndFlush(statistics);
+        // Optional<GitLabAccessInfo> accessInfo = gitLabRepository.getGitLabAccessInfo();
+        // GitLabApi gitlabApi = gitLabRepository.getGitLabApi(accessInfo);
+        // ProjectApi projectApi = gitlabApi.getProjectApi();
+        // Integer id = projectApi.getProjects().get(0).getId();
+
+        // Get the statistics
+        // System.out.println("My request: ##################################################################");
+        // System.out.println(restStatisticsMockMvc.perform(get("/api/statistics/exercise/{id}", 3).with(csrf().asHeader())));
+        // restStatisticsMockMvc.perform(get("/api/statistics/exercise/{id}", 3).with(csrf().asHeader())).andExpect(status().isOk())
+        //         .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
+        //         .andExpect(jsonPath("$.exerciseID").value(3));
+        
+        
+        //assertEquals(true,gitlabService.repositoryExists("3"));
+        
+        
+        // Get the statistics and see if it coincides with the mock stats
+        assertEquals(statisticsService.findOneByExerciseID(statistics.getExerciseID()).get().getExerciseID(), statistics.getExerciseID());
+    }
+
+
+
+
 }
diff --git a/src/test/resources/config/application.yml b/src/test/resources/config/application.yml
index e59a98231e66dd4b40213481919a16daa7b02877..153614d2fae0fdd139788d506e66b1f07b9afb51 100644
--- a/src/test/resources/config/application.yml
+++ b/src/test/resources/config/application.yml
@@ -113,7 +113,7 @@ jhipster:
     base-url: http://127.0.0.1:8080
   security:
     oauth2:
-# TODO: audience seems not really relevant, could be omitted? It is identical with client-id above
+      # TODO: audience seems not really relevant, could be omitted? It is identical with client-id above
       audience:
         - 149276ac11138d9ba72fb3cd12815e3fa2f372866df0eac0f7d1aae5fdffea24
     authentication:
@@ -142,8 +142,8 @@ application:
     highlight-pre: <mark><strong>
     highlight-post: </strong></mark>
   gitlab:
-   url: https://sharing.codeability-austria.uibk.ac.at/
-   generalAccessToken: zPxPmJE3UXAZJpBzxqej
+    url: https://sharing.codeability-austria.uibk.ac.at/
+    generalAccessToken: zPxPmJE3UXAZJpBzxqej
   registeredPlugins:
-   - "http://localhost:8081/api/sharing/config"  # may not be reachable for testing!
-   - "http://localhost:8082/api/sharingPluginConfig"  # may not be reachable for testing!
+    - 'http://localhost:8081/api/sharing/config' # may not be reachable for testing!
+    - 'http://localhost:8082/api/sharingPluginConfig' # may not be reachable for testing!