From 71ea121c75972d5652503658826001810c1ef100 Mon Sep 17 00:00:00 2001 From: Thomas Kurz Date: Thu, 22 Feb 2018 09:38:59 +0100 Subject: [PATCH 01/56] first concept --- .meteor/packages | 3 + .meteor/versions | 2 + package-lock.json | 46 ++++- packages/chatpal-search/client/admin.html | 4 + packages/chatpal-search/client/admin.js | 13 ++ packages/chatpal-search/client/result.html | 6 + packages/chatpal-search/client/result.js | 9 + packages/chatpal-search/package.js | 27 +++ packages/chatpal-search/server/provider.js | 40 ++++ .../rocketchat-lib/client/defaultTabBars.js | 4 +- .../rocketchat-search/client/admin/admin.html | 59 ++++++ .../rocketchat-search/client/admin/admin.js | 78 ++++++++ .../client/admin/provider.html | 10 + .../client/admin/provider.js | 13 ++ .../rocketchat-search/client/admin/route.js | 9 + .../client/provider/result.html | 17 ++ .../client/provider/result.js | 29 +++ .../client/search/search.html | 15 ++ .../rocketchat-search/client/search/search.js | 58 ++++++ .../rocketchat-search/client/style/style.css | 33 +++ packages/rocketchat-search/package.js | 38 ++++ packages/rocketchat-search/server/index.js | 7 + .../server/provider/defaultProvider.js | 45 +++++ .../server/service/provider.js | 67 +++++++ .../server/service/providerService.js | 188 ++++++++++++++++++ .../server/service/settings.js | 11 + 26 files changed, 821 insertions(+), 10 deletions(-) create mode 100644 packages/chatpal-search/client/admin.html create mode 100644 packages/chatpal-search/client/admin.js create mode 100644 packages/chatpal-search/client/result.html create mode 100644 packages/chatpal-search/client/result.js create mode 100644 packages/chatpal-search/package.js create mode 100644 packages/chatpal-search/server/provider.js create mode 100644 packages/rocketchat-search/client/admin/admin.html create mode 100644 packages/rocketchat-search/client/admin/admin.js create mode 100644 packages/rocketchat-search/client/admin/provider.html create mode 100644 packages/rocketchat-search/client/admin/provider.js create mode 100644 packages/rocketchat-search/client/admin/route.js create mode 100644 packages/rocketchat-search/client/provider/result.html create mode 100644 packages/rocketchat-search/client/provider/result.js create mode 100644 packages/rocketchat-search/client/search/search.html create mode 100644 packages/rocketchat-search/client/search/search.js create mode 100644 packages/rocketchat-search/client/style/style.css create mode 100644 packages/rocketchat-search/package.js create mode 100644 packages/rocketchat-search/server/index.js create mode 100644 packages/rocketchat-search/server/provider/defaultProvider.js create mode 100644 packages/rocketchat-search/server/service/provider.js create mode 100644 packages/rocketchat-search/server/service/providerService.js create mode 100644 packages/rocketchat-search/server/service/settings.js diff --git a/.meteor/packages b/.meteor/packages index 4a2f46f496933..ad0532775201d 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -183,3 +183,6 @@ steffo:meteor-accounts-saml todda00:friendly-slugs yasaricli:slugify yasinuslu:blaze-meta + +rocketchat:search +chatpal:search diff --git a/.meteor/versions b/.meteor/versions index 8c3b942df7ceb..509a076fe868d 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -21,6 +21,7 @@ caching-compiler@1.1.11 caching-html-compiler@1.1.2 callback-hook@1.1.0 cfs:http-methods@0.0.32 +chatpal:search@0.0.1 check@1.3.0 coffeescript@1.0.17 dandv:caret-position@2.1.1 @@ -199,6 +200,7 @@ rocketchat:postcss@1.0.0 rocketchat:push-notifications@0.0.1 rocketchat:reactions@0.0.1 rocketchat:sandstorm@0.0.1 +rocketchat:search@0.0.1 rocketchat:slackbridge@0.0.1 rocketchat:slashcommands-archive@0.0.1 rocketchat:slashcommands-asciiarts@0.0.1 diff --git a/package-lock.json b/package-lock.json index 94cd9bb52abda..54fe59f013c43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1999,7 +1999,7 @@ }, "cas": { "version": "https://github.com/kcbanner/node-cas/tarball/fcd27dad333223b3b75a048bce27973fb3ca0f62", - "integrity": "sha512-CyDs8nQAr4Asy6+H2oai66tomXC/Q6B/GF2zUYNww7jfT+xBvIhkiUGctzAy5bdq7cVxBZv31hWHz7+fxevElA==", + "integrity": "sha1-AL8m1JYV/7kMEdlJ0sKtJ18YXg4=", "requires": { "cheerio": "0.19.0" } @@ -3029,8 +3029,21 @@ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { + "lru-cache": "4.1.1", "shebang-command": "1.2.0", "which": "1.2.14" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + } } }, "cryptiles": { @@ -3620,7 +3633,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.6.tgz", "integrity": "sha512-IsORQDpaaSwcDP4ZZnHxgE85werpo34VYn1Ud3mq+eUsF593faR8oCZNXrROVkpFu2TsbrNhHin0aUrTsQ9vNw==", - "optional": true, "requires": { "prr": "1.0.1" } @@ -7783,7 +7795,7 @@ }, "less": { "version": "https://github.com/meteor/less.js/tarball/8130849eb3d7f0ecf0ca8d0af7c4207b0442e3f6", - "integrity": "sha512-514pMpzrABW11ploVaRcbHLf3MhollYYCJj9SyJmNT1O8ZeLCiIeqZ2SjZUM1uudohPlHgTRwmCZouzIJFJ7Jw==", + "integrity": "sha1-dD95WEi4QkZPVjcydtAMY6WS/qM=", "requires": { "errno": "0.1.6", "graceful-fs": "3.0.11", @@ -8574,8 +8586,7 @@ "natives": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.1.tgz", - "integrity": "sha512-8eRaxn8u/4wN8tGkhlc2cgwwvOLMLUMUn4IYTexMgWd+LyUDfeXVkk2ygQR0hvIHbJQXgHujia3ieUUDwNGkEA==", - "optional": true + "integrity": "sha512-8eRaxn8u/4wN8tGkhlc2cgwwvOLMLUMUn4IYTexMgWd+LyUDfeXVkk2ygQR0hvIHbJQXgHujia3ieUUDwNGkEA==" }, "natural-compare": { "version": "1.4.0", @@ -10142,8 +10153,13 @@ "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "optional": true + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true }, "pump": { "version": "2.0.1", @@ -13219,7 +13235,15 @@ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", "requires": { - "sax": "1.2.1" + "sax": "1.2.1", + "xmlbuilder": "9.0.7" + }, + "dependencies": { + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + } } }, "xmlbuilder": { @@ -13526,6 +13550,12 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, "yaqrcode": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/yaqrcode/-/yaqrcode-0.2.1.tgz", diff --git a/packages/chatpal-search/client/admin.html b/packages/chatpal-search/client/admin.html new file mode 100644 index 0000000000000..514a33e6624c6 --- /dev/null +++ b/packages/chatpal-search/client/admin.html @@ -0,0 +1,4 @@ + diff --git a/packages/chatpal-search/client/admin.js b/packages/chatpal-search/client/admin.js new file mode 100644 index 0000000000000..750f8d2aee12e --- /dev/null +++ b/packages/chatpal-search/client/admin.js @@ -0,0 +1,13 @@ +Template.SearchChatpalProviderAdmin.onCreated(function() { + this.data.getConfiguration = function(e) { + return { + name: e.target.name.value + }; + }; +}); + +Template.SearchChatpalProviderAdmin.helpers({ + configuration() { + return Template.instance().data.configuration; + } +}); diff --git a/packages/chatpal-search/client/result.html b/packages/chatpal-search/client/result.html new file mode 100644 index 0000000000000..89f45d26af89b --- /dev/null +++ b/packages/chatpal-search/client/result.html @@ -0,0 +1,6 @@ + diff --git a/packages/chatpal-search/client/result.js b/packages/chatpal-search/client/result.js new file mode 100644 index 0000000000000..de0de74f4cab7 --- /dev/null +++ b/packages/chatpal-search/client/result.js @@ -0,0 +1,9 @@ +Template.ChatpalSearchResultTemplate.onCreated(function() { + +}); + +Template.ChatpalSearchResultTemplate.helpers({ + result() { + return Template.instance().data.result; + } +}); diff --git a/packages/chatpal-search/package.js b/packages/chatpal-search/package.js new file mode 100644 index 0000000000000..cf86b37f82809 --- /dev/null +++ b/packages/chatpal-search/package.js @@ -0,0 +1,27 @@ +Package.describe({ + name: 'chatpal:search', + version: '0.0.1', + summary: 'Chatpal Search Provider', + git: '' +}); + +Package.onUse(function(api) { + api.use([ + 'ecmascript', + 'templating', + 'rocketchat:lib', + 'rocketchat:logger', + 'rocketchat:search' + ]); + + api.addFiles([ + 'server/provider.js' + ], 'server'); + + api.addFiles([ + 'client/admin.html', + 'client/admin.js', + 'client/result.html', + 'client/result.js' + ], 'client'); +}); diff --git a/packages/chatpal-search/server/provider.js b/packages/chatpal-search/server/provider.js new file mode 100644 index 0000000000000..c9f591f8a9666 --- /dev/null +++ b/packages/chatpal-search/server/provider.js @@ -0,0 +1,40 @@ +import {searchProviderService} from 'meteor/rocketchat:search'; +import {SearchProvider} from 'meteor/rocketchat:search'; + +class ChatpalProvider extends SearchProvider { + + constructor() { + super(); + this.configuration = { + name:'value' + }; + } + + get id() { + return 'search.provider.chatpal'; + } + + get name() { + return 'Chatpal Provider'; + } + + get description() { + return 'The chatpal provider uses a powerful search backend'; + } + + get resultTemplate() { + return 'ChatpalSearchResultTemplate'; + } + + get adminTemplate() { + return 'SearchChatpalProviderAdmin'; + } + + search(text, rid, payload, callback) { + Meteor.setTimeout(()=>{ + callback(null, {result:`You are searching for ${ text } but I am currently not yet implemeted, sorry ;)`}); + }, 500); + } +} + +searchProviderService.register(new ChatpalProvider()); diff --git a/packages/rocketchat-lib/client/defaultTabBars.js b/packages/rocketchat-lib/client/defaultTabBars.js index 5d8cf7c0f91b5..a323397a78738 100644 --- a/packages/rocketchat-lib/client/defaultTabBars.js +++ b/packages/rocketchat-lib/client/defaultTabBars.js @@ -1,9 +1,9 @@ RocketChat.TabBar.addButton({ groups: ['channel', 'group', 'direct'], - id: 'message-search', + id: 'rocket-search', i18nTitle: 'Search_Messages', icon: 'magnifier', - template: 'messageSearch', + template: 'RocketSearch', order: 1 }); diff --git a/packages/rocketchat-search/client/admin/admin.html b/packages/rocketchat-search/client/admin/admin.html new file mode 100644 index 0000000000000..497124040b7f4 --- /dev/null +++ b/packages/rocketchat-search/client/admin/admin.html @@ -0,0 +1,59 @@ + diff --git a/packages/rocketchat-search/client/admin/admin.js b/packages/rocketchat-search/client/admin/admin.js new file mode 100644 index 0000000000000..f3c2f0ec09ef6 --- /dev/null +++ b/packages/rocketchat-search/client/admin/admin.js @@ -0,0 +1,78 @@ +import toastr from 'toastr'; + +Template.SearchAdmin.onCreated(function() { + + this.enabled = new ReactiveVar(false); + this.providers = new ReactiveVar([]); + this.active = new ReactiveVar(); + this.loading = new ReactiveVar(true); + + this.setActiveProvider = (id) => { + this.providers.get().forEach((provider) => { + if (provider.id === id) { + this.childBinding = { + configuration: provider.configuration, + getConfiguration: (e) => { return undefined; } + }; + this.active.set(provider); + } + }); + }; + + Meteor.call('rocketchatSearchGetConfiguration', (err, config) => { + if (err) { + console.error(err); + return toastr.error(TAPi18n.__('SEARCH_MSG_ERROR_CANNOT_LOAD_CONFIGURATION')); + } + + console.debug(config); + + this.providers.set(config.providers); + this.enabled.set(config.enabled); + + this.setActiveProvider(config.active); + + this.loading.set(false); + }); + + this.store = (id, config, enabled) => { + Meteor.call('rocketchatSetActiveProvider', id, config, enabled, (err) => { + if (err) { + toastr.error(TAPi18n.__('SEARCH_MSG_ERROR_CANNOT_STORE_CONFIGURATION')); + } else { + toastr.info(TAPi18n.__('SEARCH_MSG_INFO_CONFIGURATION_STORED_SUCCESSFULLY')); + } + }); + }; +}); + +Template.SearchAdmin.events({ + 'submit form'(e, t) { + e.preventDefault(); + const enabled = e.target.enabled.value === 'true'; + const providerId = e.target.provider.value; + const config = t.childBinding.getConfiguration(e) || t.active.get().configuration; + t.store(providerId, config, enabled); + }, + 'change .search-provider-selector'(e, t) { + t.setActiveProvider(e.target.value); + } +}); + +Template.SearchAdmin.helpers({ + active() { + return Template.instance().active.get(); + }, + providers() { + return Template.instance().providers.get(); + }, + enabled() { + return Template.instance().enabled.get(); + }, + loading() { + return Template.instance().loading.get(); + }, + childBinding() { + return Template.instance().childBinding; + } +}); diff --git a/packages/rocketchat-search/client/admin/provider.html b/packages/rocketchat-search/client/admin/provider.html new file mode 100644 index 0000000000000..383454bc46d8a --- /dev/null +++ b/packages/rocketchat-search/client/admin/provider.html @@ -0,0 +1,10 @@ + diff --git a/packages/rocketchat-search/client/admin/provider.js b/packages/rocketchat-search/client/admin/provider.js new file mode 100644 index 0000000000000..a3f01d30b2195 --- /dev/null +++ b/packages/rocketchat-search/client/admin/provider.js @@ -0,0 +1,13 @@ +Template.SearchDefaultProviderAdmin.onCreated(function() { + this.data.getConfiguration = function(e) { + return { + searchAll: e.target.searchAll.checked + }; + }; +}); + +Template.SearchDefaultProviderAdmin.helpers({ + configuration() { + return Template.instance().data.configuration; + } +}); diff --git a/packages/rocketchat-search/client/admin/route.js b/packages/rocketchat-search/client/admin/route.js new file mode 100644 index 0000000000000..9654863dfd049 --- /dev/null +++ b/packages/rocketchat-search/client/admin/route.js @@ -0,0 +1,9 @@ +FlowRouter.route('/admin/Search', { + name: 'admin-search', + action() { + return BlazeLayout.render('main', { + center: 'SearchAdmin', + pageTitle: t('Search') + }); + } +}); diff --git a/packages/rocketchat-search/client/provider/result.html b/packages/rocketchat-search/client/provider/result.html new file mode 100644 index 0000000000000..8f97173c5b33b --- /dev/null +++ b/packages/rocketchat-search/client/provider/result.html @@ -0,0 +1,17 @@ + diff --git a/packages/rocketchat-search/client/provider/result.js b/packages/rocketchat-search/client/provider/result.js new file mode 100644 index 0000000000000..e77159b8953bb --- /dev/null +++ b/packages/rocketchat-search/client/provider/result.js @@ -0,0 +1,29 @@ +Template.DefaultSearchResultTemplate.onCreated(function() { + + this.data = this.data || {}; + this.result = new ReactiveVar(this.data.result); + + console.log(this.data.result); +}); + +Template.DefaultSearchResultTemplate.events({ + 'click .more'(e, t) { + + let limit = 2; + + if (t.data.payload && t.data.payload.limit) { + limit = t.data.payload.limit + 1; + } + + t.data.search( + t.data.text, + {limit} + ); + } +}); + +Template.DefaultSearchResultTemplate.helpers({ + result() { + return Template.instance().result.get(); + } +}); diff --git a/packages/rocketchat-search/client/search/search.html b/packages/rocketchat-search/client/search/search.html new file mode 100644 index 0000000000000..21b406bb96a95 --- /dev/null +++ b/packages/rocketchat-search/client/search/search.html @@ -0,0 +1,15 @@ + diff --git a/packages/rocketchat-search/client/search/search.js b/packages/rocketchat-search/client/search/search.js new file mode 100644 index 0000000000000..3b5749b3653b3 --- /dev/null +++ b/packages/rocketchat-search/client/search/search.js @@ -0,0 +1,58 @@ +import toastr from 'toastr'; + +Template.RocketSearch.onCreated(function() { + + this.loading = new ReactiveVar(false); + this.result = new ReactiveVar(); + this.resultTemplate = new ReactiveVar(); + + Meteor.call('rocketchatSearchResultTemplate', (err, template) => { + if (err) { + console.error('Cannot load result template for active search provider'); + } else { + this.resultTemplate.set(template); + } + }); + + const search = (text, payload) => { + this.loading.set(true); + + Meteor.call('rocketchatSearchSearch', text, Session.get('openedRoom'), payload, (err, result) => { + if (err) { + toastr.error(TAPi18n.__('SEARCH_MSG_ERROR_SEARCH_FAILED')); + } else { + this.result.set({ + result, + text, + payload, + search + }); + } + this.loading.set(false); + }); + }; + + this.search = search; + +}); + +Template.RocketSearch.events = { + 'keydown .rocket-searchbox input'(evt, t) { + if (evt.which === 13) { + t.search(evt.currentTarget.value); + } + } +}; + +Template.RocketSearch.helpers({ + loading() { + return Template.instance().loading.get(); + }, + result() { + return Template.instance().result.get(); + }, + resultTemplate() { + return Template.instance().resultTemplate.get(); + } +}); + diff --git a/packages/rocketchat-search/client/style/style.css b/packages/rocketchat-search/client/style/style.css new file mode 100644 index 0000000000000..9d40d7290a871 --- /dev/null +++ b/packages/rocketchat-search/client/style/style.css @@ -0,0 +1,33 @@ +.rocket-searchbox input { + width: 100%; + padding: 10px; + border: 1px solid #ddd; + border-radius: 5px; +} + +.rocket-searchresult { + margin-top: 20px; +} + +.rocket-searchresult .result { + border: 1px solid #ddd; + border-radius: 5px; + padding: 10px; + margin-bottom:10px; +} + +#search-admin h2 { + font-size: 20px; + padding: 20px; + border-bottom: 1px solid #ddd; + margin-bottom: 20px; +} + +#search-admin .rocket-form { + padding: 0 20px; +} + +#search-admin h3 { + margin: 20px 0 10px 0; +} + diff --git a/packages/rocketchat-search/package.js b/packages/rocketchat-search/package.js new file mode 100644 index 0000000000000..3fe9b0de1446d --- /dev/null +++ b/packages/rocketchat-search/package.js @@ -0,0 +1,38 @@ +Package.describe({ + name: 'rocketchat:search', + version: '0.0.1', + summary: 'Rocketchat Search Providers', + git: '' +}); + +Package.onUse(function(api) { + api.use([ + 'ecmascript', + 'templating', + 'rocketchat:lib', + 'rocketchat:logger', + 'kadira:flow-router' + ]); + + api.addFiles([ + 'client/admin/admin.html', + 'client/admin/admin.js', + 'client/admin/provider.html', + 'client/admin/provider.js', + 'client/admin/route.js', + 'client/search/search.html', + 'client/search/search.js', + 'client/provider/result.html', + 'client/provider/result.js', + 'client/style/style.css' + ], 'client'); + + api.addFiles([ + 'server/service/provider.js', + 'server/service/providerService.js', + 'server/service/settings.js', + 'server/provider/defaultProvider.js' + ], 'server'); + + api.mainModule('server/index.js', 'server'); +}); diff --git a/packages/rocketchat-search/server/index.js b/packages/rocketchat-search/server/index.js new file mode 100644 index 0000000000000..cea238a653a06 --- /dev/null +++ b/packages/rocketchat-search/server/index.js @@ -0,0 +1,7 @@ +import {searchProviderService} from './service/providerService'; +import SearchProvider from './service/provider'; + +export { + searchProviderService, + SearchProvider +}; diff --git a/packages/rocketchat-search/server/provider/defaultProvider.js b/packages/rocketchat-search/server/provider/defaultProvider.js new file mode 100644 index 0000000000000..ee28d5f665d70 --- /dev/null +++ b/packages/rocketchat-search/server/provider/defaultProvider.js @@ -0,0 +1,45 @@ +import {searchProviderService} from '../service/providerService'; +import SearchProvider from '../service/provider'; + +class DefaultProvider extends SearchProvider { + + constructor() { + super(); + this.configuration = { + searchAll:true + }; + } + + get id() { + return searchProviderService.DEFAULT_ID; + } + + get name() { + return 'Default provider'; + } + + get description() { + return 'The default provider uses mongodb for search'; + } + + get resultTemplate() { + return 'DefaultSearchResultTemplate'; + } + + get adminTemplate() { + return 'SearchDefaultProviderAdmin'; + } + + search(text, rid, payload, callback) { + + if (!payload) { + payload = {limit:1}; + } + + rid = payload.searchAll || this.configuration.searchAll ? rid : undefined; + + Meteor.call('messageSearch', text, rid, payload.limit, callback); + } +} + +searchProviderService.register(new DefaultProvider()); diff --git a/packages/rocketchat-search/server/service/provider.js b/packages/rocketchat-search/server/service/provider.js new file mode 100644 index 0000000000000..d75aa975409e4 --- /dev/null +++ b/packages/rocketchat-search/server/service/provider.js @@ -0,0 +1,67 @@ +/* globals SystemLogger */ +export default class SearchProvider { + + constructor() { + SystemLogger && SystemLogger.info(`create search provider ${ this.constructor.name }`); + this.configuration = {}; + } + + /*--- basic params ---*/ + get id() { + throw new Error('SearchProvider superclass has no id defined and should not be initiated'); + } + + get name() { + return undefined; + } + + get description() { + return undefined; + } + + /*--- templates ---*/ + get resultTemplate() { + throw new Error('Result template has to be defined'); + } + + get suggestionItemTemplate() { + return undefined; + } + + get adminTemplate() { + return undefined; + } + + /*--- search functions ---*/ + search(text, rid, payload, callback) { + throw new Error('Function search has to be implemented'); + } + + suggest(text, callback) { + callback(null, []); + } + + get supportsSuggestions() { + return false; + } + + /*--- triggers ---*/ + on(name, value) { + return true; + } + + /*--- livecycle ---*/ + init(configuration) { + if (configuration) { this.configuration = configuration; } + return this; + } + + start(callback) { + callback(); + } + + stop(callback) { + callback(); + } +} + diff --git a/packages/rocketchat-search/server/service/providerService.js b/packages/rocketchat-search/server/service/providerService.js new file mode 100644 index 0000000000000..d28f9290576d3 --- /dev/null +++ b/packages/rocketchat-search/server/service/providerService.js @@ -0,0 +1,188 @@ +/* globals SystemLogger, RocketChat */ +import Future from 'fibers/future'; +import _ from 'underscore'; + +class SearchSettings { + + static get BASE_ID() { return 'rocketchat.search.'; } + + static setValue(name, value) { + const id = `${ this.BASE_ID }${ name }`; + if (RocketChat.models.Settings.findById(id).fetch()[0]) { + RocketChat.models.Settings.updateValueById(id, value); + } else { + RocketChat.models.Settings.createWithIdAndValue(id, value); + } + } + + static getValue(name) { + const value = RocketChat.models.Settings.findById(`${ this.BASE_ID }${ name }`).fetch()[0]; + return value ? value.value : undefined; + } + +} + +class SearchProviderService { + + constructor() { + this.enabled = false; + this.providers = {}; + this.activeProvider = undefined; + } + + get DEFAULT_ID() { + return 'search.provider.default'; + } + + use(id, configuration, enabled) { + + const future = new Future(); + + if (!this.providers[id]) { throw new Error(`provider ${ id } cannot be found`); } + + const stopProvider = (callback) => { + if (this.activeProvider) { + + SystemLogger.debug(`Stopping provider '${ this.activeProvider.id }'`); + + this.activeProvider.stop(callback); + } else { + callback(); + } + }; + + stopProvider((err)=>{ + + if (!err) { + SearchSettings.setValue('enabled', enabled); + this.enabled = enabled; + + SystemLogger.debug(`Initiating provider '${ id }'`, JSON.stringify(configuration, null, 2)); + + try { + this.activeProvider = this.providers[id].init(configuration); + + SystemLogger.debug(`Store configuration for provider '${ id }'`); + + SearchSettings.setValue(`provider.${ id }`, configuration); + SearchSettings.setValue('provider', id); + + SystemLogger.debug(`Start provider '${ id }'`); + + this.activeProvider.start((err) => { + if (err) { + future.throw(err); + } else { + future.return(); + } + }); + + } catch (e) { + future.throw(e); + } + } else { + future.throw(err); + } + + }); + + return future.wait(); + + } + + register(provider) { + this.providers[provider.id] = provider; + } + + start() { + SystemLogger.debug('Load data for all providers'); + + Object.keys(this.providers).forEach(key => { + + SystemLogger.info(`Initialize search provider ${ key }`); + + const configuration = SearchSettings.getValue(`provider.${ key }`); + + this.providers[key].init(configuration); + }); + + const active = SearchSettings.getValue('provider'); + + if (active) { + this.activeProvider = this.providers[active]; + } else { + this.activeProvider = this.providers[this.DEFAULT_ID]; + } + + this.enabled = SearchSettings.getValue('enabled') && SearchSettings.getValue('enabled') === true; + + if (!this.activeProvider) { + SystemLogger.warn(`Current active provider ${ active } is not running on the system`); + } else if (this.enabled) { + this.activeProvider.start((err) => { + if (err) { + SystemLogger.error('Could not start search provider', err); + } else { + SystemLogger.info('Search provider started successfully'); + } + }); + } + } + +} + +export const searchProviderService = new SearchProviderService(); + +Meteor.startup(() => { + searchProviderService.start(); +}); + +class SearchExecutorService { + static search(text, rid, payload) { + + const future = new Future(); + + if (!searchProviderService.activeProvider) { future.throw(new Error('No active provider defined')); } + + try { + searchProviderService.activeProvider.search(text, rid, payload, (error, data) => { + if (error) { future.throw(error); } else { future.return(data); } + }); + } catch (e) { + future.throw(e); + } + + return future.wait(); + } +} + +Meteor.methods({ + 'rocketchatSearchGetConfiguration'() { + return { + active: searchProviderService.activeProvider.id, + providers: _.chain(searchProviderService.providers) + .values() + .map((provider) => { + return { + id: provider.id, + configuration: provider.configuration, + name: provider.name, + description: provider.description, + adminTemplate: provider.adminTemplate + }; + }) + .value(), + enabled: searchProviderService.enabled + }; + }, + 'rocketchatSetActiveProvider'(id, configuration, enabled) { + return searchProviderService.use(id, configuration, enabled); + }, + 'rocketchatSearchSearch'(text, rid, payload) { + return SearchExecutorService.search(text, rid, payload); + }, + 'rocketchatSearchResultTemplate'() { + return searchProviderService.activeProvider.resultTemplate; + } +}); + diff --git a/packages/rocketchat-search/server/service/settings.js b/packages/rocketchat-search/server/service/settings.js new file mode 100644 index 0000000000000..72fd02d111667 --- /dev/null +++ b/packages/rocketchat-search/server/service/settings.js @@ -0,0 +1,11 @@ +Meteor.startup(function() { + + RocketChat.models.Permissions.upsert('search-admin', { + $setOnInsert: { + _id: 'search-admin', + roles: ['admin'] + } + }); + + RocketChat.settings.addGroup('Search'); +}); From bba07931ef11cc998a8f1142b06767a56d97ef37 Mon Sep 17 00:00:00 2001 From: Thomas Kurz Date: Fri, 2 Mar 2018 17:33:53 +0100 Subject: [PATCH 02/56] first provider implmentation for mongo search --- packages/chatpal-search/client/admin.html | 4 - packages/chatpal-search/client/admin.js | 13 - packages/chatpal-search/client/style.css | 4 + packages/chatpal-search/package.js | 3 +- packages/chatpal-search/server/provider.js | 53 +- packages/rocketchat-api/server/v1/chat.js | 2 +- packages/rocketchat-i18n/i18n/en.i18n.json | 6 +- .../.app/package-lock.json | 874 ++++++++++++++++++ .../rocketchat-search/client/admin/admin.html | 59 -- .../rocketchat-search/client/admin/admin.js | 78 -- .../client/admin/provider.html | 10 - .../client/admin/provider.js | 13 - .../rocketchat-search/client/admin/route.js | 9 - .../client/provider/result.html | 53 +- .../client/provider/result.js | 46 +- .../client/search/search.html | 36 +- .../rocketchat-search/client/search/search.js | 110 ++- .../rocketchat-search/client/style/style.css | 37 +- packages/rocketchat-search/package.js | 5 - .../server/provider/defaultProvider.js | 39 +- .../server/service/provider.js | 91 +- .../server/service/providerService.js | 178 ++-- server/methods/messageSearch.js | 10 +- 23 files changed, 1281 insertions(+), 452 deletions(-) delete mode 100644 packages/chatpal-search/client/admin.html delete mode 100644 packages/chatpal-search/client/admin.js create mode 100644 packages/chatpal-search/client/style.css create mode 100644 packages/rocketchat-livechat/.app/package-lock.json delete mode 100644 packages/rocketchat-search/client/admin/admin.html delete mode 100644 packages/rocketchat-search/client/admin/admin.js delete mode 100644 packages/rocketchat-search/client/admin/provider.html delete mode 100644 packages/rocketchat-search/client/admin/provider.js delete mode 100644 packages/rocketchat-search/client/admin/route.js diff --git a/packages/chatpal-search/client/admin.html b/packages/chatpal-search/client/admin.html deleted file mode 100644 index 514a33e6624c6..0000000000000 --- a/packages/chatpal-search/client/admin.html +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/packages/chatpal-search/client/admin.js b/packages/chatpal-search/client/admin.js deleted file mode 100644 index 750f8d2aee12e..0000000000000 --- a/packages/chatpal-search/client/admin.js +++ /dev/null @@ -1,13 +0,0 @@ -Template.SearchChatpalProviderAdmin.onCreated(function() { - this.data.getConfiguration = function(e) { - return { - name: e.target.name.value - }; - }; -}); - -Template.SearchChatpalProviderAdmin.helpers({ - configuration() { - return Template.instance().data.configuration; - } -}); diff --git a/packages/chatpal-search/client/style.css b/packages/chatpal-search/client/style.css new file mode 100644 index 0000000000000..c44789479ab9f --- /dev/null +++ b/packages/chatpal-search/client/style.css @@ -0,0 +1,4 @@ +.chatpal-admin-link { + color:red !important; + text-decoration: underline !important; +} diff --git a/packages/chatpal-search/package.js b/packages/chatpal-search/package.js index cf86b37f82809..32789fb5befe7 100644 --- a/packages/chatpal-search/package.js +++ b/packages/chatpal-search/package.js @@ -19,8 +19,7 @@ Package.onUse(function(api) { ], 'server'); api.addFiles([ - 'client/admin.html', - 'client/admin.js', + 'client/style.css', 'client/result.html', 'client/result.js' ], 'client'); diff --git a/packages/chatpal-search/server/provider.js b/packages/chatpal-search/server/provider.js index c9f591f8a9666..8599dc71c623a 100644 --- a/packages/chatpal-search/server/provider.js +++ b/packages/chatpal-search/server/provider.js @@ -4,21 +4,50 @@ import {SearchProvider} from 'meteor/rocketchat:search'; class ChatpalProvider extends SearchProvider { constructor() { - super(); - this.configuration = { - name:'value' - }; + super('chatpalProvider'); + this._settings.add('Backend', 'select', 'cloud', { + values:[ + {key: 'cloud', i18nLabel: 'Cloud Service'}, + {key: 'onsite', i18nLabel: 'On-Site'} + ] + }); + this._settings.add('API_Key', 'string', '', { + enableQuery:[{ + _id: 'Search.chatpalProvider.Backend', + value: 'cloud' + }], + i18nLabel: 'Chatpal_API_Key', + i18nDescription: 'Chatpal_API_Key_Description' + }); + this._settings.add('Base_URL', 'string', '', { + enableQuery:[{ + _id: 'Search.chatpalProvider.Backend', + value: 'onsite' + }] + }); + this._settings.add('HTTP_Headers', 'string', '', { + enableQuery:[{ + _id: 'Search.chatpalProvider.Backend', + value: 'onsite' + }], + multiline: true, + i18nLabel: 'Chatpal_HTTP_Headers', + i18nDescription: 'Chatpal_HTTP_Headers_Description' + }); + this._settings.add('Main_Language', 'select', 'en', { + values: [ + {key: 'none', i18nLabel: 'Not_set'}, + {key: 'de', i18nLabel: 'German'}, + {key: 'en', i18nLabel: 'English'} + ] + }); } - get id() { - return 'search.provider.chatpal'; - } - - get name() { + get i18nLabel() { return 'Chatpal Provider'; } - get description() { + get i18nDescription() { return 'The chatpal provider uses a powerful search backend'; } @@ -26,8 +55,8 @@ class ChatpalProvider extends SearchProvider { return 'ChatpalSearchResultTemplate'; } - get adminTemplate() { - return 'SearchChatpalProviderAdmin'; + start(callback) { + callback(); } search(text, rid, payload, callback) { diff --git a/packages/rocketchat-api/server/v1/chat.js b/packages/rocketchat-api/server/v1/chat.js index 6a866923121c4..157cf3ecd2c59 100644 --- a/packages/rocketchat-api/server/v1/chat.js +++ b/packages/rocketchat-api/server/v1/chat.js @@ -137,7 +137,7 @@ RocketChat.API.v1.addRoute('chat.search', { authRequired: true }, { } let result; - Meteor.runAsUser(this.userId, () => result = Meteor.call('messageSearch', searchText, roomId, limit)); + Meteor.runAsUser(this.userId, () => result = (Meteor.call('messageSearch', searchText, roomId, limit) || {}).docs); return RocketChat.API.v1.success({ messages: result.messages diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 3e7a6a21d211e..8a590e480fa42 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -2177,5 +2177,9 @@ "your_message": "your message", "your_message_optional": "your message (optional)", "Your_password_is_wrong": "Your password is wrong!", - "Your_push_was_sent_to_s_devices": "Your push was sent to %s devices" + "Your_push_was_sent_to_s_devices": "Your push was sent to %s devices", + "Chatpal_HTTP_Headers": "Http Headers", + "Chatpal_HTTP_Headers_Description": "List of HTTP Headers, one header per line. Format: name:value", + "Chatpal_API_Key": "API Key", + "Chatpal_API_Key_Description": "You don't yet have an API Key? Get one!" } diff --git a/packages/rocketchat-livechat/.app/package-lock.json b/packages/rocketchat-livechat/.app/package-lock.json new file mode 100644 index 0000000000000..ee2c7c4708d98 --- /dev/null +++ b/packages/rocketchat-livechat/.app/package-lock.json @@ -0,0 +1,874 @@ +{ + "name": "rocketchat-livechat", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/runtime": { + "version": "7.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.40.tgz", + "integrity": "sha512-vIM68NUCWauZJTFoVUG1lggva1I8FLB9zFKwWG7Xjin4FkHpEKJv2y4x1DGVPVt93S5/zHSBj1bXYEuxOkFGzg==", + "requires": { + "core-js": "2.5.3", + "regenerator-runtime": "0.11.1" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.3.3" + } + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "autolinker": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-1.6.2.tgz", + "integrity": "sha512-IKLGtYFb3jzGTtgCpb4bm//1sXmmmgmr0msKshhYoc7EsWmLCFvuyxLcEIfcZ5gbCgZGXrnXkOkcBblOFEnlog==" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "bcrypt": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-1.0.3.tgz", + "integrity": "sha512-pRyDdo73C8Nim3jwFJ7DWe3TZCgwDfWZ6nHS5LSdU77kWbj1frruvdndP02AOavtD4y8v6Fp2dolbHgp4SDrfg==", + "requires": { + "nan": "2.6.2", + "node-pre-gyp": "0.6.36" + } + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "requires": { + "hoek": "4.2.0" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "core-js": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", + "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.2.0" + } + } + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", + "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.2" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz", + "integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=", + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "1.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "requires": { + "ajv": "5.5.2", + "har-schema": "2.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.1.0" + } + }, + "hoek": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jquery": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", + "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "moment": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz", + "integrity": "sha512-Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", + "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=" + }, + "node-pre-gyp": { + "version": "0.6.36", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz", + "integrity": "sha1-22BBEst04NR3VU6bUFsXq936t4Y=", + "requires": { + "mkdirp": "0.5.1", + "nopt": "4.0.1", + "npmlog": "4.1.2", + "rc": "1.2.5", + "request": "2.83.0", + "rimraf": "2.6.2", + "semver": "5.5.0", + "tar": "2.2.1", + "tar-pack": "3.4.1" + } + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "requires": { + "abbrev": "1.1.1", + "osenv": "0.1.4" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", + "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "rc": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.5.tgz", + "integrity": "sha1-J1zWh/bjs2zHVrqibf7oCnkDAf0=", + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.5", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "requires": { + "hoek": "4.2.0" + } + }, + "sprintf-js": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz", + "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw=" + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-pack": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.1.tgz", + "integrity": "sha512-PPRybI9+jM5tjtCbN2cxmmRU7YmqT3Zv/UDy48tAh2XRkLa9bAORtSWLkVc13+GJF+cdTh1yEnHEk3cpTaL5Kg==", + "requires": { + "debug": "2.6.9", + "fstream": "1.0.11", + "fstream-ignore": "1.0.5", + "once": "1.4.0", + "readable-stream": "2.3.3", + "rimraf": "2.6.2", + "tar": "2.2.1", + "uid-number": "0.0.6" + } + }, + "toastr": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/toastr/-/toastr-2.1.4.tgz", + "integrity": "sha1-i0O+ZPudDEFIcURvLbjoyk6V8YE=", + "requires": { + "jquery": "3.3.1" + } + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "uid-number": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", + "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=" + }, + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "underscore.string": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz", + "integrity": "sha1-LCo/n4PmR2L9xF5s6sZRQoZCE9s=", + "requires": { + "sprintf-js": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + }, + "wide-align": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "requires": { + "string-width": "1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} diff --git a/packages/rocketchat-search/client/admin/admin.html b/packages/rocketchat-search/client/admin/admin.html deleted file mode 100644 index 497124040b7f4..0000000000000 --- a/packages/rocketchat-search/client/admin/admin.html +++ /dev/null @@ -1,59 +0,0 @@ - diff --git a/packages/rocketchat-search/client/admin/admin.js b/packages/rocketchat-search/client/admin/admin.js deleted file mode 100644 index f3c2f0ec09ef6..0000000000000 --- a/packages/rocketchat-search/client/admin/admin.js +++ /dev/null @@ -1,78 +0,0 @@ -import toastr from 'toastr'; - -Template.SearchAdmin.onCreated(function() { - - this.enabled = new ReactiveVar(false); - this.providers = new ReactiveVar([]); - this.active = new ReactiveVar(); - this.loading = new ReactiveVar(true); - - this.setActiveProvider = (id) => { - this.providers.get().forEach((provider) => { - if (provider.id === id) { - this.childBinding = { - configuration: provider.configuration, - getConfiguration: (e) => { return undefined; } - }; - this.active.set(provider); - } - }); - }; - - Meteor.call('rocketchatSearchGetConfiguration', (err, config) => { - if (err) { - console.error(err); - return toastr.error(TAPi18n.__('SEARCH_MSG_ERROR_CANNOT_LOAD_CONFIGURATION')); - } - - console.debug(config); - - this.providers.set(config.providers); - this.enabled.set(config.enabled); - - this.setActiveProvider(config.active); - - this.loading.set(false); - }); - - this.store = (id, config, enabled) => { - Meteor.call('rocketchatSetActiveProvider', id, config, enabled, (err) => { - if (err) { - toastr.error(TAPi18n.__('SEARCH_MSG_ERROR_CANNOT_STORE_CONFIGURATION')); - } else { - toastr.info(TAPi18n.__('SEARCH_MSG_INFO_CONFIGURATION_STORED_SUCCESSFULLY')); - } - }); - }; -}); - -Template.SearchAdmin.events({ - 'submit form'(e, t) { - e.preventDefault(); - const enabled = e.target.enabled.value === 'true'; - const providerId = e.target.provider.value; - const config = t.childBinding.getConfiguration(e) || t.active.get().configuration; - t.store(providerId, config, enabled); - }, - 'change .search-provider-selector'(e, t) { - t.setActiveProvider(e.target.value); - } -}); - -Template.SearchAdmin.helpers({ - active() { - return Template.instance().active.get(); - }, - providers() { - return Template.instance().providers.get(); - }, - enabled() { - return Template.instance().enabled.get(); - }, - loading() { - return Template.instance().loading.get(); - }, - childBinding() { - return Template.instance().childBinding; - } -}); diff --git a/packages/rocketchat-search/client/admin/provider.html b/packages/rocketchat-search/client/admin/provider.html deleted file mode 100644 index 383454bc46d8a..0000000000000 --- a/packages/rocketchat-search/client/admin/provider.html +++ /dev/null @@ -1,10 +0,0 @@ - diff --git a/packages/rocketchat-search/client/admin/provider.js b/packages/rocketchat-search/client/admin/provider.js deleted file mode 100644 index a3f01d30b2195..0000000000000 --- a/packages/rocketchat-search/client/admin/provider.js +++ /dev/null @@ -1,13 +0,0 @@ -Template.SearchDefaultProviderAdmin.onCreated(function() { - this.data.getConfiguration = function(e) { - return { - searchAll: e.target.searchAll.checked - }; - }; -}); - -Template.SearchDefaultProviderAdmin.helpers({ - configuration() { - return Template.instance().data.configuration; - } -}); diff --git a/packages/rocketchat-search/client/admin/route.js b/packages/rocketchat-search/client/admin/route.js deleted file mode 100644 index 9654863dfd049..0000000000000 --- a/packages/rocketchat-search/client/admin/route.js +++ /dev/null @@ -1,9 +0,0 @@ -FlowRouter.route('/admin/Search', { - name: 'admin-search', - action() { - return BlazeLayout.render('main', { - center: 'SearchAdmin', - pageTitle: t('Search') - }); - } -}); diff --git a/packages/rocketchat-search/client/provider/result.html b/packages/rocketchat-search/client/provider/result.html index 8f97173c5b33b..3fa5f31ec101c 100644 --- a/packages/rocketchat-search/client/provider/result.html +++ b/packages/rocketchat-search/client/provider/result.html @@ -1,17 +1,42 @@ diff --git a/packages/rocketchat-search/client/provider/result.js b/packages/rocketchat-search/client/provider/result.js index e77159b8953bb..f15787786ce99 100644 --- a/packages/rocketchat-search/client/provider/result.js +++ b/packages/rocketchat-search/client/provider/result.js @@ -1,29 +1,45 @@ Template.DefaultSearchResultTemplate.onCreated(function() { + const self = this; - this.data = this.data || {}; - this.result = new ReactiveVar(this.data.result); + //paging + this.pageSize = this.data.settings.PageSize; - console.log(this.data.result); -}); + //global search + this.globalSearchEnabled = this.data.settings.GlobalSearchEnabled; -Template.DefaultSearchResultTemplate.events({ - 'click .more'(e, t) { + this.hasMore = new ReactiveVar(true); - let limit = 2; + this.autorun(() => { + const result = this.data.result.get(); + self.hasMore.set(!(result && result.messages.docs.length < (self.data.payload.limit || self.pageSize))); + }); +}); - if (t.data.payload && t.data.payload.limit) { - limit = t.data.payload.limit + 1; - } +Template.DefaultSearchResultTemplate.events({ + 'click .load-more button'(e, t) { + t.data.payload.limit = (t.data.payload.limit || t.pageSize) + t.pageSize; + t.data.search(); + }, + 'change #global-search'(e, t) { + t.data.parentPayload.searchAll = e.target.checked; + t.data.payload.limit = t.pageSize; + t.data.result.set(undefined); + t.data.search(); - t.data.search( - t.data.text, - {limit} - ); } }); Template.DefaultSearchResultTemplate.helpers({ result() { - return Template.instance().result.get(); + return Template.instance().data.result.get(); + }, + globalSearchEnabled() { + return Template.instance().globalSearchEnabled; + }, + searching() { + return Template.instance().data.searching.get(); + }, + hasMore() { + return Template.instance().hasMore.get(); } }); diff --git a/packages/rocketchat-search/client/search/search.html b/packages/rocketchat-search/client/search/search.html index 21b406bb96a95..930b5ff148741 100644 --- a/packages/rocketchat-search/client/search/search.html +++ b/packages/rocketchat-search/client/search/search.html @@ -1,15 +1,29 @@ diff --git a/packages/rocketchat-search/client/search/search.js b/packages/rocketchat-search/client/search/search.js index 3b5749b3653b3..ea7e2d7831285 100644 --- a/packages/rocketchat-search/client/search/search.js +++ b/packages/rocketchat-search/client/search/search.js @@ -1,58 +1,104 @@ import toastr from 'toastr'; +Meteor.startup(function() { + RocketChat.MessageAction.addButton({ + id: 'jump-to-search-message', + icon: 'jump', + label: 'Jump_to_message', + action() { + const message = this._arguments[1]; + if (Session.get('openedRoom') === message.rid) { + return RoomHistoryManager.getSurroundingMessages(message, 50); + } + + FlowRouter.goToRoomById(message.rid); + // RocketChat.MessageAction.hideDropDown(); + + if (window.matchMedia('(max-width: 500px)').matches) { + Template.instance().tabBar.close(); + } + + window.setTimeout(() => { + RoomHistoryManager.getSurroundingMessages(message, 50); + }, 400); + // 400ms is popular among game devs as a good delay before transition starts + // ie. 50, 100, 200, 400, 800 are the favored timings + }, + order: 100, + group: 'menu' + }); +}); + Template.RocketSearch.onCreated(function() { - this.loading = new ReactiveVar(false); - this.result = new ReactiveVar(); - this.resultTemplate = new ReactiveVar(); + this.error = new ReactiveVar(); + this.template = new ReactiveVar(); - Meteor.call('rocketchatSearchResultTemplate', (err, template) => { - if (err) { - console.error('Cannot load result template for active search provider'); + Meteor.call('rocketchatSearch.getProvider', (error, provider) => { + if (error) { + this.error.set({msg:'Cannot load result template for active search provider', error}); } else { - this.resultTemplate.set(template); + this.scope.settings = provider.settings; + this.template.set(provider.resultTemplate); } }); - const search = (text, payload) => { - this.loading.set(true); - - Meteor.call('rocketchatSearchSearch', text, Session.get('openedRoom'), payload, (err, result) => { - if (err) { - toastr.error(TAPi18n.__('SEARCH_MSG_ERROR_SEARCH_FAILED')); - } else { - this.result.set({ - result, - text, - payload, - search - }); - } - this.loading.set(false); - }); + this.search = () => { + + const _p = Object.assign({}, this.scope.parentPayload, this.scope.payload); + + if (this.scope.text.get()) { + + this.scope.searching.set(true); + + Meteor.call('rocketchatSearch.search', this.scope.text.get(), {rid:Session.get('openedRoom')}, _p, (err, result) => { + if (err) { + toastr.error(TAPi18n.__('SEARCH_MSG_ERROR_SEARCH_FAILED')); + } else { + this.scope.searching.set(false); + this.scope.result.set(result); + } + }); + } }; - this.search = search; + this.scope = { + searching: new ReactiveVar(false), + result: new ReactiveVar(), + text: new ReactiveVar(), + settings: {}, + parentPayload: {}, + payload: {}, + search: this.search + }; }); + Template.RocketSearch.events = { - 'keydown .rocket-searchbox input'(evt, t) { + 'keydown #message-search'(evt, t) { if (evt.which === 13) { - t.search(evt.currentTarget.value); + evt.preventDefault(); + t.scope.text.set(evt.target.value); + t.scope.result.set(undefined); + t.scope.payload = {}; + t.search(); } } }; Template.RocketSearch.helpers({ - loading() { - return Template.instance().loading.get(); + error() { + return Template.instance().error.get(); + }, + template() { + return Template.instance().template.get(); }, - result() { - return Template.instance().result.get(); + scope() { + return Template.instance().scope; }, - resultTemplate() { - return Template.instance().resultTemplate.get(); + text() { + return Template.instance().scope.text.get(); } }); diff --git a/packages/rocketchat-search/client/style/style.css b/packages/rocketchat-search/client/style/style.css index 9d40d7290a871..cff7b20c39cb0 100644 --- a/packages/rocketchat-search/client/style/style.css +++ b/packages/rocketchat-search/client/style/style.css @@ -1,33 +1,18 @@ -.rocket-searchbox input { - width: 100%; - padding: 10px; - border: 1px solid #ddd; - border-radius: 5px; +.rocket-default-search-settings { + margin-bottom: 10px; } -.rocket-searchresult { - margin-top: 20px; +.rocket-default-search-results .loading-animation { + margin-top: 10px; } -.rocket-searchresult .result { - border: 1px solid #ddd; - border-radius: 5px; - padding: 10px; - margin-bottom:10px; +.rocket-default-search-results .load-more { + margin-top: 10px; + text-align: center; + position: relative; } -#search-admin h2 { - font-size: 20px; - padding: 20px; - border-bottom: 1px solid #ddd; - margin-bottom: 20px; +.rocket-default-search-results .load-more button { + cursor: pointer; + text-decoration: underline; } - -#search-admin .rocket-form { - padding: 0 20px; -} - -#search-admin h3 { - margin: 20px 0 10px 0; -} - diff --git a/packages/rocketchat-search/package.js b/packages/rocketchat-search/package.js index 3fe9b0de1446d..3f6391143d09c 100644 --- a/packages/rocketchat-search/package.js +++ b/packages/rocketchat-search/package.js @@ -15,11 +15,6 @@ Package.onUse(function(api) { ]); api.addFiles([ - 'client/admin/admin.html', - 'client/admin/admin.js', - 'client/admin/provider.html', - 'client/admin/provider.js', - 'client/admin/route.js', 'client/search/search.html', 'client/search/search.js', 'client/provider/result.html', diff --git a/packages/rocketchat-search/server/provider/defaultProvider.js b/packages/rocketchat-search/server/provider/defaultProvider.js index ee28d5f665d70..afe0a4e8eeb5c 100644 --- a/packages/rocketchat-search/server/provider/defaultProvider.js +++ b/packages/rocketchat-search/server/provider/defaultProvider.js @@ -4,41 +4,32 @@ import SearchProvider from '../service/provider'; class DefaultProvider extends SearchProvider { constructor() { - super(); - this.configuration = { - searchAll:true - }; + super('defaultProvider'); + this._settings.add('GlobalSearchEnabled', 'boolean', false, { + i18nDescription:'If_search_returns_result_from_all_accessible_rooms' + }); + this._settings.add('PageSize', 'int', 10); } - get id() { - return searchProviderService.DEFAULT_ID; - } - - get name() { + get i18nLabel() { return 'Default provider'; } - get description() { + get i18nDescription() { return 'The default provider uses mongodb for search'; } - get resultTemplate() { - return 'DefaultSearchResultTemplate'; - } - - get adminTemplate() { - return 'SearchDefaultProviderAdmin'; - } - - search(text, rid, payload, callback) { + search(text, context, payload = {}, callback) { - if (!payload) { - payload = {limit:1}; - } + const _rid = payload.searchAll ? undefined : context.rid; - rid = payload.searchAll || this.configuration.searchAll ? rid : undefined; + const _limit = payload.limit || this._settings.get('PageSize'); - Meteor.call('messageSearch', text, rid, payload.limit, callback); + Meteor.call('messageSearch', text, _rid, _limit, (err, result)=>{ + Meteor.setTimeout(()=>{ + callback(err, result); + }, 2000); + }); } } diff --git a/packages/rocketchat-search/server/service/provider.js b/packages/rocketchat-search/server/service/provider.js index d75aa975409e4..db5b2d123cdd6 100644 --- a/packages/rocketchat-search/server/service/provider.js +++ b/packages/rocketchat-search/server/service/provider.js @@ -1,37 +1,98 @@ /* globals SystemLogger */ +import _ from 'underscore'; + +class Setting { + constructor(basekey, key, type, defaultValue, options = {}) { + this._basekey = basekey; + this.key = key; + this.type = type; + this.defaultValue = defaultValue; + this.options = options; + this._value = undefined; + } + + get value() { + return this._value; + } + + get id() { + return `Search.${ this._basekey }.${ this.key }`; + } + + load() { + this._value = RocketChat.settings.get(this.id) || this.defaultValue; + } + +} + +class Settings { + constructor(basekey) { + this.basekey = basekey; + this.settings = {}; + } + + add(key, type, defaultValue, options) { + this.settings[key] = new Setting(this.basekey, key, type, defaultValue, options); + } + + list() { + return _.values(this.settings); + } + + map() { + return this.settings; + } + + get(key) { + if (!this.settings[key]) { throw new Error('Setting is not set'); } + return this.settings[key].value; + } + + load() { + _.each(this.settings, (setting) => { + setting.load(); + }); + } +} + export default class SearchProvider { - constructor() { - SystemLogger && SystemLogger.info(`create search provider ${ this.constructor.name }`); - this.configuration = {}; + constructor(key) { + SystemLogger && SystemLogger.info(`create search provider ${ key }`); + this._key = key; + this._settings = new Settings(key); } /*--- basic params ---*/ - get id() { - throw new Error('SearchProvider superclass has no id defined and should not be initiated'); + get key() { + return this._key; } - get name() { + get i18nLabel() { return undefined; } - get description() { + get i18nDescription() { return undefined; } + get settings() { + return this._settings.list(); + } + + get settingsAsMap() { + return this._settings.map(); + } + /*--- templates ---*/ get resultTemplate() { - throw new Error('Result template has to be defined'); + return 'DefaultSearchResultTemplate'; } get suggestionItemTemplate() { return undefined; } - get adminTemplate() { - return undefined; - } - /*--- search functions ---*/ search(text, rid, payload, callback) { throw new Error('Function search has to be implemented'); @@ -51,9 +112,9 @@ export default class SearchProvider { } /*--- livecycle ---*/ - init(configuration) { - if (configuration) { this.configuration = configuration; } - return this; + run(callback) { + this._settings.load(); + this.start(callback); } start(callback) { diff --git a/packages/rocketchat-search/server/service/providerService.js b/packages/rocketchat-search/server/service/providerService.js index d28f9290576d3..14ba0c158a46a 100644 --- a/packages/rocketchat-search/server/service/providerService.js +++ b/packages/rocketchat-search/server/service/providerService.js @@ -2,48 +2,21 @@ import Future from 'fibers/future'; import _ from 'underscore'; -class SearchSettings { - - static get BASE_ID() { return 'rocketchat.search.'; } - - static setValue(name, value) { - const id = `${ this.BASE_ID }${ name }`; - if (RocketChat.models.Settings.findById(id).fetch()[0]) { - RocketChat.models.Settings.updateValueById(id, value); - } else { - RocketChat.models.Settings.createWithIdAndValue(id, value); - } - } - - static getValue(name) { - const value = RocketChat.models.Settings.findById(`${ this.BASE_ID }${ name }`).fetch()[0]; - return value ? value.value : undefined; - } - -} - class SearchProviderService { constructor() { - this.enabled = false; this.providers = {}; this.activeProvider = undefined; } - get DEFAULT_ID() { - return 'search.provider.default'; - } - - use(id, configuration, enabled) { - - const future = new Future(); + use(id, cb = function() {}) { if (!this.providers[id]) { throw new Error(`provider ${ id } cannot be found`); } const stopProvider = (callback) => { if (this.activeProvider) { - SystemLogger.debug(`Stopping provider '${ this.activeProvider.id }'`); + SystemLogger.debug(`Stopping provider '${ this.activeProvider.key }'`); this.activeProvider.stop(callback); } else { @@ -54,79 +27,87 @@ class SearchProviderService { stopProvider((err)=>{ if (!err) { - SearchSettings.setValue('enabled', enabled); - this.enabled = enabled; - - SystemLogger.debug(`Initiating provider '${ id }'`, JSON.stringify(configuration, null, 2)); - - try { - this.activeProvider = this.providers[id].init(configuration); - SystemLogger.debug(`Store configuration for provider '${ id }'`); + this.activeProvider = undefined; - SearchSettings.setValue(`provider.${ id }`, configuration); - SearchSettings.setValue('provider', id); + SystemLogger.debug(`Start provider '${ id }'`); - SystemLogger.debug(`Start provider '${ id }'`); + try { - this.activeProvider.start((err) => { + this.providers[id].run((err) => { if (err) { - future.throw(err); + cb(err); } else { - future.return(); + this.activeProvider = this.providers[id]; + cb(); } }); } catch (e) { - future.throw(e); + cb(e); } } else { - future.throw(err); + cb(err); } }); - return future.wait(); - } register(provider) { - this.providers[provider.id] = provider; + this.providers[provider.key] = provider; } start() { SystemLogger.debug('Load data for all providers'); - Object.keys(this.providers).forEach(key => { + const providers = this.providers; - SystemLogger.info(`Initialize search provider ${ key }`); + //add settings for admininistration + RocketChat.settings.addGroup('Search', function() { - const configuration = SearchSettings.getValue(`provider.${ key }`); + const self = this; - this.providers[key].init(configuration); - }); + self.add('Search.Provider', 'defaultProvider', { + type: 'select', + values: _.map(providers, (p) => { return {key:p.key, i18nLabel: p.i18nLabel}; }), + public: true + }); - const active = SearchSettings.getValue('provider'); + _.chain(providers) + .filter((provider) => provider.settings && provider.settings.length > 0) + .each(function(provider) { + self.section(provider.i18nLabel, function() { + provider.settings.forEach((setting) => { - if (active) { - this.activeProvider = this.providers[active]; - } else { - this.activeProvider = this.providers[this.DEFAULT_ID]; - } + const _options = { + type: setting.type + }; - this.enabled = SearchSettings.getValue('enabled') && SearchSettings.getValue('enabled') === true; + _.extend(_options, setting.options); - if (!this.activeProvider) { - SystemLogger.warn(`Current active provider ${ active } is not running on the system`); - } else if (this.enabled) { - this.activeProvider.start((err) => { - if (err) { - SystemLogger.error('Could not start search provider', err); - } else { - SystemLogger.info('Search provider started successfully'); - } - }); - } + _options.enableQuery = _options.enableQuery || []; + + _options.enableQuery.push({ + _id: 'Search.Provider', + value: provider.key + }); + + this.add(setting.id, setting.defaultValue, _options); + }); + }); + }); + }); + + const configProvider = _.debounce(() => { + const providerId = RocketChat.settings.get('Search.Provider'); + + if (providerId) { + this.use(providerId); + } + }, 1000); + + RocketChat.settings.get(/^Search\./, configProvider); } } @@ -137,52 +118,43 @@ Meteor.startup(() => { searchProviderService.start(); }); -class SearchExecutorService { - static search(text, rid, payload) { - +Meteor.methods({ + 'rocketchatSearch.search'(text, context, payload) { const future = new Future(); if (!searchProviderService.activeProvider) { future.throw(new Error('No active provider defined')); } + payload = payload !== null ? payload : undefined;//TODO is this cleanup necessary? + try { - searchProviderService.activeProvider.search(text, rid, payload, (error, data) => { - if (error) { future.throw(error); } else { future.return(data); } + + SystemLogger.debug(`Search:\n\tText:${ text }\n\tContext:${ JSON.stringify(context) }\n\tPayload:${ JSON.stringify(payload) }`); + + searchProviderService.activeProvider.search(text, context, payload, (error, data) => { + if (error) { + future.throw(error); + } else { + //TODO could do some access checks + future.return(data); + } }); } catch (e) { future.throw(e); } return future.wait(); - } -} + }, + 'rocketchatSearch.getProvider'() { + console.log(searchProviderService.activeProvider); + if (!searchProviderService.activeProvider) { return undefined; } -Meteor.methods({ - 'rocketchatSearchGetConfiguration'() { return { - active: searchProviderService.activeProvider.id, - providers: _.chain(searchProviderService.providers) - .values() - .map((provider) => { - return { - id: provider.id, - configuration: provider.configuration, - name: provider.name, - description: provider.description, - adminTemplate: provider.adminTemplate - }; - }) - .value(), - enabled: searchProviderService.enabled + key: searchProviderService.activeProvider.key, + resultTemplate: searchProviderService.activeProvider.resultTemplate, + settings: _.mapObject(searchProviderService.activeProvider.settingsAsMap, (setting) => { + return setting.value; + }) }; - }, - 'rocketchatSetActiveProvider'(id, configuration, enabled) { - return searchProviderService.use(id, configuration, enabled); - }, - 'rocketchatSearchSearch'(text, rid, payload) { - return SearchExecutorService.search(text, rid, payload); - }, - 'rocketchatSearchResultTemplate'() { - return searchProviderService.activeProvider.resultTemplate; } }); diff --git a/server/methods/messageSearch.js b/server/methods/messageSearch.js index 2d84ca0af10e5..7d51b7391f560 100644 --- a/server/methods/messageSearch.js +++ b/server/methods/messageSearch.js @@ -8,9 +8,9 @@ Meteor.methods({ // TODO: Evaluate why we are returning `users` and `channels`, as the only thing that gets set is the `messages`. const result = { - messages: [], - users: [], - channels: [] + messages: { + docs:[] + } }; const currentUserId = Meteor.userId(); @@ -25,7 +25,7 @@ Meteor.methods({ if (!Meteor.call('canAccessRoom', rid, currentUserId)) { return result; } - } else if (RocketChat.settings.get('Message_GlobalSearch') !== true) { + } else if (RocketChat.settings.get('Search.defaultProvider.GlobalSearchEnabled') !== true) { return result; } @@ -226,7 +226,7 @@ Meteor.methods({ }; } - result.messages = RocketChat.models.Messages.find(query, options).fetch(); + result.messages.docs = RocketChat.models.Messages.find(query, options).fetch(); } return result; From 155f590b16218116f9c4489ef159041f29129a68 Mon Sep 17 00:00:00 2001 From: Thomas Kurz Date: Wed, 7 Mar 2018 22:29:11 +0100 Subject: [PATCH 03/56] add some admin features --- packages/chatpal-search/client/key.html | 3 -- packages/chatpal-search/client/route.js | 11 ++-- packages/chatpal-search/client/style.css | 13 +++++ .../chatpal-search/client/template/admin.html | 53 ++++++++++++++++++ .../chatpal-search/client/template/admin.js | 54 +++++++++++++++++++ .../client/{ => template}/result.html | 5 ++ .../client/{ => template}/result.js | 0 packages/chatpal-search/package.js | 19 ++++--- .../chatpal-search/server/chatpal-icon.svg | 6 +++ packages/chatpal-search/server/config.js | 3 ++ packages/chatpal-search/server/index.js | 6 +-- packages/chatpal-search/server/provider.js | 4 +- packages/chatpal-search/server/utils.js | 14 +++++ packages/rocketchat-search/package.js | 2 +- .../server/model/provider.js | 2 +- 15 files changed, 173 insertions(+), 22 deletions(-) delete mode 100644 packages/chatpal-search/client/key.html create mode 100644 packages/chatpal-search/client/template/admin.html create mode 100644 packages/chatpal-search/client/template/admin.js rename packages/chatpal-search/client/{ => template}/result.html (60%) rename packages/chatpal-search/client/{ => template}/result.js (100%) create mode 100644 packages/chatpal-search/server/chatpal-icon.svg create mode 100644 packages/chatpal-search/server/config.js create mode 100644 packages/chatpal-search/server/utils.js diff --git a/packages/chatpal-search/client/key.html b/packages/chatpal-search/client/key.html deleted file mode 100644 index e747efe95faaa..0000000000000 --- a/packages/chatpal-search/client/key.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/packages/chatpal-search/client/route.js b/packages/chatpal-search/client/route.js index 30776f89fd99b..80d0671372859 100644 --- a/packages/chatpal-search/client/route.js +++ b/packages/chatpal-search/client/route.js @@ -1,10 +1,9 @@ -FlowRouter.route('/admin/chatpal-key', { - name: 'admin-chatpal-key', - action(p, up) { +FlowRouter.route('/admin/chatpal', { + name: 'chatpal-admin', + action() { return BlazeLayout.render('main', { - center: 'pageSettingsContainer', - pageTitle: t('AdminChatpalKey'), - pageTemplate: 'AdminChatpalKey' + center: 'ChatpalAdmin', + pageTitle: t('Chatpal_AdminPage') }); } }); diff --git a/packages/chatpal-search/client/style.css b/packages/chatpal-search/client/style.css index c44789479ab9f..59a809ef1e813 100644 --- a/packages/chatpal-search/client/style.css +++ b/packages/chatpal-search/client/style.css @@ -2,3 +2,16 @@ color:red !important; text-decoration: underline !important; } + +/* +.chatpalProvider .rocket-search-input { + position: absolute; + top: 5px; + width: 320px; + background-color: white; +} +*/ + +.rocket-search { + padding-top: 0 !important; +} diff --git a/packages/chatpal-search/client/template/admin.html b/packages/chatpal-search/client/template/admin.html new file mode 100644 index 0000000000000..c3162b9c1c460 --- /dev/null +++ b/packages/chatpal-search/client/template/admin.html @@ -0,0 +1,53 @@ + diff --git a/packages/chatpal-search/client/template/admin.js b/packages/chatpal-search/client/template/admin.js new file mode 100644 index 0000000000000..62e2ccd53401a --- /dev/null +++ b/packages/chatpal-search/client/template/admin.js @@ -0,0 +1,54 @@ +import toastr from 'toastr'; + +Template.ChatpalAdmin.onCreated(function() { + + const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + + this.validateEmail = (email) => { + return re.test(email.toLowerCase()); + }; + + this.apiKey = new ReactiveVar(); +}); + +Template.ChatpalAdmin.onRendered(function() { + this.$('#chatpal-tac').load('https://cerbot.redlink.io/public/tac.html'); +}); + +Template.ChatpalAdmin.events({ + 'submit form'(e, t) { + e.preventDefault(); + + const email = e.target.email.value; + const tac = e.target.readtac.checked; + + if (!tac) { return toastr.error(TAPi18n.__('CHATPAL_MSG_ERROR_TAC_MUST_BE_CHECKED')); } + if (!email || email === '') { return toastr.error(TAPi18n.__('CHATPAL_MSG_ERROR_EMAIL_MUST_BE_SET')); } + if (!t.validateEmail(email)) { return toastr.error(TAPi18n.__('CHATPAL_MSG_ERROR_EMAIL_MUST_BE_VALID')); } + + //TODO register + try { + Meteor.call('chatpalUtilsCreateKey', email, (err, key) => { + if (!key) { return toastr.error(TAPi18n.__('CHATPAL_MSG_ERROR_USERNAME_ALREADY_EXISTS')); } + + toastr.info(TAPi18n.__('CHATPAL_MSG_KEY_CREATED_SUCCESSFULLY')); + + t.apiKey.set(key); + }); + + } catch (e) { + console.log(e); + toastr.error(TAPi18n.__('CHATPAL_MSG_ERROR_USERNAME_ALREADY_EXISTS'));//TODO error messages + } + } +}); + +//template +Template.ChatpalAdmin.helpers({ + apiKey() { + return Template.instance().apiKey.get(); + }, + isAdmin() { + return RocketChat.authz.hasRole(Meteor.userId(), 'admin'); + } +}); diff --git a/packages/chatpal-search/client/result.html b/packages/chatpal-search/client/template/result.html similarity index 60% rename from packages/chatpal-search/client/result.html rename to packages/chatpal-search/client/template/result.html index 90e38eef53fd2..27d00432011f2 100644 --- a/packages/chatpal-search/client/result.html +++ b/packages/chatpal-search/client/template/result.html @@ -1,6 +1,11 @@