lita-elasticsearch-indexer 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 11fd7fd834da4c9ca3378b5b3fe9c9176c33fa10
4
+ data.tar.gz: d6ded8af78eac2d21bc3ef1899c6c1170f74f29e
5
+ SHA512:
6
+ metadata.gz: 66d84027258f128f8f49cb76c7a57b903ead954522f48fdd52b80a2ad0c0d1aeb8ea1f81962cf45f1d84ea047006006f5804068614091330855bc2977a0bf9b8
7
+ data.tar.gz: 1019e35ce7fd1e357d52e25b7c0629a8c7c3e40c6f15b6f37bafe491452b4e1aac99449a9de0d3348d9c2d488f33dba63264f214d1d716f92e0a9a4e81ec4dbc
@@ -0,0 +1,56 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # This is only used for development
14
+ docker-compose.override.yml
15
+
16
+ # lita.env contains secrets
17
+ /lita.env
18
+
19
+ # Used by dotenv library to load environment variables.
20
+ # .env
21
+
22
+ ## Specific to RubyMotion:
23
+ .dat*
24
+ .repl_history
25
+ build/
26
+ *.bridgesupport
27
+ build-iPhoneOS/
28
+ build-iPhoneSimulator/
29
+
30
+ ## Specific to RubyMotion (use of CocoaPods):
31
+ #
32
+ # We recommend against adding the Pods directory to your .gitignore. However
33
+ # you should judge for yourself, the pros and cons are mentioned at:
34
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
35
+ #
36
+ # vendor/Pods/
37
+
38
+ ## Documentation cache and generated files:
39
+ /.yardoc/
40
+ /_yardoc/
41
+ /doc/
42
+ /rdoc/
43
+
44
+ ## Environment normalization:
45
+ /.bundle/
46
+ /vendor/bundle
47
+ /lib/bundler/man/
48
+
49
+ # for a library or gem, you might want to ignore these files since the code is
50
+ # intended to run in multiple environments; otherwise, check them in:
51
+ Gemfile.lock
52
+ # .ruby-version
53
+ # .ruby-gemset
54
+
55
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
56
+ .rvmrc
@@ -0,0 +1,323 @@
1
+ Development with Docker
2
+ ===
3
+ We use [Docker](https://www.docker.com/) to run, test, and debug our application.
4
+ The following documents how to install and use Docker on a Mac. There are
5
+ [instructions](https://docs.docker.com/installation) for installing and using
6
+ docker on other operating systems.
7
+
8
+ On the mac, we use [docker for mac](https://docs.docker.com/engine/installation/mac/#/docker-for-mac).
9
+
10
+ We use [docker-compose](https://docs.docker.com/compose/) to automate most of
11
+ our interactions with the application.
12
+
13
+ Table of Contents
14
+ ===
15
+ * [Installation and Upgrade](#installation-and-upgrade)
16
+ * [Launching the Application](#launching-the-application)
17
+ * [Docker Compose](#docker-compose)
18
+ * [Dockerfile](#dockerfile)
19
+ * [Useful Docker Commands](#useful-docker-commands)
20
+ * [Bash Profile](#bash-profile)
21
+
22
+ Installation and Upgrade
23
+ ===
24
+ Docker makes it easy to install docker for mac, which includes docker, and docker-compose
25
+ on your mac, and keep them upgraded in sync. Follow the instructions
26
+ to install [Docker 4 Mac]((https://docs.docker.com/engine/installation/mac/#/docker-for-mac).
27
+
28
+ Once you have docker running, you can run any of the following commands to test
29
+ that docker is working:
30
+ ```
31
+ docker ps
32
+ ```
33
+ This should always return a table with the following headers, and 0 or more
34
+ entries:
35
+
36
+ `CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES`
37
+
38
+ ```
39
+ docker images
40
+ ```
41
+ Similar to above, it should always return a table with the following headers, and
42
+ 0 or more entries:
43
+
44
+ `REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE`
45
+
46
+ Launching the Application
47
+ ===
48
+
49
+ Create lita.env in the Application root, using lita.env.example. If you are using
50
+ slack, you will need to create a [Slack API Token](https://my.slack.com/services/new/lita)
51
+ and add it to the LITA_SLACK_TOKEN variable.
52
+
53
+ In the Application root, run the following:
54
+ ```bash
55
+ touch Gemfile.lock
56
+ docker-compose up -d
57
+ ```
58
+
59
+ Docker Compose
60
+ ===
61
+
62
+ Once you have docker installed, you can use docker-compose to run all of the
63
+ commands that you would normally run when developing and testing the application.
64
+ Docker Compose uses one or more yml files to specify everything required to build
65
+ and run the application and any other support application (databases, volume
66
+ containers, etc.) it requires. There are multiple docker-compose yml files in
67
+ the Application Root, explained below.
68
+
69
+ docker-compose.yml
70
+ ---
71
+ This is the base docker-compose file used to manage the server.
72
+
73
+ Anyone with docker and docker-compose can run the following command from within
74
+ the Application Root (where this file you are reading resides), to build the server
75
+ image (You must be connected to the internet so that docker can
76
+ pull down any base docker images, or package/gem installs, for this to work).
77
+
78
+ ```
79
+ docker-compose build
80
+ ```
81
+ Once you have built the images, you can launch containers of all services
82
+ required by the app (docker calls a running instance of a docker image a docker
83
+ container):
84
+ ```
85
+ docker-compose up -d
86
+ ```
87
+
88
+ The docker-compose definition for the 'server' service mounts the Application
89
+ Root as /var/www/app in the server docker container. Since the Dockerfile specifies
90
+ /var/www/app as its default WORKDIR, this allows you to make changes to the files
91
+ on your machine and see them reflected live in the running server (although see
92
+ [below](#dockerfile) for **important information about modifying the Gemfile**).
93
+
94
+ The Dockerfile hosts the application on port 3000 inside the container,
95
+ and the docker-compose service definition attaches this to port 3000 on the
96
+ host machine (this will fail if you have another service of any kind attached to
97
+ port 3000 on the same host).
98
+ To connect to this host you can use curl, or your browser to connect to
99
+ http://localhost:3000/api/v1/app/status to check the status of
100
+ the application. All other parts of the application are served at
101
+ http://localhost:3000.
102
+
103
+ docker-compose.dev.yml
104
+ ---
105
+ This file extends docker-compose.yml to add service definitions to make it possible
106
+ to easily run things like bundle, rspec, rails, rake, etc (see below for more).
107
+
108
+ You can use this by adding the -f docker-compose.yml -f docker-compose.dev.yml flag
109
+ to all of your docker-compose commands, e.g.
110
+ ```
111
+ docker-compose -f docker-compose.yml -f docker-compose.dev.yml run rails c
112
+ ```
113
+
114
+ Alternatively, you can use the fact that docker-compose looks for both docker-compose.yml
115
+ and docker-compose.override.yml by default, and create a symlink from docker-compose.dev.yml
116
+ to docker-compose.override.yml that will make docker-compose use both by default, without
117
+ any of the extra -f flags.
118
+ ```
119
+ ln -s docker-compose.dev.yml docker-compose.override.yml
120
+ ```
121
+ Note, you should add docker-compose.override.yml to your .gitignore, so it will
122
+ never be committed to the repo. This ensures that the default behavior for those
123
+ not wishing to use the extra functionality in docker-compose.dev.yml is preserved.
124
+
125
+ You should always specify the exact service (e.g. top level key
126
+ in the docker-compose.dev.yml file) when running docker-compose commands using this
127
+ docker-compose.dev.yml file. Otherwise, docker-compose will try to run all services,
128
+ which will cause things to run that do not need to run (such as bundle).
129
+
130
+ default docker-compose commands
131
+ ---
132
+ Using just the docker-compose.yml, e.g. docker-compose.override.yml file/symlink
133
+ is not present:
134
+
135
+ Launch the server to interact with the application:
136
+ ```
137
+ docker-compose up -d server
138
+ ```
139
+ Docker-compose is smart enough to realize all of the linked services required,
140
+ and spin them up in order. This will not launch a swift service.
141
+
142
+ Bring down and delete running containers:
143
+ ```
144
+ docker-compose down
145
+ ```
146
+
147
+ docker-compose.dev.yml docker-compose commands
148
+ ---
149
+ Either use -f docker-compose.yml -f docker-compose.dev.yml, like so:
150
+ Run rspec
151
+ ```
152
+ docker-compose -f docker-compose.yml -f docker-compose.dev.yml run rspec
153
+ docker-compose -f docker-compose.yml -f docker-compose.dev.yml run rspec spec/requests
154
+ ```
155
+
156
+ Or create a symlink from docker-compose.dev.yml to docker-compose.override.yml.
157
+ This is the recommended way to use docker-compose.dev.yml, as it will be more
158
+ permanent between invocations of the shell terminal.
159
+ ```
160
+ ln -s docker-compose.dev.yml docker-compose.override.yml
161
+ ```
162
+
163
+ Then you can run services like rspec without the extra -f flags:
164
+ ```
165
+ docker-compose run rspec
166
+ docker-compose run rspec spec/requests
167
+ ```
168
+
169
+ The following commands assume the symlink exists.
170
+ Run bundle (see
171
+ [below](#dockerfile) for **important information about modifying the Gemfile**)):
172
+ ```
173
+ docker-compose run bundle
174
+ ```
175
+
176
+ Run rake commands (default RAILS_ENV=development):
177
+ ```
178
+ docker-compose run rake db:migrate
179
+ docker-compose run rake db:seed
180
+ docker-compose run rake db:migrate RAILS_ENV=test
181
+ ```
182
+
183
+ Run rails commands (default RAILS_ENV=docker):
184
+ ```
185
+ docker-compose run rails c
186
+ docker-compose run rails c RAILS_ENV=test
187
+ ```
188
+
189
+ **Note about docker-compose down**
190
+ You should run docker-compose down using the same docker-compose yml file context,
191
+ e.g. with COMPOSE_FILE set, or the docker-compose.override.yml file in existence,
192
+ or using the -f flags for all docker-compose yml files. Otherwise, services defined
193
+ in the missing docker-compose.yml file will not be shut down and removed, and a warning
194
+ may come up in your output that says containers were 'orphaned'.
195
+
196
+ Dockerfile
197
+ ===
198
+ Docker uses a [Dockerfile](https://docs.docker.com/reference/builder/) to
199
+ specify how to build an image to host an application. We have created a
200
+ Dockerfile in the Application Root. This Dockerfile:
201
+ * installs required libraries for ruby, rails, node, etc.
202
+ * installs specific versions of ruby
203
+ * installs the sqlite client libraries
204
+ * creates /var/www/app and sets this to the default working directory
205
+ * adds Gemfile and Gemfile.lock (see below)
206
+ * bundles to install required gems into the image
207
+ * exposes 3000
208
+ * sets up to run the rails server to host the service by default
209
+
210
+ **Important information about modifying the Gemfile**
211
+ When you need to add a gem to your Gemfile, you will also need to rebuild
212
+ the server. This will permenently install the new gem into the server image.
213
+
214
+ ```
215
+ docker-compose build server
216
+ ```
217
+ You then need to run bundle, which will update Gemfile.lock in the Application
218
+ Root
219
+ ```
220
+ docker-compose -f docker-compose.yml -f docker-compose.dev.yml run bundle
221
+ ```
222
+ You should then commit and push the new Gemfile and Gemfile.lock to the repository.
223
+
224
+ Docker basics
225
+ ===
226
+
227
+ To stop all running docker containers (you must stop a container before you can
228
+ remove it or its image):
229
+ ```
230
+ docker-compose stop
231
+ ```
232
+
233
+ To stop and/or remove all containers, use the following:
234
+ ```
235
+ docker-compose down
236
+ ```
237
+
238
+ When a docker container stops for any reason, docker keeps it around in its
239
+ system. There are ways you can start and attach to a stopped container, but
240
+ in many cases this is not useful. You should remove containers on a regular basis.
241
+ When you start up the machines from scratch, you will need to run rake db:migrate,
242
+ etc. to get the database ready.
243
+
244
+ You can list all running containers using the following command:
245
+ ```
246
+ docker ps
247
+ ```
248
+ You can list all containers (both running and stopped):
249
+ ```
250
+ docker ps -a
251
+ ```
252
+
253
+ Each docker container is given a long UUID by docker (called the CONTAINERID).
254
+ You can use this UUID (or even the first 4 or more characters) to stop
255
+ and remove a container using the docker commandline instead of
256
+ using docker-compose (see Docker [commandline documentation](https://docs.docker.com/engine/reference/commandline)
257
+ for other things you can find out about a running container using the docker command):
258
+ ```
259
+ docker stop UUID
260
+ docker rm -v UUID
261
+ ```
262
+
263
+ Sometimes docker will leave files from a container on the host, which can build
264
+ up over time and cause your VM to become sluggish or behave strangely. We
265
+ recommend adding the -v (volumes) flag to docker rm commands to make sure these
266
+ files are cleaned up appropriately. Also, docker ps allows you to pass the -q
267
+ flag, and get only the UUID of the containers it lists. Using the following
268
+ command, you can easily stop all running containers:
269
+ ```
270
+ docker stop $(docker ps -q)
271
+ ```
272
+
273
+ Similarly, to remove all stopped containers (this will skip running containers, but
274
+ print a warning for each):
275
+ ```
276
+ docker rm -v $(docker ps -aq)
277
+ ```
278
+
279
+ You may also need to check for volumes that have been left behind when containers
280
+ were removed without explicitly using docker rm -v, such as when docker-compose down
281
+ is run. To list all volumes on the docker host:
282
+ ```
283
+ docker volume ls
284
+ ```
285
+
286
+ The output from this is very similar to all other docker outputs. Each volume is
287
+ assigned a UUID. You can remove a specific volume with:
288
+ ```
289
+ docker volume rm UUID
290
+ ```
291
+
292
+ You can remove all volumes using the -q pattern used in other docker commands
293
+ ```
294
+ docker volume rm $(docker volume ls -q)
295
+ ```
296
+
297
+ We recommend running some of these frequently to clean up containers and volumes that
298
+ build up over time. Sometimes, when running a combination docker rm $(docker ls -q)
299
+ pattern command when there is nothing to remove, docker will print a warning that
300
+ it requires 1 or more arguments, but this is ok. It can be useful to put some or
301
+ all of these in your Bash Profile.
302
+
303
+ Bash Profile
304
+ ===
305
+ The following can be placed in the .bash_profile file located in your
306
+ HOME directory (e.g. ~/.bash_profile)
307
+
308
+ ```bash_profile
309
+ # Docker configurations and helpers
310
+ alias docker_stop_all='docker stop $(docker ps -q)'
311
+ alias docker_cleanup='docker rm -v $(docker ps -aq)'
312
+ alias docker_images_cleanup='docker rmi $(docker images -f dangling=true -q)'
313
+ alias docker_volume_cleanup='docker volume rm $(docker volume ls -q)'
314
+
315
+ # fake rake/rails/rspec using docker under the hood
316
+ # this depends on either a docker-compose.override.yml, or COMPOSE_FILE
317
+ # environment variable
318
+ alias rails="docker-compose run rails"
319
+ alias rake="docker-compose run rake"
320
+ alias rspec="docker-compose run rspec"
321
+ alias bundle="docker-compose run bundle"
322
+ alias dcdown="docker-compose down"
323
+ ```
@@ -0,0 +1,15 @@
1
+ FROM ruby:2.3
2
+ MAINTAINER Darin London <darin.london@duke.edu>
3
+ RUN gem install -N bundler lita
4
+
5
+ #miscellaneous
6
+ RUN ["mkdir","-p","/var/www"]
7
+ WORKDIR /var/www/app
8
+ ADD Gemfile /var/www/app/Gemfile
9
+ ADD Gemfile.lock /var/www/app/Gemfile.lock
10
+ ADD lita-elasticsearch-indexer.gemspec /var/www/app/lita-elasticsearch-indexer.gemspec
11
+
12
+ RUN ["bundle", "install", "--jobs=4"]
13
+
14
+ # run the app by defualt
15
+ CMD ["lita"]
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "lita-slack"
6
+ gem "faye-websocket", "0.10.2"
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Research Application Development Group
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,46 @@
1
+ # lita-elasticsearch-indexer
2
+
3
+ A [Lita](https://www.lita.io/) handler plugin that indexes messages to
4
+ [Elasticsearch](https://www.elastic.co/).
5
+
6
+ ## Installation
7
+
8
+ Add lita-elasticsearch-indexer to your Lita instance's Gemfile:
9
+
10
+ ``` ruby
11
+ gem "lita-elasticsearch-indexer"
12
+ ```
13
+
14
+ ## Configuration
15
+
16
+ ### Required
17
+ * `elasticsearch_url` (String) - Host url for the Elasticsearch instance
18
+ * `elasticsearch_index_name` (String) - The name of the Elasticsearch index
19
+
20
+ ### Optional
21
+ * `elasticsearch_index_type` (String) - The
22
+ Elasticsearch document type. (default: 'message')
23
+ * `elasticsearch_index_options` (Proc) - A ruby `Proc` or `lambda` used to set index parameters or override the index body.
24
+
25
+ ## Usage
26
+
27
+ lita-elasticsearch-indexer is a lurker-bot that silently indexes all messages posted
28
+ by all users in any room to which it has been invited. It can also index
29
+ private messages sent directly to the bot. The bot will not index any messages
30
+ posted to rooms to which it has not been invited.
31
+
32
+ ### Setting elasticsearch index options with a Proc
33
+
34
+ Any of the optional arguments for [Elasticsearch::API::Actions index](http://www.rubydoc.info/gems/elasticsearch-api/Elasticsearch/API/Actions#index-instance_method) can be set via `elasticsearch_index_options` by creating a Proc
35
+ (or lambda) that returns a Hash. The hash will be merged with the required
36
+ parameters and passed directly to the elasticsearch client index method.
37
+
38
+ ```
39
+ config.handlers.elasticsearch_indexer.elasticsearch_index_options = lambda {|response|
40
+ options = {}
41
+ if response.message.extensions[:slack]
42
+ options[:id] = response.room.id + '-' + response.message.extensions[:slack][:timestamp]
43
+ end
44
+ options
45
+ }
46
+ ```
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,24 @@
1
+ version: '2'
2
+ services:
3
+ bundle:
4
+ image: "lita-elasticsearch-indexer_server"
5
+ volumes_from:
6
+ - workdir
7
+ entrypoint: ['bundle']
8
+ rake:
9
+ image: "lita-elasticsearch-indexer_server"
10
+ volumes_from:
11
+ - workdir
12
+ entrypoint: ['rake']
13
+ rspec:
14
+ image: "lita-elasticsearch-indexer_server"
15
+ environment:
16
+ - LITA_REDIS_HOST=redis
17
+ - LITA_ELASTICSEARCH_URL=elastic.local:9200
18
+ volumes_from:
19
+ - workdir
20
+ links:
21
+ - redis
22
+ - elasticsearch:elastic.local
23
+ entrypoint: ['rspec']
24
+ command: spec
@@ -0,0 +1,28 @@
1
+ version: '2'
2
+ services:
3
+ workdir:
4
+ image: ruby:2.3 # Reducing footprint by matching image to Dockerfile FROM
5
+ command: ['df'] # Just a quick command that exits. Mount info is a bonus.
6
+ volumes:
7
+ - .:/var/www/app
8
+ lita:
9
+ build: .
10
+ image: lita-elasticsearch-indexer_server
11
+ volumes_from:
12
+ - workdir
13
+ restart: always
14
+ links:
15
+ - redis
16
+ - elasticsearch:elastic.local
17
+ ports:
18
+ - 8080:8080
19
+ env_file:
20
+ - lita.env
21
+ redis:
22
+ image: redis
23
+ volumes:
24
+ - ./redis:/var/lib/redis
25
+ elasticsearch:
26
+ image: elasticsearch:2.2.2
27
+ ports:
28
+ - 9200
@@ -0,0 +1,12 @@
1
+ require "lita"
2
+
3
+ Lita.load_locales Dir[File.expand_path(
4
+ File.join("..", "..", "locales", "*.yml"), __FILE__
5
+ )]
6
+
7
+ require "lita/handlers/elasticsearch_indexer"
8
+
9
+ Lita::Handlers::ElasticsearchIndexer.template_root File.expand_path(
10
+ File.join("..", "..", "templates"),
11
+ __FILE__
12
+ )
@@ -0,0 +1,55 @@
1
+ require 'elasticsearch'
2
+ module Lita
3
+ module Handlers
4
+ class ElasticsearchIndexer < Handler
5
+ config :elasticsearch_url, type: String, required: true
6
+ config :elasticsearch_index_name, type: String, required: true
7
+ config :elasticsearch_index_type, type: String, default: "message"
8
+ config :elasticsearch_index_options, type: Proc
9
+
10
+ route(/^(.+)/,
11
+ :index_conversation,
12
+ help: { "info" =>
13
+ "Stores conversations in elasticsearch"
14
+ })
15
+
16
+ def elasticsearch_client
17
+ @@elasticsearch_client ||= Elasticsearch::Client.new(
18
+ urls: config.elasticsearch_url
19
+ )
20
+ end
21
+
22
+ def index_conversation(response)
23
+ user = response.user
24
+ message = response.message
25
+ room = message.room_object
26
+ index_body = {
27
+ user: {id: user.id, name: user.name},
28
+ message: {
29
+ private: message.private_message?,
30
+ body: message.body
31
+ }
32
+ }
33
+ index_body[:room] = {id: room.id, name: room.name} if room
34
+ index_params = {
35
+ body: index_body
36
+ }.merge(elasticsearch_index_options(response))
37
+ index_params[:index] = config.elasticsearch_index_name
38
+ index_params[:type] = config.elasticsearch_index_type
39
+ index = elasticsearch_client.index(index_params)
40
+ end
41
+
42
+ Lita.register_handler(self)
43
+
44
+ private
45
+
46
+ def elasticsearch_index_options(response)
47
+ if config.elasticsearch_index_options
48
+ config.elasticsearch_index_options.call(response)
49
+ else
50
+ {}
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,31 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "lita-elasticsearch-indexer"
3
+ spec.version = "0.1.1"
4
+ spec.authors = ["Darrin Mann", "Darin London"]
5
+ spec.email = ["darrin.mann@duke.edu", "darin.london@duke.edu"]
6
+ spec.description = <<-EOF
7
+ lita-elasticsearch-indexer is a lurker-bot that silently indexes all messages posted
8
+ by all users in any room to which it has been invited. It can also index
9
+ private messages sent directly to the bot. The bot will not index any messages
10
+ posted to rooms to which it has not been invited.
11
+ EOF
12
+ spec.summary = "Listens to channel conversations and stores them to elasticsearch"
13
+ spec.homepage = "https://github.com/ORI-RAD/lita-elasticsearch-indexer"
14
+ spec.license = "MIT"
15
+ spec.metadata = { "lita_plugin_type" => "handler" }
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_runtime_dependency "lita", ">= 4.7"
23
+ spec.add_runtime_dependency "elasticsearch"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "pry-byebug"
27
+ spec.add_development_dependency "rake"
28
+ spec.add_development_dependency "rack-test"
29
+ spec.add_development_dependency "rspec", ">= 3.0.0"
30
+ spec.add_development_dependency "faker"
31
+ end
@@ -0,0 +1,11 @@
1
+ #----------------------------------------------------------------------
2
+ # Copy this file to lita.env and configure lita secrets there.
3
+ # DO NOT ADD SECRETS TO THIS [lita.env.example] FILE!
4
+ #----------------------------------------------------------------------
5
+
6
+ # Slack API token for the bot. For more information, see:
7
+ # https://github.com/litaio/lita-slack#configuration
8
+ LITA_SLACK_TOKEN=REPLACE-THIS-WITH-YOUR-API-TOKEN
9
+ LITA_ELASTICSEARCH_URL=elastic.local:9200
10
+ LITA_ELASTICSEARCH_INDEX_NAME=rad-chats
11
+ LITA_REDIS_HOST=redis
@@ -0,0 +1,43 @@
1
+ Lita.configure do |config|
2
+ # The name your robot will use.
3
+ # config.robot.name = "Lita"
4
+
5
+ # The locale code for the language to use.
6
+ # config.robot.locale = :en
7
+
8
+ # The severity of messages to log. Options are:
9
+ # :debug, :info, :warn, :error, :fatal
10
+ # Messages at the selected level and above will be logged.
11
+ config.robot.log_level = :debug
12
+
13
+ # An array of user IDs that are considered administrators. These users
14
+ # the ability to add and remove other users from authorization groups.
15
+ # What is considered a user ID will change depending on which adapter you use.
16
+ # config.robot.admins = ["1", "2"]
17
+
18
+ # The adapter you want to connect with. Make sure you've added the
19
+ # appropriate gem to the Gemfile.
20
+ config.robot.adapter = :slack
21
+ config.adapters.slack.token = ENV['LITA_SLACK_TOKEN']
22
+
23
+ ## Example: Set options for the chosen adapter.
24
+ # config.adapter.username = "myname"
25
+ # config.adapter.password = "secret"
26
+
27
+ ## Example: Set options for the Redis connection.
28
+ config.redis[:host] = ENV['LITA_REDIS_HOST']
29
+ # config.redis.port = 1234
30
+
31
+ ## Example: Set configuration for any loaded handlers. See the handler's
32
+ ## documentation for options.
33
+ # config.handlers.some_handler.some_config_key = "value"
34
+ config.handlers.elasticsearch_indexer.elasticsearch_url = ENV['LITA_ELASTICSEARCH_URL']
35
+ config.handlers.elasticsearch_indexer.elasticsearch_index_name = ENV['LITA_ELASTICSEARCH_INDEX_NAME']
36
+ config.handlers.elasticsearch_indexer.elasticsearch_index_options = lambda {|response|
37
+ options = {}
38
+ if response.message.extensions[:slack]
39
+ options[:id] = response.room.id + '-' + response.message.extensions[:slack][:timestamp]
40
+ end
41
+ options
42
+ }
43
+ end
@@ -0,0 +1,4 @@
1
+ en:
2
+ lita:
3
+ handlers:
4
+ elasticsearch_indexer:
@@ -0,0 +1,116 @@
1
+ require "spec_helper"
2
+ require "faker"
3
+
4
+ describe Lita::Handlers::ElasticsearchIndexer, lita_handler: true do
5
+ describe 'config' do
6
+ let(:config) { Hash[described_class.configuration_builder.children.collect {|x| [x.name, x]}] }
7
+ # Elasticsearch::Transport Client setting hosts documentation:
8
+ # http://www.rubydoc.info/gems/elasticsearch-transport/file/README.md#Setting_Hosts
9
+ it { expect(config).to have_key(:elasticsearch_url) }
10
+ it { expect(config[:elasticsearch_url]).to be_required }
11
+ it { expect(config[:elasticsearch_url].types).to contain_exactly(String) }
12
+
13
+ # Elasticsearch::API::Actions#index documentation:
14
+ # http://www.rubydoc.info/gems/elasticsearch-api/Elasticsearch/API/Actions#index-instance_method
15
+ it { expect(config).to have_key(:elasticsearch_index_name) }
16
+ it { expect(config[:elasticsearch_index_name]).to be_required }
17
+ it { expect(config[:elasticsearch_index_name].types).to contain_exactly(String) }
18
+
19
+ it { expect(config).to have_key(:elasticsearch_index_type) }
20
+ it { expect(config[:elasticsearch_index_type]).not_to be_required }
21
+ it { expect(config[:elasticsearch_index_type].types).to contain_exactly(String) }
22
+
23
+ it { expect(config).to have_key(:elasticsearch_index_options) }
24
+ it { expect(config[:elasticsearch_index_options]).not_to be_required }
25
+ it { expect(config[:elasticsearch_index_options].types).to contain_exactly(Proc) }
26
+ end
27
+
28
+ describe '#index_conversation' do
29
+ it { is_expected.to respond_to(:index_conversation).with(1).argument }
30
+
31
+ context 'with a non-empty message' do
32
+ let(:message) { Faker::Hacker.say_something_smart }
33
+ let(:room_id) { Faker::Internet.slug }
34
+ let(:private_message) { false }
35
+
36
+ it { is_expected.to route(message).to(:index_conversation) }
37
+
38
+ context 'send_message' do
39
+ let(:method) { send_message(message, from: room_id, privately: private_message) }
40
+ let(:registry_config) { registry.config.handlers.elasticsearch_indexer }
41
+ let(:index_name) { "test-#{Faker::Internet.slug}" }
42
+ let(:index_type) { "test-#{Faker::Internet.slug}" }
43
+ let(:index_body) { {
44
+ "user" => {
45
+ "id" => user.id,
46
+ "name" => user.name
47
+ },
48
+ "message" => {
49
+ "private" => private_message,
50
+ "body" => message
51
+ }
52
+ } }
53
+ let(:elasticsearch_url) { ENV['LITA_ELASTICSEARCH_URL'] }
54
+
55
+ before do
56
+ registry_config.elasticsearch_url = elasticsearch_url
57
+ registry_config.elasticsearch_index_name = index_name
58
+ registry_config.elasticsearch_index_type = index_type
59
+
60
+ expect(registry_config.elasticsearch_url).not_to be_nil
61
+ end
62
+
63
+ it 'does not send a reply' do
64
+ expect{ method }.not_to raise_error
65
+ expect(replies).to be_empty
66
+ end
67
+
68
+ it_behaves_like 'an elasticsearch indexer' do
69
+ include_context 'with a single document indexed'
70
+
71
+ it { expect(document["_index"]).to eq(index_name) }
72
+ it { expect(document["_type"]).to eq(index_type) }
73
+ it { expect(document["_source"]).to include(index_body) }
74
+ end
75
+
76
+ context 'when elasticsearch_index_options' do
77
+ let(:id) { Faker::Internet.slug }
78
+ before do
79
+ expect {
80
+ registry_config.elasticsearch_index_options = index_options
81
+ }.not_to raise_error
82
+ end
83
+ context 'is a Proc' do
84
+ let(:index_options) {
85
+ Proc.new { |response|
86
+ {id: id}
87
+ }
88
+ }
89
+ it_behaves_like 'an elasticsearch indexer' do
90
+ include_context 'with a single document indexed'
91
+
92
+ it { expect(document["_id"]).to eq(id) }
93
+ end
94
+ end
95
+
96
+ context 'is a lambda' do
97
+ let(:index_options) {
98
+ lambda { |response|
99
+ {id: id}
100
+ }
101
+ }
102
+ it_behaves_like 'an elasticsearch indexer' do
103
+ include_context 'with a single document indexed'
104
+
105
+ it { expect(document["_id"]).to eq(id) }
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ context 'with an empty message' do
113
+ it { is_expected.not_to route('').to(:index_conversation) }
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,14 @@
1
+ require "lita-elasticsearch-indexer"
2
+ require "lita/rspec"
3
+
4
+ # loading shared examples
5
+ Dir["./spec/support/**/*.rb"].sort.each { |f| require f}
6
+
7
+ # A compatibility mode is provided for older plugins upgrading from Lita 3. Since this plugin
8
+ # was generated with Lita 4, the compatibility mode should be left disabled.
9
+ Lita.version_3_compatibility_mode = false
10
+
11
+ Lita.configure do |config|
12
+ config.redis[:host] = ENV['LITA_REDIS_HOST']
13
+ # config.redis.port = 1234
14
+ end
@@ -0,0 +1,31 @@
1
+ shared_examples 'an elasticsearch indexer' do |method_sym: :method, elasticsearch_url_sym: :elasticsearch_url|
2
+ let(:elasticsearch_client) {
3
+ Elasticsearch::Client.new(urls: send(elasticsearch_url_sym))
4
+ }
5
+ let(:existing_documents) { elasticsearch_client.search["hits"]["hits"] }
6
+ let(:new_documents) { elasticsearch_client.search["hits"]["hits"] - existing_documents }
7
+ before do
8
+ expect{ existing_documents }.not_to raise_error
9
+ expect{ send(method_sym) }.not_to raise_error
10
+ expect{ elasticsearch_client.indices.flush }.not_to raise_error
11
+ expect{ new_documents }.not_to raise_error
12
+ expect(new_documents).not_to be_empty
13
+ end
14
+ after do
15
+ new_documents.each do |d|
16
+ elasticsearch_client.delete(
17
+ id: d["_id"],
18
+ index: d["_index"],
19
+ type: d["_type"]
20
+ )
21
+ end
22
+ end
23
+ end
24
+
25
+ shared_context 'with a single document indexed' do
26
+ let(:document) { new_documents.first }
27
+ before do
28
+ expect(new_documents.length).to eq(1)
29
+ expect(document).not_to be_nil
30
+ end
31
+ end
File without changes
metadata ADDED
@@ -0,0 +1,185 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lita-elasticsearch-indexer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Darrin Mann
8
+ - Darin London
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2017-01-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: lita
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '4.7'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '4.7'
28
+ - !ruby/object:Gem::Dependency
29
+ name: elasticsearch
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: bundler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: '1.3'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: '1.3'
56
+ - !ruby/object:Gem::Dependency
57
+ name: pry-byebug
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rake
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rack-test
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rspec
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - '>='
103
+ - !ruby/object:Gem::Version
104
+ version: 3.0.0
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - '>='
110
+ - !ruby/object:Gem::Version
111
+ version: 3.0.0
112
+ - !ruby/object:Gem::Dependency
113
+ name: faker
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: |2
127
+ lita-elasticsearch-indexer is a lurker-bot that silently indexes all messages posted
128
+ by all users in any room to which it has been invited. It can also index
129
+ private messages sent directly to the bot. The bot will not index any messages
130
+ posted to rooms to which it has not been invited.
131
+ email:
132
+ - darrin.mann@duke.edu
133
+ - darin.london@duke.edu
134
+ executables: []
135
+ extensions: []
136
+ extra_rdoc_files: []
137
+ files:
138
+ - .gitignore
139
+ - Docker.README.md
140
+ - Dockerfile
141
+ - Gemfile
142
+ - LICENSE
143
+ - README.md
144
+ - Rakefile
145
+ - docker-compose.dev.yml
146
+ - docker-compose.yml
147
+ - lib/lita-elasticsearch-indexer.rb
148
+ - lib/lita/handlers/elasticsearch_indexer.rb
149
+ - lita-elasticsearch-indexer.gemspec
150
+ - lita.env.example
151
+ - lita_config.rb
152
+ - locales/en.yml
153
+ - spec/lita/handlers/elasticsearch_indexer_spec.rb
154
+ - spec/spec_helper.rb
155
+ - spec/support/elasticsearch_shared_examples.rb
156
+ - templates/.gitkeep
157
+ homepage: https://github.com/ORI-RAD/lita-elasticsearch-indexer
158
+ licenses:
159
+ - MIT
160
+ metadata:
161
+ lita_plugin_type: handler
162
+ post_install_message:
163
+ rdoc_options: []
164
+ require_paths:
165
+ - lib
166
+ required_ruby_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - '>='
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
171
+ required_rubygems_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - '>='
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ requirements: []
177
+ rubyforge_project:
178
+ rubygems_version: 2.0.14.1
179
+ signing_key:
180
+ specification_version: 4
181
+ summary: Listens to channel conversations and stores them to elasticsearch
182
+ test_files:
183
+ - spec/lita/handlers/elasticsearch_indexer_spec.rb
184
+ - spec/spec_helper.rb
185
+ - spec/support/elasticsearch_shared_examples.rb