Merge branch 'master' into julius-dev

master
trivernis 4 years ago
commit 68c9106a1a

@ -20,7 +20,7 @@
<table mat-table [dataSource]="levelSource" class="mat-elevation-z8">
<ng-container matColumnDef="level">
<th mat-header-cell *matHeaderCellDef> level</th>
<td mat-cell *matCellDef="let level"> {{level.level}} </td>
<td mat-cell *matCellDef="let level"> {{level.levelNumber}} </td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> level name</th>

@ -1,6 +1,6 @@
import {Component, OnInit, ViewChild} from '@angular/core';
import {Activitylist} from 'src/app/models/activity';
import {Levellist} from 'src/app/models/levellist';
import {LevelList} from 'src/app/models/levellist';
import {MatSort} from '@angular/material/sort';
import {MatTableDataSource} from '@angular/material/table';
import {ActivityService} from 'src/app/services/activity/activity.service';
@ -12,12 +12,12 @@ import {ActivityService} from 'src/app/services/activity/activity.service';
})
export class AboutComponent implements OnInit {
actionlist: Activitylist = new Activitylist();
levellist: Levellist = new Levellist();
levellist: LevelList = new LevelList();
displayedColumns = ['points', 'name', 'description'];
dataSource = new MatTableDataSource(this.actionlist.Actions);
displayedLevelColumns = ['level', 'name'];
levelSource = this.levellist.levels;
levelSource = new MatTableDataSource(this.levellist.levels);
constructor(private activityService: ActivityService) {
}
@ -31,6 +31,12 @@ export class AboutComponent implements OnInit {
this.dataSource = new MatTableDataSource(this.actionlist.Actions);
this.dataSource.sort = this.sort;
});
this.activityService.getLevels();
this.activityService.levelList.subscribe(response => {
this.levellist = response;
this.levelSource = new MatTableDataSource(this.levellist.levels);
this.levelSource.sort = this.sort;
});
}
}

@ -22,8 +22,9 @@
</div>
</div>
<mat-form-field class="input">
<textarea matInput #content type="text" (input)="onTextInputChange()" [(ngModel)]="textInputValue" [disabled]="posting"
<textarea matInput #content type="text" maxlength="2048" (input)="onTextInputChange()" [(ngModel)]="textInputValue" [disabled]="posting"
mat-autosize="true" matAutosizeMaxRows="3" placeholder="post something"></textarea>
<mat-hint align="end">{{content.value.length}} / 2048</mat-hint>
</mat-form-field>
<input style="display: none" id="fileInput" type="file" accept="video/*,image/*" (change)="onFileInputChange($event)" #fileInput>
<div class="input">

