annotator_store 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c6ddd11b4ff25f3477a7c2ef180080c135f192ba
4
+ data.tar.gz: 40c0857fbb2adc58ec90f65622f91ca463016d9d
5
+ SHA512:
6
+ metadata.gz: 9dde1c468bcdeb6c3a6bd7069b9bb1176e479036b3e1b4b3b4bff26b756368d4fde382ffd863596fd5dd11ed04cd6995565bb8e5191b1d23080dd5212d5b067c
7
+ data.tar.gz: 39a4e0020f14898a1d0e3b730fa4adba062baa338fdf317c10214935b357f7235637d109a067319e0c87068d4ed78b603683c4ae0a4f732d6ca6ae54d17e9470
data/CHANGELOG.md ADDED
@@ -0,0 +1,48 @@
1
+ CHANGELOG
2
+ =========
3
+
4
+ v1.0.0.pre
5
+ ----------
6
+
7
+ * Rename gem from `annotator-store` to `annotator_store`
8
+ * Fix issue with explicit require needed in main application
9
+
10
+
11
+ v0.4.0
12
+ ------
13
+
14
+ * Add support for MySQL
15
+
16
+
17
+ v0.3.0
18
+ ------
19
+
20
+ * Change create endpoint to respond with `201 CREATED`
21
+ * Test support for Ruby `>= 1.9.3`.
22
+ * Test support for Rails `>= 4.0`.
23
+
24
+
25
+ v0.2.0
26
+ ------
27
+
28
+ * Add required files to gemspec
29
+ * Add CRUD (create, read, update and delete) endpoints
30
+ * Add search endpoint with filter support for uri
31
+ * Included tests for routes, requests, models and controllers
32
+
33
+
34
+ v0.1.0
35
+ ------
36
+
37
+ * Create index page with description of API.
38
+ * Add annotation functionality & create necessary endpoints
39
+
40
+
41
+ v0.0.1
42
+ ------
43
+
44
+ Initial release, to lock the gem name ... by v1.0.0 we should have a version
45
+ ready for deployment in production environment.
46
+
47
+ * Initialise the project
48
+ * Create structure
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,28 @@
1
+ CONTRIBUTING
2
+ ============
3
+
4
+ Submitting a Pull Request
5
+ -------------------------
6
+
7
+ 1. [Fork the repository][fork].
8
+ 2. [Create a topic branch][branch] (`git checkout -b BRANCH_NAME`).
9
+ 3. [Install bundler][bundler].
10
+ 4. Check that tests pass with `rspec spec`.
11
+ 5. Write a failing test to capture existing bug or lack of feature.
12
+ 6. Run `rspec spec` to verify that test fails.
13
+ 7. Implement your feature or bug fix.
14
+ 8. Ensure tests pass.
15
+ 9. If it's a new feature or a bug fix, please add an entry to the CHANGELOG file.
16
+ 10. Check code style violations using [Rubocop][rubocop].
17
+ 11. Add a commit (`git commit -am 'AWESOME COMMIT MESSAGE'`).
18
+ 12. Push your changes to the branch (`git push origin BRANCH_NAME`).
19
+ 13. [Submit a pull request.][pr]
20
+ 14. You will get some feedback and may need to push additional commits
21
+ with more fixes to the same branch; this will update your pull request
22
+ automatically.
23
+
24
+ [branch]: http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches
25
+ [bundler]: http://bundler.io
26
+ [fork]: https://help.github.com/articles/fork-a-repo/
27
+ [pr]: https://help.github.com/articles/using-pull-requests
28
+ [rubocop]: https://github.com/bbatsov/rubocop
data/LICENSE.md ADDED
@@ -0,0 +1,23 @@
1
+ License
2
+ =======
3
+
4
+ Copyright (c) 2014 Job King'ori Maina
5
+
6
+ MIT License
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
9
+ this software and associated documentation files (the "Software"), to deal in
10
+ the Software without restriction, including without limitation the rights to
11
+ use, copy, modify, merge, publish, distribute, sub-license, and/or sell copies
12
+ of the Software, and to permit persons to whom the Software is furnished to do
13
+ so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
20
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,414 @@
1
+ Annotator Store
2
+ ===============
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/annotator_store.svg)][5]
5
+ [![Build Status](https://travis-ci.org/itsmrwave/annotator_store-gem.svg?branch=master)][13]
6
+
7
+ Rails engine to implement a [Ruby on Rails][18] backend store implementation for
8
+ [Annotator][annotator].
9
+
10
+ > Annotator an open-source JavaScript library to easily add annotation
11
+ > functionality to any webpage. Annotations can have comments, tags, links,
12
+ > users, and more. Annotator is designed for [easy extensibility][1] so its a
13
+ > cinch to add a new feature or behaviour. Annotator also fosters an active
14
+ > developer community with contributors from four continents, building 3rd party
15
+ > plugins allowing the annotation of PDFs, EPUBs, videos, images, sound, and
16
+ > more.
17
+
18
+ The gem should be up on [rubygems.org][5], the [CHANGELOG here][7] and [all the
19
+ releases listed here][8].
20
+
21
+
22
+ Contents
23
+ --------
24
+
25
+ 1. Dependencies & Versions
26
+ 2. Installation
27
+ 3. Annotation Format
28
+ 4. API Endpoints
29
+ 5. Development
30
+ 6. Testing & Appraisals
31
+ 7. Versioning
32
+ 8. Contributing
33
+ 9. License
34
+
35
+
36
+ Dependencies & Versions
37
+ ----------------------
38
+
39
+ This engine requires Rails `>= 4.0` and Ruby `>= 1.9.3` and supports more than
40
+ one database.
41
+
42
+ Supported Ruby versions:
43
+
44
+ * [X] 1.9.3
45
+ * [X] 2.0.0
46
+ * [X] 2.1.0
47
+ * [X] 2.1.1
48
+ * [X] 2.1.2
49
+
50
+ Supported Rails versions:
51
+
52
+ * [X] 4.0.x
53
+ * [X] 4.1.x
54
+ * [X] 4.2.x
55
+
56
+ Supported databases:
57
+
58
+ * [X] MySQL
59
+ * [X] PostgreSQL
60
+
61
+ _'Supported'_ means that the test suite is designed to cover these versions
62
+ only. If your version isn't supported [raise a ticket][19]; make sure you
63
+ include the versions.
64
+
65
+ Sometimes when the build is failing, it's probably a few of these
66
+ configurations. Have a [look at the builds here][13] and see section on testing
67
+ & appraisals for more information.
68
+
69
+
70
+ Installation
71
+ ------------
72
+
73
+ Add this line to your application's Gemfile:
74
+
75
+ gem 'annotator_store'
76
+
77
+ And then from the `APP_ROOT` execute:
78
+
79
+ $ bundle install
80
+
81
+ Configure your database credentials in `config/database.yml` and then run the
82
+ migrations to create the tables to store the annotations. Depending on the
83
+ database of choice you'll need to set the `DB` environment variable when running
84
+ the migrations. There are slight variations in the structure of the DB when
85
+ using MySQL and PostgreSQL. The default setting is PostgreSQL if not set.
86
+
87
+ # Copy migrations over from the engine
88
+ $ rake annotator_store:install:migrations
89
+
90
+ # To run the copied migration when using MySQL
91
+ $ DB=mysql rake db:migrate
92
+
93
+ # To run the copied migration when using PostgreSQL
94
+ $ DB=postgres rake db:migrate
95
+
96
+ # To run the copied migration without specifying type (defaults to postgres)
97
+ $ rake db:migrate
98
+
99
+ Then mount it in `config/routes.rb`:
100
+
101
+ # Configures store endpoint in your app
102
+ mount AnnotatorStore::Engine, at: '/annotator_store'
103
+
104
+ Now it should be ready for use. All the endpoints will be available at
105
+ `http://0.0.0.0:3000/annotator_store` in your app.
106
+
107
+
108
+ Annotation Format
109
+ -----------------
110
+
111
+ An annotation is a JSON document that contains a number of fields describing the
112
+ position and content of an annotation within a specified document:
113
+
114
+ {
115
+ "id": "39fc339cf058bd22176771b3e3187329", # unique id (added by backend)
116
+ "annotator_schema_version": "v1.0", # schema version: default v1.0
117
+ "created": "2011-05-24T18:52:08.036814", # created datetime in iso8601 format (added by backend)
118
+ "updated": "2011-05-26T12:17:05.012544", # updated datetime in iso8601 format (added by backend)
119
+ "text": "A note I wrote", # content of annotation
120
+ "quote": "the text that was annotated", # the annotated text (added by frontend)
121
+ "uri": "http://example.com", # URI of annotated document (added by frontend)
122
+ "ranges": [ # list of ranges covered by annotation (usually only one entry)
123
+ {
124
+ "start": "/p[69]/span/span", # (relative) XPath to start element
125
+ "end": "/p[70]/span/span", # (relative) XPath to end element
126
+ "startOffset": 0, # character offset within start element
127
+ "endOffset": 120 # character offset within end element
128
+ }
129
+ ]
130
+ }
131
+
132
+ For PostgreSQL the primary key of the annotation will be a UUID while for MySQL it
133
+ will be a normal integer id.
134
+
135
+
136
+ API Endpoints
137
+ -------------
138
+
139
+ ### Root
140
+
141
+ | Method | Path | Returns |
142
+ | ------ | ---- | ------------------------------------------------------------------------ |
143
+ | GET | / | `200 OK` with an object containing store metadata, including API version |
144
+
145
+ Returns (example):
146
+
147
+ $ curl http://example.com/annotator_store
148
+ {
149
+ "name": "Annotator Store API",
150
+ "version": "2.0.0",
151
+ "links": {
152
+ "annotation": {
153
+ "create": {
154
+ "url": "http://example.com/annotator_store/annotations",
155
+ "method": "POST",
156
+ "description": "Create or add new annotations."
157
+ },
158
+ "read": {
159
+ "url": "http://example.com/annotator_store/annotations/:id",
160
+ "method": "GET",
161
+ "description": "Read, retrieve or view existing annotation."
162
+ },
163
+ "update": {
164
+ "url": "http://example.com/annotator_store/annotations/:id",
165
+ "method": "PUT/PATCH",
166
+ "description": "Update or edit existing annotation."
167
+ },
168
+ "delete": {
169
+ "url": "http://example.com/annotator_store/annotations/:id",
170
+ "method": "DELETE",
171
+ "description": "Delete or deactivate existing annotation."
172
+ }
173
+ },
174
+ "search": {
175
+ "url": "http://example.com/annotator_store/search",
176
+ "method": "GET",
177
+ "description": "Search for annotations"
178
+ }
179
+ }
180
+ }
181
+
182
+
183
+ ### Create
184
+
185
+ | Method | Path | Returns |
186
+ | ------- | ------------ | -------------------------------------------------------------------------- |
187
+ | POST | /annotations | `201 CREATED` with location in header set to the appropriate read endpoint |
188
+
189
+ Receives an annotation object in the proper annotation format, sent with `Content-Type: application/json`.
190
+
191
+ Returns (example):
192
+
193
+ $ curl http://example.com/annotator_store/annotations
194
+ {
195
+ "id": "d41d8cd98f00b204e9800998ecf8427e",
196
+ "text": "Annotation text",
197
+ ...
198
+ }
199
+
200
+
201
+ ### Read
202
+
203
+ | Method | Path | Returns |
204
+ | ------ | ---------------- | ---------------------------------- |
205
+ | GET | /annotations/:id | `200 OK` with an annotation object |
206
+
207
+ Returns (example):
208
+
209
+ $ curl http://example.com/annotator_store/annotations/d41d8cd98f00b204e9800998ecf8427e
210
+ {
211
+ "id": "d41d8cd98f00b204e9800998ecf8427e",
212
+ "text": "Annotation text",
213
+ ...
214
+ }
215
+
216
+
217
+ ### Update
218
+
219
+ | Method | Path | Returns |
220
+ | ---------- | ---------------- | --------------------------------------------------------------------- |
221
+ | PUT/PATCH | /annotations/:id | `200 OK` with location in header set to the appropriate read endpoint |
222
+
223
+ Receives attributes in the proper annotation format, sent with `Content-Type: application/json`.
224
+
225
+ Returns (example):
226
+
227
+ $ curl http://example.com/annotator_store/annotations/d41d8cd98f00b204e9800998ecf8427e
228
+ {
229
+ "id": "d41d8cd98f00b204e9800998ecf8427e",
230
+ "text": "Annotation text",
231
+ ...
232
+ }
233
+
234
+
235
+ ### Delete
236
+
237
+ | Method | Path | Returns |
238
+ | ---------- | ---------------- | ------------------------------------------ |
239
+ | DELETE | /annotations/:id | `204 NO CONTENT` and obviously, no content |
240
+
241
+
242
+ ### Search
243
+
244
+ | Method | Path | Returns |
245
+ | ------ | -------- | ------------------------------------------------------- |
246
+ | GET | /search | An object with total and rows fields |
247
+
248
+ _Total_ is an integer denoting the total number of annotations matched by the
249
+ search, while _rows_ is a list containing what might be a subset of these
250
+ annotations.
251
+
252
+ If implemented, this endpoint should also support the `limit` and `offset` query
253
+ parameters for paging through results.
254
+
255
+ _Ps: Pagination with limit and offset not yet implemented. See [issue #1][15]._
256
+
257
+ Returns (example):
258
+
259
+ $ curl http://example.com/annotator_store/search?text=annotation
260
+ {
261
+ "total": 43127,
262
+ "rows": [
263
+ {
264
+ "id": "d41d8cd98f00b204e9800998ecf8427e",
265
+ "text": "Updated annotation text",
266
+ ...
267
+ },
268
+ ...
269
+ ]
270
+ }
271
+
272
+
273
+ Development
274
+ -----------
275
+
276
+ There's a dummy Rails application in the `spec/dummy` folder. This application
277
+ is used as a mounting point for the engine, to make testing the engine on a
278
+ Rails app extremely simple. This directory should be treated like a typical
279
+ Rails testing environment, allowing for unit, functional and integration tests.
280
+
281
+ The current dummy app was generated using Rails 4.1.6 and with PostgreSQL as the
282
+ default store. The app depends on the `DB` environment variable to know which
283
+ settings to use for the database. See `config/database.yml` for details.
284
+
285
+ Set the `DB` environment variable to either `mysql` or `postgres` to choose
286
+ between the two.
287
+
288
+ # To use MySQL
289
+ $ DB=mysql [commands to run]
290
+
291
+ # To use PostgreSQL
292
+ $ DB=postgres [commands to run]
293
+
294
+ You can start up the dummy app to give it a spin by running `rails server` in
295
+ `spec/dummy` and then browse to `http://0.0.0.0:3000/`. There's a README in
296
+ there with a few details on setup, make sure you check it out.
297
+
298
+
299
+ Testing & Appraisals
300
+ --------------------
301
+
302
+ You may extend the dummy application by generating controllers, models or views
303
+ from within the directory (`spec/dummy`), and then use those to test our engine
304
+ (I've done this already but feel free to add). Then use the rspec command to run
305
+ your specs.
306
+
307
+ #=> Run all specs
308
+ $ bundle exec rspec
309
+
310
+ #=> Run only model specs example ...
311
+ $ bundle exec rspec spec/models
312
+
313
+ #=> Run only specs for AnnotatorStore::AnnotationsController ...
314
+ $ bundle exec rspec spec/controllers/annotations_controller_spec.rb
315
+
316
+ These will run the tests as per your local default configuration.
317
+
318
+ The [appraisal gem][16] is used to integrate with bundler and rake to test the
319
+ engine against different versions of dependencies in repeatable scenarios called
320
+ _'appraisals'_. This makes it easy to check for regressions in the library
321
+ without interfering with day-to-day development using Bundler.
322
+
323
+ As a result, a separate test run is created for each Ruby version and every
324
+ Rails version (see `travis.yml` file for specifics).
325
+
326
+ Locally you can test for different Rails versions. For example:
327
+
328
+ # Run specs against rails 4.0.12
329
+ $ appraisal rails-4.0.12 rspec spec
330
+
331
+ # Run specs against rails 4.1.8
332
+ $ appraisal rails-4.1.8 rspec spec
333
+
334
+ # Run specs against rails 4.2.0
335
+ $ appraisal rails-4.2.0 rspec spec
336
+
337
+ Check the Appraisal file at the root for the different rails configurations.
338
+ [Learn more about appraisals here][17].
339
+
340
+ PostgreSQL is configured to be the default database configuration. Set the `DB`
341
+ environment variable to either `mysql` or `postgres` to choose between the two.
342
+
343
+ # To use MySQL
344
+ $ DB=mysql [commands to run your tests]
345
+
346
+ # To use PostgreSQL
347
+ $ DB=postgres [commands to run your tests]
348
+
349
+ Automated tests are configured and set up to [run on Travis-CI][13]. Any push or
350
+ pull request will be built. The `DB` environment variable should be set to
351
+ either `mysql` or `postgres` to create a build matrix with good coverage.
352
+
353
+
354
+ Versioning
355
+ ----------
356
+
357
+ Major version zero (0.y.z) is for initial development. Anything may change at
358
+ any time. The public API should not be considered stable (implicitly mean, not
359
+ production ready ... yet).
360
+
361
+ Version 1.0.0 defines the public API (implying that it is production ready). The
362
+ way in which the version number is incremented after this release is dependent
363
+ on this public API and how it changes as per [Semantic Versioning
364
+ 2.0.0][semver].
365
+
366
+ All the releases, with their respective changes are [listed here][8].
367
+
368
+
369
+ Contributing
370
+ ------------
371
+
372
+ Want to contribute to the code? First, have a look at the guide in the
373
+ [CONTRIBUTING.md][9] file for the workflow.
374
+
375
+ Then, here's some Annotator documentation to help you get up to speed:
376
+
377
+ * [Annotator Storage][10] API specifications.
378
+ * [Annotator Store Plugin][11] documentation.
379
+
380
+ In summary, this gem helps implement a store for the plugin to interact with.
381
+
382
+ Any code contributors should be [listed here][12].
383
+
384
+
385
+ License
386
+ -------
387
+
388
+ [King'ori J. Maina][2] © 2014. The MIT License bundled therein is a permissive
389
+ license that is short and to the point. It lets people do anything they want as
390
+ long as they provide attribution and waive liability.
391
+
392
+
393
+ [annotator]: http://annotatorjs.org/
394
+ [semver]: http://semver.org
395
+
396
+ [1]: http://docs.annotatorjs.org/en/latest/hacking/plugin-development.html
397
+ [2]: http://kingori.co/
398
+ [3]: http://bundler.io/gemfile.html
399
+ [4]: http://bundler.io
400
+ [5]: https://rubygems.org/gems/annotator_store
401
+ [6]: http://rubydoc.info/gems/annotator_store/frames/
402
+ [7]: https://github.com/itsmrwave/annotator_store-gem/blob/master/CHANGELOG.md
403
+ [9]: https://github.com/itsmrwave/annotator_store-gem/blob/master/CONTRIBUTING.md
404
+ [8]: https://github.com/itsmrwave/annotator_store-gem/releases
405
+ [10]: http://docs.annotatorjs.org/en/v1.2.x/storage.html
406
+ [11]: http://docs.annotatorjs.org/en/v1.2.x/plugins/store.html
407
+ [12]: https://github.com/itsmrwave/annotator_store-gem/graphs/contributors
408
+ [13]: https://travis-ci.org/itsmrwave/annotator_store-gem
409
+ [14]: https://github.com/itsmrwave/annotator-store-demo
410
+ [15]: https://github.com/itsmrwave/annotator_store-gem/issues/1
411
+ [16]: http://rubygems.org/gems/appraisal
412
+ [17]: http://www.rubydoc.info/gems/appraisal
413
+ [18]: http://rubyonrails.org
414
+ [19]: https://github.com/itsmrwave/annotator_store-gem/issues/new
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
8
+ load 'rails/tasks/engine.rake'
9
+
10
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,97 @@
1
+ require_dependency 'annotator_store/application_controller'
2
+
3
+ module AnnotatorStore
4
+ class AnnotationsController < ApplicationController
5
+ before_action :set_annotation, only: [:show, :update, :destroy]
6
+
7
+ # POST /annotations
8
+ def create
9
+ format_client_input_to_rails_convention_for_create
10
+ @annotation = Annotation.new(annotation_params)
11
+ respond_to do |format|
12
+ if @annotation.save
13
+ format.json { render :show, status: :created, location: annotation_url(@annotation) }
14
+ else
15
+ format.json { render json: @annotation.errors, status: :unprocessable_entity }
16
+ end
17
+ end
18
+ end
19
+
20
+ # GET /annotations/1
21
+ def show
22
+ end
23
+
24
+ # PATCH/PUT /annotations/1
25
+ def update
26
+ format_client_input_to_rails_convention_for_update
27
+ respond_to do |format|
28
+ if @annotation.update(annotation_params)
29
+ format.json { render :show, status: :ok, location: annotation_url(@annotation) }
30
+ else
31
+ format.json { render json: @annotation.errors, status: :unprocessable_entity }
32
+ end
33
+ end
34
+ end
35
+
36
+ # DELETE /annotations/1
37
+ def destroy
38
+ @annotation.destroy
39
+ respond_to do |format|
40
+ format.json { head :no_content, status: :no_content }
41
+ end
42
+ end
43
+
44
+ # OPTIONS /annotations
45
+ def options
46
+ respond_to do |format|
47
+ format.json { render :options }
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ # Use callbacks to share common setup or constraints between actions.
54
+ def set_annotation
55
+ @annotation = Annotation.find(params[:id])
56
+ end
57
+
58
+ # Convert the data sent by AnnotatorJS to the format that Rails expects so
59
+ # that we are able to create a proper params object
60
+ def format_client_input_to_rails_convention_for_create
61
+ params[:annotation] = {}
62
+ params[:annotation][:version] = params[:annotator_schema_version] unless params[:annotator_schema_version].blank?
63
+ params[:annotation][:text] = params[:text] unless params[:text].blank?
64
+ params[:annotation][:quote] = params[:quote] unless params[:quote].blank?
65
+ params[:annotation][:uri] = params[:uri] unless params[:uri].blank?
66
+ params[:annotation][:ranges_attributes] = params[:ranges].map do |r|
67
+ range = {}
68
+ range[:start] = r[:start]
69
+ range[:end] = r[:end]
70
+ range[:start_offset] = r[:startOffset]
71
+ range[:end_offset] = r[:endOffset]
72
+ range
73
+ end unless params[:ranges].blank?
74
+ end
75
+
76
+ # Convert the data sent by AnnotatorJS to the format that Rails expects so
77
+ # that we are able to create a proper params object
78
+ def format_client_input_to_rails_convention_for_update
79
+ params[:annotation] = {}
80
+ params[:annotation][:version] = params[:annotator_schema_version] unless params[:annotator_schema_version].blank?
81
+ params[:annotation][:text] = params[:text] unless params[:text].blank?
82
+ params[:annotation][:quote] = params[:quote] unless params[:quote].blank?
83
+ params[:annotation][:uri] = params[:uri] unless params[:uri].blank?
84
+ end
85
+
86
+ # Only allow a trusted parameter 'white list' through.
87
+ def annotation_params
88
+ params.require(:annotation).permit(
89
+ :text,
90
+ :quote,
91
+ :uri,
92
+ :version,
93
+ ranges_attributes: [:start, :end, :start_offset, :end_offset]
94
+ )
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,15 @@
1
+ module AnnotatorStore
2
+ class ApplicationController < ActionController::Base
3
+ before_action :set_headers
4
+
5
+ private
6
+
7
+ def set_headers
8
+ headers['Access-Control-Allow-Origin'] = '*'
9
+ headers['Access-Control-Expose-Headers'] = 'ETag'
10
+ headers['Access-Control-Allow-Methods'] = 'GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD'
11
+ headers['Access-Control-Allow-Headers'] = '*,x-requested-with,Content-Type,If-Modified-Since,If-None-Match'
12
+ headers['Access-Control-Max-Age'] = '86400'
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ module AnnotatorStore
2
+ class PagesController < ApplicationController
3
+ before_action :format_input, only: [:search]
4
+
5
+ def index
6
+ end
7
+
8
+ def search
9
+ @annotations = AnnotatorStore::Annotation.where(search_params)
10
+ @total = @annotations.size
11
+ end
12
+
13
+ private
14
+
15
+ def format_input
16
+ params[:search] = {}
17
+ params[:search][:uri] = params[:uri]
18
+ end
19
+
20
+ def search_params
21
+ params.require(:search).permit(:uri)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,4 @@
1
+ module AnnotatorStore
2
+ module AnnotationsHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module AnnotatorStore
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,16 @@
1
+ module AnnotatorStore
2
+ class Annotation < ActiveRecord::Base
3
+ # Associations
4
+ has_many :ranges, dependent: :destroy, autosave: true
5
+
6
+ # Allow saving of attributes on associated records through the parent,
7
+ # :autosave option is automatically enabled on every association
8
+ accepts_nested_attributes_for :ranges
9
+
10
+ # Validations
11
+ validates :version, presence: true
12
+ validates :text, presence: true
13
+ validates :quote, presence: true
14
+ validates :uri, presence: true
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ module AnnotatorStore
2
+ class Range < ActiveRecord::Base
3
+ # Associations
4
+ belongs_to :annotation
5
+
6
+ # Validations
7
+ validates :start, presence: true
8
+ validates :end, presence: true
9
+ validates :start_offset, presence: true
10
+ validates :end_offset, presence: true
11
+ end
12
+ end
@@ -0,0 +1,23 @@
1
+ json.id annotation.id
2
+
3
+ # Version
4
+ json.annotator_schema_version annotation.version
5
+
6
+ # Meta
7
+ json.uri annotation.uri
8
+
9
+ # Content
10
+ json.text annotation.text
11
+ json.quote annotation.quote
12
+ json.ranges do
13
+ json.array! annotation.ranges do |range|
14
+ json.start range.start
15
+ json.end range.end
16
+ json.startOffset range.start_offset
17
+ json.endOffset range.end_offset
18
+ end
19
+ end
20
+
21
+ # Timestamps
22
+ json.created annotation.created_at
23
+ json.updated annotation.updated_at
@@ -0,0 +1 @@
1
+ json.approved true
@@ -0,0 +1 @@
1
+ json.partial! 'annotator_store/annotations/annotation', annotation: @annotation, as: :annotation
@@ -0,0 +1,31 @@
1
+ json.name 'Annotator Store API'
2
+ json.version '2.0.0'
3
+ json.links do
4
+ json.annotation do
5
+ json.create do
6
+ json.url annotator_store.annotations_url
7
+ json.method 'POST'
8
+ json.description 'Create or add new annotations.'
9
+ end
10
+ json.read do
11
+ json.url annotator_store.annotation_url(':id')
12
+ json.method 'GET'
13
+ json.description 'Read, retrieve or view existing annotation.'
14
+ end
15
+ json.update do
16
+ json.url annotator_store.annotation_url(':id')
17
+ json.method 'PUT/PATCH'
18
+ json.description 'Update or edit existing annotation.'
19
+ end
20
+ json.delete do
21
+ json.url annotator_store.annotation_url(':id')
22
+ json.method 'DELETE'
23
+ json.description 'Delete or deactivate existing annotation.'
24
+ end
25
+ end
26
+ json.search do
27
+ json.url annotator_store.search_url
28
+ json.method 'GET'
29
+ json.description 'Search for annotations'
30
+ end
31
+ end
@@ -0,0 +1,4 @@
1
+ json.total @total
2
+ json.rows do
3
+ json.array! @annotations, partial: 'annotator_store/annotations/annotation', as: :annotation
4
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>AnnotatorStore</title>
5
+ <%= stylesheet_link_tag "annotator_store/application", media: "all" %>
6
+ <%= javascript_include_tag "annotator_store/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,15 @@
1
+ AnnotatorStore::Engine.routes.draw do
2
+
3
+ # Root path
4
+ root 'pages#index', defaults: { format: :json }
5
+
6
+ # Search
7
+ match 'search', to: 'pages#search', via: [:get], defaults: { format: :json }, constraints: { format: :json }
8
+ match 'search', to: 'annotations#options', via: [:options], defaults: { format: :json }, constraints: { format: :json }
9
+
10
+ # Annotations Endpoint
11
+ resources :annotations, only: [:create, :show, :update, :destroy], defaults: { format: :json }, constraints: { format: :json } do
12
+ match '/', to: 'annotations#options', via: [:options], on: :collection
13
+ match '/', to: 'annotations#options', via: [:options], on: :member
14
+ end
15
+ end
@@ -0,0 +1,48 @@
1
+ # This migration executes differently depending on the database set via the DB
2
+ # environment variable. For PostgreSQL we use UUIDs ... for MySQL we use normal
3
+ # primary keys.
4
+ class CreateAnnotatorStore < ActiveRecord::Migration
5
+ def self.up
6
+ # If using PostgreSQL database these are extensions are necessary
7
+ database_type = ENV['DB'] || 'postgres'
8
+ if database_type == 'postgres'
9
+ enable_extension 'plpgsql' unless extension_enabled?('plpgsql')
10
+ enable_extension 'uuid-ossp' unless extension_enabled?('uuid-ossp')
11
+ options = { id: :uuid, default: 'uuid_generate_v4()' }
12
+ else
13
+ options = {}
14
+ end
15
+
16
+ # Table to store annotations
17
+ create_table :annotator_store_annotations, options do |t|
18
+ t.string :version # Schema version
19
+ t.text :text # Content of annotation
20
+ t.text :quote # The annotated text
21
+ t.string :uri # URI of annotated document
22
+ t.timestamps # Time created_at and updated_at
23
+ end
24
+
25
+ # Table to store ranges covered by an annotation since each annotation could
26
+ # have many ranges ... at least by design in annotator.js but not yet
27
+ # implemented. Since the associated annotation's primary could be a UUID, at
28
+ # least in the case of PostgreSQL, we'll have to apply some logic to cater
29
+ # for the different scenarios.
30
+ create_table :annotator_store_ranges do |t|
31
+ if database_type == 'postgres'
32
+ t.uuid :annotation_id, index: true # Associated annotation's UUID
33
+ else
34
+ t.references :annotation, index: true # Associated annotation's normal id
35
+ end
36
+ t.string :start # Relative XPath to start element
37
+ t.string :end # Relative XPath to end element
38
+ t.integer :start_offset # Character offset within start element
39
+ t.integer :end_offset # Character offset within end element
40
+ t.timestamps
41
+ end
42
+ end
43
+
44
+ def self.down
45
+ drop_table :annotator_store_annotations
46
+ drop_table :annotator_store_ranges
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ require 'annotator_store/engine'
2
+ require 'jbuilder'
3
+
4
+ module AnnotatorStore
5
+ end
@@ -0,0 +1,11 @@
1
+ module AnnotatorStore
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace AnnotatorStore
4
+
5
+ config.generators do |g|
6
+ g.integration_tool :rspec
7
+ g.test_framework :rspec, fixture: false
8
+ g.fixture_replacement :factory_girl, dir: 'spec/factories'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module AnnotatorStore
2
+ VERSION = '1.0.0.pre'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :annotator_store do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,212 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: annotator_store
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.pre
5
+ platform: ruby
6
+ authors:
7
+ - Job King'ori Maina
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mysql2
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pg
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: appraisal
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: database_cleaner
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: factory_girl_rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: faker
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: json-schema
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec-rails
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: jbuilder
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rails
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '4.0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '4.0'
153
+ description: Rails engine to implement a Ruby backend store implementation for Annotator,
154
+ an open-source JavaScript library to easily add annotation functionality to any
155
+ webpage.
156
+ email:
157
+ - j@kingori.co
158
+ executables: []
159
+ extensions: []
160
+ extra_rdoc_files: []
161
+ files:
162
+ - CHANGELOG.md
163
+ - CONTRIBUTING.md
164
+ - LICENSE.md
165
+ - README.md
166
+ - Rakefile
167
+ - app/assets/javascripts/annotator_store/application.js
168
+ - app/assets/stylesheets/annotator_store/application.css
169
+ - app/controllers/annotator_store/annotations_controller.rb
170
+ - app/controllers/annotator_store/application_controller.rb
171
+ - app/controllers/annotator_store/pages_controller.rb
172
+ - app/helpers/annotator_store/annotations_helper.rb
173
+ - app/helpers/annotator_store/application_helper.rb
174
+ - app/models/annotator_store/annotation.rb
175
+ - app/models/annotator_store/range.rb
176
+ - app/views/annotator_store/annotations/_annotation.json.jbuilder
177
+ - app/views/annotator_store/annotations/options.json.jbuilder
178
+ - app/views/annotator_store/annotations/show.json.jbuilder
179
+ - app/views/annotator_store/pages/index.json.jbuilder
180
+ - app/views/annotator_store/pages/search.json.jbuilder
181
+ - app/views/layouts/annotator_store/application.html.erb
182
+ - config/routes.rb
183
+ - db/migrate/20141013113654_create_annotator_store.rb
184
+ - lib/annotator_store.rb
185
+ - lib/annotator_store/engine.rb
186
+ - lib/annotator_store/version.rb
187
+ - lib/tasks/annotator_store_tasks.rake
188
+ homepage:
189
+ licenses:
190
+ - MIT
191
+ metadata: {}
192
+ post_install_message:
193
+ rdoc_options: []
194
+ require_paths:
195
+ - lib
196
+ required_ruby_version: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: 1.9.3
201
+ required_rubygems_version: !ruby/object:Gem::Requirement
202
+ requirements:
203
+ - - ">"
204
+ - !ruby/object:Gem::Version
205
+ version: 1.3.1
206
+ requirements: []
207
+ rubyforge_project:
208
+ rubygems_version: 2.2.2
209
+ signing_key:
210
+ specification_version: 4
211
+ summary: Rails engine to implement a Ruby backend store implementation for Annotator.
212
+ test_files: []