Completed
Push — master ( b6e14c...5630cf )
by
unknown
53s
created

src/router/api-router.js   B

Complexity

Total Complexity 37
Complexity/F 1.54

Size

Lines of Code 197
Function Count 24

Duplication

Duplicated Lines 0
Ratio 0 %

Test Coverage

Coverage 71.43%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 0
wmc 37
c 3
b 0
f 0
nc 384
mnd 2
bc 16
fnc 24
dl 0
loc 197
ccs 40
cts 56
cp 0.7143
crap 0
rs 8.6
bpm 0.6666
cpm 1.5416
noi 0

1 Function

Rating   Name   Duplication   Size   Complexity  
B api-router.js ➔ ??? 0 17 5
1
/**
2
 * Service API router
3
 *
4
 * @since 1.0.0
5
 */
6
7 1
const Joi = require('joi');
8 1
const Status = require('./../repository/Status');
9 1
const User = require('./../repository/User');
10 1
const config = require('../config/server.config').url;
11 1
const util = require('../common/common-util');
12 1
const authUtil = require('../common/auth-util');
13 1
const dateUtil = require('../common/date-util');
14 1
const NotifierError = require('../common/Error');
15 1
const logger = require('winston');
16
17 1
module.exports = [
18
  {
19
    method: 'POST',
20
    path: `${config.apiPrefix}/login`,
21
    handler: (request, reply) => {
22 2
      const clientIP = util.getClientIp(request);
23 2
      if (process.env.ALLOWED_IP && !process.env.ALLOWED_IP.includes(clientIP)) {
24
        logger.warn(`[Auth] This client IP is not allowed.: ${clientIP}`);
25
        return reply(new NotifierError(NotifierError.Types.FORBIDDEN_IP_ADDRESS, { remoteAddress: clientIP }));
26
      }
27 2
      if (!request.payload.username || !request.payload.password) {
28
        return reply(new NotifierError(NotifierError.Types.AUTH_MISSING_PARAMS));
29
      }
30 2
      return User.find({ username: request.payload.username }).then((account) => {
31 2
        if (!account || account.length === 0 || !authUtil.comparePassword(request.payload, account[0].password)) {
32 1
          return reply(new NotifierError(NotifierError.Types.AUTH_INVALID_PARAMS));
33
        }
34 1
        const token = authUtil.generateToken(Object.assign({}, account[0], { ip: clientIP }));
35 1
        return reply().state('token', token);
36
      });
37
    },
38
    config: {
39
      auth: false,
40
    },
41
  },
42
  {
43
    method: 'PUT',
44
    path: `${config.apiPrefix}/passwords`,
45 1
    handler: (request, reply) => User.updatePassword(request.auth.credentials.username, request.payload.password)
46 1
      .then(result => reply(result))
47
      .catch(err => reply(err)),
48
    config: {
49
      validate: {
50
        payload: {
51
          password: Joi.string().min(8).required(),
52
        },
53
      },
54
    },
55
  },
56
  {
57
    method: 'GET',
58
    path: `${config.statusApiPrefix}`,
59
    handler: (request, reply) => {
60
      let filter = {};
61
      if (request.query.filter === 'current') { // 미래 포함
62
        filter = {
63
          $or: [
64
            { endTime: { $gt: new Date() } },
65
            { startTime: { $exists: false }, endTime: { $exists: false } },
66
          ],
67
        };
68
      } else if (request.query.filter === 'expired') {
69
        filter = { endTime: { $lte: new Date() } };
70
      }
71
      Promise.all([
72
        Status.find(filter, { isActivated: -1, startTime: 1, endTime: 1 }, request.query.skip, request.query.limit),
73
        Status.count(filter),
74
      ]).then(([list, totalCount]) => {
75
        reply({
76
          data: dateUtil.formatDates(list),
77
          totalCount,
78
        });
79
      }).catch(err => reply(err));
80
    },
81
    config: {
82
      validate: {
83
        query: {
84
          filter: Joi.any().valid('current', 'expired'),
85
          skip: Joi.number(),
86
          limit: Joi.number(),
87
        },
88
      },
89
    },
90
  },
91
  {
92
    method: 'GET',
93
    path: `${config.statusApiPrefix}/check`,
94
    handler: (request, reply) => {
95 4
      Status.findWithComparators(request.query.deviceType || '*', request.query.deviceVersion || '*', request.query.appVersion || '*')
96 3
        .then(result => dateUtil.formatDates(result))
97 3
        .then(result => reply({ data: result }))
98 1
        .catch(err => reply(err));
99
    },
100
    config: {
101
      validate: {
102
        query: {
103
          deviceType: Joi.string(),
104
          deviceVersion: Joi.string().regex(/^[0-9A-Za-z.*-]+$/),
105
          appVersion: Joi.string().regex(/^[0-9A-Za-z.*-]+$/),
106
        },
107
      },
108
      auth: false,
109
    },
110
  },
111
  {
112
    method: 'POST',
113
    path: `${config.statusApiPrefix}`,
114
    handler: (request, reply) => {
115 1
      const status = Object.assign({}, request.payload);
116 1
      if (status.startTime && status.endTime) {
117 1
        status.startTime = new Date(Date.parse(status.startTime));
118 1
        status.endTime = new Date(Date.parse(status.endTime));
119
      }
120 1
      Status.add(status)
121 1
        .then(result => reply(result))
122
        .catch(err => reply(err));
123
    },
124
    config: {
125
      validate: {
126
        payload: {
127
          startTime: Joi.string().isoDate(),
128
          endTime: Joi.string().isoDate(),
129
          deviceTypes: Joi.array().items(Joi.string()).required(),
130
          deviceSemVersion: Joi.string().regex(/^(([*>=<]{1,2}[0-9A-Za-z.-]*[\s]*)[\s|]*)+$/).required(),
131
          appSemVersion: Joi.string().regex(/^(([*>=<]{1,2}[0-9A-Za-z.-]*[\s]*)[\s|]*)+$/).required(),
132
          type: Joi.string().required(),
133
          contents: Joi.string(),
134
          isActivated: Joi.boolean().required(),
135
        },
136
      },
137
    },
138
  },
139
  {
140
    method: 'PUT',
141
    path: `${config.statusApiPrefix}/{statusId}`,
142
    handler: (request, reply) => {
143 1
      const status = Object.assign({}, request.payload);
144 1
      if (status.startTime && status.endTime) {
145 1
        status.startTime = new Date(Date.parse(status.startTime));
146 1
        status.endTime = new Date(Date.parse(status.endTime));
147
      }
148 1
      Status.update(request.params.statusId, status)
149 1
        .then(result => reply(result))
150
        .catch(err => reply(err));
151
    },
152
    config: {
153
      validate: {
154
        params: {
155
          statusId: Joi.string().required(),
156
        },
157
        payload: {
158
          startTime: Joi.string().isoDate(),
159
          endTime: Joi.string().isoDate(),
160
          deviceTypes: Joi.array().items(Joi.string()).required(),
161
          deviceSemVersion: Joi.string().regex(/^(([*>=<]{1,2}[0-9A-Za-z.-]*[\s]*)[\s|]*)+$/).required(),
162
          appSemVersion: Joi.string().regex(/^(([*>=<]{1,2}[0-9A-Za-z.-]*[\s]*)[\s|]*)+$/).required(),
163
          type: Joi.string().required(),
164
          contents: Joi.string(),
165
          isActivated: Joi.boolean().required(),
166
        },
167
      },
168
    },
169
  },
170
  {
171
    method: 'PUT',
172
    path: `${config.statusApiPrefix}/{statusId}/{action}`,
173
    handler: (request, reply) => {
174 2
      Status.update(request.params.statusId, { isActivated: request.params.action === 'activate' })
175 2
        .then(result => reply(result))
176
        .catch(err => reply(err));
177
    },
178
    config: {
179
      validate: {
180
        params: {
181
          statusId: Joi.string().required(),
182
          action: Joi.string().valid('activate', 'deactivate').required(),
183
        },
184
      },
185
    },
186
  },
187
  {
188
    method: 'DELETE',
189
    path: `${config.statusApiPrefix}/{statusId}`,
190
    handler: (request, reply) => {
191 1
      Status.remove(request.params.statusId)
192 1
        .then(result => reply(result))
193
        .catch(err => reply(err));
194
    },
195
    config: {
196
      validate: {
197
        params: {
198
          statusId: Joi.string().required(),
199
        },
200
      },
201
    },
202
  },
203
];
204