Completed
Push — master ( fc387c...26a6cb )
by
unknown
01:05
created

src/router/api-router.js   B

Complexity

Total Complexity 39
Complexity/F 1.63

Size

Lines of Code 203
Function Count 24

Duplication

Duplicated Lines 0
Ratio 0 %

Test Coverage

Coverage 71.93%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
nc 1536
dl 0
loc 203
ccs 41
cts 57
cp 0.7193
rs 8.2857
noi 1
cc 0
wmc 39
mnd 2
bc 17
fnc 24
crap 0
bpm 0.7083
cpm 1.625

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
          url: Joi.string().uri().allow(''),
134
          contents: Joi.string(),
135
          isActivated: Joi.boolean().required(),
136
        },
137
      },
138
    },
139
  },
140
  {
141
    method: 'PUT',
142
    path: `${config.statusApiPrefix}/{statusId}`,
143
    handler: (request, reply) => {
144 2
      const status = Object.assign({}, request.payload);
145
      let unset;
146 2
      if (!status.startTime && !status.endTime) {
147 1
        unset = { startTime: 1, endTime: 1 };
148
      } else {
149 1
        status.startTime = (status.startTime) ? new Date(Date.parse(status.startTime)) : undefined;
150 1
        status.endTime = (status.endTime) ? new Date(Date.parse(status.endTime)) : undefined;
151
      }
152
153 2
      Status.update(request.params.statusId, status, unset)
0 ignored issues
show
Bug introduced by
The variable unset seems to not be initialized for all possible execution paths. Are you sure update handles undefined variables?
Loading history...
154 2
        .then(result => reply(result))
155
        .catch(err => reply(err));
156
    },
157
    config: {
158
      validate: {
159
        params: {
160
          statusId: Joi.string().required(),
161
        },
162
        payload: {
163
          startTime: Joi.string().isoDate(),
164
          endTime: Joi.string().isoDate(),
165
          deviceTypes: Joi.array().items(Joi.string()).required(),
166
          deviceSemVersion: Joi.string().regex(/^(([*>=<]{1,2}[0-9A-Za-z.-]*[\s]*)[\s|]*)+$/).required(),
167
          appSemVersion: Joi.string().regex(/^(([*>=<]{1,2}[0-9A-Za-z.-]*[\s]*)[\s|]*)+$/).required(),
168
          type: Joi.string().required(),
169
          url: Joi.string().uri().allow(''),
170
          contents: Joi.string(),
171
          isActivated: Joi.boolean().required(),
172
        },
173
      },
174
    },
175
  },
176
  {
177
    method: 'PUT',
178
    path: `${config.statusApiPrefix}/{statusId}/{action}`,
179
    handler: (request, reply) => {
180 2
      Status.update(request.params.statusId, { isActivated: request.params.action === 'activate' })
181 2
        .then(result => reply(result))
182
        .catch(err => reply(err));
183
    },
184
    config: {
185
      validate: {
186
        params: {
187
          statusId: Joi.string().required(),
188
          action: Joi.string().valid('activate', 'deactivate').required(),
189
        },
190
      },
191
    },
192
  },
193
  {
194
    method: 'DELETE',
195
    path: `${config.statusApiPrefix}/{statusId}`,
196
    handler: (request, reply) => {
197 1
      Status.remove(request.params.statusId)
198 1
        .then(result => reply(result))
199
        .catch(err => reply(err));
200
    },
201
    config: {
202
      validate: {
203
        params: {
204
          statusId: Joi.string().required(),
205
        },
206
      },
207
    },
208
  },
209
];
210