Compare commits
	
		
			3 Commits 
		
	
	
		
			9b8bcd0722
			...
			aa96f49ae1
		
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								 | 
						aa96f49ae1 | |
| 
							
							
								 | 
						0d576b7268 | |
| 
							
							
								 | 
						b5bcc676ed | 
| 
						 | 
				
			
			@ -10,4 +10,5 @@ module.exports = {
 | 
			
		|||
  signatures: '/signatures',
 | 
			
		||||
  squads: '/squads',
 | 
			
		||||
  users: '/users',
 | 
			
		||||
  account: '/account'
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,6 @@ let check = (requiredPermission, actualPermission, res, next) => {
 | 
			
		|||
  if (actualPermission >= requiredPermission) {
 | 
			
		||||
    return next();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return res.status(403).send({
 | 
			
		||||
    success: false,
 | 
			
		||||
    message: 'permission denied'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,11 @@ const AppUserSchema = new Schema({
 | 
			
		|||
    type: String,
 | 
			
		||||
    required: true
 | 
			
		||||
  },
 | 
			
		||||
  squad: {
 | 
			
		||||
    type: mongoose.Schema.Types.ObjectId,
 | 
			
		||||
    ref: 'Squad',
 | 
			
		||||
    default: null
 | 
			
		||||
  },
 | 
			
		||||
  permission: {
 | 
			
		||||
    type: Number,
 | 
			
		||||
    get: v => Math.round(v),
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +25,14 @@ const AppUserSchema = new Schema({
 | 
			
		|||
    min: 0,
 | 
			
		||||
    max: 4,
 | 
			
		||||
    default: 0
 | 
			
		||||
  },
 | 
			
		||||
  secret: {
 | 
			
		||||
    type: String,
 | 
			
		||||
    required: true
 | 
			
		||||
  },
 | 
			
		||||
  activated: {
 | 
			
		||||
    type: Boolean,
 | 
			
		||||
    default: false
 | 
			
		||||
  }
 | 
			
		||||
}, {
 | 
			
		||||
  collection: 'app_user',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,90 @@
 | 
			
		|||
"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 AppUserModel = require('../models/app-user');
 | 
			
		||||
 | 
			
		||||
const account = express.Router();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
account.route('/')
 | 
			
		||||
  .get((req, res, next) => {
 | 
			
		||||
    AppUserModel.find({}).populate('squad').exec((err, items) => {
 | 
			
		||||
      if (err) {
 | 
			
		||||
        err.status = codes.servererror;
 | 
			
		||||
        return next(err);
 | 
			
		||||
      }
 | 
			
		||||
      res.locals.items = items;
 | 
			
		||||
      res.locals.processed = true;
 | 
			
		||||
      next();
 | 
			
		||||
    })
 | 
			
		||||
  })
 | 
			
		||||
  .all(
 | 
			
		||||
    routerHandling.httpMethodNotAllowed
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
// routes **********************
 | 
			
		||||
account.route('/:id')
 | 
			
		||||
  .patch((req, res, next) => {
 | 
			
		||||
    if (!req.body || (req.body._id && req.body._id !== req.params.id)) {
 | 
			
		||||
      // little bit different as in PUT. :id does not need to be in data, but if the _id and url id must match
 | 
			
		||||
      const err = new Error('id of PATCH resource and send JSON body are not equal ' + req.params.id + " " + req.body._id);
 | 
			
		||||
      err.status = codes.notfound;
 | 
			
		||||
      next(err);
 | 
			
		||||
      return; // prevent node to process this function further after next() has finished.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // increment version manually as we do not use .save(.)
 | 
			
		||||
    req.body.updatedAt = new Date();
 | 
			
		||||
    req.body.$inc = {__v: 1};
 | 
			
		||||
 | 
			
		||||
    // PATCH is easier with mongoose than PUT. You simply update by all data that comes from outside. no need to reset attributes that are missing.
 | 
			
		||||
    AppUserModel.findByIdAndUpdate(req.params.id, req.body, {new: true}).populate('squad').exec((err, item) => {
 | 
			
		||||
      if (err) {
 | 
			
		||||
        err.status = codes.wrongrequest;
 | 
			
		||||
      }
 | 
			
		||||
      else if (!item) {
 | 
			
		||||
        err = new Error("appUser not found");
 | 
			
		||||
        err.status = codes.notfound;
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        res.locals.items = item;
 | 
			
		||||
      }
 | 
			
		||||
      next(err);
 | 
			
		||||
    })
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  .delete((req, res, next) => {
 | 
			
		||||
    AppUserModel.findByIdAndRemove(req.params.id, (err, item) => {
 | 
			
		||||
      if (err) {
 | 
			
		||||
        err.status = codes.wrongrequest;
 | 
			
		||||
      }
 | 
			
		||||
      else if (!item) {
 | 
			
		||||
        err = new Error("item not found");
 | 
			
		||||
        err.status = codes.notfound;
 | 
			
		||||
      }
 | 
			
		||||
      // 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;
 | 
			
		||||
      next(err); // this works because err is in normal case undefined and that is the same as no parameter
 | 
			
		||||
    });
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  .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
 | 
			
		||||
account.use(routerHandling.emptyResponse);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
module.exports = account;
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +8,9 @@ const Q = require('q');
 | 
			
		|||
const _ = require('lodash');
 | 
			
		||||
const logger = require('debug')('cc:authenticate');
 | 
			
		||||
 | 
			
		||||
const apiAuthenticationMiddleware = require('../middleware/auth-middleware');
 | 
			
		||||
const checkAdmin = require('../middleware/permission-check').checkAdmin;
 | 
			
		||||
 | 
			
		||||
// HTTP status codes by name
 | 
			
		||||
const codes = require('./http-codes');
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +25,7 @@ const authenticate = express.Router();
 | 
			
		|||
// routes **********************
 | 
			
		||||
authenticate.route('/')
 | 
			
		||||
  .post((req, res, next) => {
 | 
			
		||||
    authCheck(req.body.username, req.body.password)
 | 
			
		||||
    authCheck(req.body.username, req.body.password, res)
 | 
			
		||||
      .then((user) => {
 | 
			
		||||
        if (user) {
 | 
			
		||||
          // authentication successful
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +44,7 @@ authenticate.route('/')
 | 
			
		|||
    routerHandling.httpMethodNotAllowed
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
let authCheck = (username, password) => {
 | 
			
		||||
let authCheck = (username, password, res) => {
 | 
			
		||||
  const deferred = Q.defer();
 | 
			
		||||
 | 
			
		||||
  AppUserModel.findOne({username: username}, (err, user) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -49,11 +52,15 @@ let authCheck = (username, password) => {
 | 
			
		|||
 | 
			
		||||
    const diff = 3 * 60 * 24; // time till expiration [minutes]
 | 
			
		||||
 | 
			
		||||
    if (user && bcrypt.compareSync(password, user.password)) {
 | 
			
		||||
    if (user && !user.activated) {
 | 
			
		||||
      res.status(codes.unauthorized).send('Account is not yet activated');
 | 
			
		||||
    }
 | 
			
		||||
    if (user && user.activated && bcrypt.compareSync(password, user.password)) {
 | 
			
		||||
      // authentication successful
 | 
			
		||||
      deferred.resolve({
 | 
			
		||||
        _id: user._id,
 | 
			
		||||
        username: user.username,
 | 
			
		||||
        permission: user.permission,
 | 
			
		||||
        token: jwt.sign({sub: user._id}, config.secret, {expiresIn: diff * 60}),
 | 
			
		||||
        tokenExpireDate: new Date(Date.now().valueOf() + diff * 60000 - 1000)
 | 
			
		||||
      });
 | 
			
		||||
| 
						 | 
				
			
			@ -66,58 +73,57 @@ let authCheck = (username, password) => {
 | 
			
		|||
  return deferred.promise;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// ******************************** SIGNUP ************************
 | 
			
		||||
 | 
			
		||||
//******************************** SIGNUP ************************
 | 
			
		||||
//
 | 
			
		||||
// authenticate.route('/signup')
 | 
			
		||||
//   .post((req, res, next) => {
 | 
			
		||||
//     create(req.body)
 | 
			
		||||
//       .then(() => {
 | 
			
		||||
//         res.sendStatus(200);
 | 
			
		||||
//       })
 | 
			
		||||
//       .catch((err) => {
 | 
			
		||||
//         res.status(400).send(err);
 | 
			
		||||
//       });
 | 
			
		||||
//   })
 | 
			
		||||
//
 | 
			
		||||
//   .all(
 | 
			
		||||
//     routerHandling.httpMethodNotAllowed
 | 
			
		||||
//   );
 | 
			
		||||
//
 | 
			
		||||
// let create = (userParam) => {
 | 
			
		||||
//   const deferred = Q.defer();
 | 
			
		||||
//
 | 
			
		||||
//   // validation
 | 
			
		||||
//   AppUserModel.findOne(
 | 
			
		||||
//     {username: userParam.username},
 | 
			
		||||
//     (err, user) => {
 | 
			
		||||
//       if (err) deferred.reject(err.name + ': ' + err.message);
 | 
			
		||||
//
 | 
			
		||||
//       if (user) {
 | 
			
		||||
//         // username already exists
 | 
			
		||||
//         deferred.reject('Username "' + userParam.username + '" is already taken');
 | 
			
		||||
//       } else {
 | 
			
		||||
//         createUser();
 | 
			
		||||
//       }
 | 
			
		||||
//     });
 | 
			
		||||
//
 | 
			
		||||
//   let createUser = () => {
 | 
			
		||||
//     // set user object to userParam without the cleartext password
 | 
			
		||||
//     const user = _.omit(userParam, 'password');
 | 
			
		||||
//
 | 
			
		||||
//     // add hashed password to user object
 | 
			
		||||
//     user.password = bcrypt.hashSync(userParam.password, 10);
 | 
			
		||||
//
 | 
			
		||||
//     const newUser = new AppUserModel(user);
 | 
			
		||||
//     newUser.save((err, doc) => {
 | 
			
		||||
//       if (err) deferred.reject(err.name + ': ' + err.message);
 | 
			
		||||
//
 | 
			
		||||
//       deferred.resolve();
 | 
			
		||||
//     });
 | 
			
		||||
//   };
 | 
			
		||||
//
 | 
			
		||||
//   return deferred.promise;
 | 
			
		||||
// };
 | 
			
		||||
authenticate.route('/signup')
 | 
			
		||||
  .post((req, res, next) => {
 | 
			
		||||
    create(req.body)
 | 
			
		||||
      .then(() => {
 | 
			
		||||
        res.sendStatus(200);
 | 
			
		||||
      })
 | 
			
		||||
      .catch((err) => {
 | 
			
		||||
        res.status(400).send(err);
 | 
			
		||||
      });
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  .all(
 | 
			
		||||
    routerHandling.httpMethodNotAllowed
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
let create = (userParam) => {
 | 
			
		||||
  const deferred = Q.defer();
 | 
			
		||||
 | 
			
		||||
  // validation
 | 
			
		||||
  AppUserModel.findOne(
 | 
			
		||||
    {username: userParam.username},
 | 
			
		||||
    (err, user) => {
 | 
			
		||||
      if (err) deferred.reject(err.name + ': ' + err.message);
 | 
			
		||||
 | 
			
		||||
      if (user) {
 | 
			
		||||
        // username already exists
 | 
			
		||||
        deferred.reject('Username "' + userParam.username + '" is already taken');
 | 
			
		||||
      } else {
 | 
			
		||||
        createUser();
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
  let createUser = () => {
 | 
			
		||||
    // set user object to userParam without the cleartext password
 | 
			
		||||
    const user = _.omit(userParam, 'password');
 | 
			
		||||
 | 
			
		||||
    // add hashed password to user object
 | 
			
		||||
    user.password = bcrypt.hashSync(userParam.password, 10);
 | 
			
		||||
 | 
			
		||||
    const newUser = new AppUserModel(user);
 | 
			
		||||
    newUser.save((err, doc) => {
 | 
			
		||||
      if (err) deferred.reject(err.name + ': ' + err.message);
 | 
			
		||||
 | 
			
		||||
      deferred.resolve();
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return deferred.promise;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
authenticate.use(routerHandling.emptyResponse);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -187,7 +187,7 @@ users.route('/:id')
 | 
			
		|||
      return; // prevent node to process this function further after next() has finished.
 | 
			
		||||
    }
 | 
			
		||||
    // main difference of PUT and PATCH is that PUT expects all data in request: checked by using the schema
 | 
			
		||||
    var video = new UserModel(req.body);
 | 
			
		||||
    var user = new UserModel(req.body);
 | 
			
		||||
    UserModel.findById(req.params.id, req.body, {new: true}, function (err, item) {
 | 
			
		||||
      // with parameter {new: true} the TweetNModel will return the new and changed object from the DB and not the old one.
 | 
			
		||||
      if (err) {
 | 
			
		||||
| 
						 | 
				
			
			@ -200,7 +200,7 @@ users.route('/:id')
 | 
			
		|||
        return next(err);
 | 
			
		||||
      }
 | 
			
		||||
      //  optional task 3b: check that version is still accurate
 | 
			
		||||
      else if (video.__v !== item.__v) {
 | 
			
		||||
      else if (user.__v !== item.__v) {
 | 
			
		||||
        err = new Error("version outdated. Meanwhile update on item happened. Please GET resource again")
 | 
			
		||||
        err.status = codes.conflict;
 | 
			
		||||
        return next(err);
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +209,7 @@ users.route('/:id')
 | 
			
		|||
      for (var field in UserModel.schema.paths) {
 | 
			
		||||
        if ((field !== '_id') && (field !== '__v')) {
 | 
			
		||||
          // this includes undefined. is important to reset attributes that are missing in req.body
 | 
			
		||||
          item.set(field, video[field]);
 | 
			
		||||
          item.set(field, user[field]);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,7 @@ const signatureCronJob = require('./cron-job/update-signatures');
 | 
			
		|||
 | 
			
		||||
// router modules
 | 
			
		||||
const authenticateRouter = require('./routes/authenticate');
 | 
			
		||||
const accountRouter = require('./routes/account');
 | 
			
		||||
const overviewRouter = require('./routes/overview');
 | 
			
		||||
const userRouter = require('./routes/users');
 | 
			
		||||
const squadRouter = require('./routes/squads');
 | 
			
		||||
| 
						 | 
				
			
			@ -73,6 +74,7 @@ app.use(urls.ranks, rankRouter);
 | 
			
		|||
app.use(urls.decorations, decorationRouter);
 | 
			
		||||
app.use(urls.awards, apiAuthenticationMiddleware, checkHl, awardingRouter);
 | 
			
		||||
app.use(urls.command, apiAuthenticationMiddleware, checkAdmin, commandRouter);
 | 
			
		||||
app.use(urls.account, apiAuthenticationMiddleware, checkAdmin, accountRouter);
 | 
			
		||||
 | 
			
		||||
// send index.html on all different paths
 | 
			
		||||
app.use(function (req, res) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
.overview {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  overflow-y: scroll;
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
  bottom: 20px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  padding-left: 50px;
 | 
			
		||||
  padding-top: 190px;
 | 
			
		||||
  margin-left: 10px;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.trash {
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.table {
 | 
			
		||||
  overflow-wrap: break-word;
 | 
			
		||||
  table-layout: fixed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.table-container {
 | 
			
		||||
  margin-top: 10px;
 | 
			
		||||
  overflow-x: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.table-head {
 | 
			
		||||
  background: #222222;
 | 
			
		||||
  color: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cell-outline {
 | 
			
		||||
  outline: 1px solid #D4D4D4;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,71 @@
 | 
			
		|||
<div class="overview">
 | 
			
		||||
 | 
			
		||||
  <h2>Admin Panel</h2>
 | 
			
		||||
 | 
			
		||||
  <span *ngIf="showSuccessLabel"
 | 
			
		||||
        class="label label-success label-small"
 | 
			
		||||
        style="margin-left: inherit">
 | 
			
		||||
        Erfolgreich gespeichert
 | 
			
		||||
  </span>
 | 
			
		||||
 | 
			
		||||
  <div class="pull-left" style="margin-top:20px;">
 | 
			
		||||
    <div class="table-container" style="width: 75%; min-width: 500px">
 | 
			
		||||
      <table class="table table-hover">
 | 
			
		||||
        <thead>
 | 
			
		||||
        <tr class="table-head">
 | 
			
		||||
          <th class="col-sm-1" style="border-radius: 10px 0 0 0;">Username</th>
 | 
			
		||||
          <th class="col-sm-1">Activated</th>
 | 
			
		||||
          <th class="col-sm-1">Secret</th>
 | 
			
		||||
          <th class="col-sm-1">Fraktion/ Squad</th>
 | 
			
		||||
          <th class="col-sm-1">Permission</th>
 | 
			
		||||
          <th class="col-sm-1 text-center" style="border-radius: 0 10px 0 0;"></th>
 | 
			
		||||
        </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody *ngFor="let user of users$ | async">
 | 
			
		||||
        <tr class="cell-outline">
 | 
			
		||||
          <td>
 | 
			
		||||
            {{user.username}}
 | 
			
		||||
          </td>
 | 
			
		||||
          <td style="font-weight: bold">
 | 
			
		||||
            <select id="activated" name="activated" class="form-control btn dropdown-toggle"
 | 
			
		||||
                    [(ngModel)]="user.activated" (change)="updateAppUser(user)">
 | 
			
		||||
              <option value="true">activated</option>
 | 
			
		||||
              <option value="false">deactivated</option>
 | 
			
		||||
            </select>
 | 
			
		||||
          </td>
 | 
			
		||||
          <td>
 | 
			
		||||
            {{user.secret}}
 | 
			
		||||
          </td>
 | 
			
		||||
          <td>
 | 
			
		||||
            <select class="form-control"
 | 
			
		||||
                    name="squad"
 | 
			
		||||
                    id="squad"
 | 
			
		||||
                    [(ngModel)]="user.squad"
 | 
			
		||||
                    [compareWith]="equals"
 | 
			
		||||
                    (change)="updateAppUser(user)">
 | 
			
		||||
              <option [value]="0">Ohne Fraktion/ Squad</option>
 | 
			
		||||
              <option *ngFor="let squad of squads" [ngValue]="squad">
 | 
			
		||||
                {{squad.fraction == 'BLUFOR'? 'NATO' : 'CSAT'}}: {{squad.name}}
 | 
			
		||||
              </option>
 | 
			
		||||
            </select>
 | 
			
		||||
          </td>
 | 
			
		||||
          <td>
 | 
			
		||||
            <select id="permission" name="permission" class="form-control btn dropdown-toggle"
 | 
			
		||||
                    [(ngModel)]="user.permission" (change)="updateAppUser(user)">
 | 
			
		||||
              <option value="0">User</option>
 | 
			
		||||
              <option value="1">SQL</option>
 | 
			
		||||
              <option value="2">HL</option>
 | 
			
		||||
              <option value="3">MT</option>
 | 
			
		||||
              <option value="4">Admin</option>
 | 
			
		||||
            </select>
 | 
			
		||||
          </td>
 | 
			
		||||
          <td class="text-center">
 | 
			
		||||
            <span class="glyphicon glyphicon-trash trash" title="Löschen" (click)="deleteUser(user)"></span>
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
      </table>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,70 @@
 | 
			
		|||
import {Component} from "@angular/core";
 | 
			
		||||
import {AppUser, Squad} from "../models/model-interfaces";
 | 
			
		||||
import {Observable} from "rxjs/Observable";
 | 
			
		||||
import {AppUserService} from "../services/app-user-service/app-user.service";
 | 
			
		||||
import {SquadService} from "../services/squad-service/squad.service";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'admin-panel',
 | 
			
		||||
  templateUrl: './admin.component.html',
 | 
			
		||||
  styleUrls: ['./admin.component.css']
 | 
			
		||||
})
 | 
			
		||||
export class AdminComponent {
 | 
			
		||||
 | 
			
		||||
  users$: Observable<AppUser[]>;
 | 
			
		||||
 | 
			
		||||
  squads: Squad[] = [];
 | 
			
		||||
 | 
			
		||||
  showSuccessLabel = false;
 | 
			
		||||
 | 
			
		||||
  constructor(private appUserService: AppUserService,
 | 
			
		||||
              private squadService: SquadService) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.users$ = this.appUserService.getUsers();
 | 
			
		||||
    this.squadService.findSquads().subscribe(squads => {
 | 
			
		||||
      this.squads = squads;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateAppUser(user) {
 | 
			
		||||
    let updateObject = {
 | 
			
		||||
      _id: user._id,
 | 
			
		||||
      squad: user.squad,
 | 
			
		||||
      activated: user.activated,
 | 
			
		||||
      permission: user.permission
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (updateObject.squad === "0") {
 | 
			
		||||
      updateObject.squad = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.appUserService.updateUser(updateObject)
 | 
			
		||||
      .subscribe(user => {
 | 
			
		||||
        this.showSuccessLabel = true;
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
          this.showSuccessLabel = false;
 | 
			
		||||
        }, 2000)
 | 
			
		||||
      })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  deleteUser(user) {
 | 
			
		||||
    if (confirm('Soll der Nutzer "' + user.username + '" wirklich gelöscht werden?')) {
 | 
			
		||||
      this.appUserService.deleteUser(user)
 | 
			
		||||
        .subscribe((res) => {
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * compare ngValue with ngModel to assign selected element
 | 
			
		||||
   */
 | 
			
		||||
  equals(o1: Squad , o2: Squad) {
 | 
			
		||||
    if (o1 && o2) {
 | 
			
		||||
      return o1._id === o2._id;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -21,23 +21,41 @@
 | 
			
		|||
          <li routerLinkActive="active">
 | 
			
		||||
            <a routerLink='/cc-overview' class="link">Armeeübersicht</a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li *ngIf="loginService.isLoggedIn()" routerLinkActive="active">
 | 
			
		||||
          <li *ngIf="loginService.hasPermission(2)" routerLinkActive="active">
 | 
			
		||||
            <a routerLink='/cc-users' class="link">Teilnehmer</a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li *ngIf="loginService.isLoggedIn()" routerLinkActive="active">
 | 
			
		||||
          <li *ngIf="loginService.hasPermission(2)" routerLinkActive="active">
 | 
			
		||||
            <a routerLink='/cc-squads' class="link">Squads</a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li *ngIf="loginService.isLoggedIn()" routerLinkActive="active">
 | 
			
		||||
          <li *ngIf="loginService.hasPermission(2)" routerLinkActive="active">
 | 
			
		||||
            <a routerLink='/cc-decorations' class="link">Auszeichnungen</a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li *ngIf="loginService.isLoggedIn()" routerLinkActive="active">
 | 
			
		||||
          <li *ngIf="loginService.hasPermission(2)" routerLinkActive="active">
 | 
			
		||||
            <a routerLink='/cc-ranks' class="link">Ränge</a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li *ngIf="loginService.hasPermission(1) && !loginService.hasPermission(2)" class="dropdown">
 | 
			
		||||
            <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
 | 
			
		||||
               aria-expanded="false">
 | 
			
		||||
              Beantragen
 | 
			
		||||
              <span class="caret"></span>
 | 
			
		||||
            </a>
 | 
			
		||||
            <ul class="dropdown-menu">
 | 
			
		||||
              <li>
 | 
			
		||||
                <a [routerLink]="['/request-promotion']">Beförderung</a>
 | 
			
		||||
              </li>
 | 
			
		||||
              <li>
 | 
			
		||||
                <a [routerLink]="['/request-award']">Orden/ Auszeichnung</a>
 | 
			
		||||
              </li>
 | 
			
		||||
            </ul>
 | 
			
		||||
          </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
 | 
			
		||||
        <ul class="nav navbar-nav" style="float: right">
 | 
			
		||||
          <li *ngIf="loginService.hasPermission(4)" routerLinkActive="active">
 | 
			
		||||
            <a routerLink='/admin-panel' class="link">Admin Panel</a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li *ngIf="authEnabled" class="link" style="cursor: pointer">
 | 
			
		||||
            <a *ngIf="loginService.isLoggedIn()" (click)="logout()" >Abmelden</a>
 | 
			
		||||
            <a *ngIf="loginService.isLoggedIn()" (click)="logout()">Abmelden</a>
 | 
			
		||||
          </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
      </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,9 +3,11 @@ export class AppConfig {
 | 
			
		|||
 | 
			
		||||
  public readonly apiUrl = '';
 | 
			
		||||
 | 
			
		||||
  public readonly apiAppUserPath        = '/account/';
 | 
			
		||||
  public readonly apiAwardPath          = '/awardings/';
 | 
			
		||||
  public readonly apiDecorationPath     = '/decorations/';
 | 
			
		||||
  public readonly apiAuthenticationPath = '/authenticate';
 | 
			
		||||
  public readonly apiSignupPath         = '/authenticate/signup';
 | 
			
		||||
  public readonly apiRankPath           = '/ranks/';
 | 
			
		||||
  public readonly apiSquadPath          = '/squads/';
 | 
			
		||||
  public readonly apiUserPath           = '/users/';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,19 +22,25 @@ import {RankStore} from "./services/stores/rank.store";
 | 
			
		|||
import {RankService} from "./services/rank-service/rank.service";
 | 
			
		||||
import {DecorationItemComponent} from "./decorations/decoration-list/decoration-item.component";
 | 
			
		||||
import {AppConfig} from "./app.config";
 | 
			
		||||
import {LoginGuard} from "./login/login.guard";
 | 
			
		||||
import {LoginGuardAdmin, LoginGuardHL, LoginGuardSQL} from "./login/login.guard";
 | 
			
		||||
import {AwardingService} from "./services/awarding-service/awarding.service";
 | 
			
		||||
import {HttpClient} from "./services/http-client";
 | 
			
		||||
import {ArmyService} from "./services/army-service/army.service";
 | 
			
		||||
import { ClipboardModule } from 'ngx-clipboard';
 | 
			
		||||
import {AppUserService} from "./services/app-user-service/app-user.service";
 | 
			
		||||
import {AppUserStore} from "./services/stores/app-user.store";
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [BrowserModule, FormsModule, ReactiveFormsModule, appRouting, HttpModule, ClipboardModule],
 | 
			
		||||
  providers: [
 | 
			
		||||
    HttpClient,
 | 
			
		||||
    LoginService,
 | 
			
		||||
    LoginGuard,
 | 
			
		||||
    LoginGuardSQL,
 | 
			
		||||
    LoginGuardHL,
 | 
			
		||||
    LoginGuardAdmin,
 | 
			
		||||
    ArmyService,
 | 
			
		||||
    AppUserService,
 | 
			
		||||
    AppUserStore,
 | 
			
		||||
    UserService,
 | 
			
		||||
    UserStore,
 | 
			
		||||
    SquadService,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,14 @@
 | 
			
		|||
import {Routes, RouterModule} from '@angular/router';
 | 
			
		||||
import {LoginComponent} from './login/index';
 | 
			
		||||
import {NotFoundComponent} from './not-found/not-found.component';
 | 
			
		||||
import {LoginGuard} from './login/login.guard';
 | 
			
		||||
import {LoginGuardAdmin, LoginGuardHL} from './login/login.guard';
 | 
			
		||||
import {usersRoutes, usersRoutingComponents} from "./users/users.routing";
 | 
			
		||||
import {squadsRoutes, squadsRoutingComponents} from "./squads/squads.routing";
 | 
			
		||||
import {decorationsRoutes, decorationsRoutingComponents} from "./decorations/decoration.routing";
 | 
			
		||||
import {ranksRoutes, ranksRoutingComponents} from "./ranks/ranks.routing";
 | 
			
		||||
import {armyRoutes, armyRoutingComponents} from "./army/army.routing";
 | 
			
		||||
import {SignupComponent} from "./login/signup.component";
 | 
			
		||||
import {AdminComponent} from "./admin/admin.component";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export const appRoutes: Routes = [
 | 
			
		||||
| 
						 | 
				
			
			@ -15,10 +17,13 @@ export const appRoutes: Routes = [
 | 
			
		|||
  {path: '', redirectTo: '/cc-overview', pathMatch: 'full'},
 | 
			
		||||
 | 
			
		||||
  {path: 'login', component: LoginComponent},
 | 
			
		||||
  {path: 'cc-users', children: usersRoutes, canActivate: [LoginGuard]},
 | 
			
		||||
  {path: 'cc-squads', children: squadsRoutes, canActivate: [LoginGuard]},
 | 
			
		||||
  {path: 'cc-decorations', children: decorationsRoutes, canActivate: [LoginGuard]},
 | 
			
		||||
  {path: 'cc-ranks', children: ranksRoutes, canActivate: [LoginGuard]},
 | 
			
		||||
  {path: 'signup', component: SignupComponent},
 | 
			
		||||
  {path: 'cc-users', children: usersRoutes, canActivate: [LoginGuardHL]},
 | 
			
		||||
  {path: 'cc-squads', children: squadsRoutes, canActivate: [LoginGuardHL]},
 | 
			
		||||
  {path: 'cc-decorations', children: decorationsRoutes, canActivate: [LoginGuardHL]},
 | 
			
		||||
  {path: 'cc-ranks', children: ranksRoutes, canActivate: [LoginGuardHL]},
 | 
			
		||||
 | 
			
		||||
  {path: 'admin-panel', component: AdminComponent, canActivate: [LoginGuardAdmin]},
 | 
			
		||||
 | 
			
		||||
  /** Redirect Konfigurationen **/
 | 
			
		||||
  {path: '404', component: NotFoundComponent},
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +32,7 @@ export const appRoutes: Routes = [
 | 
			
		|||
 | 
			
		||||
export const appRouting = RouterModule.forRoot(appRoutes);
 | 
			
		||||
 | 
			
		||||
export const routingComponents = [LoginComponent, ...armyRoutingComponents , NotFoundComponent, ...usersRoutingComponents,
 | 
			
		||||
export const routingComponents = [LoginComponent, SignupComponent, AdminComponent, ...armyRoutingComponents , NotFoundComponent, ...usersRoutingComponents,
 | 
			
		||||
  ...squadsRoutingComponents, ...decorationsRoutingComponents, ...ranksRoutingComponents];
 | 
			
		||||
 | 
			
		||||
export const routingProviders = [LoginGuard];
 | 
			
		||||
export const routingProviders = [LoginGuardHL];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@
 | 
			
		|||
  margin: 0 auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-signin .form-signin-heading, .form-signin .checkbox {
 | 
			
		||||
.form-signin .form-signin-heading, .form-signin .checkbox, #inputEmail {
 | 
			
		||||
  margin-bottom: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@
 | 
			
		|||
      </button>
 | 
			
		||||
      <span *ngIf="showErrorLabel"
 | 
			
		||||
            class="center-block label label-danger" style="font-size: medium; padding: 2px; margin-top: 2px">
 | 
			
		||||
        Login fehlgeschlagen
 | 
			
		||||
        {{error}}
 | 
			
		||||
    </span>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,8 @@ export class LoginComponent implements OnInit {
 | 
			
		|||
 | 
			
		||||
  showErrorLabel = false;
 | 
			
		||||
 | 
			
		||||
  error: string;
 | 
			
		||||
 | 
			
		||||
  loading = false;
 | 
			
		||||
 | 
			
		||||
  returnUrl: string;
 | 
			
		||||
| 
						 | 
				
			
			@ -25,8 +27,8 @@ export class LoginComponent implements OnInit {
 | 
			
		|||
  ngOnInit() {
 | 
			
		||||
    // reset login status
 | 
			
		||||
    this.loginService.logout();
 | 
			
		||||
    // redirect to user overview on success
 | 
			
		||||
    this.returnUrl = '/cc-users'
 | 
			
		||||
    // redirect on success
 | 
			
		||||
    this.returnUrl = '/cc-overview'
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  login(username: string, password: string) {
 | 
			
		||||
| 
						 | 
				
			
			@ -38,6 +40,8 @@ export class LoginComponent implements OnInit {
 | 
			
		|||
            this.router.navigate([this.returnUrl]);
 | 
			
		||||
          },
 | 
			
		||||
          error => {
 | 
			
		||||
            console.log(error)
 | 
			
		||||
            this.error = error._body;
 | 
			
		||||
            this.showErrorLabel = true;
 | 
			
		||||
            setTimeout(() => {
 | 
			
		||||
              this.showErrorLabel = false;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,14 +2,57 @@ import { Injectable } from '@angular/core';
 | 
			
		|||
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class LoginGuard implements CanActivate {
 | 
			
		||||
export class LoginGuardSQL implements CanActivate {
 | 
			
		||||
 | 
			
		||||
  constructor(private router: Router) { }
 | 
			
		||||
 | 
			
		||||
  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
 | 
			
		||||
    if (localStorage.getItem('currentUser')) {
 | 
			
		||||
      // logged in so return true
 | 
			
		||||
      return true;
 | 
			
		||||
      let currentUser = JSON.parse(localStorage.getItem('currentUser'));
 | 
			
		||||
      if (currentUser.permission === 1) {
 | 
			
		||||
        // 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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class LoginGuardHL 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 >= 2) {
 | 
			
		||||
        // 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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class LoginGuardAdmin 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 === 4) {
 | 
			
		||||
        // logged and correct permission so return true
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // not logged in so redirect to login page with the return url
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
<form class="form-signin" (ngSubmit)="login(userName.value, password.value, secret.value)">
 | 
			
		||||
 | 
			
		||||
  <div class="row">
 | 
			
		||||
    <h2 style="text-align: center;" class="form-signin-heading">Registrieren</h2>
 | 
			
		||||
 | 
			
		||||
    <p>Dieses Formular nur ausfüllen wenn du einer <b>HL</b> angehörst oder <b>SQL</b> bist. Dabei den Nutzernamen aus dem OPT Forum verwenden!
 | 
			
		||||
      Im Forum eine Nachricht an <a href="https://opt-dev.de/dashboard/index.php?conversation-add/&userID=9" target="_blank">HardiReady</a>
 | 
			
		||||
      senden, in welcher der 'geheime Text' drin steht, den du bei der Registrierung nutzt.<br>
 | 
			
		||||
      Dabei kann es sich um irgend eine willkürliche Zeichenfolge oder einen Satz handeln - dient nur dem Abgleich.
 | 
			
		||||
      Anschließend wird dein Account aktiviert und du wirst darüber per PN informiert.</p>
 | 
			
		||||
 | 
			
		||||
    <label for="inputEmail" class="sr-only">Benutzername</label>
 | 
			
		||||
    <input #userName id="inputEmail" class="form-control" placeholder="Benutzername" required="" autofocus="">
 | 
			
		||||
 | 
			
		||||
    <label for="inputPassword" class="sr-only">Passwort</label>
 | 
			
		||||
    <input #password type="password" id="inputPassword" class="form-control" placeholder="Passwort" required="">
 | 
			
		||||
 | 
			
		||||
    <label for="inputSecret" class="sr-only">Secret</label>
 | 
			
		||||
    <input #secret type="text" id="inputSecret" class="form-control" placeholder="Geheimer Text für PN Abgleich"
 | 
			
		||||
           required="">
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <div class="form-group">
 | 
			
		||||
      <button type="submit" class="btn btn-lg btn-block btn-primary">
 | 
			
		||||
        <span *ngIf="!loading">Registrieren</span>
 | 
			
		||||
        <span *ngIf="loading" class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span>
 | 
			
		||||
      </button>
 | 
			
		||||
      <span *ngIf="showErrorLabel"
 | 
			
		||||
            class="center-block label label-danger" style="font-size: medium; padding: 2px; margin-top: 2px">
 | 
			
		||||
        Login fehlgeschlagen
 | 
			
		||||
    </span>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</form>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
import {Component, OnInit} from "@angular/core";
 | 
			
		||||
import {ActivatedRoute, Router} from "@angular/router";
 | 
			
		||||
import {LoginService} from "../services/login-service/login-service";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  moduleId: module.id,
 | 
			
		||||
  templateUrl: './signup.component.html',
 | 
			
		||||
  styleUrls: ['./login.component.css']
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export class SignupComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
  showErrorLabel = false;
 | 
			
		||||
 | 
			
		||||
  loading = false;
 | 
			
		||||
 | 
			
		||||
  returnUrl: string;
 | 
			
		||||
 | 
			
		||||
  constructor(private route: ActivatedRoute,
 | 
			
		||||
              private router: Router,
 | 
			
		||||
              private loginService: LoginService) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    // reset login status
 | 
			
		||||
    this.loginService.logout();
 | 
			
		||||
    // redirect on success
 | 
			
		||||
    this.returnUrl = '/cc-overview'
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  login(username: string, password: string, secret: string) {
 | 
			
		||||
    if (username.length > 0 && password.length > 0 && secret.length > 0) {
 | 
			
		||||
      this.loading = true;
 | 
			
		||||
      this.loginService.signUp(username, password, secret)
 | 
			
		||||
        .subscribe(
 | 
			
		||||
          data => {
 | 
			
		||||
            console.log(data)
 | 
			
		||||
            //this.router.navigate([this.returnUrl]);
 | 
			
		||||
          },
 | 
			
		||||
          error => {
 | 
			
		||||
            this.showErrorLabel = true;
 | 
			
		||||
            setTimeout(() => {
 | 
			
		||||
              this.showErrorLabel = false;
 | 
			
		||||
            }, 4000);
 | 
			
		||||
            this.loading = false;
 | 
			
		||||
          });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +1,12 @@
 | 
			
		|||
export interface AppUser {
 | 
			
		||||
  _id?: string;
 | 
			
		||||
  username?: string;
 | 
			
		||||
  squad?: Squad;
 | 
			
		||||
  secret?: string;
 | 
			
		||||
  activated: boolean;
 | 
			
		||||
  permission: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface User {
 | 
			
		||||
  _id?: string;
 | 
			
		||||
  boardUserId?: number;
 | 
			
		||||
| 
						 | 
				
			
			@ -68,59 +77,3 @@ export interface Army {
 | 
			
		|||
  },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Tag {
 | 
			
		||||
  label: string;
 | 
			
		||||
}
 | 
			
		||||
export interface Assignee {
 | 
			
		||||
  name?: string;
 | 
			
		||||
  email?: string;
 | 
			
		||||
}
 | 
			
		||||
export interface Task {
 | 
			
		||||
  id?: number;
 | 
			
		||||
  title?: string;
 | 
			
		||||
  description?: string;
 | 
			
		||||
  tags?: Tag[];
 | 
			
		||||
  favorite?: boolean;
 | 
			
		||||
  state?: string;
 | 
			
		||||
  assignee?: Assignee;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const states = ['BACKLOG', 'IN_PROGRESS', 'TEST', 'COMPLETED'];
 | 
			
		||||
 | 
			
		||||
export function createInitialTask(): Task {
 | 
			
		||||
  return {
 | 
			
		||||
    assignee: {},
 | 
			
		||||
    tags: [],
 | 
			
		||||
    state: states[0]
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export const stateGroups = [
 | 
			
		||||
  {
 | 
			
		||||
    label: 'Planung',
 | 
			
		||||
    states: ['BACKLOG']
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    label: 'Entwicklung',
 | 
			
		||||
    states: ['IN_PROGRESS', 'TEST']
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    label: 'In Produktion',
 | 
			
		||||
    states: ['COMPLETED']
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export const stateTexts = {
 | 
			
		||||
  'BACKLOG': 'Backlog',
 | 
			
		||||
  'IN_PROGRESS': 'In Bearbeitung',
 | 
			
		||||
  'TEST': 'Im Test',
 | 
			
		||||
  'COMPLETED': 'Abgeschlossen'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const statesAsObjects = [{name: 'BACKLOG', text: 'Backlog'},
 | 
			
		||||
  {name: 'IN_PROGRESS', text: 'In Bearbeitung'},
 | 
			
		||||
  {name: 'TEST', text: 'Test'},
 | 
			
		||||
  {name: 'COMPLETED', text: 'Abgeschlossen'}];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
import {Injectable} from "@angular/core";
 | 
			
		||||
import {AppUser, User} from "../../models/model-interfaces";
 | 
			
		||||
import {URLSearchParams} from "@angular/http";
 | 
			
		||||
import {Observable} from "rxjs/Observable";
 | 
			
		||||
import {ADD, EDIT, LOAD, REMOVE} from "../stores/user.store";
 | 
			
		||||
import {AppConfig} from "../../app.config";
 | 
			
		||||
import {HttpClient} from "../http-client";
 | 
			
		||||
import {AppUserStore} from "../stores/app-user.store";
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AppUserService {
 | 
			
		||||
 | 
			
		||||
  users$: Observable<AppUser[]>;
 | 
			
		||||
 | 
			
		||||
  constructor(private http: HttpClient,
 | 
			
		||||
              private appUserStore: AppUserStore,
 | 
			
		||||
              private config: AppConfig) {
 | 
			
		||||
    this.users$ = appUserStore.items$;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getUsers() {
 | 
			
		||||
    this.http.get(this.config.apiUrl + this.config.apiAppUserPath)
 | 
			
		||||
      .map(res => res.json())
 | 
			
		||||
      .do((users) => {
 | 
			
		||||
        this.appUserStore.dispatch({type: LOAD, data: users});
 | 
			
		||||
      }).subscribe(_ => {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return this.users$;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateUser(user: AppUser) {
 | 
			
		||||
      return this.http.patch(this.config.apiUrl + this.config.apiAppUserPath + user._id, user)
 | 
			
		||||
        .map(res => res.json())
 | 
			
		||||
        .do(savedUser => {
 | 
			
		||||
          const action = {type: EDIT, data: savedUser};
 | 
			
		||||
          this.appUserStore.dispatch(action);
 | 
			
		||||
        });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  deleteUser(user) {
 | 
			
		||||
    return this.http.delete(this.config.apiUrl + this.config.apiAppUserPath + user._id)
 | 
			
		||||
      .do(res => {
 | 
			
		||||
        this.appUserStore.dispatch({type: REMOVE, data: user});
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -24,6 +24,17 @@ export class LoginService {
 | 
			
		|||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  signUp(username: string, password: string, secret: string) {
 | 
			
		||||
    return this.http.post(this.config.apiUrl + this.config.apiSignupPath, {username: username, password: password, secret: secret})
 | 
			
		||||
      .map((response: Response) => {
 | 
			
		||||
        // login successful if there's a jwt token in the response
 | 
			
		||||
        let user = response.json();
 | 
			
		||||
        if (user) {
 | 
			
		||||
          //TODO
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  logout() {
 | 
			
		||||
    // remove user from local storage
 | 
			
		||||
    localStorage.removeItem('currentUser');
 | 
			
		||||
| 
						 | 
				
			
			@ -33,4 +44,9 @@ export class LoginService {
 | 
			
		|||
    return !this.authEnabled || localStorage.getItem('currentUser') != null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  hasPermission(level : number) {
 | 
			
		||||
    let currentUser = JSON.parse(localStorage.getItem('currentUser'));
 | 
			
		||||
    return this.isLoggedIn() && currentUser.permission >= level;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
import {BehaviorSubject} from "rxjs/BehaviorSubject";
 | 
			
		||||
import {AppUser, User} from "../../models/model-interfaces";
 | 
			
		||||
 | 
			
		||||
export const LOAD = 'LOAD';
 | 
			
		||||
export const ADD = 'ADD';
 | 
			
		||||
export const EDIT = 'EDIT';
 | 
			
		||||
export const REMOVE = 'REMOVE';
 | 
			
		||||
 | 
			
		||||
export class AppUserStore {
 | 
			
		||||
 | 
			
		||||
  private appUsers: AppUser[] = [];
 | 
			
		||||
 | 
			
		||||
  items$ = new BehaviorSubject<AppUser[]>([]);
 | 
			
		||||
 | 
			
		||||
  dispatch(action) {
 | 
			
		||||
    this.appUsers = this._reduce(this.appUsers, action);
 | 
			
		||||
    this.items$.next(this.appUsers);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _reduce(users: AppUser[], action) {
 | 
			
		||||
    switch (action.type) {
 | 
			
		||||
      case LOAD:
 | 
			
		||||
        return [...action.data];
 | 
			
		||||
      case ADD:
 | 
			
		||||
        return [...users, action.data];
 | 
			
		||||
      case EDIT:
 | 
			
		||||
        return users.map(user => {
 | 
			
		||||
          const editedUser = action.data;
 | 
			
		||||
          if (user._id !== editedUser._id) {
 | 
			
		||||
            return user;
 | 
			
		||||
          }
 | 
			
		||||
          return editedUser;
 | 
			
		||||
        });
 | 
			
		||||
      case REMOVE:
 | 
			
		||||
        return users.filter(user => user._id !== action.data._id);
 | 
			
		||||
      default:
 | 
			
		||||
        return users;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.7 KiB  | 
		Loading…
	
		Reference in New Issue