add awarding request for sql
							parent
							
								
									aa96f49ae1
								
							
						
					
					
						commit
						609395febc
					
				| 
						 | 
					@ -10,5 +10,6 @@ module.exports = {
 | 
				
			||||||
  signatures: '/signatures',
 | 
					  signatures: '/signatures',
 | 
				
			||||||
  squads: '/squads',
 | 
					  squads: '/squads',
 | 
				
			||||||
  users: '/users',
 | 
					  users: '/users',
 | 
				
			||||||
  account: '/account'
 | 
					  account: '/account',
 | 
				
			||||||
 | 
					  request: '/request'
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,11 @@ const AwardingSchema = new Schema({
 | 
				
			||||||
    type: String,
 | 
					    type: String,
 | 
				
			||||||
    required: true
 | 
					    required: true
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  proposer: {
 | 
				
			||||||
 | 
					    type: mongoose.Schema.Types.ObjectId,
 | 
				
			||||||
 | 
					    ref: 'AppUser',
 | 
				
			||||||
 | 
					    required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  confirmed: {
 | 
					  confirmed: {
 | 
				
			||||||
    type: Boolean,
 | 
					    type: Boolean,
 | 
				
			||||||
    default: true
 | 
					    default: true
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,33 @@
 | 
				
			||||||
 | 
					"use strict";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const mongoose = require('mongoose');
 | 
				
			||||||
 | 
					const Schema = mongoose.Schema;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PromotionSchema = new Schema({
 | 
				
			||||||
 | 
					  userId: {
 | 
				
			||||||
 | 
					    type: mongoose.Schema.Types.ObjectId,
 | 
				
			||||||
 | 
					    ref: 'User'
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  proposer: {
 | 
				
			||||||
 | 
					    type: mongoose.Schema.Types.ObjectId,
 | 
				
			||||||
 | 
					    ref: 'AppUser',
 | 
				
			||||||
 | 
					    required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  rankLvl: {
 | 
				
			||||||
 | 
					    type: Number,
 | 
				
			||||||
 | 
					    get: v => Math.round(v),
 | 
				
			||||||
 | 
					    set: v => Math.round(v),
 | 
				
			||||||
 | 
					    required: true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  confirmed: {
 | 
				
			||||||
 | 
					    type: Boolean,
 | 
				
			||||||
 | 
					    default: true
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}, {
 | 
				
			||||||
 | 
					  collection: 'promotion',
 | 
				
			||||||
 | 
					  timestamps: {createdAt: 'timestamp'}
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					// optional more indices
 | 
				
			||||||
 | 
					PromotionSchema.index({timestamp: 1});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = mongoose.model('Promotion', PromotionSchema);
 | 
				
			||||||
| 
						 | 
					@ -61,6 +61,7 @@ let authCheck = (username, password, res) => {
 | 
				
			||||||
        _id: user._id,
 | 
					        _id: user._id,
 | 
				
			||||||
        username: user.username,
 | 
					        username: user.username,
 | 
				
			||||||
        permission: user.permission,
 | 
					        permission: user.permission,
 | 
				
			||||||
 | 
					        squad: user.squad,
 | 
				
			||||||
        token: jwt.sign({sub: user._id}, config.secret, {expiresIn: diff * 60}),
 | 
					        token: jwt.sign({sub: user._id}, config.secret, {expiresIn: diff * 60}),
 | 
				
			||||||
        tokenExpireDate: new Date(Date.now().valueOf() + diff * 60000 - 1000)
 | 
					        tokenExpireDate: new Date(Date.now().valueOf() + diff * 60000 - 1000)
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,9 +9,23 @@ const codes = require('./http-codes');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const routerHandling = require('../middleware/router-handling');
 | 
					const routerHandling = require('../middleware/router-handling');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
 | 
				
			||||||
 | 
					const checkHl = require('../middleware/permission-check').checkHl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Mongoose Model using mongoDB
 | 
					// Mongoose Model using mongoDB
 | 
				
			||||||
const AwardingModel = require('../models/awarding');
 | 
					const AwardingModel = require('../models/awarding');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// result set for proposer(appUser) population
 | 
				
			||||||
 | 
					const resultSet = {
 | 
				
			||||||
 | 
					  '__v': 0,
 | 
				
			||||||
 | 
					  'updatedAt': 0,
 | 
				
			||||||
 | 
					  'timestamp': 0,
 | 
				
			||||||
 | 
					  'password': 0,
 | 
				
			||||||
 | 
					  'permission': 0,
 | 
				
			||||||
 | 
					  'secret': 0,
 | 
				
			||||||
 | 
					  'activated': 0
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const awarding = express.Router();
 | 
					const awarding = express.Router();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,7 +53,7 @@ awarding.route('/')
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      AwardingModel.find(filter, {}, {sort: {date: 'desc'}})
 | 
					      AwardingModel.find(filter, {}, {sort: {date: 'desc'}})
 | 
				
			||||||
        .populate('decorationId').exec((err, items) => {
 | 
					        .populate('decorationId').populate('proposer', resultSet).exec((err, items) => {
 | 
				
			||||||
        if (err) {
 | 
					        if (err) {
 | 
				
			||||||
          err.status = codes.servererror;
 | 
					          err.status = codes.servererror;
 | 
				
			||||||
          return next(err);
 | 
					          return next(err);
 | 
				
			||||||
| 
						 | 
					@ -56,17 +70,18 @@ awarding.route('/')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .post((req, res, next) => {
 | 
					  .post(apiAuthenticationMiddleware, checkHl, (req, res, next) => {
 | 
				
			||||||
    const rank = new AwardingModel(req.body);
 | 
					    const award = new AwardingModel(req.body);
 | 
				
			||||||
 | 
					    award.proposer = req.user._id;
 | 
				
			||||||
    // timestamp and default are set automatically by Mongoose Schema Validation
 | 
					    // timestamp and default are set automatically by Mongoose Schema Validation
 | 
				
			||||||
    rank.save((err) => {
 | 
					    award.save((err) => {
 | 
				
			||||||
      if (err) {
 | 
					      if (err) {
 | 
				
			||||||
        err.status = codes.wrongrequest;
 | 
					        err.status = codes.wrongrequest;
 | 
				
			||||||
        err.message += ' in fields: ' + Object.getOwnPropertyNames(err.errors);
 | 
					        err.message += ' in fields: ' + Object.getOwnPropertyNames(err.errors);
 | 
				
			||||||
        return next(err);
 | 
					        return next(err);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      res.status(codes.created);
 | 
					      res.status(codes.created);
 | 
				
			||||||
      res.locals.items = rank;
 | 
					      res.locals.items = award;
 | 
				
			||||||
      next();
 | 
					      next();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
| 
						 | 
					@ -76,7 +91,7 @@ awarding.route('/')
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
awarding.route('/:id')
 | 
					awarding.route('/:id')
 | 
				
			||||||
  .delete((req, res, next) => {
 | 
					  .delete(apiAuthenticationMiddleware, checkHl, (req, res, next) => {
 | 
				
			||||||
    AwardingModel.findByIdAndRemove(req.params.id, (err, item) => {
 | 
					    AwardingModel.findByIdAndRemove(req.params.id, (err, item) => {
 | 
				
			||||||
      if (err) {
 | 
					      if (err) {
 | 
				
			||||||
        err.status = codes.wrongrequest;
 | 
					        err.status = codes.wrongrequest;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,54 @@
 | 
				
			||||||
 | 
					"use strict";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// modules
 | 
				
			||||||
 | 
					const express = require('express');
 | 
				
			||||||
 | 
					const logger = require('debug')('cc:awardings');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// HTTP status codes by name
 | 
				
			||||||
 | 
					const codes = require('./http-codes');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const routerHandling = require('../middleware/router-handling');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Mongoose Model using mongoDB
 | 
				
			||||||
 | 
					const AwardingModel = require('../models/awarding');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const request = express.Router();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// routes **********************
 | 
				
			||||||
 | 
					request.route('/award')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .post((req, res, next) => {
 | 
				
			||||||
 | 
					    const award = new AwardingModel(req.body);
 | 
				
			||||||
 | 
					    award.confirmed = false;
 | 
				
			||||||
 | 
					    award.proposer = req.user._id;
 | 
				
			||||||
 | 
					    // timestamp and default are set automatically by Mongoose Schema Validation
 | 
				
			||||||
 | 
					    award.save((err) => {
 | 
				
			||||||
 | 
					      if (err) {
 | 
				
			||||||
 | 
					        err.status = codes.wrongrequest;
 | 
				
			||||||
 | 
					        err.message += ' in fields: ' + Object.getOwnPropertyNames(err.errors);
 | 
				
			||||||
 | 
					        return next(err);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      res.status(codes.created);
 | 
				
			||||||
 | 
					      res.locals.items = award;
 | 
				
			||||||
 | 
					      next();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .all(
 | 
				
			||||||
 | 
					    routerHandling.httpMethodNotAllowed
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					request.route('/promotion')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .all(
 | 
				
			||||||
 | 
					    routerHandling.httpMethodNotAllowed
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// this middleware function can be used, if you like or remove it
 | 
				
			||||||
 | 
					// it looks for object(s) in res.locals.items and if they exist, they are send to the client as json
 | 
				
			||||||
 | 
					request.use(routerHandling.emptyResponse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = request;
 | 
				
			||||||
| 
						 | 
					@ -42,8 +42,9 @@ users.route('/')
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
      const nameQuery = req.query.q;
 | 
					      const nameQuery = req.query.q;
 | 
				
			||||||
      const fractionFilter = req.query.fractFilter;
 | 
					      const fractionFilter = req.query.fractFilter;
 | 
				
			||||||
 | 
					      const squadFilter = req.query.squadId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      UserModel.find({}, res.locals.filter, res.locals.limitskip, (err, users) => {
 | 
					      UserModel.find({}, (err, users) => {
 | 
				
			||||||
        if (err) return next(err);
 | 
					        if (err) return next(err);
 | 
				
			||||||
        if (users.length === 0) {
 | 
					        if (users.length === 0) {
 | 
				
			||||||
          res.locals.items = users;
 | 
					          res.locals.items = users;
 | 
				
			||||||
| 
						 | 
					@ -56,8 +57,18 @@ users.route('/')
 | 
				
			||||||
          // filter by name
 | 
					          // filter by name
 | 
				
			||||||
          if (!nameQuery || (nameQuery && user.username.toLowerCase().includes(nameQuery.toLowerCase()))) {
 | 
					          if (!nameQuery || (nameQuery && user.username.toLowerCase().includes(nameQuery.toLowerCase()))) {
 | 
				
			||||||
            getExtendedUser(user, next, (extUser) => {
 | 
					            getExtendedUser(user, next, (extUser) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              // filter by squad
 | 
				
			||||||
 | 
					              if (squadFilter) {
 | 
				
			||||||
 | 
					                if (extUser.squad && extUser.squad._id.toString() === squadFilter) {
 | 
				
			||||||
 | 
					                  resUsers.push(extUser);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else {
 | 
				
			||||||
 | 
					                  rowsLength -= 1;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
              // filter by fraction
 | 
					              // filter by fraction
 | 
				
			||||||
              if (!fractionFilter ||
 | 
					              else if (!fractionFilter ||
 | 
				
			||||||
                (fractionFilter && extUser.squad && extUser.squad.fraction.toLowerCase() === fractionFilter) ||
 | 
					                (fractionFilter && extUser.squad && extUser.squad.fraction.toLowerCase() === fractionFilter) ||
 | 
				
			||||||
                (fractionFilter && fractionFilter === 'unassigned' && !extUser.squad)) {
 | 
					                (fractionFilter && fractionFilter === 'unassigned' && !extUser.squad)) {
 | 
				
			||||||
                resUsers.push(extUser);
 | 
					                resUsers.push(extUser);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@ const urls = require('./config/api-url');
 | 
				
			||||||
const restAPIchecks = require('./middleware/request-checks.js');
 | 
					const restAPIchecks = require('./middleware/request-checks.js');
 | 
				
			||||||
const errorResponseWare = require('./middleware/error-response');
 | 
					const errorResponseWare = require('./middleware/error-response');
 | 
				
			||||||
const apiAuthenticationMiddleware = require('./middleware/auth-middleware');
 | 
					const apiAuthenticationMiddleware = require('./middleware/auth-middleware');
 | 
				
			||||||
const checkHl = require('./middleware/permission-check').checkHl;
 | 
					const checkSql = require('./middleware/permission-check').checkSql;
 | 
				
			||||||
const checkAdmin = require('./middleware/permission-check').checkAdmin;
 | 
					const checkAdmin = require('./middleware/permission-check').checkAdmin;
 | 
				
			||||||
const signatureCronJob = require('./cron-job/update-signatures');
 | 
					const signatureCronJob = require('./cron-job/update-signatures');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,7 @@ const squadRouter = require('./routes/squads');
 | 
				
			||||||
const rankRouter = require('./routes/ranks');
 | 
					const rankRouter = require('./routes/ranks');
 | 
				
			||||||
const decorationRouter = require('./routes/decorations');
 | 
					const decorationRouter = require('./routes/decorations');
 | 
				
			||||||
const awardingRouter = require('./routes/awardings');
 | 
					const awardingRouter = require('./routes/awardings');
 | 
				
			||||||
 | 
					const requestRouter = require('./routes/request');
 | 
				
			||||||
const signatureRouter = require('./routes/signatures');
 | 
					const signatureRouter = require('./routes/signatures');
 | 
				
			||||||
const commandRouter = require('./routes/command');
 | 
					const commandRouter = require('./routes/command');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,7 +73,8 @@ app.use(urls.users, userRouter);
 | 
				
			||||||
app.use(urls.squads, squadRouter);
 | 
					app.use(urls.squads, squadRouter);
 | 
				
			||||||
app.use(urls.ranks, rankRouter);
 | 
					app.use(urls.ranks, rankRouter);
 | 
				
			||||||
app.use(urls.decorations, decorationRouter);
 | 
					app.use(urls.decorations, decorationRouter);
 | 
				
			||||||
app.use(urls.awards, apiAuthenticationMiddleware, checkHl, awardingRouter);
 | 
					app.use(urls.request, apiAuthenticationMiddleware, checkSql, requestRouter);
 | 
				
			||||||
 | 
					app.use(urls.awards, awardingRouter);
 | 
				
			||||||
app.use(urls.command, apiAuthenticationMiddleware, checkAdmin, commandRouter);
 | 
					app.use(urls.command, apiAuthenticationMiddleware, checkAdmin, commandRouter);
 | 
				
			||||||
app.use(urls.account, apiAuthenticationMiddleware, checkAdmin, accountRouter);
 | 
					app.use(urls.account, apiAuthenticationMiddleware, checkAdmin, accountRouter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,5 +12,6 @@ export class AppConfig {
 | 
				
			||||||
  public readonly apiSquadPath          = '/squads/';
 | 
					  public readonly apiSquadPath          = '/squads/';
 | 
				
			||||||
  public readonly apiUserPath           = '/users/';
 | 
					  public readonly apiUserPath           = '/users/';
 | 
				
			||||||
  public readonly apiOverviewPath       = '/overview';
 | 
					  public readonly apiOverviewPath       = '/overview';
 | 
				
			||||||
 | 
					  public readonly apiRequestAwardPath   = '/request/award'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
import {Routes, RouterModule} from '@angular/router';
 | 
					import {Routes, RouterModule} 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} from './login/login.guard';
 | 
					import {LoginGuardAdmin, LoginGuardHL, 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";
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@ import {ranksRoutes, ranksRoutingComponents} from "./ranks/ranks.routing";
 | 
				
			||||||
import {armyRoutes, armyRoutingComponents} from "./army/army.routing";
 | 
					import {armyRoutes, armyRoutingComponents} from "./army/army.routing";
 | 
				
			||||||
import {SignupComponent} from "./login/signup.component";
 | 
					import {SignupComponent} from "./login/signup.component";
 | 
				
			||||||
import {AdminComponent} from "./admin/admin.component";
 | 
					import {AdminComponent} from "./admin/admin.component";
 | 
				
			||||||
 | 
					import {RequestAwardComponent} from "./request/award/req-award.component";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const appRoutes: Routes = [
 | 
					export const appRoutes: Routes = [
 | 
				
			||||||
| 
						 | 
					@ -18,6 +19,9 @@ export const appRoutes: Routes = [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  {path: 'login', component: LoginComponent},
 | 
					  {path: 'login', component: LoginComponent},
 | 
				
			||||||
  {path: 'signup', component: SignupComponent},
 | 
					  {path: 'signup', component: SignupComponent},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {path: 'request-award', component: RequestAwardComponent, canActivate: [LoginGuardSQL]},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  {path: 'cc-users', children: usersRoutes, canActivate: [LoginGuardHL]},
 | 
					  {path: 'cc-users', children: usersRoutes, canActivate: [LoginGuardHL]},
 | 
				
			||||||
  {path: 'cc-squads', children: squadsRoutes, canActivate: [LoginGuardHL]},
 | 
					  {path: 'cc-squads', children: squadsRoutes, canActivate: [LoginGuardHL]},
 | 
				
			||||||
  {path: 'cc-decorations', children: decorationsRoutes, canActivate: [LoginGuardHL]},
 | 
					  {path: 'cc-decorations', children: decorationsRoutes, canActivate: [LoginGuardHL]},
 | 
				
			||||||
| 
						 | 
					@ -32,7 +36,7 @@ export const appRoutes: Routes = [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const appRouting = RouterModule.forRoot(appRoutes);
 | 
					export const appRouting = RouterModule.forRoot(appRoutes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const routingComponents = [LoginComponent, SignupComponent, AdminComponent, ...armyRoutingComponents , NotFoundComponent, ...usersRoutingComponents,
 | 
					export const routingComponents = [LoginComponent, SignupComponent, RequestAwardComponent, AdminComponent, ...armyRoutingComponents , NotFoundComponent, ...usersRoutingComponents,
 | 
				
			||||||
  ...squadsRoutingComponents, ...decorationsRoutingComponents, ...ranksRoutingComponents];
 | 
					  ...squadsRoutingComponents, ...decorationsRoutingComponents, ...ranksRoutingComponents];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const routingProviders = [LoginGuardHL];
 | 
					export const routingProviders = [LoginGuardHL];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,7 @@
 | 
				
			||||||
        </tr>
 | 
					        </tr>
 | 
				
			||||||
        </thead>
 | 
					        </thead>
 | 
				
			||||||
        <tbody *ngFor="let award of user.awards">
 | 
					        <tbody *ngFor="let award of user.awards">
 | 
				
			||||||
        <tr class="cell-outline">
 | 
					        <tr *ngIf="award.confirmed" class="cell-outline">
 | 
				
			||||||
          <td class="text-center" *ngIf="award.decorationId.isMedal">
 | 
					          <td class="text-center" *ngIf="award.decorationId.isMedal">
 | 
				
			||||||
            <img height="90px" src="resource/decoration/{{award.decorationId._id}}.png">
 | 
					            <img height="90px" src="resource/decoration/{{award.decorationId._id}}.png">
 | 
				
			||||||
          </td>
 | 
					          </td>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,7 @@ export interface Award {
 | 
				
			||||||
  userId: string,
 | 
					  userId: string,
 | 
				
			||||||
  decorationId?: Decoration;
 | 
					  decorationId?: Decoration;
 | 
				
			||||||
  reason?: string;
 | 
					  reason?: string;
 | 
				
			||||||
 | 
					  proposer?: AppUser;
 | 
				
			||||||
  date?: number; // since Date.now() returns a number
 | 
					  date?: number; // since Date.now() returns a number
 | 
				
			||||||
  confirmed?: boolean;
 | 
					  confirmed?: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,43 @@
 | 
				
			||||||
 | 
					.decoration-preview {
 | 
				
			||||||
 | 
					  padding: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.trash {
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.table {
 | 
				
			||||||
 | 
					  overflow-wrap: break-word;
 | 
				
			||||||
 | 
					  table-layout: fixed;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.table-container {
 | 
				
			||||||
 | 
					  margin-top: 40px;
 | 
				
			||||||
 | 
					  overflow-x: auto;
 | 
				
			||||||
 | 
					  width: 50%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* enable scrolling for long list of awardings */
 | 
				
			||||||
 | 
					.overview {
 | 
				
			||||||
 | 
					  position: fixed;
 | 
				
			||||||
 | 
					  overflow-y: scroll;
 | 
				
			||||||
 | 
					  overflow-x: hidden;
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  border-left: thin solid lightgrey;
 | 
				
			||||||
 | 
					  padding: 20px 0 0 50px;
 | 
				
			||||||
 | 
					  margin-left: 10px;
 | 
				
			||||||
 | 
					  height: 100vh;
 | 
				
			||||||
 | 
					  bottom: 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.form-group {
 | 
				
			||||||
 | 
					  width: 25%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					h3 {
 | 
				
			||||||
 | 
					  margin: 80px 0 20px -20px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					label {
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,116 @@
 | 
				
			||||||
 | 
					<form #form="ngForm" class="overview">
 | 
				
			||||||
 | 
					  <h3>Auszeichnung beantragen</h3>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <div class="form-group">
 | 
				
			||||||
 | 
					    <label for="user">Teilnehmer</label>
 | 
				
			||||||
 | 
					    <select class="form-control"
 | 
				
			||||||
 | 
					            name="user"
 | 
				
			||||||
 | 
					            id="user"
 | 
				
			||||||
 | 
					            [(ngModel)]="user"
 | 
				
			||||||
 | 
					            [compareWith]="equals"
 | 
				
			||||||
 | 
					            required
 | 
				
			||||||
 | 
					            (change)="toggleUser()"
 | 
				
			||||||
 | 
					            style="min-width: 200px;">
 | 
				
			||||||
 | 
					      <option *ngFor="let user of users" [ngValue]="user">
 | 
				
			||||||
 | 
					        {{user.username}}
 | 
				
			||||||
 | 
					      </option>
 | 
				
			||||||
 | 
					    </select>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <div *ngIf="showForm">
 | 
				
			||||||
 | 
					    <div class="form-group">
 | 
				
			||||||
 | 
					      <label for="decoration">Auszeichnung</label>
 | 
				
			||||||
 | 
					      <select class="form-control"
 | 
				
			||||||
 | 
					              name="decoration"
 | 
				
			||||||
 | 
					              id="decoration"
 | 
				
			||||||
 | 
					              #decorationField
 | 
				
			||||||
 | 
					              (change)="toggleDecoPreview(decoDescription, decorationField.value, decoPreview)"
 | 
				
			||||||
 | 
					              [ngModel]="undefined"
 | 
				
			||||||
 | 
					              required>
 | 
				
			||||||
 | 
					        <option *ngFor="let deco of decorations" [value]="deco._id">
 | 
				
			||||||
 | 
					          {{deco.fraction == 'BLUFOR'? 'NATO' : deco.fraction == 'OPFOR'? 'CSAT' : 'Global'}}: {{deco.name}}
 | 
				
			||||||
 | 
					        </option>
 | 
				
			||||||
 | 
					      </select>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <show-error text="Auszeichnung" path="decoration"></show-error>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="div-table-row" [style.display]="decoPreviewDisplay" style="margin-top: 5px; margin-bottom:10px">
 | 
				
			||||||
 | 
					      <div class="col-sm-1 decoration-preview">
 | 
				
			||||||
 | 
					        <img class="center-block" #decoPreview>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div class="col-sm-2"
 | 
				
			||||||
 | 
					           style="border-radius: 0px 15px 15px 0px; font-style: oblique" #decoDescription>
 | 
				
			||||||
 | 
					         
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="form-group">
 | 
				
			||||||
 | 
					      <label for="reason">Begründung</label>
 | 
				
			||||||
 | 
					      <textarea class="form-control center-block" name="reason" [ngModel]="undefined" required
 | 
				
			||||||
 | 
					                id="reason" placeholder="Begründung eingeben..." rows="3" #awardTextArea></textarea>
 | 
				
			||||||
 | 
					      <show-error text="Begründung" path="reason"></show-error>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <button id="cancel"
 | 
				
			||||||
 | 
					            (click)="cancel()"
 | 
				
			||||||
 | 
					            class="btn btn-default">
 | 
				
			||||||
 | 
					      Abbrechen
 | 
				
			||||||
 | 
					    </button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <button id="save"
 | 
				
			||||||
 | 
					            (click)="addAwarding(decorationField, awardTextArea, decoPreview, decoDescription)"
 | 
				
			||||||
 | 
					            class="btn btn-default"
 | 
				
			||||||
 | 
					            [disabled]="!form.valid">
 | 
				
			||||||
 | 
					      Bestätigen
 | 
				
			||||||
 | 
					    </button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <span *ngIf="showSuccessLabel"
 | 
				
			||||||
 | 
					          class="label label-success label-small"
 | 
				
			||||||
 | 
					          style="margin-left: inherit">
 | 
				
			||||||
 | 
					  Erfolgreich gespeichert
 | 
				
			||||||
 | 
					  </span>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="table-container">
 | 
				
			||||||
 | 
					      <table class="table table-hover">
 | 
				
			||||||
 | 
					        <thead>
 | 
				
			||||||
 | 
					        <tr>
 | 
				
			||||||
 | 
					          <th class="col-sm-1">Bild</th>
 | 
				
			||||||
 | 
					          <th class="col-sm-2">Bezeichnung</th>
 | 
				
			||||||
 | 
					          <th class="col-sm-2">Begründung</th>
 | 
				
			||||||
 | 
					          <th class="col-sm-1 ">Antragsteller</th>
 | 
				
			||||||
 | 
					          <th class="col-sm-1 text-right">Datum</th>
 | 
				
			||||||
 | 
					          <th class="col-sm-1 text-center">Status</th>
 | 
				
			||||||
 | 
					        </tr>
 | 
				
			||||||
 | 
					        </thead>
 | 
				
			||||||
 | 
					        <tbody *ngFor="let award of awards">
 | 
				
			||||||
 | 
					        <tr>
 | 
				
			||||||
 | 
					          <td class="table-cell-id" *ngIf="award.decorationId.isMedal">
 | 
				
			||||||
 | 
					            <img height="40px" src="resource/decoration/{{award.decorationId._id}}.png">
 | 
				
			||||||
 | 
					          </td>
 | 
				
			||||||
 | 
					          <td class="table-cell-id" *ngIf="!award.decorationId.isMedal">
 | 
				
			||||||
 | 
					            <img width="60px" src="resource/decoration/{{award.decorationId._id}}.png">
 | 
				
			||||||
 | 
					          </td>
 | 
				
			||||||
 | 
					          <td>
 | 
				
			||||||
 | 
					            {{award.decorationId.name}}
 | 
				
			||||||
 | 
					          </td>
 | 
				
			||||||
 | 
					          <td>
 | 
				
			||||||
 | 
					            {{award.reason}}
 | 
				
			||||||
 | 
					          </td>
 | 
				
			||||||
 | 
					          <td>
 | 
				
			||||||
 | 
					            {{award.proposer?.username}}
 | 
				
			||||||
 | 
					          </td>
 | 
				
			||||||
 | 
					          <td class="text-right">
 | 
				
			||||||
 | 
					            <a class="small text-nowrap">{{award.date | date: 'dd.MM.yyyy'}}</a>
 | 
				
			||||||
 | 
					          </td>
 | 
				
			||||||
 | 
					          <td class="text-center">
 | 
				
			||||||
 | 
					            {{award.confirmed? 'Bestätigt' : 'In Bearbeitung'}}
 | 
				
			||||||
 | 
					          </td>
 | 
				
			||||||
 | 
					        </tr>
 | 
				
			||||||
 | 
					        </tbody>
 | 
				
			||||||
 | 
					      </table>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</form>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,113 @@
 | 
				
			||||||
 | 
					import {Component, ViewChild} from "@angular/core";
 | 
				
			||||||
 | 
					import {ActivatedRoute, Router} from "@angular/router";
 | 
				
			||||||
 | 
					import {Award, Decoration, User} from "../../models/model-interfaces";
 | 
				
			||||||
 | 
					import {NgForm} from "@angular/forms";
 | 
				
			||||||
 | 
					import {AwardingService} from "../../services/awarding-service/awarding.service";
 | 
				
			||||||
 | 
					import {DecorationService} from "../../services/decoration-service/decoration.service";
 | 
				
			||||||
 | 
					import {UserService} from "../../services/user-service/user.service";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					  templateUrl: './req-award.component.html',
 | 
				
			||||||
 | 
					  styleUrls: ['./req-award.component.css'],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class RequestAwardComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @ViewChild(NgForm) form: NgForm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  showForm = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  showSuccessLabel = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  user: User = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  decorations: Decoration[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  awards: Award[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  users: User[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  decoPreviewDisplay = 'none';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constructor(private router: Router,
 | 
				
			||||||
 | 
					              private route: ActivatedRoute,
 | 
				
			||||||
 | 
					              private userService: UserService,
 | 
				
			||||||
 | 
					              private awardingService: AwardingService,
 | 
				
			||||||
 | 
					              private decorationService: DecorationService) {
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnInit() {
 | 
				
			||||||
 | 
					    let currentUser = JSON.parse(localStorage.getItem('currentUser'));
 | 
				
			||||||
 | 
					    // show only current users squad members
 | 
				
			||||||
 | 
					    this.userService.findUsers('', undefined, currentUser.squad).subscribe(users => {
 | 
				
			||||||
 | 
					      this.users = users;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  toggleUser() {
 | 
				
			||||||
 | 
					    this.decorationService.findDecorations('', this.user.squad.fraction).subscribe(decorations => {
 | 
				
			||||||
 | 
					      this.decorations = decorations;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.awardingService.getUserAwardings(this.user._id).subscribe(awards => {
 | 
				
			||||||
 | 
					      this.awards = awards;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.showForm = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  toggleDecoPreview(descriptionField, decorationId, image) {
 | 
				
			||||||
 | 
					    this.decoPreviewDisplay = 'flex'; // visible & keep same height for all children
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const description = this.decorations.find(
 | 
				
			||||||
 | 
					      decoration => decoration._id === decorationId
 | 
				
			||||||
 | 
					    ).description;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    image.src = 'resource/decoration/' + decorationId + '.png';
 | 
				
			||||||
 | 
					    descriptionField.innerHTML = description;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  addAwarding(decorationField, reasonField, previewImage, descriptionField) {
 | 
				
			||||||
 | 
					    const decorationId = decorationField.value;
 | 
				
			||||||
 | 
					    const reason = reasonField.value;
 | 
				
			||||||
 | 
					    if (decorationId && reason.length > 0) {
 | 
				
			||||||
 | 
					      const award = {
 | 
				
			||||||
 | 
					        "userId": this.user._id,
 | 
				
			||||||
 | 
					        "decorationId": decorationId,
 | 
				
			||||||
 | 
					        "reason": reason,
 | 
				
			||||||
 | 
					        "date": Date.now()
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      this.awardingService.requestAwarding(award).subscribe(() => {
 | 
				
			||||||
 | 
					        this.awardingService.getUserAwardings(this.user._id)
 | 
				
			||||||
 | 
					          .subscribe(awards => {
 | 
				
			||||||
 | 
					            this.awards = awards;
 | 
				
			||||||
 | 
					            console.log(awards[0])
 | 
				
			||||||
 | 
					            this.decoPreviewDisplay = 'none';
 | 
				
			||||||
 | 
					            decorationField.value = undefined;
 | 
				
			||||||
 | 
					            reasonField.value = previewImage.src = descriptionField.innerHTML = '';
 | 
				
			||||||
 | 
					            this.showSuccessLabel = true;
 | 
				
			||||||
 | 
					            setTimeout(() => {
 | 
				
			||||||
 | 
					              this.showSuccessLabel = false;
 | 
				
			||||||
 | 
					            }, 2000)
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cancel() {
 | 
				
			||||||
 | 
					    this.router.navigate(['..'], {relativeTo: this.route});
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * compare ngValue with ngModel to assign selected element
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  equals(o1: User, o2: User) {
 | 
				
			||||||
 | 
					    if (o1 && o2) {
 | 
				
			||||||
 | 
					      return o1._id === o2._id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,10 @@ export class AwardingService {
 | 
				
			||||||
    return this.http.post(this.config.apiUrl + this.config.apiAwardPath, award)
 | 
					    return this.http.post(this.config.apiUrl + this.config.apiAwardPath, award)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  requestAwarding(award) {
 | 
				
			||||||
 | 
					    return this.http.post(this.config.apiUrl + this.config.apiRequestAwardPath, award)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deleteAwarding(awardingId) {
 | 
					  deleteAwarding(awardingId) {
 | 
				
			||||||
    return this.http.delete(this.config.apiUrl + this.config.apiAwardPath + awardingId)
 | 
					    return this.http.delete(this.config.apiUrl + this.config.apiAwardPath + awardingId)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,12 +17,15 @@ export class UserService {
 | 
				
			||||||
    this.users$ = userStore.items$;
 | 
					    this.users$ = userStore.items$;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  findUsers(query = '', fractionFilter?) {
 | 
					  findUsers(query = '', fractionFilter?, squadFilter?) {
 | 
				
			||||||
    const searchParams = new URLSearchParams();
 | 
					    const searchParams = new URLSearchParams();
 | 
				
			||||||
    searchParams.append('q', query);
 | 
					    searchParams.append('q', query);
 | 
				
			||||||
    if (fractionFilter) {
 | 
					    if (fractionFilter) {
 | 
				
			||||||
      searchParams.append('fractFilter', fractionFilter);
 | 
					      searchParams.append('fractFilter', fractionFilter);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (squadFilter) {
 | 
				
			||||||
 | 
					      searchParams.append('squadId', squadFilter);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    this.http.get(this.config.apiUrl + this.config.apiUserPath, searchParams)
 | 
					    this.http.get(this.config.apiUrl + this.config.apiUserPath, searchParams)
 | 
				
			||||||
      .map(res => res.json())
 | 
					      .map(res => res.json())
 | 
				
			||||||
      .do((users) => {
 | 
					      .do((users) => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,6 +70,7 @@
 | 
				
			||||||
        <th class="col-sm-2">Bezeichnung</th>
 | 
					        <th class="col-sm-2">Bezeichnung</th>
 | 
				
			||||||
        <th class="col-sm-2">Begründung</th>
 | 
					        <th class="col-sm-2">Begründung</th>
 | 
				
			||||||
        <th class="col-sm-1 text-right">Datum</th>
 | 
					        <th class="col-sm-1 text-right">Datum</th>
 | 
				
			||||||
 | 
					        <th class="col-sm-1 text-center">Status</th>
 | 
				
			||||||
        <th class="col-sm-1 text-center"></th>
 | 
					        <th class="col-sm-1 text-center"></th>
 | 
				
			||||||
      </tr>
 | 
					      </tr>
 | 
				
			||||||
      </thead>
 | 
					      </thead>
 | 
				
			||||||
| 
						 | 
					@ -90,6 +91,9 @@
 | 
				
			||||||
        <td class="text-right">
 | 
					        <td class="text-right">
 | 
				
			||||||
          <a class="small text-nowrap">{{award.date | date: 'dd.MM.yyyy'}}</a>
 | 
					          <a class="small text-nowrap">{{award.date | date: 'dd.MM.yyyy'}}</a>
 | 
				
			||||||
        </td>
 | 
					        </td>
 | 
				
			||||||
 | 
					        <td class="text-center">
 | 
				
			||||||
 | 
					          {{award.confirmed? 'Bestätigt' : 'In Bearbeitung'}}
 | 
				
			||||||
 | 
					        </td>
 | 
				
			||||||
        <td class="text-center">
 | 
					        <td class="text-center">
 | 
				
			||||||
          <span class="glyphicon glyphicon-trash trash" title="Löschen" (click)="deleteAwarding(award._id)"></span>
 | 
					          <span class="glyphicon glyphicon-trash trash" title="Löschen" (click)="deleteAwarding(award._id)"></span>
 | 
				
			||||||
        </td>
 | 
					        </td>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue