Compare commits

..

2 Commits

Author SHA1 Message Date
Florian Hartwich 07df5bd4c8 Add delete war option 2017-07-14 23:50:58 +02:00
Florian Hartwich 6bf7992f0f Add war submit form 2017-07-14 23:33:17 +02:00
15 changed files with 278 additions and 38 deletions

View File

@ -69,17 +69,15 @@ wars.route('/')
if (error) { if (error) {
return next(error); return next(error);
} }
let obj = JSON.parse(`${stdout}`);
console.log(obj);
PlayerModel.create(obj, function (err) {
if (err) {
return next(err);
}
exec(__dirname + '/../war-parser/clean.sh /../' + folderName + ' | tee ' + folderName + '/clean.log', (error) => { exec(__dirname + '/../war-parser/clean.sh /../' + folderName + ' | tee ' + folderName + '/clean.log', (error) => {
if (error) { if (error) {
return next(error); return next(error);
} }
let obj = JSON.parse(`${stdout}`);
PlayerModel.create(obj, function (err) {
if (err) {
return next(err);
}
res.status(codes.created); res.status(codes.created);
res.locals.items = item; res.locals.items = item;
return next(); return next();
@ -131,10 +129,12 @@ wars.route('/:id')
WarModel.findByIdAndRemove(req.params.id, (err, item) => { WarModel.findByIdAndRemove(req.params.id, (err, item) => {
if (err) { if (err) {
err.status = codes.wrongrequest; err.status = codes.wrongrequest;
return next(err);
} }
else if (!item) { else if (!item) {
err = new Error("item not found"); err = new Error("item not found");
err.status = codes.notfound; err.status = codes.notfound;
return next(err);
} }
//TODO: add removal of resource files //TODO: add removal of resource files
@ -144,7 +144,7 @@ wars.route('/:id')
// we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler user.use(..) // we don't set res.locals.items and thus it will send a 204 (no content) at the end. see last handler user.use(..)
res.locals.processed = true; res.locals.processed = true;
next(err); // this works because err is in normal case undefined and that is the same as no parameter next();
}) })
}) })

View File

@ -28,8 +28,13 @@
<span class="caret"></span> <span class="caret"></span>
</a> </a>
<ul class="dropdown-menu scrollable-menu"> <ul class="dropdown-menu scrollable-menu">
<li *ngIf="loginService.hasPermission(3)">
<a routerLink='/cc-wars' class="link">Hinzufügen...</a>
</li>
<li *ngFor="let war of wars"> <li *ngFor="let war of wars">
<a [routerLink]="['/cc-wars/' + war._id]">{{war.title}} <small>{{war.date | date: 'dd.MM.yy'}}</small></a> <a [routerLink]="['/cc-wars/' + war._id]">{{war.title}}
<small>{{war.date | date: 'dd.MM.yy'}}</small>
</a>
</li> </li>
</ul> </ul>
</li> </li>
@ -45,7 +50,8 @@
<li *ngIf="loginService.hasPermission(2)" routerLinkActive="active"> <li *ngIf="loginService.hasPermission(2)" routerLinkActive="active">
<a routerLink='/cc-ranks' class="link">Ränge</a> <a routerLink='/cc-ranks' class="link">Ränge</a>
</li> </li>
<li *ngIf="loginService.hasPermission(1) && !loginService.hasPermission(2) && loginService.hasSquad()" class="dropdown"> <li *ngIf="loginService.hasPermission(1) && !loginService.hasPermission(2) && loginService.hasSquad()"
class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false"> aria-expanded="false">
Beantragen Beantragen

View File

@ -1,7 +1,7 @@
import {RouterModule, Routes} from "@angular/router"; import {RouterModule, Routes} from "@angular/router";
import {LoginComponent} from "./login/index"; import {LoginComponent} from "./login/index";
import {NotFoundComponent} from "./not-found/not-found.component"; import {NotFoundComponent} from "./not-found/not-found.component";
import {LoginGuardAdmin, LoginGuardHL, LoginGuardSQL} from "./login/login.guard"; import {LoginGuardAdmin, LoginGuardHL, LoginGuardMT, LoginGuardSQL} from "./login/login.guard";
import {usersRoutes, usersRoutingComponents} from "./users/users.routing"; import {usersRoutes, usersRoutingComponents} from "./users/users.routing";
import {squadsRoutes, squadsRoutingComponents} from "./squads/squads.routing"; import {squadsRoutes, squadsRoutingComponents} from "./squads/squads.routing";
import {decorationsRoutes, decorationsRoutingComponents} from "./decorations/decoration.routing"; import {decorationsRoutes, decorationsRoutingComponents} from "./decorations/decoration.routing";
@ -13,7 +13,7 @@ import {RequestAwardComponent} from "./request/award/req-award.component";
import {RequestPromotionComponent} from "./request/promotion/req-promotion.component"; import {RequestPromotionComponent} from "./request/promotion/req-promotion.component";
import {ConfirmPromotionComponent} from "./request/confirm-promotion/confirm-promotion.component"; import {ConfirmPromotionComponent} from "./request/confirm-promotion/confirm-promotion.component";
import {ConfirmAwardComponent} from "./request/confirm-award/confirm-award.component"; import {ConfirmAwardComponent} from "./request/confirm-award/confirm-award.component";
import {WarDetailComponent} from "./wars/war-detail.component"; import {warRoutes, warsRoutingComponents} from "./wars/wars.routing";
export const appRoutes: Routes = [ export const appRoutes: Routes = [
@ -21,7 +21,7 @@ export const appRoutes: Routes = [
{path: 'cc-overview', children: armyRoutes}, {path: 'cc-overview', children: armyRoutes},
{path: '', redirectTo: '/cc-overview', pathMatch: 'full'}, {path: '', redirectTo: '/cc-overview', pathMatch: 'full'},
{path: 'cc-wars/:id', component: WarDetailComponent}, {path: 'cc-wars', children: warRoutes},
{path: 'login', component: LoginComponent}, {path: 'login', component: LoginComponent},
{path: 'signup', component: SignupComponent}, {path: 'signup', component: SignupComponent},
@ -47,6 +47,6 @@ export const appRouting = RouterModule.forRoot(appRoutes);
export const routingComponents = [LoginComponent, SignupComponent, RequestAwardComponent, RequestPromotionComponent, ConfirmAwardComponent, export const routingComponents = [LoginComponent, SignupComponent, RequestAwardComponent, RequestPromotionComponent, ConfirmAwardComponent,
ConfirmPromotionComponent, AdminComponent, ...armyRoutingComponents, NotFoundComponent, ...usersRoutingComponents, ConfirmPromotionComponent, AdminComponent, ...armyRoutingComponents, NotFoundComponent, ...usersRoutingComponents,
...squadsRoutingComponents, ...decorationsRoutingComponents, ...ranksRoutingComponents, WarDetailComponent]; ...squadsRoutingComponents, ...decorationsRoutingComponents, ...ranksRoutingComponents, ...warsRoutingComponents];
export const routingProviders = [LoginGuardHL]; export const routingProviders = [LoginGuardSQL, LoginGuardHL, LoginGuardMT, LoginGuardAdmin];

View File

@ -1,6 +1,6 @@
<h1>Übersicht über alle Spieler, Squads und Armeen</h1> <h1>Übersicht über alle Spieler, Squads und Armeen</h1>
<div style="width: 1900px; margin-left: 25%"> <div style="width: 1200px; margin-left: 25%">
<div class="div-table" style="width: 490px; float:left"> <div class="div-table" style="width: 490px; float:left">
<h3 class="text-blufor army-head">NATO</h3> <h3 class="text-blufor army-head">NATO</h3>

View File

@ -1,10 +1,11 @@
import { Injectable } from '@angular/core'; import {Injectable} from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import {Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
@Injectable() @Injectable()
export class LoginGuardSQL implements CanActivate { export class LoginGuardSQL implements CanActivate {
constructor(private router: Router) { } constructor(private router: Router) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (localStorage.getItem('currentUser')) { if (localStorage.getItem('currentUser')) {
@ -16,7 +17,7 @@ export class LoginGuardSQL implements CanActivate {
} }
// not logged in so redirect to login page with the return url // not logged in so redirect to login page with the return url
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }}); this.router.navigate(['/login'], {queryParams: {returnUrl: state.url}});
return false; return false;
} }
} }
@ -24,7 +25,8 @@ export class LoginGuardSQL implements CanActivate {
@Injectable() @Injectable()
export class LoginGuardHL implements CanActivate { export class LoginGuardHL implements CanActivate {
constructor(private router: Router) { } constructor(private router: Router) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (localStorage.getItem('currentUser')) { if (localStorage.getItem('currentUser')) {
@ -36,7 +38,28 @@ export class LoginGuardHL implements CanActivate {
} }
// not logged in so redirect to login page with the return url // not logged in so redirect to login page with the return url
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }}); this.router.navigate(['/login'], {queryParams: {returnUrl: state.url}});
return false;
}
}
@Injectable()
export class LoginGuardMT implements CanActivate {
constructor(private router: Router) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (localStorage.getItem('currentUser')) {
let currentUser = JSON.parse(localStorage.getItem('currentUser'));
if (currentUser.permission >= 3) {
// logged and correct permission so return true
return true;
}
}
// not logged in so redirect to login page with the return url
this.router.navigate(['/login'], {queryParams: {returnUrl: state.url}});
return false; return false;
} }
} }
@ -44,7 +67,8 @@ export class LoginGuardHL implements CanActivate {
@Injectable() @Injectable()
export class LoginGuardAdmin implements CanActivate { export class LoginGuardAdmin implements CanActivate {
constructor(private router: Router) { } constructor(private router: Router) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (localStorage.getItem('currentUser')) { if (localStorage.getItem('currentUser')) {
@ -56,7 +80,7 @@ export class LoginGuardAdmin implements CanActivate {
} }
// not logged in so redirect to login page with the return url // not logged in so redirect to login page with the return url
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }}); this.router.navigate(['/login'], {queryParams: {returnUrl: state.url}});
return false; return false;
} }
} }

