1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 | const auth = require('./auth');
|
6 | const handleSitemap400 = require('./error.js').handleSitemap400;
|
7 | const httpUtils = require('./utils/http');
|
8 | const scope = require('./scope');
|
9 |
|
10 |
|
11 |
|
12 | const TYPES = [ 'answerspaces', 'interactions' ];
|
13 |
|
14 | function assertUidOption (options) {
|
15 | if (!options.uid) {
|
16 | throw new TypeError('"uid" is mandatory');
|
17 | }
|
18 | }
|
19 |
|
20 | function assertIdOption (options) {
|
21 | if (options.type !== 'answerspaces' && !options.id) {
|
22 | throw new TypeError('"id" is mandatory');
|
23 | }
|
24 | }
|
25 |
|
26 | function assertOptionsMatchResult (options, result) {
|
27 | const resultId = result[options.type].id;
|
28 | if (options.id && options.id !== resultId) {
|
29 | throw new Error(`request-result mismatch: id=${options.id}, result=${resultId}`);
|
30 | }
|
31 | const resultName = result[options.type].name;
|
32 | if (options.type === 'answerspaces' && options.uid !== resultName) {
|
33 | throw new Error(`request-result mismatch: name=${options.uid}, result=${resultName}`);
|
34 | }
|
35 | }
|
36 |
|
37 | function assertTypeOption (options) {
|
38 | if (!options.type) {
|
39 | throw new TypeError('"type" is mandatory');
|
40 | }
|
41 | }
|
42 |
|
43 | function assertTypeAnswerspaces (options) {
|
44 | if (options.type !== 'answerspaces') {
|
45 | throw new TypeError('"type" must be "answerspaces"');
|
46 | }
|
47 | }
|
48 |
|
49 | function assertKnownTypeOption (options) {
|
50 | if (!~TYPES.indexOf(options.type)) {
|
51 | throw new TypeError(`"${options.type}" is not a known type`);
|
52 | }
|
53 | }
|
54 |
|
55 | function assertDataOption (options) {
|
56 | if (!options.data || typeof options.data !== 'object') {
|
57 | throw new TypeError('"data" object is mandatory');
|
58 | }
|
59 | }
|
60 |
|
61 | function assertMatchingIdOption (options) {
|
62 | if (options.id && options.id !== options.data.id) {
|
63 | throw new Error(`"id"s in resource and options do not match: ${options.id}, ${options.data.id}`);
|
64 | }
|
65 | }
|
66 |
|
67 | function decorateWithOptionsAssertions (fn, assertions) {
|
68 | return (options) => {
|
69 | options = options || {};
|
70 | assertions.forEach((assert) => assert(options));
|
71 |
|
72 | return fn(options);
|
73 | };
|
74 | }
|
75 |
|
76 | const makeResourceURL = (options, a) => {
|
77 | let result = `${a.origin}/_api/v2/answerspaces/${options.uid}`;
|
78 | if (options.type !== 'answerspaces') {
|
79 | result += `/${options.type}`;
|
80 | if (options.id) {
|
81 | result += `/${options.id}`;
|
82 | }
|
83 | }
|
84 | return result;
|
85 | };
|
86 |
|
87 | const deleteResource = decorateWithOptionsAssertions((options) => {
|
88 | return auth.read()
|
89 | .then((a) => httpUtils.sendRequest({
|
90 | credential: a.credential,
|
91 | method: 'DELETE',
|
92 | url: makeResourceURL(options, a)
|
93 | }));
|
94 | }, [
|
95 | assertUidOption,
|
96 | assertTypeOption,
|
97 | assertKnownTypeOption,
|
98 | assertIdOption
|
99 | ]);
|
100 |
|
101 | const getResource = decorateWithOptionsAssertions((options) => {
|
102 | return auth.read()
|
103 | .then((a) => httpUtils.sendRequest({
|
104 | credential: a.credential,
|
105 | url: makeResourceURL(options, a)
|
106 | }))
|
107 | .then((result) => {
|
108 | assertOptionsMatchResult(options, result);
|
109 | return result;
|
110 | });
|
111 | }, [
|
112 | assertUidOption,
|
113 | assertTypeOption,
|
114 | assertKnownTypeOption,
|
115 | assertIdOption
|
116 | ]);
|
117 |
|
118 | const CREDS_MISSING = 'no credentials';
|
119 | const CREDS_GOOD = 'authorised';
|
120 | const CREDS_BAD = 'access denied';
|
121 |
|
122 |
|
123 | function getAuthStatus () {
|
124 | return auth.read()
|
125 | .then(() => scope.getUID())
|
126 | .then((uid) => getResource({ uid, type: 'answerspaces' }))
|
127 | .then(() => CREDS_GOOD)
|
128 | .catch((err) => {
|
129 | if (err.message === '401') {
|
130 | return CREDS_BAD;
|
131 | }
|
132 | if (err.message.indexOf('not yet logged in') === 0) {
|
133 | return CREDS_MISSING;
|
134 | }
|
135 | throw err;
|
136 | });
|
137 | }
|
138 |
|
139 | const putResource = decorateWithOptionsAssertions((options) => {
|
140 | const body = {};
|
141 | body[options.type] = options.data;
|
142 | let method;
|
143 | if (options.id || options.type === 'answerspaces') {
|
144 | method = 'PUT';
|
145 | } else {
|
146 | method = 'POST';
|
147 | }
|
148 | return auth.read()
|
149 | .then((a) => httpUtils.sendRequest({
|
150 | body,
|
151 | credential: a.credential,
|
152 | method,
|
153 | url: makeResourceURL(options, a)
|
154 | }));
|
155 | }, [
|
156 | assertUidOption,
|
157 | assertTypeOption,
|
158 | assertKnownTypeOption,
|
159 | assertDataOption,
|
160 | assertMatchingIdOption
|
161 | ]);
|
162 |
|
163 |
|
164 | const wipeSiteMap = decorateWithOptionsAssertions((options) => {
|
165 | const data = options.data;
|
166 | options = Object.assign({}, options);
|
167 | options.data = {
|
168 | id: data.id,
|
169 | name: data.name,
|
170 | sitemap: ''
|
171 | };
|
172 | return putResource(options)
|
173 | .catch(handleSitemap400);
|
174 | }, [
|
175 | assertTypeAnswerspaces
|
176 | ]);
|
177 |
|
178 | module.exports = {
|
179 | CREDS_MISSING,
|
180 | CREDS_GOOD,
|
181 | CREDS_BAD,
|
182 | deleteResource,
|
183 | getAuthStatus,
|
184 | getResource,
|
185 | putResource,
|
186 | TYPES,
|
187 | wipeSiteMap
|
188 | };
|