Passed
Push — master ( 18e035...333973 )
by Apocist
52s queued 17s
created

nodeVBulletinAPI.js ➔ constructor   B

Complexity

Conditions 5
Paths 324

Size

Total Lines 57
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 5
eloc 38
c 4
b 0
f 0
nc 324
nop 5
dl 0
loc 57
rs 8.5013

1 Function

Rating   Name   Duplication   Size   Complexity  
A nodeVBulletinAPI.js ➔ ... ➔ this.__waitingForInitializationCallback 0 2 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
'use strict';
2
const md5 = require('js-md5'),
3
    os = require('os'),
4
    request = require('request'),
5
    _ = require('underscore'),
6
    Forum = require('./Forum'),
7
    Member = require('./Member'),
8
    //Post = require('./Post'),
9
    Thread = require('./Thread'),
10
    {version} = require('./package.json');
11
12
/**
13
 *
14
 */
15
class VBApi {
16
    /**
17
     * Initialize a vb api connection .This needs to be called for the first time
18
     * @param {string} apiUrl
19
     * @param {string} apiKey
20
     * @param {string} platformName
21
     * @param {string} platformVersion
22
     * @param {object=} options - A fallback to the old style config
23
     * @param {string=} options.apiUrl
24
     * @param {string=} options.apiKey
25
     * @param {string=} options.platformName
26
     * @param {string=} options.platformVersion
27
     */
28
    constructor(apiUrl, apiKey, platformName, platformVersion, options) {
29
        this.defaultVars = {
30
            baseUrl: '', //Needed for cookie related commands
31
            apiUrl: '',
32
            apiKey: '',
33
            clientName: 'nodeVBulletinAPI',
34
            clientVersion: version,
35
            uniqueId: ''
36
        };
37
38
        this.clientSessionVars = {
39
            apiVersion: '',
40
            apiAccessToken: '',
41
            sessionHash: '', // Unused?
42
            apiClientId: '',
43
            secret: '',
44
            inited: false,
45
            error: null
46
        };
47
48
        /**
49
         * @typedef UserVars
50
         * @property {string} dbsessionhash
51
         * @property {number} userid
52
         * @property {string} username
53
         * @property {boolean} loggedIn
54
         * @type {UserVars}
55
         */
56
        this.userSessionVars = {
57
            dbsessionhash: '',
58
            username: '',
59
            userid: 0,
60
            loggedIn: false
61
        };
62
63
        /** @private */
64
        this.__waitingForInitializationCallback = function () {
65
        }; // A blank callback to be filled in
66
67
        options = options || {};
68
        options.apiUrl = apiUrl || options.apiUrl || '';
69
        options.apiKey = apiKey || options.apiKey || '';
70
        options.platformName = platformName || options.platformName || '';
71
        options.platformVersion = platformVersion || options.platformVersion || '';
72
73
        if (
74
            options.apiUrl !== ''
75
            && options.apiUrl !== ''
76
            && options.platformName !== ''
77
            && options.platformVersion !== ''
78
        ) {
79
            this.__initialize(options);
80
        } else {
81
            this.clientSessionVars.error = 'apiInit(): Initialization requires a `apiUrl`, `apiKey`, `platformName`, and `platformVersion`';
82
            this.__waitingForInitializationCallback(false);
83
        }
84
    }
85
86
    /**
87
     * Initialize a vb api connection. This needs to be called for the first time
88
     * @param {object} options
89
     * @param {string} options.apiUrl
90
     * @param {string} options.apiKey
91
     * @param {string} options.platformName
92
     * @param {string} options.platformVersion
93
     * @private
94
     */
95
    __initialize(options) {
96
        let that = this;
97
        // Run itself as a self invoked promise that is awaited by nothing. callMethod shall wait until this is finished
98
        (async function __initialize_self() {
99
            let error = null;
100
            let result = null;
101
            let regex_url = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
102
            let url_parts = regex_url.exec(options.apiUrl);
103
            that.defaultVars.baseUrl = that.defaultVars.baseUrl || url_parts[1] + ':' + url_parts[2] + url_parts[3] + '/';
104
            that.defaultVars.apiUrl = that.defaultVars.apiUrl || options.apiUrl;
105
            that.defaultVars.apiKey = that.defaultVars.apiKey || options.apiKey;
106
            that.defaultVars.uniqueId = that.defaultVars.uniqueId || md5(that.defaultVars.clientName + that.defaultVars.clientVersion + options.platformName + options.platformVersion + that.constructor.getMacAddress() + new Date().getTime());
107
108
            try {
109
                /**
110
                 *
111
                 * @type {{}}
112
                 * @property {string} apiversion
113
                 * @property {string} apiaccesstoken
114
                 * @property {string} sessionhash
115
                 * @property {string} apiclientid
116
                 * @property {string} secret
117
                 */
118
                let response = await that.callMethod({
119
                    method: 'api_init',
120
                    params: {
121
                        clientname: that.defaultVars.clientName,
122
                        clientversion: that.defaultVars.clientVersion,
123
                        platformname: options.platformName,
124
                        platformversion: options.platformVersion,
125
                        uniqueid: that.defaultVars.uniqueId
126
                    }
127
                });
128
129
                that.clientSessionVars.apiVersion = '';
130
                that.clientSessionVars.apiAccessToken = '';
131
                that.clientSessionVars.sessionHash = '';
132
                that.clientSessionVars.apiClientId = '';
133
                that.clientSessionVars.secret = '';
134
                that.clientSessionVars.inited = false;
135
                if (
136
                    response.apiversion
137
                    && response.apiaccesstoken
138
                    && response.sessionhash
139
                    && response.apiclientid
140
                    && response.secret
141
                ) {
142
                    that.clientSessionVars.apiVersion = response.apiversion;
143
                    that.clientSessionVars.apiAccessToken = response.apiaccesstoken;
144
                    that.clientSessionVars.sessionHash = response.sessionhash;
145
                    that.clientSessionVars.apiClientId = response.apiclientid;
146
                    that.clientSessionVars.secret = response.secret;
147
                    that.clientSessionVars.inited = true;
148
                    that.__waitingForInitializationCallback(true);
149
                    result = that;
150
                }
151
152
                if (result === null) {
153
                    that.clientSessionVars.error = that.constructor.parseErrorMessage(response) || 'TODO ERROR (api connection did not return a session)';
154
                    that.__waitingForInitializationCallback(false);
155
                    error = that.clientSessionVars.error;
156
                }
157
            } catch (e) {
158
                that.clientSessionVars.error = e;
159
                that.__waitingForInitializationCallback(false);
160
                // reject(e);
161
                error = e;
162
            }
163
            return error || result;
164
        }());
165
    }
166
167
    /**
168
     * Will return after #initialize() is complete. Otherwise may reject() after 15 second timeout
169
     * @param {number=15} waitTime
170
     * @returns {Promise<void>}
171
     * @fulfill {void}
172
     * @reject {string} - Error Reason
173
     */
174
    async waitForInitialization(waitTime) {
175
        let that = this;
176
        waitTime = waitTime || 15;
177
        return new Promise(async function (resolve, reject) {
178
            if (that.clientSessionVars.inited === true) {
179
                resolve();
180
            } else if (that.clientSessionVars.error !== null) {
181
                reject(that.clientSessionVars.error);
182
            }
183
184
            /**
185
             * @type {number}
186
             * @private
187
             */
188
            that.__waitingForInitializationTimeout = setTimeout(
189
                function () {
190
                    that.__waitingForInitializationCallback = function () {
191
                    }; // Set back to a blank function
192
                    if (that.clientSessionVars.inited === true) {
193
                        resolve();
194
                    } else {
195
                        reject('Connection could not be achieved due to timed out', that.clientSessionVars.error);
196
                    }
197
198
                },
199
                waitTime * 1000 // 1 minute timeout
200
            );
201
            /**
202
             * @param {boolean=true} success
203
             * @private
204
             */
205
            that.__waitingForInitializationCallback = function (success) {
206
                if (that.__waitingForInitializationTimeout) {
207
                    clearTimeout(that.__waitingForInitializationTimeout);
208
                }
209
                if (success === false) {
210
                    reject(that.clientSessionVars.error);
211
                } else {
212
                    resolve();
213
                }
214
            };
215
        })
216
    }
217
218
    /**
219
     *
220
     * @param {object} options
221
     * @param {string} options.method - Required action to take
222
     * @param {object<string,string>} [options.params={}] - Optional parameter variables
223
     * @param {?object<string,string>} [options.cookies] - Optional cookie variables
224
     * @returns {Promise<{}>}
225
     * @fulfill {{}}
226
     * @reject {string} - Error Reason
227
     */
228
    async callMethod(options) {
229
        let that = this;
230
        let sign = true;
231
        options = options || {};
232
        options.params = options.params || {};
233
        return new Promise(async function (resolve, reject) {
234
            try {
235
                if (!options.method) {
236
                    reject('callMethod(): requires a supplied method');
237
                    return;
238
                }
239
240
                // Sign all calls except for api_init
241
                if (options.method === 'api_init') {
242
                    sign = false;
243
                }
244
245
                // await a valid session before continuing (skipping waiting on __initialize())
246
                if (sign === true) {
247
                    await that.waitForInitialization();
248
                }
249
250
                // Gather our sessions variables together
251
                let reqParams = {
252
                    api_m: options.method,
253
                    api_c: that.clientSessionVars.apiClientId, //clientId
254
                    api_s: that.clientSessionVars.apiAccessToken, //apiAccessToken (may be empty)
255
                    api_v: that.clientSessionVars.apiVersion //api version
256
                };
257
                _.extend(reqParams, options.params); // Combine the arrays
258
259
                if (sign === true) {
260
                    // Generate a signature to validate that we are authenticated
261
                    if (that.clientSessionVars.inited) {
262
                        reqParams.api_sig = md5(that.clientSessionVars.apiAccessToken + that.clientSessionVars.apiClientId + that.clientSessionVars.secret + that.defaultVars.apiKey);
263
                    } else {
264
                        reject('callMethod(): requires initialization. Not initialized');
265
                        return;
266
                    }
267
                }
268
269
                // Create a valid http Request
270
                let reqOptions = {
271
                    url: that.defaultVars.apiUrl,
272
                    formData: reqParams,
273
                    headers: {
274
                        'User-Agent': that.defaultVars.clientName
275
                    }
276
                };
277
278
                // Some command require adding a cookie, we'll do that here
279
                if (options.cookies) {
280
                    let j = request.jar();
281
                    for (let variable in options.cookies) {
282
                        if (options.cookies.hasOwnProperty(variable)) {
283
                            let cookieString = variable + '=' + options.cookies[variable];
284
                            let cookie = request.cookie(cookieString);
285
                            j.setCookie(cookie, that.defaultVars.baseUrl);
286
                        }
287
                    }
288
                    reqOptions.jar = j;// Adds cookies to the request
289
                }
290
291
                request.post(
292
                    reqOptions,
293
                    function (error, response, body) {
294
                        if (!error && response.statusCode === 200) {
295
                            resolve(JSON.parse(body));
296
                        } else {
297
                            //console.log('No response');
298
                            reject('callMethod(): no response.');
299
                        }
300
                    }
301
                );
302
            } catch (e) {
303
                reject(e);
304
            }
305
        });
306
    }
307
308
    /**
309
     * Attempts to log in a user.
310
     * @param {string} username - Username
311
     * @param {string} password - clear text password TODO need to secure this more?
312
     * @param {object=} options
313
     * @param {string=} options.username - Ignore, already required at username
314
     * @param {string=} options.password - Ignore, already required at password
315
     * @returns {Promise<UserVars>}
316
     * @fulfill {UserVars}
317
     * @reject {string} - Error Reason. Expects: (TODO list common errors here)
318
     */
319
    async login(username, password, options) {
320
        options = options || {};
321
        options.username = username || options.username || '';
322
        options.password = md5(password || options.password || '');
323
        return await this.loginMD5('', '', options);
324
    }
325
326
    /**
327
     *
328
     * Attempts to log in a user. Requires the password to be pre md5 hashed.
329
     * @param {string} username - Username
330
     * @param {string} password - MD5 hashed password TODO need to secure this more?
331
     * @param {object=} options
332
     * @param {string=} options.username - Ignore, already required at username
333
     * @param {string=} options.password - Ignore, already required at password
334
     * @returns {Promise<UserVars>}
335
     * @fulfill {UserVars}
336
     * @reject {string} - Error Reason. Expects: (TODO list common errors here)
337
     */
338
    async loginMD5(username, password, options) {
339
        let that = this;
340
        options = options || {};
341
        options.username = username || options.username || {};
342
        options.password = password || options.password || {};
343
        return new Promise(async function (resolve, reject) {
344
            try {
345
                let response = await that.callMethod(
346
                    {
347
                        method: 'login_login',
348
                        params: {
349
                            vb_login_username: options.username || '',
350
                            vb_login_md5password: options.password || ''
351
                        }
352
                    }
353
                );
354
                /**
355
                 redirect_login - (NOT A ERROR) Login successful
356
                 badlogin - Username or Password incorrect. Login failed.
357
                 badlogin_strikes - Username or Password incorrect. Login failed. You have used {X} out of 5 login attempts. After all 5 have been used, you will be unable to login for 15 minutes.
358
                 */
359
                let error = that.constructor.parseErrorMessage(response);
360
                if (response.session) {
361
                    that.userSessionVars = response.session;
362
                    if (error === 'redirect_login') {
363
                        that.userSessionVars.username = options.username;
364
                        that.userSessionVars.loggedIn = true;
365
                    }
366
                }
367
                if (error === 'redirect_login') {
368
                    error = null;
369
                }
370
                if (error === null) {
371
                    resolve(that.userSessionVars);
372
                } else {
373
                    reject(error);
374
                }
375
376
            } catch (e) {
377
                reject(e);
378
            }
379
        });
380
    }
381
382
    /**
383
     * Attempts to log the user out.
384
     * @returns {Promise<boolean>} - Returns true on success, otherwise error code is rejected
385
     * @fulfill {boolean}
386
     * @reject {string} - Error Reason
387
     */
388
    async logout() {
389
        let that = this;
390
        return new Promise(async function (resolve, reject) {
391
            let error;
392
            try {
393
                let response = await that.callMethod({
394
                    method: 'login_logout'
395
                });
396
                error = that.constructor.parseErrorMessage(response);
397
                if (response.session) {
398
                    that.userSessionVars = response.session;
399
                    if (error === 'cookieclear') {
400
                        that.userSessionVars.username = '';
401
                        that.userSessionVars.loggedIn = false;
402
                    }
403
                }
404
                if (error === 'cookieclear') {
405
                    error = null;
406
                }
407
            } catch (e) {
408
                reject(e);
409
            }
410
411
            if (error) {
412
                reject(error);
413
            } else {
414
                resolve(true)
415
            }
416
        });
417
    }
418
419
    /**
420
     * Return a Mac address of a network interface for machine identification
421
     * @returns {string} macAddress
422
     */
423
    static getMacAddress() {
424
        let interfaces = os.networkInterfaces();
425
        let address = '';
426
        loop1:
427
            for (let k in interfaces) {
428
                if (interfaces.hasOwnProperty(k)) {
429
                    for (let k2 in interfaces[k]) {
430
                        if (interfaces[k].hasOwnProperty(k2)) {
431
                            let addressI = interfaces[k][k2];
432
                            if (
433
                                (addressI.family === 'IPv4' || addressI.family === 'IPv6')
434
                                && addressI.hasOwnProperty('internal')
435
                                && addressI.internal === false
436
                                && addressI.hasOwnProperty('mac')
437
                                && addressI.mac !== '00:00:00:00:00:00'
438
                            ) {
439
                                address = addressI.mac;
440
                                break loop1;
441
                            }
442
                        }
443
                    }
444
                }
445
            }
446
        return address;
447
    }
448
449
    /**
450
     *
451
     * @param {object} response - Response object from callMethod()
452
     * @returns {string} status - Error message
453
     */
454
    static parseErrorMessage(response) {
455
        let retur = '';
456
        if (
457
            response.hasOwnProperty('response')
458
            && response.response.hasOwnProperty('errormessage')
459
        ) {
460
            if (_.isArray(response.response.errormessage)) {
461
                retur = response.response.errormessage[0]
462
            } else {
463
                retur = response.response.errormessage;
464
            }
465
        }
466
        return retur;
467
    }
468
469
    /**
470
     * List every Forum and sub forum available to the user.
471
     * @returns {Promise<Forum[]>} - Array of Forum objects
472
     * @fulfill {Forum[]}
473
     * @reject {string} - Error Reason. Expects: (TODO list common errors here)
474
     */
475
    async getForums() {
476
        let that = this;
477
        return new Promise(async function (resolve, reject) {
478
            let forums = [];
479
            try {
480
                let response = await that.callMethod(
481
                    {
482
                        method: 'api_forumlist'
483
                    });
484
485
                if (response) {
486
                    for (let forum in response) {
487
                        if (response.hasOwnProperty(forum)) {
488
                            forums.push(new Forum(response[forum]));
489
                        }
490
                    }
491
                }
492
            } catch (e) {
493
                reject(e);
494
            }
495
            resolve(forums);
496
        });
497
    }
498
499
    /**
500
     * List detailed info about a forum and it's sub-forums and threads
501
     * @param {number} forumId - Forum id
502
     * @param {object=} options - Secondary Options
503
     * @param {number=} options.forumid - Ignore, already required at forumId
504
     * TODO note additional options
505
     * @returns {Promise<Forum>} - Returns a Forum object
506
     * @fulfill {Forum}
507
     * @reject {string} - Error Reason. Expects: (TODO list common errors here)
508
     */
509
    async getForum(forumId, options) {
510
        let that = this;
511
        options = options || {};
512
        options.forumid = forumId || options.forumid || ''; //required
513
514
        return new Promise(async function (resolve, reject) {
515
            let forum = null;
516
            try {
517
                let response = await that.callMethod({
518
                    method: 'forumdisplay',
519
                    params: options
520
                });
521
                if (
522
                    response
523
                    && response.hasOwnProperty('response')
524
                ) {
525
                    forum = new Forum(response.response);
526
                }
527
            } catch (e) {
528
                reject(e);
529
            }
530
            if (forum !== null) {
531
                resolve(forum);
532
            } else {
533
                reject();
534
            }
535
        });
536
    }
537
538
    /**
539
     * List detailed information about a Thread and it's Posts
540
     * @param {number} threadId - Thread id
541
     * @param {object=} options - Secondary Options
542
     * @param {number=} options.threadid - Ignore, already required at threadId
543
     * TODO note additional options
544
     * @returns {Promise<Thread>} - Returns a Thread object
545
     * @fulfill {Thread}
546
     * @reject {string} - Error Reason. Expects: (TODO list common errors here)
547
     */
548
    async getThread(threadId, options) {
549
        let that = this;
550
        options = options || {};
551
        options.threadid = threadId || options.threadid || ''; //required
552
553
        return new Promise(async function (resolve, reject) {
554
            let thread = null;
555
            try {
556
                let response = await that.callMethod({
557
                    method: 'showthread',
558
                    params: options
559
                });
560
                if (
561
                    response
562
                    && response.hasOwnProperty('response')
563
                ) {
564
                    thread = new Thread(response.response);
565
                }
566
            } catch (e) {
567
                reject(e);
568
            }
569
            if (thread !== null) {
570
                resolve(thread);
571
            } else {
572
                reject();
573
            }
574
        });
575
    }
576
577
    /**
578
     * Attempts to submit a new Post into a specified Thread
579
     * @param {number} threadId - Thread id
580
     * @param {string} message - Post Message
581
     * @param {object=} options
582
     * @param {boolean=} options.signature  - Optionally append your signature
583
     * @param {number=} options.threadid - Ignore, already required at threadId
584
     * @param {string=} options.message - Ignore, already required at message
585
     * TODO note additional options
586
     * @returns {Promise<*>} - Returns a unhandled response currently
587
     * @fulfill {*}
588
     * @reject {string} - Error Reason. Expects: (TODO list common errors here)
589
     */
590
    async newPost(threadId, message, options) {
591
        let that = this;
592
        options = options || {};
593
        options.threadid = threadId || options.threadid || ''; //required
594
        options.message = message || options.message || ''; //required
595
        if (options.signature === true) {
596
            //System only handle 1 or 0. defaults to 0
597
            options.signature = '1';
598
        }
599
600
        return new Promise(async function (resolve, reject) {
601
            try {
602
                let response = await that.callMethod({
603
                    method: 'newreply_postreply',
604
                    params: options
605
                });
606
                let possibleError = that.constructor.parseErrorMessage(response);
607
                //success is errormessgae 'redirect_postthanks'
608
                //error 'threadclosed' if thread is closed. FIXME does not error
609
                //reports threadid and postid
610
                if (
611
                    possibleError === 'redirect_postthanks'
612
                    && response.hasOwnProperty('show')
613
                ) {
614
                    resolve(response.show);
615
                } else {
616
                    reject(possibleError || response);
617
                }
618
            } catch (e) {
619
                reject(e);
620
            }
621
        });
622
    }
623
624
    /**
625
     * Attempts to edit an existing Post
626
     * @param {number} postId - Post id
627
     * @param {string} message - Post Message
628
     * @param {object=} options
629
     * @param {string=} options.reason - Reason for editing
630
     * @param {boolean=} options.signature - Optionally append your signature
631
     * @param {number=} options.postid - Ignore, already required at postId
632
     * @param {string=} options.message - Ignore, already required at message
633
     * TODO note additional options
634
     * @returns {Promise<*>} - Returns a unhandled response currently
635
     * @fulfill {*}
636
     * @reject {string} - Error Reason. Expects: (TODO list common errors here)
637
     */
638
    async editPost(postId, message, options) {
639
        let that = this;
640
        options = options || {};
641
        options.postid = postId || options.postid || ''; //required
642
        options.message = message || options.message || ''; //required
643
        if (options.signature === true) {
644
            //System only handle 1 or 0. defaults to 0
645
            options.signature = '1';
646
        }
647
648
        return new Promise(async function (resolve, reject) {
649
            try {
650
                let response = await that.callMethod({
651
                    method: 'editpost_updatepost',
652
                    params: options
653
                });
654
                let possibleError = that.constructor.parseErrorMessage(response);
655
                //success is errormessgae 'redirect_editthanks'
656
                if (possibleError === 'redirect_editthanks') {
657
                    resolve({postid: options.postid});
658
                } else {
659
                    reject(possibleError || response);
660
                }
661
            } catch (e) {
662
                reject(e);
663
            }
664
        });
665
    }
666
667
    /**
668
     * Attempts to retrieve data about a specific user found by username
669
     * @param {string} username - Username
670
     * @param {object=} options - Secondary Options
671
     * @param {string=} options.username - Ignore, already required at username
672
     * @returns {Promise<Member>} - Returns a Member object
673
     * @fulfill {Member}
674
     * @reject {string} - Error Reason. Expects: (TODO list common errors here)
675
     */
676
    async getMember(username, options) {
677
        let that = this;
678
        options = options || {};
679
        options.username = username || options.username || ''; //required
680
681
        return new Promise(async function (resolve, reject) {
682
            let thread = null;
683
            try {
684
                let response = await that.callMethod({
685
                    method: 'member',
686
                    params: options
687
                });
688
                if (
689
                    response
690
                    && response.hasOwnProperty('response')
691
                ) {
692
                    thread = new Member(response.response);
693
                }
694
            } catch (e) {
695
                reject(e);
696
            }
697
            if (thread !== null) {
698
                resolve(thread);
699
            } else {
700
                reject();
701
            }
702
        });
703
    }
704
705
    /**
706
     * TODO untested - does not seem to function yet
707
     * Attempts to delete an existing Post
708
     * @param {number} postId - Post id
709
     * @param {number} threadId - Thread id
710
     * @param {object=} options
711
     * @param {string=} options.reason - Reason for deleting
712
     * @param {number=} options.postid - Ignore, already required at postId
713
     * @param {number=} options.threadid - Ignore, already required at threadId
714
     * TODO note additional options
715
     * @returns {Promise<*>} - Returns a unhandled response currently
716
     * @fulfill {*}
717
     * @reject {string} - Error Reason. Expects: (TODO list common errors here)
718
     */
719
    async deletePost(postId, threadId, options) {
720
        let that = this;
721
        options = options || {};
722
        options.postid = postId || options.postid || ''; //required
723
        options.threadid = threadId || options.threadid || ''; // TODO required????
724
725
        return new Promise(async function (resolve, reject) {
726
            try {
727
                let response = await that.callMethod({
728
                    method: 'editpost_deletepost',
729
                    params: options
730
                });
731
                let possibleError = that.constructor.parseErrorMessage(response);
732
                //unknown response
733
                if (
734
                    possibleError === 'redirect_deletepost'
735
                    && response.hasOwnProperty('show')
736
                ) {
737
                    //console.log('response', response);
738
                    resolve(response.show);
739
                } else {
740
                    reject(possibleError || response);
741
                }
742
            } catch (e) {
743
                reject(e);
744
            }
745
        });
746
    }
747
748
    /**
749
     * Attempts to submit a new Thread into a specified Forum. This will also be considered the first Post
750
     * @param {number} forumId - Forum Id
751
     * @param {string} subject - Post/Thread Subject
752
     * @param {string} message - Post Message
753
     * @param {object=} options
754
     * @param {boolean=} options.signature - Optionally append your signature
755
     * @param {number=} options.forumid - Ignore, already required at postId
756
     * @param {string=} options.subject - Ignore, already required at postId
757
     * @param {string=} options.message - Ignore, already required at postId
758
     * TODO note additional options
759
     * @returns {Promise<*>} - Returns a unhandled response currently
760
     * @fulfill {*}
761
     * @reject {string} - Error Reason. Expects: (TODO list common errors here)
762
     */
763
    async newThread(forumId, subject, message, options) {
764
        let that = this;
765
        options = options || {};
766
        options.forumid = forumId || options.forumid || ''; //required
767
        options.subject = subject || options.subject || ''; //required
768
        options.message = message || options.message || ''; //required
769
770
        if (options.signature === true) {
771
            //System only handle 1 or 0. defaults to 0
772
            options.signature = '1'; // FIXME This didn't seem to work
773
        }
774
775
        return new Promise(async function (resolve, reject) {
776
            try {
777
                let response = await that.callMethod({
778
                    method: 'newthread_postthread',
779
                    params: options
780
                });
781
                let possibleError = that.constructor.parseErrorMessage(response);
782
                //success is errormessgae 'redirect_postthanks'
783
                //reports threadid and postid
784
                if (
785
                    possibleError === 'redirect_postthanks'
786
                    && response.hasOwnProperty('show')
787
                ) {
788
                    resolve(response.show);
789
                } else {
790
                    reject(possibleError || response);
791
                }
792
            } catch (e) {
793
                reject(e);
794
            }
795
        });
796
    }
797
798
    /**
799
     * TODO incomplete - does not seem to function yet
800
     * Attempts to close a specific Thread. Requires a user to have a 'inline mod' permissions
801
     * @param {number} threadId - Id of Thread to close
802
     * @returns {Promise<*>} - Returns a unhandled response currently
803
     * @fulfill {*}
804
     * @reject {string} - Error Reason. Expects: (TODO list common errors here)
805
     */
806
    async modCloseThread(threadId) {
807
        let that = this;
808
        let cookies = {};
809
        if (threadId) {
810
            //TODO multiple ids are delimited with a '-'. eg: 123-345-456
811
            cookies.vbulletin_inlinethread = threadId;
812
        }
813
        return new Promise(async function (resolve, reject) {
814
            try {
815
                let response = await that.callMethod({
816
                    method: 'inlinemod_close',
817
                    cookies: cookies || {}
818
                });
819
                //let possibleError = that.constructor.parseErrorMessage(response);
820
                //unknown responses
821
                /*if (
822
                    possibleError === 'redirect_postthanks'
823
                    && response.hasOwnProperty('show')
824
                ) {*/
825
                resolve(response);
826
                /*} else {
827
                    reject(possibleError || response);
828
                }*/
829
            } catch (e) {
830
                reject(e);
831
            }
832
        });
833
    }
834
835
    /**
836
     * TODO incomplete - does not seem to function yet
837
     * Attempts to open a specific Thread. Requires a user to have a 'inline mod' permissions
838
     * @param {number} threadId - Id of Thread to open
839
     * @returns {Promise<*>} - Returns a unhandled response currently
840
     * @fulfill {*}
841
     * @reject {string} - Error Reason. Expects: (TODO list common errors here)
842
     */
843
    async modOpenThread(threadId) {
844
        let that = this;
845
        let cookies = {};
846
        if (threadId) {
847
            //TODO multiple ids are delimited with a '-'. eg: 123-345-456
848
            cookies.vbulletin_inlinethread = threadId;
849
        }
850
        return new Promise(async function (resolve, reject) {
851
            try {
852
                let response = await that.callMethod({
853
                    method: 'inlinemod_open',
854
                    cookies: cookies || {}
855
                });
856
                //let possibleError = that.constructor.parseErrorMessage(response);
857
                //unknown responses
858
                /*if (
859
                    possibleError === 'redirect_postthanks'
860
                    && response.hasOwnProperty('show')
861
                ) {*/
862
                resolve(response);
863
                /*} else {
864
                    reject(possibleError || response);
865
                }*/
866
            } catch (e) {
867
                reject(e);
868
            }
869
        });
870
    }
871
872
    /**
873
     * TODO incomplete - does not seem to function yet
874
     * Attempts to delete a specific Thread. Requires a user to have a 'inline mod' permissions
875
     * @param {number} threadId - Id of Thread to close
876
     * @returns {Promise<*>} - Returns a unhandled response currently
877
     * @fulfill {*}
878
     * @reject {string} - Error Reason. Expects: (TODO list common errors here)
879
     */
880
    async modDeleteThread(threadId) {
881
        let that = this;
882
        let cookies = {};
883
        if (threadId) {
884
            //TODO multiple ids are delimited with a '-'. eg: 123-345-456
885
            cookies.vbulletin_inlinethread = threadId;
886
        }
887
        return new Promise(async function (resolve, reject) {
888
            try {
889
                let response = await that.callMethod({
890
                    method: 'inlinemod_dodeletethreads',
891
                    cookies: cookies || {}
892
                });
893
                //let possibleError = that.constructor.parseErrorMessage(response);
894
                //unknown responses
895
                /*if (
896
                    possibleError === 'redirect_postthanks'
897
                    && response.hasOwnProperty('show')
898
                ) {*/
899
                resolve(response);
900
                /*} else {
901
                    reject(possibleError || response);
902
                }*/
903
            } catch (e) {
904
                reject(e);
905
            }
906
        });
907
    }
908
}
909
910
module.exports = VBApi;
911