@ -1,6 +1,6 @@
import {Component, OnInit, ViewChild, ElementRef} from '@angular/core';
import {Post} from 'src/app/models/post';
import {FeedService, Sort} from 'src/app/services/feed/feed.service';
import {FeedService, Sort, PostingState} from 'src/app/services/feed/feed.service';
import {Activitylist} from 'src/app/models/activity';
import {DatasharingService} from '../../services/datasharing.service';
import {ActivityService} from 'src/app/services/activity/activity.service';
@ -63,10 +63,14 @@ export class FeedComponent implements OnInit {
this.feedService.postsAvailable.subscribe(available => {
this.loadingMostLiked = this.loadingNew = available;
});
this.feedService.posting.subscribe(posting => {
this.feedService.postingState.subscribe(postingState => {
const temp = this.posting;
this.posting = posting;
if (temp !== this.posting && !this.posting) {
this.posting = postingState.posting;
this.errorOccurred = postingState.errorOccured;
this.errorMessage = postingState.errorMessage;
if (!this.posting && this.posting !== temp && !postingState.errorOccured) {
this.resetPostInput();
}
});
@ -79,22 +83,9 @@ export class FeedComponent implements OnInit {
*/
createPost(postElement, activityId: string) {
if (postElement && activityId && this.checked) {
this.posting = true;
this.feedService.createPostActivity(postElement.value, activityId, this.file).subscribe(() => {
}, (error: IErrorResponse) => {
this.errorOccurred = true;
this.posting = false;
this.errorMessage = error.error.errors[0].message;
});
this.feedService.createPostActivity(postElement.value, activityId, this.file).subscribe();
} else if (postElement) {
this.posting = true;
this.feedService.createPost(postElement.value, this.file).subscribe((result) => {
}, (error: IErrorResponse) => {
console.log(error);
this.posting = false;
this.errorOccurred = true;
this.errorMessage = error.error.errors[0].message;
});
this.feedService.createPost(postElement.value, this.file).subscribe();
}
}

@ -1,16 +1,23 @@
<mat-card class="post" *ngFor="let post of childPostList" [class.selected]="post === selectedPost" tabindex="0">
<mat-card-header>
<div mat-card-avatar (click)="showUserProfile(this.post)">
<img class="profile-picture" [src]="post.author.profilePicture"/>
<img class="profile-picture" [src]="post.author.profilePicture" />
</div>
<div id="button-box">
<button mat-icon-button [matMenuTriggerFor]="menu" id="menu-button" *ngIf="post.deletable">
<button mat-icon-button [matMenuTriggerFor]="menu" id="menu-button" *ngIf="loggedIn">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="deletePost(post)">
<button *ngIf="post.deletable" mat-menu-item (click)="deletePost(post)">
<span>delete post</span>
</button>
<button mat-menu-item [matMenuTriggerFor]="reportMenu">report</button>
</mat-menu>
<mat-menu #reportMenu="matMenu">
<button *ngFor="let reason of reportReasons" mat-menu-item [matTooltip]="reason.description"
matTooltipShowDelay="200" (click)="reportPost(reason, post)">
{{reason.name}}
</button>
</mat-menu>
</div>
<mat-card-title>
@ -22,10 +29,11 @@
</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<mat-spinner *ngIf="post.mediaLoading && post.mediaType === 'IMAGE'" style="margin:0 auto; margin-top: 2em;" diameter="50"></mat-spinner>
<mat-spinner *ngIf="post.mediaLoading && post.mediaType === 'IMAGE'" style="margin:0 auto; margin-top: 2em;"
diameter="50"></mat-spinner>
<div class="postMedia">
<div [hidden]="post.mediaLoading">
<img *ngIf="post.mediaType === 'IMAGE'" [src]="post.mediaUrl" (load)="onLoad(this.post)" alt="post image"/>
<img *ngIf="post.mediaType === 'IMAGE'" [src]="post.mediaUrl" (load)="onLoad(this.post)" alt="post image" />
</div>
<video *ngIf="post.mediaType === 'VIDEO'" controls>
<source [src]="post.mediaUrl" type="video/webm">
@ -41,13 +49,17 @@
</div>
<div class="postVoteButtons">
<button mat-button (click)="voteUp(post)" matTooltip="vote up" matTooltipShowDelay="500">
<mat-icon class="voteButton voted" aria-hidden="false" color="primary" *ngIf="post.userVote == 'UPVOTE'">thumb_up</mat-icon>
<mat-icon class="voteButton" aria-hidden="false" *ngIf="!post.userVote || post.userVote == 'DOWNVOTE'">thumb_up</mat-icon>
<mat-icon class="voteButton voted" aria-hidden="false" color="primary" *ngIf="post.userVote == 'UPVOTE'">
thumb_up</mat-icon>
<mat-icon class="voteButton" aria-hidden="false" *ngIf="!post.userVote || post.userVote == 'DOWNVOTE'">thumb_up
</mat-icon>
</button>
<div class="voteCount">{{post.upvotes}}</div>
<button mat-button (click)="voteDown(post)" matTooltip="vote down" matTooltipShowDelay="500">
<mat-icon class="voteButton voted" aria-hidden="false" color="primary" *ngIf="post.userVote == 'DOWNVOTE'">thumb_down</mat-icon>
<mat-icon class="voteButton" aria-hidden="false" *ngIf="!post.userVote || post.userVote == 'UPVOTE'">thumb_down</mat-icon>
<mat-icon class="voteButton voted" aria-hidden="false" color="primary" *ngIf="post.userVote == 'DOWNVOTE'">
thumb_down</mat-icon>
<mat-icon class="voteButton" aria-hidden="false" *ngIf="!post.userVote || post.userVote == 'UPVOTE'">thumb_down
</mat-icon>
</button>
<div class="voteCount">{{post.downvotes}}</div>
</div>
@ -57,4 +69,4 @@
</span>
</div>
</mat-card-actions>
</mat-card>
</mat-card>

@ -1,7 +1,10 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {Post} from 'src/app/models/post';
import {FeedService} from 'src/app/services/feed/feed.service';
import {Router} from '@angular/router';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Post } from 'src/app/models/post';
import { FeedService } from 'src/app/services/feed/feed.service';
import { Router } from '@angular/router';
import { DatasharingService } from 'src/app/services/datasharing.service';
import { ActivityService } from 'src/app/services/activity/activity.service';
import { ReportReason } from 'src/app/models/reportReason';
@Component({
selector: 'feed-postlist',
@ -13,11 +16,23 @@ export class PostlistComponent implements OnInit {
@Input() childPostList: Post[];
@Output() voteEvent = new EventEmitter<boolean>();
selectedPost: Post;
loggedIn = false;
reportReasons: ReportReason[] = new Array();
constructor(private feedService: FeedService, private router: Router) {
constructor(private feedService: FeedService,
private data: DatasharingService,
private router: Router,
private activityService: ActivityService) {
}
ngOnInit() {
this.data.currentUser.subscribe(user => {
this.loggedIn = user.loggedIn;
});
this.activityService.getReportReasons();
this.activityService.reportReasonList.subscribe(response => {
this.reportReasons = response;
});
}
voteUp(pPost: Post) {
@ -49,6 +64,10 @@ export class PostlistComponent implements OnInit {
});
}
reportPost(reason: ReportReason, post: Post) {
this.feedService.reportPost(reason.id, post.id).subscribe();
}
onLoad(post: Post) {
post.mediaLoading = false;
}

@ -4,40 +4,30 @@
<mat-toolbar id="toolbar" fxShow="true" fxHide.gt-sm="true">
<mat-toolbar-row>
<div class="hover-box" matTooltip="upload new picture" *ngIf="isAdmin" (click)="openFileUploadDialog()">
<img class="profile-picture" [src]="groupProfile.picture"/>
<img class="profile-picture" [src]="groupProfile.picture" />
<mat-icon id="icon">camera_alt</mat-icon>
</div>
<div *ngIf="!isAdmin" (click)="openPfpLightbox()">
<img class="profile-picture" [src]="groupProfile.picture"/>
<img class="profile-picture" [src]="groupProfile.picture" />
</div>
<span id="username">{{groupProfile.name}}</span>
<div class="button-box">
<button mat-icon-button *ngIf="!groupProfile.joined"
class="request-button"
matTooltip="join group" matTooltipShowDelay="500"
(click)="joinGroup(groupProfile)"
[disabled]="!groupProfile.allowedToJoinGroup">
<button mat-icon-button *ngIf="!groupProfile.joined" class="request-button" matTooltip="join group"
matTooltipShowDelay="500" (click)="joinGroup(groupProfile)" [disabled]="!groupProfile.allowedToJoinGroup">
<mat-icon>group_add</mat-icon>
</button>
<button mat-icon-button *ngIf="groupProfile.joined"
class="request-button"
matTooltip="leave group" matTooltipShowDelay="500"
(click)="leaveGroup(groupProfile)">
<button mat-icon-button *ngIf="groupProfile.joined" class="request-button" matTooltip="leave group"
matTooltipShowDelay="500" (click)="leaveGroup(groupProfile)">
<mat-icon>directions_run</mat-icon>
</button>
<button mat-icon-button
class="request-button"
matTooltip="create event" matTooltipShowDelay="500"
(click)="openDialog()"
[disabled]="!isAdmin">
<button mat-icon-button class="request-button" matTooltip="create event" matTooltipShowDelay="500"
(click)="openDialog()" [disabled]="!isAdmin">
<mat-icon>event</mat-icon>
</button>
<div style="display: contents;" *ngIf="groupProfile.deletable">
<button mat-icon-button
class="request-button"
matTooltip="delete this group" matTooltipShowDelay="0"
(click)="deleteGroup()">
<button mat-icon-button class="request-button" matTooltip="delete this group" matTooltipShowDelay="0"
(click)="deleteGroup()">
<mat-icon>delete</mat-icon>
</button>
</div>
@ -45,8 +35,8 @@
</mat-toolbar-row>
<mat-toolbar-row>
<div class="info-box">
<span id="handle" class="pointer"
(click)="showUserProfile(groupProfile.creator)">created by {{groupProfile.creator.username}}
<span id="handle" class="pointer" (click)="showUserProfile(groupProfile.creator)">created by
{{groupProfile.creator.username}}
@{{groupProfile.creator.handle}}</span>
</div>
</mat-toolbar-row>
@ -60,42 +50,32 @@
<mat-toolbar id="toolbar" fxShow="true" fxHide.lt-md="true">
<mat-toolbar-row>
<div class="hover-box" matTooltip="upload new picture" *ngIf="isAdmin" (click)="openFileUploadDialog()">
<img class="profile-picture" [src]="groupProfile.picture"/>
<img class="profile-picture" [src]="groupProfile.picture" />
<mat-icon id="icon">camera_alt</mat-icon>
</div>
<div *ngIf="!isAdmin" (click)="openPfpLightbox()">
<img class="profile-picture" [src]="groupProfile.picture"/>
<img class="profile-picture" [src]="groupProfile.picture" />
</div>
<span id="username">{{groupProfile.name}}</span>
<span id="handle" class="pointer"
(click)="showUserProfile(groupProfile.creator)">created by {{groupProfile.creator.username}}
<span id="handle" class="pointer" (click)="showUserProfile(groupProfile.creator)">created by
{{groupProfile.creator.username}}
@{{groupProfile.creator.handle}}</span>
<div class="button-box">
<button mat-icon-button *ngIf="!groupProfile.joined"
class="request-button"
matTooltip="join group" matTooltipShowDelay="500"
(click)="joinGroup(groupProfile)"
[disabled]="!groupProfile.allowedToJoinGroup">
<button mat-icon-button *ngIf="!groupProfile.joined" class="request-button" matTooltip="join group"
matTooltipShowDelay="500" (click)="joinGroup(groupProfile)" [disabled]="!groupProfile.allowedToJoinGroup">
<mat-icon>group_add</mat-icon>
</button>
<button mat-icon-button *ngIf="groupProfile.joined"
class="request-button"
matTooltip="leave group" matTooltipShowDelay="500"
(click)="leaveGroup(groupProfile)">
<button mat-icon-button *ngIf="groupProfile.joined" class="request-button" matTooltip="leave group"
matTooltipShowDelay="500" (click)="leaveGroup(groupProfile)">
<mat-icon>directions_run</mat-icon>
</button>
<button mat-icon-button
class="request-button"
matTooltip="create event" matTooltipShowDelay="500"
(click)="openDialog()"
[disabled]="!isAdmin">
<button mat-icon-button class="request-button" matTooltip="create event" matTooltipShowDelay="500"
(click)="openDialog()" [disabled]="!isAdmin">
<mat-icon>event</mat-icon>
</button>
<div style="display: contents;" *ngIf="groupProfile.deletable">
<button mat-icon-button
class="request-button"
matTooltip="delete this group" matTooltipShowDelay="0"
(click)="deleteGroup()">
<button mat-icon-button class="request-button" matTooltip="delete this group" matTooltipShowDelay="0"
(click)="deleteGroup()">
<mat-icon>delete</mat-icon>
</button>
</div>
@ -116,24 +96,24 @@
</mat-panel-title>
</mat-expansion-panel-header>
<div class="list">
<mat-card class="card" *ngFor="let event of groupProfile.events"
[class.selected]="event === selectedEvent"
tabindex="0">
<mat-card class="card" *ngFor="let event of groupProfile.events" [class.selected]="event === selectedEvent"
tabindex="0">
<mat-card-header>
<mat-card-title>{{event.name}}</mat-card-title>
<mat-card-subtitle>{{event.date}}</mat-card-subtitle>
<div class="button-box">
<button *ngIf="!event.joined" mat-icon-button class="request-button"
matTooltip="join event" matTooltipShowDelay="500"
(click)="joinEvent(event)">
<button *ngIf="!event.joined" mat-icon-button class="request-button" matTooltip="join event"
matTooltipShowDelay="500" (click)="joinEvent(event)">
<mat-icon>event_available</mat-icon>
</button>
<button *ngIf="event.joined" mat-icon-button class="request-button"
matTooltip="leave event" matTooltipShowDelay="500"
(click)="leaveEvent(event)"
[disabled]="!event.joined">
<button *ngIf="event.joined" mat-icon-button class="request-button" matTooltip="leave event"
matTooltipShowDelay="500" (click)="leaveEvent(event)" [disabled]="!event.joined">
<mat-icon>event_busy</mat-icon>
</button>
<button *ngIf="event.deletable" mat-icon-button class="request-button" matTooltip="delete event"
matTooltipShowDelay="0" (click)="deleteEvent(event)">
<mat-icon>delete</mat-icon>
</button>
</div>
</mat-card-header>
</mat-card>
@ -145,8 +125,32 @@
Members
</mat-panel-title>
</mat-expansion-panel-header>
<div class="list">
<user-list [userList]="groupProfile.members"></user-list>
<div id="list">
<mat-card class="member-card" *ngFor="let user of groupProfile.members"
[class.selected]="user === selectedUser" tabindex="0">
<mat-card-header>
<div mat-card-avatar (click)="showUserProfile(user)">
<img class="card-picture" [src]="user.profilePicture" />
</div>
<mat-card-title class="pointer" (click)="showUserProfile(user)">{{user.username}}</mat-card-title>
<mat-card-subtitle class="pointer" (click)="showUserProfile(user)">{{user.handle}}</mat-card-subtitle>
<mat-card-subtitle hidden class="pointer" (click)="showUserProfile(user)">[admin]
</mat-card-subtitle>
<div id="icon-box" *ngIf="isCreator">
<button mat-icon-button [matMenuTriggerFor]="menu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button *ngIf="!user.isGroupAdmin" mat-menu-item (click)="addGroupAdmin(user)">
<span>give admin rights</span>
</button>
<button *ngIf="user.isGroupAdmin" mat-menu-item (click)="removeGroupAdmin(user)">
<span>revoke admin rights</span>
</button>
</mat-menu>
</div>
</mat-card-header>
</mat-card>
</div>
</mat-expansion-panel>
</mat-accordion>
@ -156,5 +160,4 @@
<h1>Group not found :(</h1>
</div>
<mat-spinner *ngIf="loading" style="margin:0 auto; margin-top: 10em;" diameter="100"></mat-spinner>
</div>
</div>

@ -107,13 +107,63 @@ $mat-card-header-size: 100px !default
margin-top: 0.5em
margin-bottom: 0.5em
.profile-picture
background-image: url(https://material.angular.io/assets/img/examples/shiba1.jpg)
background-size: cover
.profile-picture:hover
cursor: pointer
$mat-card-header-size-small: 54px !default
.profile-picture-small
height: $mat-card-header-size-small
width: $mat-card-header-size-small
border-radius: 50%
flex-shrink: 0
background-size: cover
transition-duration: 0.5s
z-index: 10
object-fit: cover
.member-card
box-sizing: border-box
width: 100%
margin-top: 0.5em
outline: none
user-select: none
::ng-deep .mat-card-header-text
width: 1000%
margin: auto 0 auto 24px
.mat-card-subtitle
margin: 0
word-break: break-all
.mat-card-title
margin: 0
word-break: break-all
.request-button
margin-top: 0.5em
margin-bottom: 0.5em
.pointer:hover
cursor: pointer
.icon-box
text-align: right
width: 100%
$pic-size: 40px !default
.card-picture
cursor: pointer
height: $pic-size
width: $pic-size
border-radius: 50%
flex-shrink: 0
background-size: cover
transition-duration: 0.5s
z-index: 10
object-fit: cover
.pointer
cursor: pointer

@ -1,15 +1,15 @@
import {Component, OnInit, ViewChild} from '@angular/core';
import {Data, NavigationEnd, Router} from '@angular/router';
import {User} from 'src/app/models/user';
import {MatSort} from '@angular/material/sort';
import {RequestService} from 'src/app/services/request/request.service';
import {DatasharingService} from '../../services/datasharing.service';
import {GroupService} from 'src/app/services/group/group.service';
import {Group} from 'src/app/models/group';
import {Event} from 'src/app/models/event';
import {MatDialog, MatDialogRef} from '@angular/material/dialog';
import {DialogGroupFileUploadComponent} from './fileUpload/fileUpload.component';
import {Lightbox} from 'ngx-lightbox';
import { Component, OnInit, ViewChild } from '@angular/core';
import { Data, NavigationEnd, Router } from '@angular/router';
import { User } from 'src/app/models/user';
import { MatSort } from '@angular/material/sort';
import { RequestService } from 'src/app/services/request/request.service';
import { DatasharingService } from '../../services/datasharing.service';
import { GroupService } from 'src/app/services/group/group.service';
import { Group } from 'src/app/models/group';
import { Event } from 'src/app/models/event';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { DialogGroupFileUploadComponent } from './fileUpload/fileUpload.component';
import { Lightbox } from 'ngx-lightbox';
// DIALOG COMPONENT to create events
@Component({
@ -76,6 +76,7 @@ export class GroupComponent implements OnInit {
self: User;
id: string;
isAdmin = false;
isCreator = false;
groupNotFound = false;
loading = false;
@ -100,7 +101,7 @@ export class GroupComponent implements OnInit {
});
}
@ViewChild(MatSort, {static: true}) sort: MatSort;
@ViewChild(MatSort, { static: true }) sort: MatSort;
ngOnInit() {
this.loading = true;
@ -120,6 +121,11 @@ export class GroupComponent implements OnInit {
this.isAdmin = true;
}
}
if (this.groupProfile.creator.userID === this.self.userID) {
this.isCreator = true;
} else {
this.isCreator = false;
}
for (const member of this.groupProfile.members) {
member.allowedToSendRequest = this.requestService.isAllowedToSendRequest(member.userID, this.self);
}
@ -174,6 +180,10 @@ export class GroupComponent implements OnInit {
});
}
public deleteEvent(event: Event) {
this.groupService.deleteEvent(event.id).subscribe();
}
public showUserProfile(user: User) {
this.router.navigate(['profile/' + user.userID]);
}
@ -185,9 +195,9 @@ export class GroupComponent implements OnInit {
private deleteGroup() {
this.groupService.deleteGroup(this.groupProfile.id)
.subscribe(response => {
this.router.navigateByUrl('');
});
.subscribe(response => {
this.router.navigateByUrl('');
});
}
leaveGroup() {
@ -198,11 +208,23 @@ export class GroupComponent implements OnInit {
});
}
addGroupAdmin(user: User) {
this.groupService.addGroupAdmin(user.userID.toString(), this.id).subscribe(response => {
user.isGroupAdmin = true;
});
}
removeGroupAdmin(user: User) {
this.groupService.removeGroupAdmin(user.userID.toString(), this.id).subscribe(response => {
user.isGroupAdmin = false;
});
}
openPfpLightbox() {
this.lightbox.open([{
src: this.groupProfile.picture,
thumb: this.groupProfile.picture,
}], 0, {disableScrolling: true});
}], 0, { disableScrolling: true });
}
}

@ -1,6 +1,147 @@
<mat-toolbar>Imprint</mat-toolbar>
<div id="imprint">
<p>The greenvironment network is being developed by the greenvironment team</p>
<h2>Contact</h2>
<p>Email: nick.derkoenig@greenvironment.net</p>
<mat-toolbar>Imprint</mat-toolbar>
<div id="text-box">
<h1 id="privacy-policy">Privacy Policy</h1>
<p>Last updated: January 22, 2020</p>
<p>This Privacy Policy describes Our policies and procedures on the collection, use and disclosure of Your information
when You use the Service and tells You about Your privacy rights and how the law protects You.</p>
<h1 id="interpretation-and-definitions">Interpretation and Definitions</h1>
<h2 id="interpretation">Interpretation</h2>
<p>The words of which the initial letter is capitalized have meanings defined under the following conditions.</p>
<p>The following definitions shall have the same meaning regardless of whether they appear in singular or in plural.
</p>
<h2 id="definitions">Definitions</h2>
<p>For the purposes of this Privacy Policy:</p>
<ul>
<li>
<p><strong>You</strong> means the individual accessing or using the Service, or We, or other legal entity on
behalf of which such individual is accessing or using the Service, as applicable.</p>
</li>
<li>
<p><strong>Team Greenvironment</strong> (referred to as either &quot;Team Greenvironment&quot;, &quot;We&quot;,
&quot;Us&quot; or &quot;Our&quot; in this Agreement) refers to the Greenvironment team.</p>
</li>
<li>
<p><strong>Account</strong> means a unique account created for You to access our Service or parts of our Service.
</p>
</li>
<li>
<p><strong>Website</strong> refers to Greenvironment, accessible from <a
href="https://greenvironment.net/">https://greenvironment.net/</a></p>
</li>
<li>
<p><strong>Service</strong> refers to the Website.</p>
</li>
<li>
<p><strong>Third-party Social Media Service</strong> refers to any website or any social network website through
which a User can log in or create an account to use the Service.</p>
</li>
<li>
<p><strong>Personal Data</strong> is any information that relates to an identified or identifiable individual.</p>
</li>
<li>
<p><strong>Cookies</strong> are small files that are placed on Your computer, mobile device or any other device by
a website, containing the details of Your browsing history on that website among its many uses.</p>
</li>
<li>
<p><strong>Usage Data</strong> refers to data collected automatically, either generated by the use of the Service
or from the Service infrastructure itself (for example, the duration of a page visit).</p>
</li>
</ul>
<h1 id="collecting-and-using-your-personal-data">Collecting and Using Your Personal Data</h1>
<h2 id="types-of-data-collected">Types of Data Collected</h2>
<h3 id="account-data">Account Data</h3>
<p>While using Our Service, We may ask You to provide Us with certain personally identifiable information that will be
saved to your account:</p>
<h4 id="email-address">Email Address</h4>
<p>To identify a unique user as a human and to provide a way to log in.</p>
<h4 id="password">Password</h4>
<p>To provide a secured access to your account. It will only be saved as a hashed value.</p>
<h4 id="username">Username</h4>
<p>The display name of the user as a human friendly way of representation.</p>
<h4 id="handle">Handle</h4>
<p>A unique username that can be used for identification.</p>
<h4 id="posts">Posts</h4>
<p>Collected to display them to other users.</p>
<h4 id="votes">Votes</h4>
<p>The Upvote or Downvote performed on a post to display the sum of votes all users performed.</p>
<h4 id="profile-pictures">Profile Pictures</h4>
<p>A way to enhance the users profile. Stored public accessible on the server.</p>
<h4 id="invites">Invites</h4>
<p>Only visible to the user who was addressed.</p>
<h4 id="friends">Friends</h4>
<p>Only the User and his friend can see that they are friends.The data will be deleted after the friendship is
canceled.</p>
<h4 id="rang-points-and-rang">Rang points and rang</h4>
<p>Collected to show other user how good the user helped to protect the environment. Rang and rang points are visible
to all users.</p>
<h4 id="groupsevents">Groups/Events</h4>
<p>The date is used to assign the user to groups and events. Collected to show them to other group- /Event- members.
</p>
<h4 id="chatroom">Chatroom</h4>
<p>The member are showed to each others.</p>
<h4 id="chat-messages">Chat Messages</h4>
<p>Stored in plain text in the database. The message is visible to all other group members even if the user left the
group</p>
<h3 id="cookies">Cookies</h3>
<p>We use Cookies to save the session of the user. So if the user visits Greenvironment the next time he is already
logged in. You can instruct your browser to refuse all Cookies or to indicate when a Cookie is being saved. However,
if ou do not accept Cookies, You may not be able to use some parts of our Service.</p>
<h2 id="use-of-your-personal-data">Use of Your Personal Data</h2>
<p>Your Personal Data will be used for the following purposes:</p>
<ul>
<li><strong>To manage Your Account:</strong> to manage Your registration as a user of the Service. The Personal Data
You provide can give You access to different functionalities of the Service that are available to You as a
registered user.</li>
<li><strong>To contact You:</strong> To contact You by email.</li>
</ul>
<h2 id="retention-of-your-personal-data">Retention of Your Personal Data</h2>
<p>We will retain Your Personal Data only for as long as is necessary for the purposes set out in this Privacy Policy.
We will retain and use Your Personal Data to the extent necessary to comply with our legal obligations (for example,
if we are required to retain your data to comply with applicable laws), resolve disputes, and enforce our legal
agreements and policies.</p>
<h2 id="transfer-of-your-personal-data">Transfer of Your Personal Data</h2>
<p>Your information, including Personal Data, is processed at Our operating offices and in any other places where the
parties involved in the processing are located. It means that this information may be transferred to — and
maintained on — computers located outside of Your state, province, country or other governmental jurisdiction where
the data protection laws may differ than those from Your jurisdiction.</p>
<p>Your consent to this Privacy Policy followed by Your submission of such information represents Your agreement to
that transfer.</p>
<p>We will take all steps reasonably necessary to ensure that Your data is treated securely and in accordance with
this Privacy Policy and no transfer of Your Personal Data will take place to an organization or a country unless
there are adequate controls in place including the security of Your data and other personal information.</p>
<h2 id="disclosure-of-your-personal-data">Disclosure of Your Personal Data</h2>
<h3 id="other-legal-requirements">Other legal requirements</h3>
<p>We may disclose Your Personal Data in the good faith belief that such action is necessary to:</p>
<ul>
<li>Comply with a legal obligation</li>
<li>Protect and defend the rights or property of the Greenvironment Team</li>
<li>Prevent or investigate possible wrongdoing in connection with the Service</li>
<li>Protect the personal safety of Users of the Service or the public</li>
<li>Protect against legal liability</li>
</ul>
<h2 id="security-of-your-personal-data">Security of Your Personal Data</h2>
<p>The security of Your Personal Data is important to Us, but remember that no method of transmission over the
Internet, or method of electronic storage is 100% secure. While We strive to use technical acceptable means to
protect Your Personal Data, We cannot guarantee its absolute security.</p>
<h1 id="links-to-other-websites">Links to Other Websites</h1>
<p>Our Service may contain links to other websites that are not operated by Us. If You click on a third party link,
You will be directed to that third party's site. We strongly advise You to review the Privacy Policy of every site
You visit.</p>
<p>We have no control over and assume no responsibility for the content, privacy policies or practices of any third
party sites or services.</p>
<h1 id="changes-to-this-privacy-policy">Changes to this Privacy Policy</h1>
<p>We may update our Privacy Policy from time to time. We will notify You of any changes by posting the new Privacy
Policy on this page.</p>
<p>We will let You know via email and/or a prominent notice on Our Service, prior to the change becoming effective and
update the &quot;Last updated&quot; date at the top of this Privacy Policy.</p>
<p>You are advised to review this Privacy Policy periodically for any changes. Changes to this Privacy Policy are
effective when they are posted on this page.</p>
<h1 id="contact-us">Contact Us</h1>
<p>If you have any questions about this Privacy Policy, You can contact us:</p>
<ul>
<li>By email: <a href="mailto:greenvironment@hotmail.com">greenvironment@hotmail.com</a></li>
</ul>
</div>
</div>

@ -3,12 +3,18 @@
#imprint
padding: 2em
max-width: 35em
position: fixed
width: 100%
height: calc(100% - 56px)
overflow: scroll
#text-box
margin: 0 auto
max-width: 800px
padding: 2em
::ng-deep a
color: $primary-color
h1.mat-display-1
margin: 0

@ -4,7 +4,6 @@ import {DatasharingService} from '../../services/datasharing.service';
import {RequestService} from '../../services/request/request.service';
import {SettingsService} from '../../services/settings/settings.service';
import {environment} from 'src/environments/environment';
import {Levellist} from 'src/app/models/levellist';
import {Router} from '@angular/router';
import {User} from 'src/app/models/user';
import {OverlayContainer} from '@angular/cdk/overlay';
@ -33,7 +32,6 @@ export class MainNavigationComponent implements OnInit {
userId: number;
username: string;
user: User;
levellist: Levellist = new Levellist();
level: string;
points: number;
profileUrl = '/profile/1';

@ -1,7 +1,7 @@
import {Component, OnInit} from '@angular/core';
import {NavigationEnd, Router} from '@angular/router';
import {User} from 'src/app/models/user';
import {Levellist} from 'src/app/models/levellist';
import {LevelList} from 'src/app/models/levellist';
import {RequestService} from 'src/app/services/request/request.service';
import {DatasharingService} from '../../services/datasharing.service';
import {ProfileService} from 'src/app/services/profile/profile.service';
@ -18,7 +18,7 @@ import {Lightbox} from 'ngx-lightbox';
styleUrls: ['./profile.component.sass']
})
export class ProfileComponent implements OnInit {
levellist: Levellist = new Levellist();
levellist: LevelList = new LevelList();
ownProfile = false;
userProfile: User = new User();
self: User;

@ -28,6 +28,14 @@
</button>
</mat-form-field>
</div>
<p class="check-box">
<mat-checkbox color="primary" [(ngModel)]="ageCheck" >I am older than 16 years.
</mat-checkbox>
</p>
<p class="check-box">
<mat-checkbox color="primary" [(ngModel)]="imprintCheck">I've read the <a routerLink="/imprint">privacy policy</a>.
</mat-checkbox>
</p>
<button mat-raised-button color="primary"
(click)="onClickSubmit(username.value,email.value,password.value, repeatpassword.value)">Register
</button>

@ -5,6 +5,8 @@
padding: 2em
max-width: 35em
margin: 0 auto
::ng-deep a
color: $primary-color
.example-container
display: flex
@ -26,6 +28,10 @@ input.example-right-align
.mat-error
margin-bottom: 0.25em
.check-box
float: left
margin-right: 1em
.mat-raised-button
margin: 0.25em
width: 100%

@ -14,6 +14,8 @@ export class RegisterComponent implements OnInit {
errorMessage: string;
hide1 = true;
hide2 = true;
ageCheck = false;
imprintCheck = false;
constructor(private registerService: RegisterService) {
this.registration = {username: null, passwordHash: null, email: null};
@ -28,7 +30,7 @@ export class RegisterComponent implements OnInit {
onClickSubmit(pUsername: string, pEmail: string, pPasswordHash: string, pPasswordHashRepeat: string) {
this.errorOccurred = false;
this.errorMessage = ' ';
if (this.passwordSame(pPasswordHash, pPasswordHashRepeat)) {
if (this.passwordSame(pPasswordHash, pPasswordHashRepeat) && this.boxesChecked()) {
this.registration.username = pUsername.trim();
this.registration.email = pEmail.trim().toLowerCase();
this.registration.passwordHash = sha512.sha512(pPasswordHash);
@ -38,7 +40,6 @@ export class RegisterComponent implements OnInit {
passwordSame(pwd: string, pwd2: string) {
if (pwd === pwd2) {
console.log('password same');
return true;
} else {
this.errorOccurred = true;
@ -47,6 +48,21 @@ export class RegisterComponent implements OnInit {
}
}
boxesChecked(): boolean {
if (this.imprintCheck && this.ageCheck) {
console.log('all boxes checked');
return true;
} else {
this.errorOccurred = true;
if (!this.ageCheck) {
this.errorMessage = 'You have to confirm your age.';
} else if (!this.imprintCheck) {
this.errorMessage = 'You have to confirm that you read the privacy policy.';
}
return false;
}
}
ngOnInit() {
}

@ -1,10 +1,11 @@
import {IEvent} from './interfaces/IEvent';
import { IEvent } from './interfaces/IEvent';
export class Event {
id: string;
name: string;
date: string;
joined: boolean;
deletable: boolean;
public assignFromResponse(eventDataResponse: IEvent) {
this.id = eventDataResponse.id;
@ -12,6 +13,7 @@ export class Event {
const temp = new Date(Number(eventDataResponse.dueDate));
this.date = temp.toLocaleString('en-GB');
this.joined = eventDataResponse.joined;
this.deletable = eventDataResponse.deletable;
return this;
}

@ -1,5 +1,3 @@
import {Levellist} from 'src/app/models/levellist';
export class FriendInfo {
id: number;
name: string;

@ -1,7 +1,8 @@
import {User} from 'src/app/models/user';
import {Event} from 'src/app/models/event';
import {IGroup} from './interfaces/IGroup';
import {environment} from 'src/environments/environment';
import { User } from 'src/app/models/user';
import { Event } from 'src/app/models/event';
import { IGroup } from './interfaces/IGroup';
import { environment } from 'src/environments/environment';
import { IUser } from './interfaces/IUser';
export class Group {
id: number;
@ -32,10 +33,7 @@ export class Group {
}
}
if (groupDataResponse.admins) {
for (const admin of groupDataResponse.admins) {
user = new User();
this.admins.push(user.assignFromResponse(admin));
}
this.updateAdmins(groupDataResponse.admins);
}
if (groupDataResponse.events) {
for (const event of groupDataResponse.events) {
@ -48,6 +46,21 @@ export class Group {
return this;
}
public updateAdmins(admins: IUser[]) {
this.admins = [];
for (const admin of admins) {
const user = new User();
this.admins.push(user.assignFromResponse(admin));
}
for (const admin of this.admins) {
for (const member of this.members) {
if (member.userID === admin.userID) {
member.isGroupAdmin = true;
}
}
}
}
buildPictureUrl(path: string): string {
if (path) {
return environment.greenvironmentUrl + path;

@ -7,4 +7,6 @@ export interface IEvent {
dueDate: string;
joined: boolean;
deletable: boolean;
}

@ -1,23 +1,27 @@
export class Levellist {
levels: { level: number, name: string, points: number }[] = [
{level: 0, name: 'Green Horn', points: 0},
{level: 1, name: 'Good Willed', points: 100},
{level: 2, name: 'Helper', points: 200},
{level: 3, name: 'World Saver', points: 300},
{level: 4, name: 'Hero of the Green Country', points: 400},
{level: 5, name: 'Champion of the Earth', points: 500},
{level: 6, name: 'Intergallactic Superhero', points: 600},
];
export class Level {
id: number;
name: string;
levelNumber: number;
points: number;
getLevelName(level: number): any {
let name = 'not defined';
constructor(id: number, name: string, levelNumber: number, points: number) {
this.id = id;
this.name = name;
this.levelNumber = levelNumber;
this.points = points;
}
}
export class LevelList {
levels: Level[] = [];
getLevelName(level: number): string {
let name = 'not defined';
for (const rank of this.levels) {
if (level === rank.level) {
if (level === rank.levelNumber) {
name = rank.name;
}
}
return name;
}
}

@ -0,0 +1,11 @@
export class ReportReason {
id: number;
name: string;
description: string;
constructor(id: number, name: string, describtion: string) {
this.id = id;
this.name = name;
this.description = describtion;
}
}

@ -1,9 +1,9 @@
import {FriendRequest} from 'src/app/models/friendRequest';
import {FriendInfo} from 'src/app/models/friendinfo';
import {GroupInfo} from 'src/app/models/groupinfo';
import {Post} from 'src/app/models/post';
import {IUser} from './interfaces/IUser';
import {environment} from 'src/environments/environment';
import { FriendRequest } from 'src/app/models/friendRequest';
import { FriendInfo } from 'src/app/models/friendinfo';
import { GroupInfo } from 'src/app/models/groupinfo';
import { Post } from 'src/app/models/post';
import { IUser } from './interfaces/IUser';
import { environment } from 'src/environments/environment';
export class User {
loggedIn = false;
@ -19,6 +19,7 @@ export class User {
friendCount: number;
groupCount: number;
isAdmin: boolean = false;
isGroupAdmin: boolean;
darkmode = false;

@ -1,18 +1,51 @@
import {Injectable} from '@angular/core';
import {BehaviorSubject} from 'rxjs';
import {Activity, Activitylist} from 'src/app/models/activity';
import {environment} from 'src/environments/environment';
import {Http} from '@angular/http';
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { Activity, Activitylist } from 'src/app/models/activity';
import { Level, LevelList } from 'src/app/models/levellist';
import { ReportReason } from 'src/app/models/reportReason';
import { environment } from 'src/environments/environment';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { BaseService } from '../base.service';
@Injectable({
providedIn: 'root'
})
export class ActivityService {
export class ActivityService extends BaseService {
public activitylist = new BehaviorSubject<Activitylist>(new Activitylist());
public levelList = new BehaviorSubject<LevelList>(new LevelList());
public reportReasonList = new BehaviorSubject<ReportReason[]>(new Array());
constructor(private http: Http) {
constructor(http: HttpClient) {
super(http);
}
private static buildGetActivityBody(): any {
const body = {
query: `query{getActivities{
id name description points
}}`, variables: {}
};
return body;
}
private static buildGetLevelsBody(): any {
const body = {
query: `query{getLevels{
id name levelNumber points
}}`, variables: {}
};
return body;
}
private static buildGetReportReasonsBody(): any {
const body = {
query: `query{getReportReasons {
id name description
}}`, variables: {}
};
return body;
}
changeUserInfo(pActivitylist: Activitylist) {
@ -21,22 +54,35 @@ export class ActivityService {
public getActivities() {
if (this.activitylist.getValue().Actions.length < 1) {
const headers = new Headers();
headers.set('Content-Type', 'application/json');
this.http.post(environment.graphQLUrl, this.buildJson()).subscribe(result => {
// push onto subject
this.activitylist.next(this.renderActivity(result.json()));
});
this.http.post(environment.graphQLUrl, ActivityService.buildGetActivityBody(), { headers: this.headers })
.pipe(this.retryRated())
.subscribe(result => {
// push onto subject
this.activitylist.next(this.renderActivity(result));
});
}
}
public buildJson(): any {
const body = {
query: `query{getActivities{
id name description points
}}`, variables: {}
};
return body;
public getLevels() {
if (this.levelList.getValue().levels.length < 1) {
this.http.post(environment.graphQLUrl, ActivityService.buildGetLevelsBody(), { headers: this.headers })
.pipe(this.retryRated())
.subscribe(result => {
// push onto subject
this.levelList.next(this.renderLevels(result));
});
}
}
public getReportReasons() {
if (this.reportReasonList.getValue().length < 1) {
this.http.post(environment.graphQLUrl, ActivityService.buildGetReportReasonsBody(), { headers: this.headers })
.pipe(this.retryRated())
.subscribe(result => {
// push onto subject
this.reportReasonList.next(this.renderReportReasons(result));
});
}
}
public renderActivity(response: any): Activitylist {
@ -50,5 +96,28 @@ export class ActivityService {
}
return activitylist;
}
public renderLevels(response: any): LevelList {
const levelList = new LevelList();
for (const level of response.data.getLevels) {
levelList.levels.push(new Level(
level.id,
level.name,
level.levelNumber,
level.points));
}
return levelList;
}
public renderReportReasons(response: any): ReportReason[] {
const reportReasons: ReportReason[] = new Array();
for (const reason of response.data.getReportReasons) {
reportReasons.push(new ReportReason(
reason.id,
reason.name,
reason.description));
}
return reportReasons;
}
}

@ -1,14 +1,15 @@
import {Injectable} from '@angular/core';
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import {Post} from 'src/app/models/post';
import {Author} from 'src/app/models/author';
import {environment} from 'src/environments/environment';
import {Activity} from 'src/app/models/activity';
import {BehaviorSubject, Observable} from 'rxjs';
import {tap} from 'rxjs/operators';
import {BaseService} from '../base.service';
import {formatDate} from '@angular/common';
import {IFileUploadResult} from '../../models/interfaces/IFileUploadResult';
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Post } from 'src/app/models/post';
import { Author } from 'src/app/models/author';
import { environment } from 'src/environments/environment';
import { Activity } from 'src/app/models/activity';
import { BehaviorSubject, Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { BaseService } from '../base.service';
import { formatDate } from '@angular/common';
import { IFileUploadResult } from '../../models/interfaces/IFileUploadResult';
import { IErrorResponse } from 'src/app/models/interfaces/IErrorResponse';
const createPostGqlQuery = `mutation($content: String!, $type: PostType) {
createPost(content: $content, type: $type) {
@ -70,6 +71,12 @@ const downvotePostGqlQuery = `mutation($postId: ID!) {
}
}`;
const reportPostGqlQuery = `mutation($reasonId: ID!, $postId: ID!) {
reportPost(postId: $postId, reasonId: $reasonId) {
id
}
}`;
const getPostsGqlQuery = `query($first: Int, $offset: Int, $sort: SortType){
getPosts (first: $first, offset: $offset, sort: $sort) {
id,
@ -98,6 +105,11 @@ export enum Sort {
NEW = 'NEW',
TOP = 'TOP',
}
export class PostingState {
posting = false;
errorOccured = false;
errorMessage = 'An error occured.';
}
@Injectable({
providedIn: 'root'
@ -109,7 +121,7 @@ export class FeedService extends BaseService {
}
public postsAvailable = new BehaviorSubject<boolean>(true);
public posting = new BehaviorSubject<boolean>(false);
public postingState = new BehaviorSubject<PostingState>(new PostingState());
public posts: BehaviorSubject<Post[]> = new BehaviorSubject([]);
private activePostList: Sort = Sort.NEW;
private offset = 0;
@ -187,41 +199,73 @@ export class FeedService extends BaseService {
* @param file - a file that is being uploaded with the post
*/
private createPostRequest(body: { variables: any; query: string }, file?: File) {
this.posting.next(true);
this.setPostingState(true);
if (file) {
return this.postGraphql(body, null, 0)
.pipe(tap(response => {
const updatedPosts = this.posts.getValue();
const post = this.constructPost(response);
this.uploadPostImage(post.id, file).subscribe((result) => {
if (this.activePostList === Sort.NEW) {
post.mediaUrl = result.fileName;
post.mediaType = result.fileName.endsWith('.png') ? 'IMAGE' : 'VIDEO';
updatedPosts.unshift(post);
this.posts.next(updatedPosts);
this.posting.next(false);
}
.pipe(tap(response => {
const updatedPosts = this.posts.getValue();
const post = this.constructPost(response);
this.uploadPostImage(post.id, file).subscribe((result) => {
if (result.success) {
if (this.activePostList === Sort.NEW) {
post.mediaUrl = result.fileName;
post.mediaType = result.fileName.endsWith('.png') ? 'IMAGE' : 'VIDEO';
updatedPosts.unshift(post);
this.posts.next(updatedPosts);
this.setPostingState(false);
}
} else {
console.error(result.error);
this.setPostingError(result.error);
this.deletePost(post.id).subscribe();
}
}, error => {
console.error(error);
this.posting.next(false);
this.deletePost(post.id);
this.setPostingError(error);
this.deletePost(post.id).subscribe();
});
}, (error: IErrorResponse) => {
this.setPostingError(error.error.errors[0].message);
}
));
));
} else if (!file) {
return this.postGraphql(body, null, 0)
.pipe(tap(response => {
this.posting.next(false);
const updatedPosts = this.posts.getValue();
if (this.activePostList === Sort.NEW) {
const post = this.constructPost(response);
updatedPosts.unshift(post);
this.posts.next(updatedPosts);
}
}));
.pipe(tap(response => {
this.setPostingState(false);
const updatedPosts = this.posts.getValue();
if (this.activePostList === Sort.NEW) {
const post = this.constructPost(response);
updatedPosts.unshift(post);
this.posts.next(updatedPosts);
}
}, (error: IErrorResponse) => {
console.log(error);
this.setPostingError(error.error.errors[0].message);
}));
}
}
setPostingState(b: boolean) {
if (b) {
this.postingState.getValue().posting = true;
this.postingState.getValue().errorOccured = false;
this.postingState.getValue().errorMessage = '';
this.postingState.next(this.postingState.getValue());
} else {
this.postingState.getValue().posting = false;
this.postingState.getValue().errorOccured = false;
this.postingState.getValue().errorMessage = '';
this.postingState.next(this.postingState.getValue());
}
}
setPostingError(error: string) {
this.postingState.getValue().posting = false;
this.postingState.getValue().errorOccured = true;
this.postingState.getValue().errorMessage = error;
this.postingState.next(this.postingState.getValue());
}
/**
* Uploads a file for a post
* @param postId
@ -262,6 +306,22 @@ export class FeedService extends BaseService {
return this.postGraphql(body);
}
/**
* reports a post
* @param postId
* @param reasonId
*/
public reportPost(reasonId: number, postId: number): any {
const body = {
query: reportPostGqlQuery, variables: {
postId,
reasonId
}
};
return this.postGraphql(body);
}
/**
* Deletes a post
* @param pPostID
@ -274,7 +334,7 @@ export class FeedService extends BaseService {
postId: pPostID
}
};
return this.http.post(environment.graphQLUrl, body, {headers: this.headers})
return this.http.post(environment.graphQLUrl, body, { headers: this.headers })
.pipe(this.retryRated());
}
@ -287,7 +347,7 @@ export class FeedService extends BaseService {
this.postsAvailable.next(true);
this.posts.next([]);
return this.http.post(environment.graphQLUrl, FeedService.buildGetPostBody(sort, 0),
{headers: this.headers})
{ headers: this.headers })
.pipe(this.retryRated())
.subscribe(response => {
this.posts.next(this.constructAllPosts(response.data.getPosts));
@ -301,7 +361,7 @@ export class FeedService extends BaseService {
public getNextPosts() {
this.offset += this.offsetStep;
const body = FeedService.buildGetPostBody(this.activePostList, this.offset);
this.http.post(environment.graphQLUrl, body, {headers: this.headers})
this.http.post(environment.graphQLUrl, body, { headers: this.headers })
.pipe(this.retryRated())
.subscribe(response => {
const posts = this.constructAllPosts(response.data.getPosts);

@ -1,14 +1,14 @@
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {environment} from 'src/environments/environment';
import {User} from 'src/app/models/user';
import {Event} from 'src/app/models/event';
import {BehaviorSubject} from 'rxjs';
import {Group} from 'src/app/models/group';
import {tap} from 'rxjs/operators';
import {BaseService} from '../base.service';
import {IFileUploadResult} from '../../models/interfaces/IFileUploadResult';
import {DatasharingService} from 'src/app/services/datasharing.service';
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from 'src/environments/environment';
import { User } from 'src/app/models/user';
import { Event } from 'src/app/models/event';
import { BehaviorSubject } from 'rxjs';
import { Group } from 'src/app/models/group';
import { tap } from 'rxjs/operators';
import { BaseService } from '../base.service';
import { IFileUploadResult } from '../../models/interfaces/IFileUploadResult';
import { DatasharingService } from 'src/app/services/datasharing.service';
const getGroupGraphqlQuery = `query($groupId: ID!) {
getGroup(groupId:$groupId){
@ -20,7 +20,7 @@ const getGroupGraphqlQuery = `query($groupId: ID!) {
creator{id name handle}
admins{id name handle}
members{id name handle profilePicture}
events{id name dueDate joined}
events{id name dueDate joined deletable}
}
}`;
@ -40,14 +40,14 @@ export class GroupService extends BaseService {
*/
private static buildGetGroupBody(id: string): any {
return {
query: getGroupGraphqlQuery, variables: {groupId: id}
query: getGroupGraphqlQuery, variables: { groupId: id }
};
}
public getGroupData(groupId: string) {
const url = environment.graphQLUrl;
return this.http.post(url, GroupService.buildGetGroupBody(groupId), {headers: this.headers})
return this.http.post(url, GroupService.buildGetGroupBody(groupId), { headers: this.headers })
.pipe(this.retryRated())
.pipe(tap(response => {
const group_ = new Group();
@ -64,6 +64,7 @@ export class GroupService extends BaseService {
name
dueDate
joined
deletable
}
}`, variables: {
name: name,
@ -73,13 +74,58 @@ export class GroupService extends BaseService {
};
return this.postGraphql(body, null, 0)
.pipe(tap(response => {
const event = new Event();
event.assignFromResponse(response.data.createEvent);
const group = this.group.getValue();
group.events.push(event);
this.group.next(group);
}));
.pipe(tap(response => {
const event = new Event();
event.assignFromResponse(response.data.createEvent);
const group = this.group.getValue();
group.events.push(event);
this.group.next(group);
}));
}
public addGroupAdmin(userId: string, groupId: string) {
const body = {
query: `mutation($groupId: ID!, $userId: ID!) {
addGroupAdmin(groupId: $groupId, userId: $userId) {
admins{id name handle}
}
}`, variables: {
userId,
groupId
}
};
const group = this.group.getValue();
group.admins = [];
this.group.next(group);
return this.postGraphql(body, null, 0)
.pipe(tap(response => {
const group = this.group.getValue();
group.updateAdmins(response.data.addGroupAdmin.admins);
this.group.next(group);
}));
}
public removeGroupAdmin(userId: string, groupId: string) {
const body = {
query: `mutation($groupId: ID!, $userId: ID!) {
removeGroupAdmin(groupId: $groupId, userId: $userId) {
admins{id name handle}
}
}`, variables: {
userId,
groupId
}
};
const group = this.group.getValue();
group.admins = [];
this.group.next(group);
return this.postGraphql(body, null, 0)
.pipe(tap(response => {
const group = this.group.getValue();
group.updateAdmins(response.data.removeGroupAdmin.admins);
this.group.next(group);
}));
}
public joinEvent(eventId: string) {
@ -97,8 +143,6 @@ export class GroupService extends BaseService {
}
public leaveEvent(eventId: string) {
const headers = new Headers();
headers.set('Content-Type', 'application/json');
const body = {
query: `mutation($eventId: ID!) {
leaveEvent(eventId: $eventId) {
@ -108,7 +152,29 @@ export class GroupService extends BaseService {
eventId: eventId
}
};
return this.postGraphql(body);
return this.postGraphql(body)
.pipe(this.retryRated());
}
public deleteEvent(eventId: string) {
const body = {
query: `mutation($eventId: ID!) {
deleteEvent(eventId: $eventId)
}`, variables: {
eventId
}
};
return this.postGraphql(body)
.pipe(this.retryRated())
.pipe(tap(response => {
const group = this.group.getValue();
for (let i = 0; i < group.events.length; i++) {
if (group.events[i].id === eventId) {
group.events.splice(i, 1);
}
}
this.group.next(group);
}));
}
public changeProfilePicture(file: any, id: number) {
@ -127,9 +193,9 @@ export class GroupService extends BaseService {
}
};
return this.postGraphql(body)
.pipe(tap(response => {
this.data.deleteGroup(groupId);
}));
.pipe(tap(response => {
this.data.deleteGroup(groupId);
}));
}
public leaveGroup(groupId: number) {
@ -141,8 +207,8 @@ export class GroupService extends BaseService {
}
};
return this.postGraphql(body)
.pipe(tap(response => {
this.data.deleteGroup(groupId);
}));
.pipe(tap(response => {
this.data.deleteGroup(groupId);
}));
}
}

Loading…
Cancel
Save