UNPKG

4.55 kBJavaScriptView Raw
1'use strict';
2
3// local modules
4
5const auth = require('./auth');
6const handleSitemap400 = require('./error.js').handleSitemap400;
7const httpUtils = require('./utils/http');
8const scope = require('./scope');
9
10// this module
11
12const TYPES = [ 'answerspaces', 'interactions' ];
13
14function assertUidOption (options) {
15 if (!options.uid) {
16 throw new TypeError('"uid" is mandatory');
17 }
18}
19
20function assertIdOption (options) {
21 if (options.type !== 'answerspaces' && !options.id) {
22 throw new TypeError('"id" is mandatory');
23 }
24}
25
26function 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
37function assertTypeOption (options) {
38 if (!options.type) {
39 throw new TypeError('"type" is mandatory');
40 }
41}
42
43function assertTypeAnswerspaces (options) {
44 if (options.type !== 'answerspaces') {
45 throw new TypeError('"type" must be "answerspaces"');
46 }
47}
48
49function assertKnownTypeOption (options) {
50 if (!~TYPES.indexOf(options.type)) {
51 throw new TypeError(`"${options.type}" is not a known type`);
52 }
53}
54
55function assertDataOption (options) {
56 if (!options.data || typeof options.data !== 'object') {
57 throw new TypeError('"data" object is mandatory');
58 }
59}
60
61function 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
67function decorateWithOptionsAssertions (fn, assertions) {
68 return (options) => {
69 options = options || {};
70 assertions.forEach((assert) => assert(options));
71
72 return fn(options);
73 };
74}
75
76const 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
87const 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
101const 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
118const CREDS_MISSING = 'no credentials';
119const CREDS_GOOD = 'authorised';
120const CREDS_BAD = 'access denied';
121
122// getAuthStatus () => Promise
123function 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
139const 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// just like putResource, but for a limited set of answerSpace data
164const 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
178module.exports = {
179 CREDS_MISSING,
180 CREDS_GOOD,
181 CREDS_BAD,
182 deleteResource,
183 getAuthStatus,
184 getResource,
185 putResource,
186 TYPES,
187 wipeSiteMap
188};