diff --git a/src/app/entities/travel-dto.ts b/src/app/entities/travel-dto.ts
new file mode 100644
index 0000000..e392298
--- /dev/null
+++ b/src/app/entities/travel-dto.ts
@@ -0,0 +1,17 @@
+import { User, UserId } from './user';
+
+export type TravelId = number;
+
+export class TravelDto {
+ constructor(
+ public id: TravelId = -1,
+ public driverInfo: User = null,
+ public travelersInfo: User[] = [],
+ public departureDate: string = '',
+ public origin: string = '',
+ public destination: string = '',
+ public places: number = 0,
+ public matrixRoomId: string = '',
+ public description?: string
+ ) { }
+}
diff --git a/src/app/entities/travel.ts b/src/app/entities/travel.ts
index 1b92123..40d9eec 100644
--- a/src/app/entities/travel.ts
+++ b/src/app/entities/travel.ts
@@ -1,21 +1,32 @@
-import { User } from './user';
+import { TravelDto } from './travel-dto';
+import { User, UserId } from './user';
export type TravelId = number;
-export class Travel {
- constructor(
- public id: TravelId = -1,
- public driverInfo: User = null,
- public travelersInfo: User[] = [],
- public departureDate: string = '',
- public origin: string = '',
- public destination: string = '',
- public places: number = 0,
- public matrixRoomId: string = '',
- public description?: string
- ) { }
+export class Travel extends TravelDto {
+ constructor(travelDto: TravelDto) {
+ super(travelDto.id,
+ travelDto.driverInfo,
+ travelDto.travelersInfo,
+ travelDto.departureDate,
+ travelDto.origin,
+ travelDto.destination,
+ travelDto.places,
+ travelDto.matrixRoomId,
+ travelDto.description);
+ }
availablePlaces(): number {
return this.places - this.travelersInfo.length;
}
+
+ hasTraveler(id: UserId): boolean {
+ let hasTraveler = false;
+ this.travelersInfo.forEach(traveler => {
+ if (traveler.id === id) {
+ hasTraveler = true;
+ }
+ });
+ return hasTraveler;
+ }
}
diff --git a/src/app/pages/travel/travel.component.html b/src/app/pages/travel/travel.component.html
index 1f7349b..01c4ced 100644
--- a/src/app/pages/travel/travel.component.html
+++ b/src/app/pages/travel/travel.component.html
@@ -9,8 +9,14 @@
ID: {{ travel.id }}
Conductor: {{ travel.driverInfo.name }}
{{ travel.description }}
+ Travelers
+
-
+
+
+
\ No newline at end of file
diff --git a/src/app/pages/travel/travel.component.ts b/src/app/pages/travel/travel.component.ts
index 3161dd5..d02a8d5 100644
--- a/src/app/pages/travel/travel.component.ts
+++ b/src/app/pages/travel/travel.component.ts
@@ -1,6 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
-import { AuthService } from 'src/app/services/auth.service';
+import { AbilityService } from 'src/app/services/ability.service';
import { Travel, TravelId } from '../../entities/travel';
import { ApiService } from '../../services/api.service';
@@ -16,7 +16,7 @@ export class TravelComponent implements OnInit {
constructor(
private router: Router,
- private authService: AuthService,
+ private abilityService: AbilityService,
private apiService: ApiService,
private route: ActivatedRoute
) { }
@@ -25,15 +25,7 @@ export class TravelComponent implements OnInit {
this.route.queryParams.subscribe(params => {
this.travelId = this.route.snapshot.paramMap.get('id') as unknown as TravelId;
- this.apiService.getTravel(this.travelId)
- .subscribe(res => {
- if (res.success) {
- this.travel = res.data;
- }
- else {
- console.error('Error getting travel ' + this.travelId + ': ' + res.error);
- }
- });
+ this.loadTravel();
});
}
@@ -41,11 +33,57 @@ export class TravelComponent implements OnInit {
this.router.navigateByUrl('/');
}
+ get canJoin(): boolean {
+ return this.abilityService.canJoinTravel(this.travel);
+ }
+
+ join(): void {
+ this.apiService.joinTravel(this.travel.id)
+ .subscribe(res => {
+ if (res.success) {
+ console.log('Joined travel');
+ this.loadTravel();
+ }
+ else {
+ console.error('Error joining travel id=' + this.travel.id + ': ' + res.error.code + ' ' + res.error.msg);
+ }
+ });
+ }
+
+ get canLeave(): boolean {
+ return this.abilityService.canLeaveTravel(this.travel);
+ }
+
+ leave(): void {
+ this.apiService.leaveTravel(this.travel.id)
+ .subscribe(res => {
+ if (res.success) {
+ console.log('Left travel');
+ this.loadTravel();
+ }
+ else {
+ console.error('Error leaving travel id=' + this.travel.id + ': ' + res.error.code + ' ' + res.error.msg);
+ }
+ });
+ }
+
+ get canEdit(): boolean {
+ return this.abilityService.canEditTravel(this.travel);
+ }
+
edit(): void {
this.router.navigateByUrl(`/travel/${this.travelId}/edit`);
}
- get canEdit(): boolean {
- return this.authService.canEditTravel(this.travel);
+ private loadTravel(): void {
+ this.apiService.getTravel(this.travelId)
+ .subscribe(res => {
+ if (res.success) {
+ this.travel = new Travel(res.data);
+ }
+ else {
+ console.error('Error getting travel ' + this.travelId + ': ' + res.error);
+ }
+ });
}
}
diff --git a/src/app/services/ability.service.spec.ts b/src/app/services/ability.service.spec.ts
new file mode 100644
index 0000000..ec39538
--- /dev/null
+++ b/src/app/services/ability.service.spec.ts
@@ -0,0 +1,16 @@
+import { TestBed } from '@angular/core/testing';
+
+import { AbilityService } from './ability.service';
+
+describe('AbilityService', () => {
+ let service: AbilityService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(AbilityService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});
diff --git a/src/app/services/ability.service.ts b/src/app/services/ability.service.ts
new file mode 100644
index 0000000..3eb6b16
--- /dev/null
+++ b/src/app/services/ability.service.ts
@@ -0,0 +1,49 @@
+import { Injectable } from '@angular/core';
+import { Travel } from '../entities/travel';
+import { AuthService } from './auth.service';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class AbilityService {
+
+ constructor(
+ private authService: AuthService
+ ) { }
+
+ canEditTravel(travel: Travel): boolean {
+ if (travel == null) {
+ return false;
+ }
+ const user = this.authService.currentUser();
+ if (user == null) {
+ return false;
+ }
+
+ return user.admin || (user.id === travel.driverInfo.id);
+ }
+
+ canJoinTravel(travel: Travel): boolean {
+ if (travel == null) {
+ return false;
+ }
+ const user = this.authService.currentUser();
+ if (user == null) {
+ return false;
+ }
+
+ return (travel.driverInfo.id !== user.id) && (! travel.hasTraveler(user.id));
+ }
+
+ canLeaveTravel(travel: Travel): boolean {
+ if (travel == null) {
+ return false;
+ }
+ const user = this.authService.currentUser();
+ if (user == null) {
+ return false;
+ }
+
+ return travel.hasTraveler(user.id);
+ }
+}
diff --git a/src/app/services/api.service.ts b/src/app/services/api.service.ts
index e61d89e..b1404bb 100644
--- a/src/app/services/api.service.ts
+++ b/src/app/services/api.service.ts
@@ -8,6 +8,7 @@ import { PUBLIC_API_URL, TRAVEL_API_URL, USER_API_URL } from '../app.config';
import { ListDto } from '../entities/list-dto';
import { User } from '../entities/user';
import { AuthService } from './auth.service';
+import { TravelDto } from '../entities/travel-dto';
export type ApiCall = (params?: { [param: string]: any }) => (Observable>>);
@@ -28,7 +29,7 @@ export class ApiService {
}
getTravel = (travelId: TravelId) => {
- return this.callApi(PUBLIC_API_URL + '/travel', { travelId });
+ return this.callApi(PUBLIC_API_URL + '/travel', { travelId });
}
getTravels = (params?: { [param: string]: any }) => {
@@ -47,6 +48,14 @@ export class ApiService {
return this.callApi(TRAVEL_API_URL + '/edit', null, travel);
}
+ joinTravel = (travelId: TravelId) => {
+ return this.callApi(TRAVEL_API_URL + '/join', { travelId });
+ }
+
+ leaveTravel = (travelId: TravelId) => {
+ return this.callApi(TRAVEL_API_URL + '/leave', { travelId });
+ }
+
private callApi(
url: string,
params?: { [param: string]: any },
diff --git a/src/app/services/auth.service.ts b/src/app/services/auth.service.ts
index dae3189..432e743 100644
--- a/src/app/services/auth.service.ts
+++ b/src/app/services/auth.service.ts
@@ -34,18 +34,6 @@ export class AuthService {
return User.fromClaims(claims);
}
- canEditTravel(travel: Travel): boolean {
- if (travel == null) {
- return false;
- }
- const user = this.currentUser();
- if (user == null) {
- return false;
- }
-
- return user.admin || (user.id === travel.driverInfo.id);
- }
-
private async configureAndTryLogin(): Promise {
this.oauthService.configure(authConfig);
this.oauthService.setupAutomaticSilentRefresh();