├── .editorconfig ├── .gitignore ├── .npmignore ├── README.md ├── config.js.dist ├── index.js ├── lib ├── megaplan.js ├── megaplan │ ├── client.js │ ├── dicts.js │ ├── lang.ru.js │ ├── request.js │ └── serverconf.js └── utils.js ├── package-lock.json └── package.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://EditorConfig.org 2 | 3 | root = true 4 | 5 | [lib/**.js] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | charset = utf-8 9 | indent_style = tab 10 | indent_size = 4 11 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /config.js 3 | /test 4 | /docs 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /config.js 3 | /config.js.dist 4 | /test.js 5 | /index.js 6 | /docs -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Megaplan client module for NodeJS 2 | --------------------------------- 3 | 4 | A NodeJS library to work with megaplan.ru API ver. 1 5 | 6 | Provides a class that implements Megaplan authentication and request signing. 7 | Only supports POST requests. The complete API documentation is at: 8 | https://dev.megaplan.ru/api/index.html 9 | 10 | At first you need to install library 11 | 12 | ```sh 13 | npm install megaplanjs --save 14 | ``` 15 | 16 | You can generate documentaion with commands: 17 | 18 | ```sh 19 | npm install 20 | npm run docs 21 | ``` 22 | 23 | Authorization 24 | ============= 25 | 26 | To authorize using a password: 27 | 28 | ```js 29 | var megaplan = require ('megaplanjs'); 30 | var client = new megaplan.Client('my.megaplan.ru').auth('me', 'pass'); 31 | client.on('auth', function (res, err) { 32 | // store res.access_id, res.secret_key if you need these (see below) 33 | console.log('authenticated', res, err); 34 | 35 | client.tasks().send(function (tasks) { 36 | console.log(tasks); // a lot of results 37 | }, function (err) { 38 | console.log(err); 39 | }); 40 | }); 41 | ``` 42 | 43 | To authorize using tokens: 44 | 45 | ```js 46 | var megaplan = require ('megaplanjs'); 47 | var client = new megaplan.Client('xyz.megaplan.ru', access_id, secret_key); 48 | client.tasks().send(function (tasks) { 49 | console.log(tasks); // still a lot of results 50 | }, function (err) { 51 | console.log(err); 52 | }); 53 | ``` 54 | 55 | To authorize using one-time-key: 56 | 57 | ```js 58 | var megaplan = require ('megaplanjs'); 59 | var client = new megaplan.Client('xyz.megaplan.ru').auth('', '', '4gih4y4gih4yH77QebicH77Qebic'); 60 | client.tasks().send(function (tasks) { 61 | console.log(tasks); // still a lot of results 62 | }, function (err) { 63 | console.log(err); 64 | }); 65 | ``` 66 | 67 | Usage 68 | ===== 69 | 70 | ```js 71 | var megaplan = require("megaplanjs"); 72 | // SET here your megaplan URL, login and password 73 | var client = new megaplan.Client("my.megaplan.ru").auth("me", "pass"); 74 | 75 | client.on("auth", function(res, err) { 76 | // show user's tasks 77 | client.tasks({ folder: "owner" }).send( 78 | function(tasks) { 79 | console.log(tasks); 80 | }, 81 | function(err) { 82 | console.log(err); 83 | } 84 | ); 85 | }); 86 | ``` 87 | 88 | Look `index.js` for more examples. It's pretty simple to use 89 | 90 | Copylefts 91 | ========= 92 | 93 | Code originally written by Alexej Yaroshevich under the MIT License. 94 | 95 | Enjoy! 96 | -------------------------------------------------------------------------------- /config.js.dist: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | host: 'my.megaplan.ru', 3 | user: 'me', 4 | pass: 'pass' 5 | }; 6 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | var MegaplanClient = require ('./lib/megaplan.js').Client 3 | , config = require ('./config.js') 4 | , util = require('util'); 5 | 6 | var client = new MegaplanClient(config.host).auth(config.user, config.pass); 7 | 8 | client.on('auth', function (res, err) { 9 | util.debug('authenticated', res, err); 10 | 11 | // set default callback to print out the result to console 12 | client.callbacks(function (out) { 13 | util.debug(util.inspect(out, false, 5)); 14 | }, function (err) { 15 | util.error(err); 16 | (err.error||{}).message && util.error('message', err.error.message); 17 | }); 18 | 19 | // show user's tasks 20 | client.tasks({folder: 'owner'}).send(); 21 | 22 | // show all visible tasks using custom handler 23 | client.tasks().send(function (tasks) { 24 | util.puts(util.inspect(tasks)); 25 | }); 26 | 27 | // global serach for a Keyword 28 | client.search('Keyword').send(); 29 | 30 | // fetch employees 31 | client.employees().send(); 32 | 33 | // what is time on the other side? 34 | client.datetime().send(); 35 | 36 | // task creation 37 | var myId = 2; 38 | client 39 | .task_create('Testing: ASAP buy an elephant', 'We need an elephant to go to Persia', myId) 40 | .send(function (out) { 41 | newTaskId = out.id; 42 | util.puts('task created with id: ', out.id); 43 | client.task_create({ 44 | name: 'Testing: Look for a good elephants on the market', 45 | statement: 'Go to the market and look for a good, big, mighty elephants to buy', 46 | responsible: myId, 47 | super_task: out.id, 48 | deadline: {datetime: new Date(Date.now() + 135*60*1000 /* 135 minutes after now */)}, 49 | auditors: [0, myId], 50 | severity: 'high' 51 | }).send(function (out) { 52 | // fetch history for a currently created task 53 | client.history(newTaskId).send(); 54 | }); 55 | }); 56 | 57 | // fetch history for a task with id 1 (1000001) 58 | client.history(1).send(); 59 | 60 | }); 61 | -------------------------------------------------------------------------------- /lib/megaplan.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true, laxcomma:true, boss:true, strict:false, devel:true, smarttabs:true, onecase:true */ 2 | 3 | var Request = require('./megaplan/request.js') 4 | , Client = require('./megaplan/client.js'); 5 | 6 | module.exports = { 7 | 'Request': Request, 8 | 'Client': Client 9 | }; 10 | -------------------------------------------------------------------------------- /lib/megaplan/client.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true, laxcomma:true, boss:true, strict:false, devel:true, smarttabs:true, onecase:true */ 2 | 3 | var inherits = require('util').inherits 4 | , EventEmitter = require('events').EventEmitter 5 | , Request = require('./request.js') 6 | , ServerConf = require('./serverconf.js') 7 | , dicts = require('./dicts.js') 8 | , utils = require('../utils.js'); 9 | 10 | /** 11 | * @class MegaplanClient 12 | * @classdesc Client class that stores authentication and have some useful methods. 13 | * 14 | * Класс пользователя, который хранит авторизацию и включает в себя остальные методы для работы с API. 15 | * 16 | * [Official API documentaion]{@link https://help.megaplan.ru/API} 17 | * 18 | * @constructor 19 | * @param {String|MegaplanServerConf} server Hostname or Object 20 | * @param {String} [access_id] 21 | * @param {String} [secret_key] 22 | * @param {Function} [success_callback] 23 | * @param {Function} [fail_callback] 24 | */ 25 | var Client = function MegaplanClient (server, access_id, secret_key, success_callback, fail_callback) { 26 | // super call 27 | EventEmitter.call(this); 28 | 29 | var o = server; 30 | (o instanceof Object && !ServerConf.isSelfLikeObject(o)) || (o = { 31 | server: server, 32 | access_id: access_id, 33 | secret_key: secret_key, 34 | success_callback: success_callback, 35 | fail_callback: fail_callback 36 | }); 37 | 38 | // set initials 39 | this.server = new ServerConf(o.server); 40 | this.callbacks(o.success_callback, o.fail_callback); 41 | this.auth2(o); 42 | }; 43 | /** @lends MegaplanClient */ 44 | var clientProto = { 45 | 46 | server: null, 47 | 48 | access_id: null, 49 | secret_key: null, 50 | 51 | request_success_callback: null, 52 | request_fail_callback: null, 53 | 54 | callbacks: function (success, fail) { 55 | this.request_success_callback = success; 56 | this.request_fail_callback = fail; 57 | }, 58 | 59 | /** 60 | * Sends a request. 61 | * 62 | * Посылает запрос. 63 | * 64 | * @private 65 | * @param {String} uri URL to send request to. URL для отправки запрса 66 | * @param {Object} [data] Data to send in request. Данные для запроса 67 | * @param {String|Function} [res_data_filter] 68 | * @param {Function} [req_data_filter] 69 | * @param {MegaplanRequest} 70 | */ 71 | __request: function (uri, data, res_data_filter, req_data_filter) { 72 | var signed = (uri !== '::auth'); 73 | 74 | //console.log({'requesting uri ': uri, 'data': data, 'res_data_filter': res_data_filter, 'req_data_filter': req_data_filter, 'signed': signed, 'auth': [this.access_id, this.secret_key]}); 75 | 76 | if (signed && (!this.access_id || !this.secret_key)) { 77 | throw "Authenticate first"; 78 | } 79 | 80 | uri = utils.subst_uri(uri); 81 | data = data || {}; 82 | 83 | var req = new Request(this.server, this.access_id, this.secret_key, uri, data, res_data_filter, req_data_filter); 84 | 85 | req.callbacks(this.request_success_callback, this.request_fail_callback); 86 | signed && req.sign(); 87 | 88 | return req; 89 | }, 90 | 91 | /** 92 | * Adds a comment to a task/project/contractor/... 93 | * 94 | * Добавляет комментарий к задаче/проекту/клиенту/... 95 | * 96 | * [More info]{@link https://help.megaplan.ru/API_comment_create} 97 | * 98 | * @private 99 | * @param {String} type One of :subject_types. Один из :subject_types 100 | * @param {Number} id ID of subject item. ID задачи/проекта/клиента/... 101 | * @param {String} text Content of a comment. Содержания комментария. 102 | * @param {String} hours Time spent for a subject item (task usually). 103 | * Время, потраченное на эту позицию (обычно задача). 104 | * @returns {MegaplanRequest} 105 | */ 106 | __add_comment: function (type, id, text, hours) { 107 | if (!id || !text) { 108 | throw "Can't post empty comment to nothing"; 109 | } 110 | return this.__request("::comment/create.api", { 111 | subject_type: type || 'task', 112 | subject_id: utils.normalize_id(id), 113 | model: { 114 | text: text, 115 | work: hours 116 | } 117 | }); 118 | }, 119 | 120 | /** 121 | 122 | * @event auth 123 | * @description 124 | * Params: Object - o hash with access_id, secrey_key, and some other auth information on success or error on fail. 125 | * 126 | * Параметры: Объект - хеш из access_id, secret_key и некоторая другая информация об авторизации при удачном входе 127 | * или об ошибке 128 | * 129 | * [More info]{@link https://help.megaplan.ru/API_authorization} 130 | */ 131 | EVN_AUTH: 'auth', 132 | 133 | /** 134 | * UserInfo 135 | * 136 | * Идентификационная информация. 137 | * 138 | * [More info]{@link https://dev.megaplan.ru/api/API_authorization.html#id17} 139 | * @returns {MegaplanRequest} 140 | */ 141 | id: function() { 142 | return this.__request('::userinfo/id.api', 'user'); 143 | }, 144 | 145 | /** 146 | * Authenticates the client with login-pass pair 147 | * If auth succeed then o.succeed will be called with object {access_id, secret_key}. 148 | * These values can be stored and used later to create {MegaplanClient} instances instantly. 149 | * 150 | * Производит авторизацию клиента по паре логин-пароль. 151 | * Если авторизация успешна, то будет вызвано событие auth с объектом {access_id, secret_key}. 152 | * Эти значения могут использоваться позже для создания экземляра класса {MegaplanClient} самостоятельно. 153 | * 154 | * [More info]{@link https://help.megaplan.ru/API_authorization} 155 | * 156 | * @param {String} login 157 | * @param {String} password 158 | * @param {String} one_time_key 159 | * @returns {MegaplanClient} 160 | */ 161 | auth: function (login, password, one_time_key) { 162 | var that = this, o, args; 163 | o = (login instanceof Object) ? (login) : { 164 | login: login, 165 | password: password, 166 | one_time_key: one_time_key 167 | }; 168 | 169 | if ((!o.login || !o.password) && !o.one_time_key) { 170 | throw "No login/password information provided to auth method"; 171 | } 172 | 173 | if (o.one_time_key) { 174 | args = { 175 | one_time_key: one_time_key 176 | }; 177 | } 178 | else { 179 | args = { 180 | login: o.login, 181 | password: utils.md5(o.password) 182 | }; 183 | } 184 | this.__request ('::auth', args).send( 185 | function (data) { 186 | that.auth2(data); 187 | o.success && o.success (data); 188 | }, 189 | function (err) { 190 | that.emit(that.EVN_AUTH, null, err); 191 | o.fail && o.fail (err); 192 | } 193 | ); 194 | 195 | return this; 196 | }, 197 | 198 | /** 199 | * Instant authentication with token-secret pair. 200 | * 201 | * Авторизация по паре token-secret 202 | * 203 | * [More info]{@link https://help.megaplan.ru/API_authorization} 204 | * 205 | * @param {String} access_id 206 | * @param {String} secret_key 207 | * @returns {MegaplanClient} 208 | */ 209 | auth2: function (access_id, secret_key) { 210 | var that = this, o = (access_id instanceof Object) ? (access_id) : { 211 | access_id: access_id, 212 | secret_key: secret_key 213 | }; 214 | if (!o.access_id && !o.secret_key) { 215 | return; 216 | } 217 | 218 | this.access_id = o.access_id; 219 | this.secret_key = o.secret_key; 220 | 221 | process.nextTick(function () { 222 | that.emit(that.EVN_AUTH, o); 223 | }); 224 | 225 | return this; 226 | }, 227 | 228 | /** 229 | * Global quick search. 230 | * 231 | * Глобальный быстрый поиск 232 | * 233 | * [More info]{@link https://help.megaplan.ru/API_search_quick} 234 | * 235 | * @param {String} search 236 | * @returns {MegaplanRequest} 237 | */ 238 | search: function (search) { 239 | (search instanceof Object) && (search = search.search || search.qs || search.text); 240 | return this.__request('::search/quick.api', {qs: search}, null, false); 241 | }, 242 | 243 | /** 244 | * Current time on server. 245 | * 246 | * Текущее время на сервере 247 | * 248 | * [More info]{@link https://help.megaplan.ru/API_system_datetime} 249 | * 250 | * @returns {MegaplanRequest} 251 | */ 252 | datetime: function () { 253 | return this.__request('::system/datetime.api', null, 'datetime'); 254 | }, 255 | 256 | /** 257 | * History. 258 | * If subject_id not set, method will return history on all subjects. 259 | * 260 | * История. 261 | * Если subject_id не установлен, метод возвращает историю по всем проектам и задачам. 262 | * 263 | * More info [here (get history on one subject)]{@link https://help.megaplan.ru/API_system_datetime} and 264 | [here (get history on all subjects)]{@link https://help.megaplan.ru/API_history_all} 265 | * 266 | * @param {Number} [subject_id] id of object 267 | * @param {String} [subject_type=task] task or project 268 | * @returns {MegaplanRequest} 269 | */ 270 | history: function (id, type) { 271 | var o = id; 272 | (o instanceof Object) || (o = { 273 | subject_type: type || 'task', 274 | subject_id: utils.normalize_id(id) 275 | }); 276 | var method = o.subject_id ? '/list.api' : '/all.api'; 277 | return this.__request('::history'+method, o, 'changes'); 278 | }, 279 | 280 | /** 281 | * Feedback 282 | * 283 | * Обратная связь. 284 | * 285 | * [More info]{@link https://help.megaplan.ru/API_system_feedback} 286 | * @param {String} message 287 | * @returns {MegaplanRequest} 288 | */ 289 | feedback: function (message) { 290 | var o = message; 291 | (o instanceof Object) || (o = { 292 | message: message 293 | }); 294 | return this.__request('::system/feedback.api', o); 295 | }, 296 | 297 | /** 298 | * Task creation. 299 | * 300 | * Создание задачи. 301 | * 302 | * [More info]{@link https://help.megaplan.ru/API_task_create} 303 | * 304 | * @todo Add support of attaches 305 | * @param {String} [name] Название 306 | * @param {String} [statement] Суть задачи 307 | * @param {Number} [responsible] Код ответственного 308 | * @param {String} [super_task] Код надзадачи (если число) или код проекта (если строка в формате ‘p<код проекта>’ 309 | * @param {Date|Object} [deadline] Дедлайн 310 | * @param {Date} [dealline.datetime] День и время 311 | * @param {Date} [dealline.date] Только день 312 | * @param {String} [dealline.type] Тип дедлайна 313 | * @param {Array} [executors] Коды соисполнителей 314 | * @param {Array} [auditors] Коды аудиторов 315 | * @param {Number} [severity] Код важности (с версии 2011.3 допустимо отсутствие параметра важности или важность 316 | * с MasterType=high) 317 | * @param {Number} [customer] Код заказчика 318 | * @param {Number} [is_group] (0/1) Массовая задача (каждому соисполнителю будет создана своя задача) 319 | * @param {Object} [attaches] There is no support of attaches at the moment. Sorry. Должен содержать ключ add в 320 | * котором находится массив с файлами 321 | * @param {Array} attaches.add Массив приложенных файлов, должен передаваться POST-запросом 322 | * @param {String} attaches.add.context Данные(контент файла), закодированные с использованием MIME base64 323 | * @param {String} attaches.add.name Имя файла (будет фигурировать при выводе задачи) 324 | * @returns {MegaplanRequest} 325 | */ 326 | task_create: function (name, statement, responsible, super_task, deadline, executors, auditors, severity, customer, is_group/*, attaches*/) { 327 | var o = name; 328 | (o instanceof Object) || (o = { 329 | name: name, 330 | statement: statement, 331 | responsible: responsible, 332 | super_task: super_task, 333 | deadline: (deadline||{}).datetime || deadline, 334 | deadline_date: (deadline||{}).date, 335 | deadline_type: (deadline||{}).type, 336 | executors: executors, 337 | auditors: auditors, 338 | severity: severity, 339 | customer: customer, 340 | is_group: is_group/*, 341 | attaches: attaches*/ 342 | }); 343 | o.responsible = utils.normalize_id(o.responsible); 344 | o.super_task = utils.normalize_id(o.super_task); 345 | o.executors = (o.executors && o.executors.map) ? o.executors.map(utils.normalize_id) : null; 346 | o.auditors = (o.auditors && o.auditors.map) ? o.auditors.map(utils.normalize_id) : null; 347 | o.is_group = o.is_group ? 1 : 0; 348 | o.customer = utils.normalize_id(o.customer); 349 | 350 | // todo: add support of attaches object 351 | delete o.attaches; 352 | 353 | return this.__request('::task/create.api', {model: utils.objectFilter(o)}, 'task'); 354 | }, 355 | 356 | /** 357 | * @todo Редактирование задачи 358 | * @todo Действие над задачей 359 | * @todo Допустимые действия над задачей 360 | * @todo Допустимые действия для списка задач 361 | * @todo Добавить задачу в избранное 362 | * @todo Запрос на изменение дедлайна 363 | * @todo Принять или отклонить запрос на изменение дедлайна 364 | * @todo Изменение соисполнителей 365 | * @todo Изменение аудиторов 366 | * @todo Делегирование задачи 367 | * @todo Проверка прав на делегирование задачи 368 | * @todo Список пользователей, которым можно делегировать задачу 369 | * @todo Список задач и проектов, которые можно указывать как надзадачи для других задач 370 | * @todo Список проектов, которые можно указывать как надпроекты для других задач 371 | * @todo Конвертация задачи в проект 372 | */ 373 | 374 | /** 375 | * Returns your tasks as a list of objects. 376 | * 377 | * Список задач как список объектов. 378 | * 379 | * [More info]{@link https://help.megaplan.ru/API_task_list} 380 | * 381 | * @param {String} [status=any] Статус 382 | * @param {String} [folder=all] Папка 383 | * @param {Number} [favorites_only=0] Только избранное 384 | * @param {String} [search] Строка поиска 385 | * @param {Boolean} [detailed=false] Нужно ли показывать в списке задач все поля из карточки задачи 386 | * @param {Boolean} [only_actual=false] Если true, то будут выводиться только незавершенные задачи 387 | * @param {String} [filter_id] Код фильтра 388 | * @param {Boolean} [count] Вернуть кол-во задач, удовлетворяющих условиям, вместо списка 389 | * @param {Number} [employee_id] Код сотрудника, для которого ищем задачи 390 | * @param {String} [sort_by] Поле модели задачи по которому производить сортировку результата 391 | * @param {String} [sort_order=asc] Порядок сортировки: asc (по возрастанию), desc (по убыванию) 392 | * @param {Boolean} [show_actions] Нужно ли показывать в списке возможные действия над задачей 393 | * @param {Number} [limit] Сколько выбрать задач (LIMIT) 394 | * @param {Number} [offset] Начиная с какой выбирать задачи (OFFSET) 395 | * @returns {MegaplanRequest} 396 | */ 397 | tasks: function (status, folder, favorites_only, search, detailed, only_actual, filter_id, count, employee_id, sort_by, sort_order, show_actions, limit, offset) { 398 | var o = status; 399 | (o instanceof Object) || (o = { 400 | status: status || 'actual', 401 | folder: folder || 'incoming', 402 | favorites_only: favorites_only ? 1 : 0, 403 | search: search, 404 | detailed: !!detailed, 405 | only_actual: only_actual || only_actual === undefined, 406 | filter_id: filter_id, 407 | count: !!count, 408 | employee_id: utils.normalize_id(employee_id), 409 | sort_by: sort_by, 410 | sort_order: (sort_order||'').toLowerCase() === 'desc' ? 'desc' : 'asc', 411 | show_actions: !!show_actions, 412 | limit: limit, 413 | offset: offset 414 | }); 415 | 416 | return this.__request('::task/list.api', utils.objectFilter(o), 'tasks'); 417 | }, 418 | 419 | /** 420 | * Detailed task. 421 | * 422 | * Карточка задачи. 423 | * 424 | * [More info]{@link https://help.megaplan.ru/API_task_card} 425 | * 426 | * @param {Number} id Task ID 427 | * @returns {MegaplanRequest} 428 | */ 429 | task: function (task_id) { 430 | return this.__request('::task/card.api', { id: task_id }); 431 | }, 432 | 433 | /** 434 | * Get task comments. 435 | * 436 | * Получить список комментариев к задаче. 437 | * 438 | * [More info]{@link https://help.megaplan.ru/API_comment_list} 439 | * 440 | * @param {Number} subject_id Task ID 441 | * @returns {MegaplanRequest} 442 | */ 443 | task_comments: function (task_id) { 444 | return this.__request('::comment/list.api', { subject_type: 'task', subject_id: task_id }); 445 | }, 446 | 447 | /** 448 | * Send comment to a task. 449 | * 450 | * Написание комментария к задаче. 451 | * 452 | * [More info]{@link https://help.megaplan.ru/API_comment_create} 453 | * 454 | * @param {Number} subject_id Task ID. ID задачи 455 | * @param {String} text Content. Содержание 456 | * @param {String} [hours] Time spend to a task. Время, потраченное на задачу 457 | * @returns {MegaplanRequest} 458 | */ 459 | task_comment_create: function (task_id, text, hours) { 460 | return this.__add_comment("task", task_id, text, hours || 0); 461 | }, 462 | 463 | // Sets reaction by token 464 | react: function (token, message) { 465 | return this.__request('::reaction/do.api', { token: token, params: { text : message }}); 466 | }, 467 | 468 | 469 | /** 470 | * Returns projects as a list of objects. 471 | * 472 | * Список проектов как список объектов. 473 | * 474 | * [More info]{@link https://help.megaplan.ru/API_project_list} 475 | * 476 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 477 | * официальную документацию для получения большей информации 478 | * @returns {MegaplanRequest} 479 | */ 480 | projects: function (o) { 481 | o = o || {}; 482 | return this.__request('::project/list.api', utils.objectFilter(o)); 483 | }, 484 | 485 | 486 | /** 487 | * Create project. 488 | * 489 | * Создает проект. 490 | * 491 | * [More info]{@link https://help.megaplan.ru/API_project_create} 492 | * 493 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 494 | * официальную документацию для получения большей информации 495 | * @returns {MegaplanRequest} 496 | */ 497 | project_create: function (o) { 498 | o = o || {}; 499 | return this.__request('::project/Create.api', utils.objectFilter(o)); 500 | }, 501 | 502 | 503 | /** 504 | * Edit project. 505 | * 506 | * Редактирует проект. 507 | * 508 | * [More info]{@link https://help.megaplan.ru/API_project_edit} 509 | * 510 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 511 | * официальную документацию для получения большей информации 512 | * @returns {MegaplanRequest} 513 | */ 514 | project_edit: function (o) { 515 | return this.__request('::project/edit.api', utils.objectFilter(o)); 516 | }, 517 | 518 | 519 | /** 520 | * Make action on project. 521 | * 522 | * Производит действие над проектом. 523 | * 524 | * [More info]{@link https://help.megaplan.ru/API_project_action} 525 | * 526 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 527 | * официальную документацию для получения большей информации 528 | * @returns {MegaplanRequest} 529 | */ 530 | project_action: function (o) { 531 | return this.__request('::project/action.api', utils.objectFilter(o)); 532 | }, 533 | 534 | 535 | /** 536 | * Send comment to a project. 537 | * 538 | * Написание комментария к проекту. 539 | * 540 | * [More info]{@link https://help.megaplan.ru/API_comment_create} 541 | * 542 | * @param {Number} project_id Project ID. ID проекта 543 | * @param {String} text Content. Текст комментария 544 | * @param {String} [hours] Time spend to a project. Время, потраченное на проект 545 | * @returns {MegaplanRequest} 546 | */ 547 | project_comment_create: function (project_id, text, hours) { 548 | return this.__add_comment("project", project_id, text, hours || 0); 549 | }, 550 | 551 | 552 | 553 | 554 | /** 555 | * Returns tags as a list of objects. 556 | * 557 | * Список меток как список объектов. 558 | * 559 | * [More info]{@link https://help.megaplan.ru/API_tags_list} 560 | * 561 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите официальную документацию для получения большей информации 562 | * @returns {MegaplanRequest} 563 | */ 564 | tags: function (o) { 565 | o = o || {}; 566 | return this.__request('::tags/list.api', utils.objectFilter(o)); 567 | }, 568 | 569 | 570 | /** 571 | * Create tag. 572 | * 573 | * Создает метку. 574 | * 575 | * [More info]{@link https://help.megaplan.ru/API_tags_create} 576 | * 577 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите официальную документацию для получения большей информации 578 | * @returns {MegaplanRequest} 579 | */ 580 | tag_create: function (o) { 581 | o = o || {}; 582 | return this.__request('::tags/Create.api', utils.objectFilter(o)); 583 | }, 584 | 585 | 586 | /** 587 | * Update tag. 588 | * 589 | * Обновляет метку. 590 | * 591 | * [More info]{@link https://help.megaplan.ru/API_tags_update} 592 | * 593 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите официальную документацию для получения большей информации 594 | * @returns {MegaplanRequest} 595 | */ 596 | tag_update: function (o) { 597 | return this.__request('::tags/update.api', utils.objectFilter(o)); 598 | }, 599 | 600 | 601 | /** 602 | * Delete tag. 603 | * 604 | * Удаление метки. 605 | * 606 | * [More info]{@link https://help.megaplan.ru/API_tags_delete} 607 | * 608 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите официальную документацию для получения большей информации 609 | * @returns {MegaplanRequest} 610 | */ 611 | tag_delete: function (o) { 612 | return this.__request('::tags/delete.api', utils.objectFilter(o)); 613 | }, 614 | 615 | /** 616 | * Assign tag. 617 | * 618 | * Назначение метки. 619 | * 620 | * [More info]{@link https://help.megaplan.ru/API_tags_assign} 621 | * 622 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите официальную документацию для получения большей информации 623 | * @returns {MegaplanRequest} 624 | */ 625 | tag_assign: function (o) { 626 | return this.__request('::tags/assign.api', utils.objectFilter(o)); 627 | }, 628 | 629 | 630 | /** 631 | * Search tags. 632 | * 633 | * Поиск по меткам. 634 | * 635 | * [More info]{@link https://help.megaplan.ru/API_tags_search} 636 | * 637 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите официальную документацию для получения большей информации 638 | * @returns {MegaplanRequest} 639 | */ 640 | tags_search: function (o) { 641 | return this.__request('::tags/search.api', utils.objectFilter(o)); 642 | }, 643 | 644 | 645 | 646 | 647 | /** 648 | * Get list of todolists. 649 | * 650 | * Получает список списков дел. 651 | * 652 | * [More info]{@link https://help.megaplan.ru/API_todolist_list} 653 | * 654 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 655 | * официальную документацию для получения большей информации 656 | * @returns {MegaplanRequest} 657 | */ 658 | todolists: function (o) { 659 | return this.__request('::todo/list.api', utils.objectFilter(o)); 660 | }, 661 | 662 | /** 663 | * Create todolist. 664 | * 665 | * Создание списка дел. 666 | * 667 | * [More info]{@link https://help.megaplan.ru/API_todolist_create} 668 | * 669 | * @param {String} name Name of new todolist. Имя нового списка дел 670 | * @returns {MegaplanRequest} 671 | */ 672 | todolist_create: function (name) { 673 | var o = name; 674 | (o instanceof Object) || (o = { 675 | name: name 676 | }); 677 | return this.__request('::todo/create.api', utils.objectFilter(o)); 678 | }, 679 | 680 | 681 | /** 682 | * Edit todolist. 683 | * 684 | * Редактирует список дел. 685 | * 686 | * [More info]{@link https://help.megaplan.ru/API_todolist_edit} 687 | * 688 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 689 | * официальную документацию для получения большей информации 690 | * @returns {MegaplanRequest} 691 | */ 692 | todolist_edit: function (o) { 693 | return this.__request('::todo/edit.api', utils.objectFilter(o)); 694 | }, 695 | 696 | 697 | /** 698 | * Delete todolist. 699 | * 700 | * Удаляет список дел. 701 | * 702 | * [More info]{@link https://help.megaplan.ru/API_todolist_delete} 703 | * 704 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 705 | * официальную документацию для получения большей информации 706 | * @returns {MegaplanRequest} 707 | */ 708 | todolist_delete: function (o) { 709 | return this.__request('::todo/delete.api', utils.objectFilter(o)); 710 | }, 711 | 712 | 713 | /** 714 | * Get list of events. 715 | * 716 | * Получает список событий. 717 | * 718 | * [More info]{@link https://help.megaplan.ru/API_event_list} 719 | * 720 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 721 | * официальную документацию для получения большей информации 722 | * @returns {MegaplanRequest} 723 | */ 724 | events: function (o) { 725 | return this.__request('::event/list.api', utils.objectFilter(o)); 726 | }, 727 | 728 | 729 | /** 730 | * Get card of event. 731 | * 732 | * Получает карточку события. 733 | * 734 | * [More info]{@link https://help.megaplan.ru/API_event_card} 735 | * 736 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 737 | * официальную документацию для получения большей информации 738 | * @returns {MegaplanRequest} 739 | */ 740 | event_card: function (o) { 741 | return this.__request('::event/card.api', utils.objectFilter(o)); 742 | }, 743 | 744 | 745 | /** 746 | * Create a event. 747 | * 748 | * Создает событие. 749 | * 750 | * [More info]{@link https://help.megaplan.ru/API_event_create} 751 | * 752 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 753 | * официальную документацию для получения большей информации 754 | * @returns {MegaplanRequest} 755 | */ 756 | event_create: function (o) { 757 | return this.__request('::event/create.api', utils.objectFilter(o)); 758 | }, 759 | 760 | 761 | /** 762 | * Edit a event. 763 | * 764 | * Редактирует событие. 765 | * 766 | * [More info]{@link https://help.megaplan.ru/API_event_edit} 767 | * 768 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 769 | * официальную документацию для получения большей информации 770 | * @returns {MegaplanRequest} 771 | */ 772 | event_edit: function (o) { 773 | return this.__request('::event/edit.api', utils.objectFilter(o)); 774 | }, 775 | 776 | 777 | /** 778 | * Get list of employees. 779 | * 780 | * Получает список сотрудников. 781 | * 782 | * [More info]{@link https://help.megaplan.ru/API_employee_list} 783 | * 784 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 785 | * официальную документацию для получения большей информации 786 | * @returns {MegaplanRequest} 787 | */ 788 | employees: function (o) { 789 | return this.__request('::employee/list.api', utils.objectFilter(o)); 790 | }, 791 | 792 | 793 | /** 794 | * Get card of employee. 795 | * 796 | * Получает карточку сотрудника. 797 | * 798 | * [More info]{@link https://help.megaplan.ru/API_employee_card} 799 | * 800 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 801 | * официальную документацию для получения большей информации 802 | * @returns {MegaplanRequest} 803 | */ 804 | employee_card: function (o) { 805 | return this.__request('::employee/card.api', utils.objectFilter(o)); 806 | }, 807 | 808 | 809 | /** 810 | * Create a employee. 811 | * 812 | * Создает сотрудника. 813 | * 814 | * [More info]{@link https://help.megaplan.ru/API_employee_create} 815 | * 816 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 817 | * официальную документацию для получения большей информации 818 | * @returns {MegaplanRequest} 819 | */ 820 | employee_create: function (o) { 821 | return this.__request('::employee/create.api', utils.objectFilter(o)); 822 | }, 823 | 824 | 825 | /** 826 | * Edit a employee. 827 | * 828 | * Редактирует сотрудника. 829 | * 830 | * [More info]{@link https://help.megaplan.ru/API_employee_edit} 831 | * 832 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 833 | * официальную документацию для получения большей информации 834 | * @returns {MegaplanRequest} 835 | */ 836 | employee_edit: function (o) { 837 | return this.__request('::employee/edit.api', utils.objectFilter(o)); 838 | }, 839 | 840 | 841 | /** 842 | * Get list of departments. 843 | * 844 | * Получает список отделов. 845 | * 846 | * [More info]{@link https://help.megaplan.ru/API_department_list} 847 | * 848 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 849 | * официальную документацию для получения большей информации 850 | * @returns {MegaplanRequest} 851 | */ 852 | departments: function (o) { 853 | return this.__request('::department/list.api', utils.objectFilter(o)); 854 | }, 855 | 856 | 857 | 858 | /** 859 | * Make import information to Megaplan. Method created for internet shops. 860 | * 861 | * Делает импорт информации в Мегаплан. Метод создан для интернет магазинов. 862 | * 863 | * [More info]{@link https://help.megaplan.ru/API_online_store} 864 | * 865 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 866 | * официальную документацию для получения большей информации 867 | * @returns {MegaplanRequest} 868 | */ 869 | add_online_store: function (o) { 870 | return this.__request(':trade/Deal/createFromOnlineStore.api', utils.objectFilter(o)); 871 | }, 872 | 873 | 874 | 875 | 876 | 877 | /** 878 | * Get list of contractors. 879 | * 880 | * Получает список клиентов. 881 | * 882 | * [Mode info]{@link https://help.megaplan.ru/API_contractor_list} 883 | * 884 | * @param {Number} [filter_id] Идентификатор фильтра 885 | * @param {String} [search] Условие поиска 886 | * @param {Number} [limit] Сколько выбрать событий (LIMIT) 887 | * @param {Number} [offset] Начиная с какого выбирать события (OFFSET) 888 | * @returns {MegaplanRequest} 889 | */ 890 | contractors: function (filter_id, search, limit, offset, model, phone) { 891 | var o = filter_id; 892 | (o instanceof Object) || (o = { 893 | filter_id: filter_id, 894 | qs: search, 895 | limit: limit, 896 | offset: offset, 897 | model: model, 898 | phone: phone 899 | }); 900 | 901 | return this.__request('::contractor/list.api', utils.objectFilter(o), 'clients'); 902 | }, 903 | 904 | 905 | /** 906 | * Create or edit contractor. 907 | * 908 | * Создает или изменяет клиента. 909 | * 910 | * [More info]{@link https://help.megaplan.ru/API_contractor_save} 911 | * 912 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 913 | * официальную документацию для получения большей информации 914 | * @returns {MegaplanRequest} 915 | */ 916 | contractor_save: function (o) { 917 | return this.__request('::contractor/save.api', utils.objectFilter(o)); 918 | }, 919 | 920 | 921 | /** 922 | * Get card of contractor. 923 | * 924 | * Получает карточку клиента. 925 | * 926 | * [More info]{@link https://help.megaplan.ru/API_contractor_card} 927 | * 928 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 929 | * официальную документацию для получения большей информации 930 | * @returns {MegaplanRequest} 931 | */ 932 | contractor_card: function (o) { 933 | return this.__request('::contractor/card.api', utils.objectFilter(o)); 934 | }, 935 | 936 | 937 | /** 938 | * Delete contractor. 939 | * 940 | * Удаляет клиента. 941 | * 942 | * [More info]{@link https://help.megaplan.ru/API_contractor_delete} 943 | * 944 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 945 | * официальную документацию для получения большей информации 946 | * @returns {MegaplanRequest} 947 | */ 948 | contractor_delete: function (o) { 949 | return this.__request('::contractor/delete.api', utils.objectFilter(o)); 950 | }, 951 | 952 | 953 | /** 954 | * Get list of contractor`s fields. 955 | * 956 | * Получает список полей клиента. 957 | * 958 | * [More info]{@link https://help.megaplan.ru/API_Contractor_fields} 959 | * 960 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 961 | * официальную документацию для получения большей информации 962 | * @returns {MegaplanRequest} 963 | */ 964 | contractor_list_fields: function () { 965 | return this.__request('::contractor/listFields.api'); 966 | }, 967 | 968 | 969 | /** 970 | * Send comment to a contractor. 971 | * 972 | * Написание комментария к клиенту. 973 | * 974 | * [More info]{@link https://help.megaplan.ru/API_comment_create} 975 | * 976 | * @param {Number} contractor_id Contractor ID. ID клиента 977 | * @param {String} text Content. Текст комментария 978 | * @param {String} [hours] Time spend to a task. Время, потраченное на клиента 979 | * @returns {MegaplanRequest} 980 | */ 981 | contractor_comment_create: function (contractor_id, text, hours) { 982 | if (!contractor_id || !text) { 983 | throw "Can't post empty comment to nothing"; 984 | } 985 | return this.__request("::comment/create.api", { 986 | subject_type: 'contractor', 987 | subject_id: contractor_id, 988 | model: { 989 | text: text, 990 | work: hours || 0 991 | } 992 | }); 993 | }, 994 | 995 | 996 | 997 | /** 998 | * Get list of deals. 999 | * 1000 | * Получает список сделок. 1001 | * 1002 | * [More info]{@link https://help.megaplan.ru/API_deal_list} 1003 | * 1004 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 1005 | * официальную документацию для получения большей информации 1006 | * @returns {MegaplanRequest} 1007 | */ 1008 | deals: function (o) { 1009 | return this.__request('::deal/list.api', utils.objectFilter(o)); 1010 | }, 1011 | 1012 | 1013 | /** 1014 | * Get list of programs. 1015 | * 1016 | * Получает список схем сделок. 1017 | * 1018 | * [More info]{@link https://dev.megaplan.ru/api/API_deals.html#id12} 1019 | * 1020 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 1021 | * официальную документацию для получения большей информации 1022 | * @returns {MegaplanRequest} 1023 | */ 1024 | programs: function (limit, offset) { 1025 | var o = limit; 1026 | (o instanceof Object) || (o = { 1027 | limit: limit, 1028 | offset: offset 1029 | }); 1030 | 1031 | return this.__request('::program/list.api', utils.objectFilter(o)); 1032 | }, 1033 | 1034 | 1035 | /** 1036 | * Create or edit deal. 1037 | * 1038 | * Создает или редактирует сделку. 1039 | * 1040 | * [More info]{@link https://help.megaplan.ru/API_deal_save} 1041 | * 1042 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 1043 | * официальную документацию для получения большей информации 1044 | * @returns {MegaplanRequest} 1045 | */ 1046 | deal_save: function (o) { 1047 | return this.__request('::deal/save.api', utils.objectFilter(o)); 1048 | }, 1049 | 1050 | 1051 | /** 1052 | * Get card of deal. 1053 | * 1054 | * Получает карточку сделки. 1055 | * 1056 | * [More info]{@link https://help.megaplan.ru/API_deal_card} 1057 | * 1058 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 1059 | * официальную документацию для получения большей информации 1060 | * @returns {MegaplanRequest} 1061 | */ 1062 | deal_card: function (o) { 1063 | return this.__request('::deal/card.api', utils.objectFilter(o)); 1064 | }, 1065 | 1066 | 1067 | /** 1068 | * Linking task/deal to a deal. 1069 | * 1070 | * Привязка сделки или задачи к сделке. 1071 | * 1072 | * [More info]{@link https://dev.megaplan.ru/api/API_deals.html#api-deal-link} 1073 | * 1074 | * @param {Object} o parameters of request. More info in official documentation. Параметры запроса. Смотрите 1075 | * официальную документацию для получения большей информации 1076 | * @returns {MegaplanRequest} 1077 | */ 1078 | save_relation: function (deal_id, related_object_id, related_object_type) { 1079 | var o = deal_id; 1080 | (o instanceof Object) || (o = { 1081 | Id: deal_id, 1082 | RelatedObjectId: related_object_id, 1083 | RelatedObjectType: related_object_type 1084 | }); 1085 | return this.__request("::relation/saveRelation.api", utils.objectFilter(o)); 1086 | }, 1087 | 1088 | 1089 | /** 1090 | * Send comment to a deal. 1091 | * 1092 | * Написание комментария к сделке. 1093 | * 1094 | * [More info]{@link https://help.megaplan.ru/API_comment_create} 1095 | * 1096 | * @param {Number} deal_id Deal ID. ID сделки 1097 | * @param {String} text Content. Текст комментария 1098 | * @param {String} [hours] Time spend to a task. Время, потраченное на сделку 1099 | * @returns {MegaplanRequest} 1100 | */ 1101 | deal_comment_create: function (deal_id, text, hours) { 1102 | if (!deal_id || !text) { 1103 | throw "Can't post empty comment to nothing"; 1104 | } 1105 | return this.__request("::comment/create.api", { 1106 | subject_type: 'deal', 1107 | subject_id: deal_id, 1108 | model: { 1109 | text: text, 1110 | work: hours || 0 1111 | } 1112 | }); 1113 | }, 1114 | 1115 | }; 1116 | 1117 | inherits(Client, EventEmitter); 1118 | for (var i in clientProto) { 1119 | clientProto.hasOwnProperty(i) && (Client.prototype[i] = clientProto[i]); 1120 | } 1121 | 1122 | module.exports = Client; 1123 | -------------------------------------------------------------------------------- /lib/megaplan/dicts.js: -------------------------------------------------------------------------------- 1 | // Dictionaries for megaplanjs library 2 | module.exports = { 3 | 4 | // uri shortcuts 5 | uri_shortcuts: { 6 | ':notify': 'SdfNotify', 7 | ':common': 'BumsCommonApiV01', 8 | ':task': 'BumsTaskApiV01', 9 | ':project': 'BumsProjectApiV01', 10 | ':time': 'BumsTimeApiV01', 11 | ':trade': 'BumsTradeApiV01', 12 | ':staff': 'BumsStaffApiV01', 13 | ':crm': 'BumsCrmApiV01', 14 | 15 | '::userinfo': ':common/UserInfo', 16 | '::user': ':common/User', 17 | '::auth': ':common/User/authorize.api', 18 | '::system': ':common/System', 19 | '::search': ':common/Search', 20 | '::history': ':common/History', 21 | '::tags': ':common/Tags', 22 | '::task': ':task/Task', 23 | '::comment': ':common/Comment', 24 | '::reaction': ':notify/ReactionApi', 25 | '::project': ':project/Project', 26 | '::todo': ':time/TodoList', 27 | '::event': ':time/Event', 28 | '::employee': ':staff/Employee', 29 | '::department': ':staff/Department', 30 | '::contractor': ':crm/Contractor', 31 | '::deal': ':trade/Deal', 32 | '::program' : ':trade/Program', 33 | '::relation' : ':trade/Deal', 34 | }, 35 | 36 | // megaplan task folders 37 | folders: [ 38 | 'incoming', 39 | 'responsible', 40 | 'executor', 41 | 'owner', 42 | 'auditor', 43 | 'all' 44 | ], 45 | 46 | // megaplan task statuses 47 | task_statuses: [ 48 | 'actual', 49 | 'inprocess', 50 | 'new', 51 | 'overdue', 52 | 'done', 53 | 'delayed', 54 | 'completed', 55 | 'failed', 56 | 'any' 57 | ], 58 | 59 | // megaplan action types 60 | action_types: [ 61 | 'act_accept_task', 62 | 'act_reject_task', 63 | 'act_accept_work', 64 | 'act_reject_work', 65 | 'act_done', 66 | 'act_pause', 67 | 'act_resume', 68 | 'act_cancel', 69 | 'act_expire', 70 | 'act_renew' 71 | ], 72 | 73 | // megaplan subject types 74 | subject_types: [ 75 | 'task', 76 | 'project' 77 | ], 78 | 79 | // megaplan orders 80 | order_type: [ 81 | 'asc', 82 | 'desc' 83 | ], 84 | 85 | // inner errors 86 | request_errors: { 87 | ':hangup': 'connection closed unexpectedly', 88 | ':invalidjson': 'received invalid json string', 89 | ':network': 'request dropped' 90 | } 91 | 92 | }; 93 | -------------------------------------------------------------------------------- /lib/megaplan/lang.ru.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | /* doc.replace(/^([a-z]+)\t([a-z а-я\(\)<>,]+)\t(.*?)$/i, "$1: '$3', // $2"); */ 4 | 5 | folders: { 6 | incoming: 'входящие', 7 | responsible: 'ответственный', 8 | executor: 'соисполнитель', 9 | owner: 'исходящие', 10 | auditor: 'аудируемые', 11 | all: 'все' 12 | }, 13 | 14 | task_statuses: { 15 | actual: 'актуальные', 16 | inprocess: 'в процессе', 17 | "new": 'новые', 18 | overdue: 'просроченные', 19 | done: 'условно завершенные', 20 | delayed: 'отложенные', 21 | completed: 'завершенные', 22 | failed: 'проваленные', 23 | any: 'любые' 24 | }, 25 | 26 | task_fields_full: { 27 | id: 'ID задачи', 28 | name: 'Название', // string 29 | status: 'Статус', // string 30 | deadline: 'Дедлайн', // datetime 31 | owner: 'Постановщик (сотрудник)', // object (Id, Name) 32 | responsible: 'Ответственный (сотрудник)', // object (Id, Name) 33 | severity: 'Важность', // string 34 | super_task: 'Надзадача', // object (Id, Name) 35 | project: 'Проект', // object (Id, Name) 36 | favorite: 'В избранном', // integer 37 | time_created: 'Время создания', // datetime 38 | time_updated: 'Время последней модификации', // datetime 39 | folders: 'Список папок, в которые попадает задача', // array 40 | tags: 'Тэги, привязанные к задаче', // array 41 | activity: 'Дата и время последней активности по задаче', // datetime 42 | actions: 'Список доступных действий над задачей', // array 43 | is_overdue: 'Является ли задача просроченной', // bool 44 | comments_unread: 'Количество непрочитанных комментариев' // integer 45 | }, 46 | 47 | task_fields: { 48 | id: 'идентификатор', 49 | name: 'наименование', 50 | activity: 'активность', 51 | deadline: 'дата дедлайна', 52 | responsible: 'ответственный', 53 | owner: 'постановщик', 54 | contractor: 'заказчик', 55 | start: 'старт', 56 | planned_finish: 'плановый финиш', 57 | planned_work: 'запланировано', 58 | actual_work: 'отработано', 59 | completed: 'процент завершения', 60 | bonus: 'бонус', 61 | fine: 'штраф', 62 | planned_time: 'длительность' 63 | }, 64 | 65 | project_fields_full: { 66 | id: 'ID проекта', // integer 67 | name: 'Название', // string 68 | status: 'Статус', // string 69 | deadline: 'Дедлайн', // datetime 70 | owner: 'Владелец (сотрудник)', // object (Id, Name) 71 | responsible: 'Менеджер (сотрудник)', // object (Id, Name) 72 | severity: 'Важность', // object (Id, Name) 73 | super_project: 'Надпроект', // object (Id, Name) 74 | favorite: 'В избранном', // integer 75 | time_created: 'Время создания', // datetime 76 | time_updated: 'Время последней модификации', // datetime 77 | tags: 'Тэги, привязанные к проекту', // array 78 | start: 'Старт проекта', // datetime 79 | activity: 'Дата и время последней активности по проекту', // datetime 80 | actions: 'Список допустимых действий над проектом', // array 81 | is_overdue: 'Является ли проект просроченным', // bool 82 | }, 83 | 84 | employee_fields_full: { 85 | id: 'ID сотрудника', // integer 86 | name: 'Полное имя', // string 87 | last_name: 'Фамилия', // string 88 | first_name: 'Имя', // string 89 | middle_name: 'Отчество', // string 90 | position: 'Должность', // object (Id, Name) 91 | department: 'Отдел', // object (Id, Name) 92 | phones: 'Телефоны', // array 93 | email: 'E-mail', // string 94 | status: 'Статус', // object (Id, Name) 95 | time_created: 'Время создания', // datetime 96 | fire_day: 'Дата увольнения', // date 97 | avatar: 'Адрес аватара сотрудника ', // string 98 | login: 'Логин сотрудника', // string 99 | }, 100 | 101 | department_fields_full: { 102 | id: 'ID отдела', // integer 103 | name: 'Название отдела', // string 104 | head: 'Начальник отдела', // object (Id, Name) 105 | employees: 'Список сотрудников отдела', // array 106 | employees_count: 'Количество сотрудников в отделе', // integer 107 | }, 108 | 109 | todolist_fields_full: { 110 | id: 'Id списка дел', // integer 111 | name: 'Название списка дел', // string 112 | todo_count: 'Количество незавершенных дел в списке', // integer 113 | }, 114 | 115 | event_fields_full: { 116 | id: 'Id события', // integer 117 | description: 'Описание события', // string 118 | name: 'Название события', // string 119 | time_created: 'Дата и время создания', // datetime 120 | start_time: 'Начало события', // datetime 121 | duration: 'Продолжительность события', // integer 122 | is_personal: 'Личное дело?', // boolean 123 | event_category: 'Категория события', // string 124 | participants: 'Список участников', // object (Id, Name) 125 | contractors: 'Список контрагентов', // object (Id, Name) 126 | reminders: ' Напоминания', // object (Transport, TimeBefore) 127 | has_todo: 'Имеет дела?', // boolean 128 | has_communication: 'Имеет коммуникации?', // boolean 129 | todo_list_id: 'Код списка дел, в котором находится событие', // integer 130 | position: 'Порядковый номер события внутри списка дел', // integer 131 | owner: 'Id пользователя, создавшего событие', // integer 132 | is_finished: 'Является ли событие завершенным', // boolean 133 | place: 'Место события', // string 134 | is_favorite: 'Добавлено ли событие в избранное', // bool 135 | time_updated: 'Время последней модификации события', // datetime 136 | can_edit: 'Можно ли редактировать событие', // bool 137 | is_overdue: 'Просрочено ли событие', // bool 138 | }, 139 | 140 | event_place_fields_full: { 141 | id: 'Id места', // integer 142 | name: 'Название места', // string 143 | }, 144 | 145 | event_category_fields_full: { 146 | id: 'Id категории', // integer 147 | name: 'Название категории', // string 148 | }, 149 | 150 | comment_fields_full: { 151 | id: 'ID комментария', // integer 152 | text: 'Текст комментария', // string 153 | work: 'Кол-во потраченных минут, которое приплюсовано к комментируемому объекту (задаче или проекту)', // integer 154 | work_date: 'Дата, на которую списаны потраченные часы', // date 155 | time_created: 'Время создания', // datetime 156 | author: 'Автор комментария (сотрудник)', // object (Id, Name) 157 | avatar: 'Адрес аватара автора', // string 158 | attaches: 'Файлы, прикрепленные к комментарию', // object (Name, Url) 159 | is_unread: 'Является ли комментарий непрочитанным', // bool 160 | is_favorite: 'Находится ли комментарий в избранном', // bool 161 | }, 162 | 163 | comment_oops: { 164 | first_unread_comment: 'ID первого непрочитанного комментария', // integer 165 | }, 166 | 167 | notifications: { 168 | id: 'ID уведомления', // integer 169 | subject: 'Предмет уведомления (см. пояснение ниже)', // object(Id,Name,Type) 170 | content: 'Содержимое уведомления (см. пояснение ниже)', // string или object(Subject,Text,Author) 171 | time_created: 'Время создания уведомления', // datetime 172 | }, 173 | 174 | contractor_fields_full: { 175 | id: 'Идентификатор клиента', // integer 176 | name: 'Имя клиента', // string 177 | birthday: 'Дата рождения', // datetime 178 | description: 'Описание клиента', // string 179 | email: 'E-mail', // string 180 | facebook: ' Facebook', // string 181 | jabber: 'Jabber', // string 182 | payers: 'Список плательщиков', // object (Id, Name) 183 | person_type: 'Тип клиента', // string 184 | prefer_transport: 'Предпочтительный способ связи', // string 185 | promising_rate: 'Перспективность', // string 186 | responsibles: '', // object (Id, Name) 187 | site: 'Сайт', // string 188 | time_created: 'Время создания', // datetime 189 | time_updated: 'Время обновления', // datetime 190 | twitter: 'Twitter', // string 191 | type: 'Тип', // string 192 | } 193 | }; 194 | -------------------------------------------------------------------------------- /lib/megaplan/request.js: -------------------------------------------------------------------------------- 1 | /*jshint laxbreak:true, laxcomma:true, boss:true, strict:false, devel:true, smarttabs:true, onecase:true */ 2 | 3 | var http = require('http') 4 | , https = require('https') 5 | , qs = require('qs') 6 | , errors = require('./dicts.js').request_errors 7 | , utils = require('../utils.js'); 8 | 9 | /** 10 | * MegaplanRequest class 11 | * @class MegaplanRequest 12 | * @constuctor 13 | * @param {MegaplanServerConf} server 14 | * @param {String} access_id 15 | * @param {String} secret_key 16 | * @param {String} uri Base uri of megaplan API. Базовый URI Megaplan API 17 | * @param {Object} [data] Some data to send to Megaplan API. Данные, которые будут отправлены в Megaplan API 18 | * @param {String|Function} [res_data_filter] Some key to return from response instead of all data or callback to filter response data. Некоторый ключ для возвращения ответа вместо всех данных или callback для фильтрации данных 19 | * @param {Function} [req_data_filter] Callback to filter request data. keysToPascalCase by default. Callback дя фильтрации ответа. По умолчанию keysToPascalCase 20 | */ 21 | var Request = function MegaplanRequest (server, access_id, secret_key, uri, data, res_data_filter, req_data_filter) { 22 | this.server = server; 23 | 24 | this.uri = uri; 25 | this.url = [ this.server.hostname, uri ].join('/'); 26 | 27 | this.access_id = access_id; 28 | this.secret_key = secret_key; 29 | 30 | this.now = (new Date()).toUTCString(); 31 | this.data = data || {}; 32 | 33 | this.req_data_filter = req_data_filter !== false ? req_data_filter : function (v) { return v; }; 34 | this.res_data_filter = res_data_filter !== false ? res_data_filter : function (v) { return v; }; 35 | }; 36 | Request.prototype = { 37 | server: null, 38 | // common 39 | method: 'POST', 40 | content_type: 'application/x-www-form-urlencoded', 41 | user_agent: 'MegaplanJS Client', 42 | // user data 43 | uri: null, 44 | access_id: null, 45 | secret_key: null, 46 | signature: null, 47 | auth_key: null, 48 | // something speccy 49 | now: null, 50 | data: null, 51 | req_data_filter: null, 52 | res_data_filter: null, 53 | // default callbacks 54 | success_callback: null, 55 | fail_callback: null, 56 | 57 | callbacks: function (success, fail) { 58 | this.success_callback = success; 59 | this.fail_callback = fail; 60 | }, 61 | 62 | sign: function () { 63 | var text = [ this.method, '', this.content_type, this.now, this.url ].join("\n"); 64 | this.signature = utils.make_signature(this.secret_key, text); 65 | this.auth_key = [ this.access_id, this.signature ].join(':'); 66 | return this; 67 | }, 68 | 69 | /** 70 | * Proceed prepared request and calls success_callback (or fail_callback) with result 71 | * 72 | * Производит подготовку и отправку запроса и вызывает success_callback (или fail_callback) с результатом 73 | * 74 | * @memberof MegaplanRequest 75 | * @param {Function} [success] Callback for fine results. Callback для успешного запроса 76 | * @param {Function} [fail] Callback for errors. Callback для ошибок 77 | */ 78 | send: function (success, fail) { 79 | var req, options, req_data_filter, total; 80 | 81 | success = success || this.success_callback; 82 | fail = fail || this.fail_callback; 83 | 84 | req_data_filter = this.req_data_filter || function (h) { 85 | return utils.convertKeysToPascalCase(h); 86 | }; 87 | total = this.data.count || false; 88 | data = this.data && qs.stringify(req_data_filter(this.data)); 89 | // todo: qs.stringify can't create boundaries and attach files to post body. 90 | // need to more powerfull thing to do it 91 | 92 | // todo: move port and protocol configuration out of here 93 | options = { 94 | method: this.method, 95 | hostname: this.server.hostname, 96 | port: this.server.port, 97 | path: '/' + this.uri, 98 | headers: { 99 | 'Date': this.now, // really? 100 | 'Accept': 'application/json', 101 | 'User-Agent': this.user_agent, 102 | 'Content-Length': data.length, 103 | 'Content-Type': this.content_type 104 | } 105 | }; 106 | if (this.server.auth) { 107 | options.auth = this.server.auth; 108 | } 109 | if (this.auth_key) { 110 | options.headers['X-Authorization'] = this.auth_key; 111 | } 112 | 113 | var jkey = this.res_data_filter; 114 | success = success || function () {}; 115 | fail = fail || function () {}; 116 | 117 | // console.log(options, data);//process.exit(); 118 | 119 | var transport = this.server.scheme === 'http' ? http : https; 120 | 121 | req = transport.request(options, function (res) { 122 | // console.log('STATUS: ' + res.statusCode); 123 | // console.log('HEADERS: ' + JSON.stringify(res.headers)); 124 | var chunks = []; 125 | res.setEncoding('utf8'); 126 | res.on('data', function (chunk) { 127 | // console.log('BODY: ' + chunk); 128 | chunks.push(chunk); 129 | }); 130 | res.on('end', function () { 131 | var json, result; 132 | try { 133 | json = JSON.parse(chunks.join('')); 134 | chunks = null; 135 | if ((json.status && json.status.code) !== 'ok') { 136 | return fail ({'error': json.status}); 137 | } 138 | 139 | // move it to client mb? 140 | result = json.data || json.json || {}; 141 | result = utils.convertKeysToUnderscore(result); 142 | result = utils.convertValuesToNatives(result); 143 | if (jkey && (typeof jkey === 'string') && !result[jkey] && !total) { 144 | throw "key " + jkey + " not exists in json"; 145 | } 146 | if (jkey && (typeof jkey === 'function')) { 147 | result = jkey(result); 148 | } else if (jkey && !total) { 149 | result = result[jkey]; 150 | } 151 | return success (result); 152 | 153 | } catch (e) { 154 | // json broken? 155 | fail ({ 156 | 'error': {'code': ':invalidjson', 'message': errors[':invalidjson']}, 157 | 'exception': e 158 | }); 159 | } 160 | }); 161 | res.on('close', function () { 162 | if (!chunks) { 163 | // all is ok. im right? 164 | return; 165 | } 166 | fail({ 167 | 'error': {'code': ':hangup', 'message': errors[':hangup']}, 168 | 'chunks': chunks 169 | }); 170 | }); 171 | }); 172 | 173 | req.on('error', function (e) { 174 | // console.log('problem with request: ' + e.message); 175 | fail({ 176 | 'error': {'code': ':network', 'message': errors[':network']}, 177 | 'exception': e 178 | }); 179 | }); 180 | 181 | // write data to request body 182 | req.write(data); 183 | 184 | req.end(); 185 | 186 | return this; 187 | } 188 | }; 189 | 190 | module.exports = Request; 191 | -------------------------------------------------------------------------------- /lib/megaplan/serverconf.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Megaplan server configuration class. 4 | * 5 | * Конфигурация сервера Megaplan 6 | * 7 | * @class MegaplanServerConf 8 | * @constuctor 9 | * @param {String|Object} server Hostname or Object 10 | * @param {String} server.hostname 11 | * @param {Number} [server.port=443] 12 | * @param {String} [server.scheme=https] http or https 13 | * @param {String} [server.auth] Basic authentication 14 | * @param {String} [server.user] Or user 15 | * @param {String} [pass] And password 16 | * @param {Number} [port=443] 17 | * @param {String} [scheme=https] http or https 18 | * @param {String} [auth] Basic authentication 19 | */ 20 | var serverconf = function MegaplanServerConf (hostname, port, scheme, auth) { 21 | if (hostname instanceof MegaplanServerConf) { 22 | return hostname; 23 | } 24 | 25 | var o = hostname; 26 | (o instanceof Object) || (o = { 27 | hostname: hostname, 28 | port: port, 29 | scheme: scheme, 30 | auth: auth 31 | }); 32 | 33 | this.hostname = o.hostname || o.host; 34 | if (!this.hostname) { 35 | throw "No required property `hostname` provided"; 36 | } 37 | 38 | this.port = Number(o.port || 443); 39 | this.scheme = (this.port === 443 || o.scheme === 'https') ? 'https' : 'http'; 40 | this.auth = o.auth || [ o.user, o.pass ].join(':').replace(/^:/,'') || false; 41 | }; 42 | serverconf.prototype = { 43 | hostname: null, 44 | port: null, 45 | scheme: null, 46 | auth: null 47 | }; 48 | serverconf.isSelfLikeObject = function (o) { 49 | return (o.host || o.hostname) || (o instanceof serverconf); 50 | }; 51 | 52 | module.exports = serverconf; 53 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | // Pack of helpers 2 | 3 | var crypto = require('crypto') 4 | , dicts = require('./megaplan/dicts.js') 5 | , utils 6 | , createDate; 7 | 8 | createDate = function (date) { 9 | if (date === '') return null; 10 | return new Date(date); 11 | }; 12 | 13 | utils = { 14 | // Just a base64.encode 15 | b64encode: function (data) { 16 | return (new Buffer(data)).toString('base64'); 17 | }, 18 | 19 | md5: function (text) { 20 | return crypto.createHash("md5").update( text ).digest('hex'); 21 | }, 22 | 23 | // Converts "abc_def" string to "AbcDef" 24 | toPascalCase: function (s) { 25 | return String(s).substr(0, 1).toUpperCase() + String(s).substr(1).replace(/_[a-z]/ig, function ($0) { return $0.substr(1,1).toUpperCase(); }); 26 | }, 27 | 28 | // Converts "AbcDef" string to "abc_def" 29 | toUnderscore: function (s) { 30 | return String(s).replace(/[A-Z]/g, function ($0) { return "_" + $0.toLowerCase(); }).replace(/^_/,''); 31 | }, 32 | 33 | is_native: function (h) { 34 | return typeof h !== 'object' || h instanceof Array || h instanceof Date || h instanceof String || h instanceof Boolean || h instanceof Number || h instanceof Function || h instanceof RegExp; 35 | }, 36 | 37 | // Creates an object and fills it by :h but before executes converter on :h.key 38 | convertKeys: function (h, converter) { 39 | var r = {}; 40 | if (utils.is_native(h) && !(h instanceof Array)) { 41 | return h; 42 | } 43 | for (var k in h) { 44 | (r[converter(k)] = utils.convertKeys(h[k], converter)); 45 | } 46 | return r; 47 | }, 48 | 49 | // Converts an object with under_scored keys to an object with PascalCased keys 50 | convertKeysToPascalCase: function (h) { 51 | return utils.convertKeys(h, utils.toPascalCase); 52 | }, 53 | 54 | // Converts an object with PascalCased keys to an object with under_scored keys 55 | convertKeysToUnderscore: function (h) { 56 | return utils.convertKeys(h, utils.toUnderscore); 57 | }, 58 | 59 | objectFilter: function (h, callback) { 60 | var r = {}; 61 | callback = callback || function (v, k) { return v == null; }; 62 | for (var i in h) { 63 | if (!h.hasOwnProperty(i)) continue; 64 | if (!callback(h[i], i)) r[i] = h[i]; 65 | } 66 | return r; 67 | }, 68 | 69 | // megaplan specific helpers below 70 | 71 | keysToConvertTo: { 72 | 'time_created': createDate, 73 | 'time_updated': createDate, 74 | 'fire_day': createDate, 75 | 'start_time': createDate, 76 | 'activity': createDate, 77 | 'appearance_day': createDate, 78 | 'birthday': createDate 79 | }, 80 | convertValuesToNatives: function (h) { 81 | if (utils.is_native(h) && !(h instanceof Array)) { 82 | return h; 83 | } 84 | for (var k in h) { 85 | if (!h.hasOwnProperty(k)) continue; 86 | if ((typeof h[k] === 'string') || (h[k] instanceof String)) { 87 | if (!utils.keysToConvertTo[k]) continue; 88 | var conv = utils.keysToConvertTo[k]; 89 | h[k] = h[k] === '' ? null : conv(h[k]); 90 | } else { 91 | h[k] = utils.convertValuesToNatives(h[k]); 92 | } 93 | } 94 | return h; 95 | }, 96 | 97 | // replaces shortcuts in :uri string with their values 98 | subst_uri: function (uri) { 99 | var parts = dicts.uri_shortcuts; 100 | var result = String(uri); 101 | [ /^::[a-z]+/, /^:[a-z]+/ ].forEach (function (v) { 102 | result = result.replace(v, function ($0) { 103 | return parts[$0] || ''; 104 | }); 105 | }); 106 | return result; 107 | }, 108 | 109 | // secret signer method 110 | make_signature: function (key, text) { 111 | return utils.b64encode(crypto.createHmac('sha1', key).update( text ).digest('hex')); 112 | }, 113 | 114 | // megaplan ids must be higher than 1000000 115 | normalize_id: function (id) { 116 | if (id === null || id === undefined) { 117 | return id; 118 | } 119 | var is_project = /^p\d+/.test(String(id)); 120 | is_project && (id = id.replace(/^p/, '')); 121 | id = Number(id) + (Number(id) < 1000000 ? 1000000 : 0); 122 | return is_project ? 'p' + id : id; 123 | } 124 | 125 | }; 126 | 127 | module.exports = utils; 128 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "megaplanjs", 3 | "version": "1.0.4", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ansi-styles": { 8 | "version": "3.2.1", 9 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 10 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 11 | "dev": true, 12 | "requires": { 13 | "color-convert": "^1.9.0" 14 | } 15 | }, 16 | "array-uniq": { 17 | "version": "1.0.3", 18 | "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", 19 | "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", 20 | "dev": true 21 | }, 22 | "babylon": { 23 | "version": "7.0.0-beta.19", 24 | "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz", 25 | "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==", 26 | "dev": true 27 | }, 28 | "bluebird": { 29 | "version": "3.5.2", 30 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz", 31 | "integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg==", 32 | "dev": true 33 | }, 34 | "catharsis": { 35 | "version": "0.8.9", 36 | "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz", 37 | "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=", 38 | "dev": true, 39 | "requires": { 40 | "underscore-contrib": "~0.3.0" 41 | } 42 | }, 43 | "chalk": { 44 | "version": "2.4.1", 45 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", 46 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", 47 | "dev": true, 48 | "requires": { 49 | "ansi-styles": "^3.2.1", 50 | "escape-string-regexp": "^1.0.5", 51 | "supports-color": "^5.3.0" 52 | } 53 | }, 54 | "color-convert": { 55 | "version": "1.9.3", 56 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 57 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 58 | "dev": true, 59 | "requires": { 60 | "color-name": "1.1.3" 61 | } 62 | }, 63 | "color-name": { 64 | "version": "1.1.3", 65 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 66 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 67 | "dev": true 68 | }, 69 | "core-util-is": { 70 | "version": "1.0.2", 71 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 72 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 73 | "dev": true 74 | }, 75 | "dom-serializer": { 76 | "version": "0.1.0", 77 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", 78 | "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", 79 | "dev": true, 80 | "requires": { 81 | "domelementtype": "~1.1.1", 82 | "entities": "~1.1.1" 83 | }, 84 | "dependencies": { 85 | "domelementtype": { 86 | "version": "1.1.3", 87 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", 88 | "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", 89 | "dev": true 90 | } 91 | } 92 | }, 93 | "domelementtype": { 94 | "version": "1.3.0", 95 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", 96 | "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", 97 | "dev": true 98 | }, 99 | "domhandler": { 100 | "version": "2.4.2", 101 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", 102 | "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", 103 | "dev": true, 104 | "requires": { 105 | "domelementtype": "1" 106 | } 107 | }, 108 | "domutils": { 109 | "version": "1.7.0", 110 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", 111 | "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", 112 | "dev": true, 113 | "requires": { 114 | "dom-serializer": "0", 115 | "domelementtype": "1" 116 | } 117 | }, 118 | "entities": { 119 | "version": "1.1.1", 120 | "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", 121 | "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", 122 | "dev": true 123 | }, 124 | "escape-string-regexp": { 125 | "version": "1.0.5", 126 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 127 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 128 | "dev": true 129 | }, 130 | "graceful-fs": { 131 | "version": "4.1.11", 132 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 133 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", 134 | "dev": true 135 | }, 136 | "has-flag": { 137 | "version": "3.0.0", 138 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 139 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 140 | "dev": true 141 | }, 142 | "htmlparser2": { 143 | "version": "3.9.2", 144 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", 145 | "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", 146 | "dev": true, 147 | "requires": { 148 | "domelementtype": "^1.3.0", 149 | "domhandler": "^2.3.0", 150 | "domutils": "^1.5.1", 151 | "entities": "^1.1.1", 152 | "inherits": "^2.0.1", 153 | "readable-stream": "^2.0.2" 154 | } 155 | }, 156 | "inherits": { 157 | "version": "2.0.3", 158 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 159 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 160 | "dev": true 161 | }, 162 | "ink-docstrap": { 163 | "version": "1.3.2", 164 | "resolved": "https://registry.npmjs.org/ink-docstrap/-/ink-docstrap-1.3.2.tgz", 165 | "integrity": "sha512-STx5orGQU1gfrkoI/fMU7lX6CSP7LBGO10gXNgOZhwKhUqbtNjCkYSewJtNnLmWP1tAGN6oyEpG1HFPw5vpa5Q==", 166 | "dev": true, 167 | "requires": { 168 | "moment": "^2.14.1", 169 | "sanitize-html": "^1.13.0" 170 | } 171 | }, 172 | "isarray": { 173 | "version": "1.0.0", 174 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 175 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 176 | "dev": true 177 | }, 178 | "js2xmlparser": { 179 | "version": "3.0.0", 180 | "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", 181 | "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", 182 | "dev": true, 183 | "requires": { 184 | "xmlcreate": "^1.0.1" 185 | } 186 | }, 187 | "jsdoc": { 188 | "version": "3.5.5", 189 | "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz", 190 | "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==", 191 | "dev": true, 192 | "requires": { 193 | "babylon": "7.0.0-beta.19", 194 | "bluebird": "~3.5.0", 195 | "catharsis": "~0.8.9", 196 | "escape-string-regexp": "~1.0.5", 197 | "js2xmlparser": "~3.0.0", 198 | "klaw": "~2.0.0", 199 | "marked": "~0.3.6", 200 | "mkdirp": "~0.5.1", 201 | "requizzle": "~0.2.1", 202 | "strip-json-comments": "~2.0.1", 203 | "taffydb": "2.6.2", 204 | "underscore": "~1.8.3" 205 | } 206 | }, 207 | "klaw": { 208 | "version": "2.0.0", 209 | "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz", 210 | "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=", 211 | "dev": true, 212 | "requires": { 213 | "graceful-fs": "^4.1.9" 214 | } 215 | }, 216 | "lodash.clonedeep": { 217 | "version": "4.5.0", 218 | "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", 219 | "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", 220 | "dev": true 221 | }, 222 | "lodash.escaperegexp": { 223 | "version": "4.1.2", 224 | "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", 225 | "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=", 226 | "dev": true 227 | }, 228 | "lodash.isplainobject": { 229 | "version": "4.0.6", 230 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 231 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", 232 | "dev": true 233 | }, 234 | "lodash.isstring": { 235 | "version": "4.0.1", 236 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", 237 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", 238 | "dev": true 239 | }, 240 | "lodash.mergewith": { 241 | "version": "4.6.2", 242 | "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", 243 | "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", 244 | "dev": true 245 | }, 246 | "marked": { 247 | "version": "0.3.19", 248 | "resolved": "http://registry.npmjs.org/marked/-/marked-0.3.19.tgz", 249 | "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", 250 | "dev": true 251 | }, 252 | "minimist": { 253 | "version": "0.0.8", 254 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 255 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 256 | "dev": true 257 | }, 258 | "mkdirp": { 259 | "version": "0.5.1", 260 | "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 261 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 262 | "dev": true, 263 | "requires": { 264 | "minimist": "0.0.8" 265 | } 266 | }, 267 | "moment": { 268 | "version": "2.22.2", 269 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", 270 | "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=", 271 | "dev": true 272 | }, 273 | "number-is-nan": { 274 | "version": "1.0.1", 275 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 276 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 277 | "dev": true 278 | }, 279 | "postcss": { 280 | "version": "6.0.23", 281 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", 282 | "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", 283 | "dev": true, 284 | "requires": { 285 | "chalk": "^2.4.1", 286 | "source-map": "^0.6.1", 287 | "supports-color": "^5.4.0" 288 | } 289 | }, 290 | "process-nextick-args": { 291 | "version": "2.0.0", 292 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 293 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", 294 | "dev": true 295 | }, 296 | "qs": { 297 | "version": "6.0.4", 298 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.0.4.tgz", 299 | "integrity": "sha1-UQGdhHIMk5uCc36EVWp4Izjs6ns=" 300 | }, 301 | "readable-stream": { 302 | "version": "2.3.6", 303 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 304 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 305 | "dev": true, 306 | "requires": { 307 | "core-util-is": "~1.0.0", 308 | "inherits": "~2.0.3", 309 | "isarray": "~1.0.0", 310 | "process-nextick-args": "~2.0.0", 311 | "safe-buffer": "~5.1.1", 312 | "string_decoder": "~1.1.1", 313 | "util-deprecate": "~1.0.1" 314 | } 315 | }, 316 | "requizzle": { 317 | "version": "0.2.1", 318 | "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz", 319 | "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=", 320 | "dev": true, 321 | "requires": { 322 | "underscore": "~1.6.0" 323 | }, 324 | "dependencies": { 325 | "underscore": { 326 | "version": "1.6.0", 327 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", 328 | "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", 329 | "dev": true 330 | } 331 | } 332 | }, 333 | "safe-buffer": { 334 | "version": "5.1.2", 335 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 336 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 337 | "dev": true 338 | }, 339 | "sanitize-html": { 340 | "version": "1.19.1", 341 | "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-1.19.1.tgz", 342 | "integrity": "sha512-zNYr6FvBn4bZukr9x2uny6od/9YdjCLwF+FqxivqI0YOt/m9GIxfX+tWhm52tBAPUXiTTb4bJTGVagRz5b06bw==", 343 | "dev": true, 344 | "requires": { 345 | "chalk": "^2.3.0", 346 | "htmlparser2": "^3.9.0", 347 | "lodash.clonedeep": "^4.5.0", 348 | "lodash.escaperegexp": "^4.1.2", 349 | "lodash.isplainobject": "^4.0.6", 350 | "lodash.isstring": "^4.0.1", 351 | "lodash.mergewith": "^4.6.0", 352 | "postcss": "^6.0.14", 353 | "srcset": "^1.0.0", 354 | "xtend": "^4.0.0" 355 | } 356 | }, 357 | "source-map": { 358 | "version": "0.6.1", 359 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 360 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 361 | "dev": true 362 | }, 363 | "srcset": { 364 | "version": "1.0.0", 365 | "resolved": "https://registry.npmjs.org/srcset/-/srcset-1.0.0.tgz", 366 | "integrity": "sha1-pWad4StC87HV6D7QPHEEb8SPQe8=", 367 | "dev": true, 368 | "requires": { 369 | "array-uniq": "^1.0.2", 370 | "number-is-nan": "^1.0.0" 371 | } 372 | }, 373 | "string_decoder": { 374 | "version": "1.1.1", 375 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 376 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 377 | "dev": true, 378 | "requires": { 379 | "safe-buffer": "~5.1.0" 380 | } 381 | }, 382 | "strip-json-comments": { 383 | "version": "2.0.1", 384 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 385 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 386 | "dev": true 387 | }, 388 | "supports-color": { 389 | "version": "5.5.0", 390 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 391 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 392 | "dev": true, 393 | "requires": { 394 | "has-flag": "^3.0.0" 395 | } 396 | }, 397 | "taffydb": { 398 | "version": "2.6.2", 399 | "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", 400 | "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", 401 | "dev": true 402 | }, 403 | "underscore": { 404 | "version": "1.8.3", 405 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", 406 | "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", 407 | "dev": true 408 | }, 409 | "underscore-contrib": { 410 | "version": "0.3.0", 411 | "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz", 412 | "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=", 413 | "dev": true, 414 | "requires": { 415 | "underscore": "1.6.0" 416 | }, 417 | "dependencies": { 418 | "underscore": { 419 | "version": "1.6.0", 420 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", 421 | "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", 422 | "dev": true 423 | } 424 | } 425 | }, 426 | "util-deprecate": { 427 | "version": "1.0.2", 428 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 429 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 430 | "dev": true 431 | }, 432 | "xmlcreate": { 433 | "version": "1.0.2", 434 | "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", 435 | "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=", 436 | "dev": true 437 | }, 438 | "xtend": { 439 | "version": "4.0.1", 440 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 441 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", 442 | "dev": true 443 | } 444 | } 445 | } 446 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "megaplanjs", 3 | "version": "1.0.4", 4 | "description": "NodeJS Megaplan API", 5 | "main": "lib/megaplan.js", 6 | "scripts": { 7 | "start": "node index.js", 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "docs": "rm -r docs/ || echo && node ./node_modules/jsdoc/jsdoc.js -t ./node_modules/ink-docstrap/template -c ./node_modules/ink-docstrap/template/jsdoc.conf.json -d ./docs -r ./README.md ./lib" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git@github.com:zxqfox/megaplanjs.git" 14 | }, 15 | "keywords": [ 16 | "megaplan", 17 | "api", 18 | "node" 19 | ], 20 | "author": "Alex Yaroshevich ", 21 | "license": "MIT", 22 | "dependencies": { 23 | "qs": "~6.0.4" 24 | }, 25 | "devDependencies": { 26 | "ink-docstrap": "^1.1.0", 27 | "jsdoc": "^3.4.0" 28 | } 29 | } 30 | --------------------------------------------------------------------------------