f82255961b
Jenkins Production Deployment
Reviewed-on: #20 Co-authored-by: Patrick Müller <mail@pmueller.me> Co-committed-by: Patrick Müller <mail@pmueller.me>
208 lines
5.2 KiB
TypeScript
208 lines
5.2 KiB
TypeScript
import {Component, OnDestroy, OnInit} from '@angular/core';
|
|
import {Subject} from 'rxjs';
|
|
import {takeUntil} from 'rxjs/operators';
|
|
import {HttpErrorResponse} from '@angular/common/http';
|
|
import {ApiService} from '../../services/api.service';
|
|
import {UtilsService} from '../../services/utils.service';
|
|
import {AdminAuthService} from '../../services/admin-auth.service';
|
|
import {Event} from '../../models/event';
|
|
import {User} from '../../models/user';
|
|
|
|
@Component({
|
|
selector: 'app-admin',
|
|
templateUrl: './admin.component.html',
|
|
styleUrls: ['./admin.component.css']
|
|
})
|
|
export class AdminComponent implements OnInit, OnDestroy {
|
|
|
|
private destroy$ = new Subject<void>();
|
|
|
|
isLoggedIn: boolean = false;
|
|
events: Event[] = [];
|
|
selectedCalendar: string = '';
|
|
name: string = '';
|
|
eventFilter: string = 'future'; // Default value for filter
|
|
eventSorting: string = 'start_asc'; // Default value for sorting
|
|
|
|
/**
|
|
* Why the page is not showing events, when it is not.
|
|
*
|
|
* 'denied' and 'unavailable' are kept apart on purpose. Only a 401 is worth
|
|
* sending someone to the login page; bouncing them there for a 403 produces
|
|
* a loop where signing in succeeds and lands them straight back here, and
|
|
* bouncing them for an unreachable API produces the same loop with no way
|
|
* out at all.
|
|
*/
|
|
failure: 'denied' | 'unavailable' | null = null;
|
|
|
|
constructor(
|
|
private api: ApiService
|
|
) {
|
|
}
|
|
|
|
ngOnInit(): void {
|
|
this.api.me().pipe(takeUntil(this.destroy$)).subscribe({
|
|
next: (user: User) => {
|
|
this.isLoggedIn = true;
|
|
this.name = user.fullName;
|
|
UtilsService.saveNameToLocalStorage(user.fullName);
|
|
|
|
// Signed in, but not for this app. The API would answer 403 to
|
|
// every events call, so say so once instead of failing per call.
|
|
if (!user.apps.includes('calendar')) {
|
|
this.failure = 'denied';
|
|
return;
|
|
}
|
|
|
|
this.getEvents();
|
|
},
|
|
error: (error: HttpErrorResponse) => {
|
|
if (error.status === 401) {
|
|
AdminAuthService.goToLogin();
|
|
return;
|
|
}
|
|
this.failure = error.status === 403 ? 'denied' : 'unavailable';
|
|
}
|
|
});
|
|
}
|
|
|
|
ngOnDestroy(): void {
|
|
this.destroy$.next();
|
|
this.destroy$.complete();
|
|
}
|
|
|
|
getEvents(): void {
|
|
this.events = [];
|
|
|
|
if (this.selectedCalendar === '') {
|
|
return;
|
|
}
|
|
|
|
this.api.getEvents(this.selectedCalendar).pipe(takeUntil(this.destroy$)).subscribe({
|
|
next: (events: Event[]): void => {
|
|
for (let event of events) {
|
|
if (event.status !== 'DELETED') {
|
|
this.events.push({
|
|
...event,
|
|
startDateTime: new Date(event.startDateTime),
|
|
endDateTime: new Date(event.endDateTime),
|
|
createdDate: new Date(event.createdDate),
|
|
lastModifiedDate: new Date(event.lastModifiedDate)
|
|
});
|
|
}
|
|
}
|
|
this.filterEvents();
|
|
this.sortEvents();
|
|
},
|
|
// Without this a failed load is indistinguishable from an empty
|
|
// calendar - which is exactly what the old bundle looks like against
|
|
// the post-cutover API, and how a deploy in progress gets mistaken for
|
|
// lost data.
|
|
error: (error: HttpErrorResponse): void => {
|
|
if (error.status === 401) {
|
|
AdminAuthService.goToLogin();
|
|
return;
|
|
}
|
|
this.failure = error.status === 403 ? 'denied' : 'unavailable';
|
|
}
|
|
});
|
|
}
|
|
|
|
handleCalendarChange() {
|
|
this.getEvents();
|
|
}
|
|
|
|
getCalendarId(text: string): number {
|
|
switch (text) {
|
|
case 'public':
|
|
return 1;
|
|
case 'members':
|
|
return 2;
|
|
case 'choir':
|
|
return 4;
|
|
case 'management':
|
|
return 3;
|
|
case 'birthdays':
|
|
return 5;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
filterEvents() {
|
|
this.events = this.events.filter((event) => {
|
|
return this.checkEventMeetsFilterCriteria(event);
|
|
});
|
|
}
|
|
|
|
checkEventMeetsFilterCriteria(event: Event): boolean {
|
|
// Always return birthdays regardless of date
|
|
if(event.calendarId === 5) {
|
|
return true;
|
|
}
|
|
|
|
switch (this.eventFilter) {
|
|
case '':
|
|
return true;
|
|
case 'all':
|
|
return true;
|
|
case 'future':
|
|
return this.reduceToDay(new Date(event.endDateTime)) >= this.reduceToDay(new Date());
|
|
case 'past':
|
|
return this.reduceToDay(new Date(event.endDateTime)) < this.reduceToDay(new Date());
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
reduceToDay(date: Date): Date {
|
|
let dayOnlyDate: Date = new Date();
|
|
dayOnlyDate.setFullYear(date.getFullYear());
|
|
dayOnlyDate.setMonth(date.getMonth());
|
|
dayOnlyDate.setDate(date.getDate());
|
|
dayOnlyDate.setHours(0, 0, 0, 0);
|
|
|
|
return dayOnlyDate;
|
|
}
|
|
|
|
getUserName(): string {
|
|
return this.name;
|
|
}
|
|
|
|
sortEvents(): void {
|
|
this.events.sort((a, b) => {
|
|
switch (this.eventSorting) {
|
|
case '':
|
|
return 1;
|
|
case 'start_asc':
|
|
return a.startDateTime > b.startDateTime ? 1 : -1;
|
|
case 'start_desc':
|
|
return a.startDateTime > b.startDateTime ? -1 : 1;
|
|
case 'created_asc':
|
|
return a.createdDate > b.createdDate ? 1 : -1;
|
|
case 'created_desc':
|
|
return a.createdDate > b.createdDate ? -1 : 1;
|
|
default:
|
|
return 1;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* There is no sign-in form here any more, and no account creation: accounts
|
|
* exist only by invitation from the admin app. Both are one redirect.
|
|
*/
|
|
signIn(): void {
|
|
AdminAuthService.goToLogin();
|
|
}
|
|
|
|
logout(): void {
|
|
UtilsService.clearName();
|
|
void AdminAuthService.signOut();
|
|
}
|
|
|
|
reload(): void {
|
|
window.location.reload();
|
|
}
|
|
}
|