import { HttpResponse } from '@angular/common/http'; import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { Router } from '@angular/router'; import { faFolder } from '@fortawesome/free-solid-svg-icons'; import { ApplicationInfoService } from 'app/core/application/applicationInfo.service'; import { Account } from 'app/core/auth/account.model'; import { AccountService } from 'app/core/auth/account.service'; import { AlertService } from 'app/core/util/alert.service'; import { LikesService } from 'app/entities/likes/likes.service'; import { ExerciseService } from 'app/exercise/service/exercise.service'; import { SearchService } from 'app/search/service/search-service'; import { ShoppingBasketInfo, ShoppingBasketRedirectInfoDTO } from 'app/shared/model/basket/shopping-basket-info.model'; import { Exercise, searchResultToExercise } from 'app/shared/model/exercise.model'; import { Person } from 'app/shared/model/person.model'; import { PluginActionInfo } from 'app/shared/model/search/search-result-dto.model'; import { PluginService } from 'app/shared/service/plugin-service'; import { WatchlistManager } from 'app/shared/watchlist/watchlist-manager'; import { Subscription } from 'rxjs'; @Component({ selector: 'jhi-exercise-details', templateUrl: './exercise-details.component.html', styleUrls: ['./exercise-details.component.scss'], }) export class ExerciseDetailsComponent implements OnInit, OnDestroy { @Input() exercise: Exercise | undefined; @Output() exerciseChangedEvent = new EventEmitter<Exercise>(); markDownExercise: Exercise | undefined; account: Account | null = null; authSubscription?: Subscription; hasLiked: Boolean | null = null; likeSubscription?: Subscription; authenticated = false; downloadWithChildren = false; treeIcon = faFolder; oerLink?: String; oerExerciseMatch = new RegExp('/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})$'); constructor( private accountService: AccountService, protected pluginService: PluginService, private searchService: SearchService, private likesService: LikesService, private jhiAlertService: AlertService, private watchlistManager: WatchlistManager, private exerciseService: ExerciseService, private applicationInfoService: ApplicationInfoService, private router: Router ) {} ngOnInit(): void { this.authSubscription = this.accountService.getAuthenticationState().subscribe(account => (this.account = account)); this.applicationInfoService.loadOerLink().subscribe( (res: string) => { this.oerLink = res; }, error => // eslint-disable-next-line no-console console.error(error) ); } public isAuthenticated(): boolean { return this.accountService.isAuthenticated(); } isOnCurrentWatchlist(e: Exercise): boolean { return this.watchlistManager.isExerciseOnCurrentWatchlist(e); } handleForCurrentWatchlist(e: Exercise): void { if (this.watchlistManager.isExerciseOnCurrentWatchlist(e)) { e.numberOfWatchlistEntries = e.numberOfWatchlistEntries - 1; } else { e.numberOfWatchlistEntries = e.numberOfWatchlistEntries + 1; } this.watchlistManager.handleCheckForCurrentWatchlist(e); } 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 isEditable(): boolean { if (!this.exercise) return false; if (!this.exercise.gitlabURL) return false; const matchGroups = this.exercise.gitlabURL.match(this.oerExerciseMatch); if (!matchGroups) return false; // Just for Testing: allow every edit if (this.oerLink) return true; const email = this.accountService.getUserEMail(); if (!email || email == '') return false; // test all: creator, publisher let potentialEditors: Person[] = []; // potentialEditors.concat(this.exercise.contributor); potentialEditors = potentialEditors.concat(this.exercise.creator); potentialEditors = potentialEditors.concat(this.exercise.publisher); for (let i = 0; i < potentialEditors.length; i++) { if (potentialEditors[i].email.localeCompare(email, undefined, { sensitivity: 'base' }) === 0) return true; } return false; } public getOEResourceLink(): string { if (this.oerLink) { const matchGroups = this.exercise!.gitlabURL.match(this.oerExerciseMatch); if (!matchGroups) return ''; const guid = matchGroups[1]; return this.oerLink.toString() + '/en/update/1/' + guid; } return ''; } public download(): void { this.exportProject(this.exercise!.originalResult.exerciseId); } exportProject(exerciseId: string) { const recursion = this.downloadWithChildren ? 'WITH_DESCENDANTS' : 'JUST_PROJECT'; return this.searchService.exportProject(exerciseId, recursion).subscribe( (response: HttpResponse<Blob>) => { this.jhiAlertService.addAlert({ type: 'success', translationKey: 'artemisApp.programmingExercise.export.successMessage', }); // success('artemisApp.programmingExercise.export.successMessage'); if (response.body) { const zipFile = new Blob([response.body], { type: 'application/zip' }); const url = window.URL.createObjectURL(zipFile); const link = document.createElement('a'); link.setAttribute('href', url); link.setAttribute('download', response.headers.get('filename')!); document.body.appendChild(link); // Required for FF link.click(); window.URL.revokeObjectURL(url); } }, () => alert('Unable to export exercise. Please log in to export, or check your git lab permissions.') ); } openLink(link: string): void { window.open(link); } hasChildren(): boolean { return ( this.exercise !== undefined && this.exercise !== null && this.exercise.originalResult !== undefined && this.exercise.originalResult !== null && this.exercise.originalResult.file !== undefined && this.exercise.originalResult.file !== null && this.exercise.originalResult.file.children !== undefined && this.exercise.originalResult.file.children !== null && this.exercise.originalResult.file.children.length > 0 ); } searchChildren(parentId: string): void { this.router.navigate(['/search'], { queryParams: { p: parentId } }); } toParent(parentId: string): void { this.exerciseService.loadExercise(parentId).subscribe(searchResult => { this.exercise = searchResultToExercise(searchResult); this.exercise = this.exerciseService.populateExerciseWithData(this.exercise); this.exerciseChangedEvent.emit(this.exercise); }), () => { alert('parent cannot be loaded'); }; } ngOnDestroy(): void { if (this.authSubscription) { this.authSubscription.unsubscribe(); } } /** * correct missing image urls */ correctImageURL(event: Event): void { const srcElement = event.srcElement as HTMLImageElement; if (srcElement) { srcElement.src = '/content/images/Logo_codeAbility_4c_300dpi_RGB3.gif'; } } likeAction(): void { // to do call like service this.likesService.likeExercise(this.exercise!.originalResult.exerciseId).subscribe(() => // eslint-disable-next-line no-console console.log('Liked post' + this.exercise!.originalResult.exerciseId) ); this.exercise!.numberOfLikes = this.exercise!.numberOfLikes + 1; this.exercise!.userHasLiked = true; // eslint-disable-next-line no-console console.log(`Reloaded number of likes is ${this.exercise!.numberOfLikes}`); } unlikeAction(): void { // to do call like service this.likesService.unlikeExercise(this.exercise!.originalResult.exerciseId).subscribe(() => // eslint-disable-next-line no-console console.log('Unliked post ' + this.exercise!.originalResult.exerciseId) ); this.exercise!.numberOfLikes = this.exercise!.numberOfLikes - 1; this.exercise!.userHasLiked = false; // eslint-disable-next-line no-console console.log(`Reloaded number of likes is ${this.exercise!.numberOfLikes}`); } toggleWithChildren() { this.downloadWithChildren = !this.downloadWithChildren; } selectREADME(): void { this.markDownExercise = this.exercise; } }