View File

@ -30,7 +30,7 @@ export interface Player {
export interface War { export interface War {
_id?: string; _id?: string;
title?: string; title?: string;
date?: Date; date?: string;
ptBlufor?: number; ptBlufor?: number;
ptOpfor?: number; ptOpfor?: number;
bestPlayerId?: Player; bestPlayerId?: Player;

View File

@ -21,7 +21,7 @@ export class WarService {
} }
submitDecoration(war: War, logFile?) { submitWar(war: War, logFile?) {
let body; let body;
if (logFile) { if (logFile) {
@ -34,11 +34,13 @@ export class WarService {
body.append('log', logFile, logFile.name); body.append('log', logFile, logFile.name);
} }
return this.http.post(this.config.apiUrl + this.config.apiDecorationPath, body) return this.http.post(this.config.apiUrl + this.config.apiWarPath, body)
.map(res => res.json())
}
deleteWar(id: string) {
return this.http.delete(this.config.apiUrl + this.config.apiWarPath + '/' + id)
.map(res => res.json()) .map(res => res.json())
.do(savedDecoration => {
console.log('saved successfully')
});
} }
} }

View File

@ -10,8 +10,11 @@
</h3> </h3>
<div style="margin-left: 500px; margin-top:1%"> <div style="margin-left: 500px; margin-top:1%">
<a class="btn btn-default btn-" style="margin: 20px" target="_blank" href="resource/logs/{{war._id}}/clean.log">Logfile <a class="btn btn-default" style="margin: 20px" target="_blank" href="resource/logs/{{war._id}}/clean.log">Logfile
anzeigen</a> anzeigen</a>
<button *ngIf="loginService.hasPermission(3)" class="btn btn-warning" style="margin: 20px" (click)="delete()">
Schlacht löschen
</button>
<form class="form-group"> <form class="form-group">
<label class="radio-inline"> <label class="radio-inline">
<input type="radio" name="fractSelect" <input type="radio" name="fractSelect"

View File

@ -1,7 +1,8 @@
import {Component} from "@angular/core"; import {Component} from "@angular/core";
import {Player, War} from "../models/model-interfaces"; import {Player, War} from "../models/model-interfaces";
import {WarService} from "../services/war-service/war.service"; import {WarService} from "../services/war-service/war.service";
import {ActivatedRoute} from "@angular/router"; import {ActivatedRoute, Router} from "@angular/router";
import {LoginService} from "../services/login-service/login-service";
@Component({ @Component({
@ -21,8 +22,10 @@ export class WarDetailComponent {
sortOrder = "desc"; sortOrder = "desc";
constructor(private route: ActivatedRoute, constructor(private router: Router,
private warService: WarService) { private route: ActivatedRoute,
private warService: WarService,
private loginService: LoginService) {
} }
ngOnInit() { ngOnInit() {
@ -39,7 +42,6 @@ export class WarDetailComponent {
filterPlayersByFraction(fraction: string) { filterPlayersByFraction(fraction: string) {
if (fraction) { if (fraction) {
this.players = this.war.players.filter((player) => { this.players = this.war.players.filter((player) => {
console.log(player.fraction + " .... " + fraction);
return player.fraction === fraction; return player.fraction === fraction;
}) })
} else { } else {
@ -47,4 +49,13 @@ export class WarDetailComponent {
} }
} }
delete() {
if (confirm('Soll die Schlacht "' + this.war.title + '" wirklich gelöscht werden?')) {
this.warService.deleteWar(this.war._id)
.subscribe((res) => {
this.router.navigate(['../..'], {relativeTo: this.route});
})
}
}
} }

View File

@ -0,0 +1,28 @@
.overview {
position: fixed;
width: 25%;
padding-left: 50px;
padding-top: 70px;
margin-left: 10px;
}
.load-arrow {
background: url(../../assets/loading.png) no-repeat;
display: block;
width: 120px;
height: 120px;
}
/* Loading Animation */
.glyphicon-refresh-animate {
animation: spin 1.5s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}

View File

@ -0,0 +1,75 @@
<form #form="ngForm" class="overview">
<h3>Schlacht hinzufügen</h3>
<div class="form-group">
<label for="title">Titel</label>
<input type="text" class="form-control"
[(ngModel)]="war.title"
name="title"
id="title"
required maxlength="50"/>
<show-error text="Name" path="title"></show-error>
</div>
<div class="form-group">
<label for="date">Datum</label>
<input type="date" class="form-control"
[(ngModel)]="war.date"
name="date"
id="date"
required/>
<show-error text="Datum" path="date"></show-error>
</div>
<div class="form-group">
<label for="ptblu">Punkte NATO</label>
<input type="number" class="form-control" step="1"
[(ngModel)]="war.ptBlufor"
name="ptblu"
id="ptblu"
required/>
<show-error text="Punkte NATO" path="ptnblu"></show-error>
</div>
<div class="form-group">
<label for="ptopf">Punkte CSAT</label>
<input type="number" class="form-control" step="1"
[(ngModel)]="war.ptOpfor"
name="ptopf"
id="ptopf"
required/>
<show-error text="Punkte CSAT" path="ptopf"></show-error>
</div>
<div class="form-group">
<label for="log">Logfile</label>
<input id="log" name="log" class="ui-button form-control" type="file"
(change)="fileChange($event)">
<span class="label label-bg label-danger center-block" style="font-size:small" *ngIf="showImageError">
Logfile muss im Format RPT, LOG oder TXT vorliegen
</span>
</div>
<button id="cancel"
*ngIf="!loading"
(click)="cancel()"
class="btn btn-default">
Abbrechen
</button>
<button id="save"
*ngIf="!loading"
(click)="saveWar()"
class="btn btn-default"
[disabled]="!form.valid">
Bestätigen
</button>
<span *ngIf="loading" class="load-arrow glyphicon-refresh-animate"></span>
<span *ngIf="showErrorLabel"
class="center-block label label-danger" style="font-size: medium; padding: 2px; margin-top: 2px">
{{error}}
</span>
</form>

View File

@ -0,0 +1,72 @@
import {Component, ViewChild} from "@angular/core";
import {Player, War} from "../models/model-interfaces";
import {WarService} from "../services/war-service/war.service";
import {ActivatedRoute, Router} from "@angular/router";
import {NgForm} from "@angular/forms";
@Component({
selector: 'war-submit',
templateUrl: './war-submit.component.html',
styleUrls: ['./war-submit.component.css']
})
export class WarSubmitComponent {
war: War = {date: new Date().toISOString().slice(0, 10), players: []};
fileList: FileList;
showImageError = false;
showErrorLabel = false;
loading = false;
error;
@ViewChild(NgForm) form: NgForm;
constructor(private route: ActivatedRoute,
private router: Router,
private warService: WarService) {
}
fileChange(event) {
if (!event.target.files[0].name.endsWith('.rpt')
&& !event.target.files[0].name.endsWith('.log')
&& !event.target.files[0].name.endsWith('.txt')) {
this.showImageError = true;
this.fileList = undefined;
} else {
this.showImageError = false;
this.fileList = event.target.files;
}
}
saveWar() {
let file: File;
console.log(this.war.date)
if (this.fileList) {
file = this.fileList[0];
this.loading = true;
this.warService.submitWar(this.war, file)
.subscribe(war => {
this.router.navigate([war._id], {relativeTo: this.route});
},
error => {
this.error = error._body;
this.showErrorLabel = true;
this.loading = false;
});
} else {
return window.alert(`Logfile ist ein Pflichtfeld`);
}
}
cancel() {
this.router.navigate(['..'], {relativeTo: this.route});
return false;
}
}

View File

@ -0,0 +1,19 @@
import {Routes} from "@angular/router";
import {WarSubmitComponent} from "./war-submit.component";
import {WarDetailComponent} from "./war-detail.component";
import {LoginGuardMT} from "../login/login.guard";
export const warRoutes: Routes = [
{
path: '',
component: WarSubmitComponent,
canActivate: [LoginGuardMT]
},
{
path: ':id',
component: WarDetailComponent,
}];
export const warsRoutingComponents = [WarSubmitComponent, WarDetailComponent];

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB