annotot 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 73ff37edcbe6076b7c13b627f604e810444a3ef2
4
+ data.tar.gz: 48dc1b3a6e082c65ad30059de75efef4795dd69e
5
+ SHA512:
6
+ metadata.gz: 3b9cd548ed28a8d7bea2fbff4012fcf5cc0325dd798c4af622479100b645a3d8b614187bb4b2e5177c9c1ca1726d80a2b0aba7661eb78772fae49f60ac295a36
7
+ data.tar.gz: 7b60a2cb545fcb9aae0a58a243f298bebc762fc39a50bd89ac0c567b878907f68cc0325d0a138d80138d6950dcbe42c10fc482f19277050a3e6605e64783eb9a
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ © 2018 The Board of Trustees of the Leland Stanford Junior University.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,55 @@
1
+ # Annotot
2
+ [![Build Status](https://travis-ci.org/mejackreed/annotot.svg?branch=master)](https://travis-ci.org/mejackreed/annotot)
3
+
4
+ Need to persist annotations quick and easily? Annotot, the original mini annotation API is for you. Don't annotate, annotot instead.
5
+
6
+ ![](annotot.png)
7
+
8
+ This logo, "Annotot", is a derivative of "[Sweet Potato Tator Tots](https://www.flickr.com/photos/flyfarther79/6270223411/)" by [Lisa Brettschneider](https://www.flickr.com/photos/flyfarther79/) used under [CC BY-NC 2.0](https://creativecommons.org/licenses/by-nc/2.0/). "Annotot" is also licensed under [CC BY-NC 2.0](https://creativecommons.org/licenses/by-nc/2.0/).
9
+
10
+ ## Usage
11
+
12
+ Annotot provides a simple RESTful endpoint for persisting annotations. Just configure your client to work with its endpoint.
13
+
14
+ For Mirador integration, you can use the provided `AnnototEndpoint`:
15
+
16
+ ```javascript
17
+ // Within Mirador creation options
18
+ ...
19
+ annotationEndpoint: {
20
+ name: 'Annotot',
21
+ module: 'AnnototEndpoint',
22
+ options: {
23
+ endpoint: 'https://www.annotot.biz/annotot/annotations'
24
+ }
25
+ },
26
+ ...
27
+ ```
28
+
29
+ If you want to configure Annotot to receive annotations from external sources make sure that you enable CORs in the Rails application. This can be done using [rack-cors](https://github.com/cyu/rack-cors).
30
+
31
+ ## Installation
32
+ Add this line to your application's Gemfile:
33
+
34
+ ```ruby
35
+ gem 'annotot'
36
+ ```
37
+
38
+ And then execute:
39
+ ```bash
40
+ $ bundle install
41
+ ```
42
+
43
+ Install the gem:
44
+ ```bash
45
+ $ rails g annotot:install
46
+ ```
47
+
48
+ If you are serving both Mirador and Annotot in the same application, the integration will be easier. You can just require the `annotot_endpoint.js` file.
49
+
50
+ ```javascript
51
+ //= require annotot/annotot_endpoint
52
+ ```
53
+
54
+ ## License
55
+ The gem is available as open source under the terms of the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0).
@@ -0,0 +1,17 @@
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
+ Bundler::GemHelper.install_tasks
7
+
8
+ require 'engine_cart/rake_task'
9
+ require 'rspec/core/rake_task'
10
+ RSpec::Core::RakeTask.new(:spec)
11
+
12
+ task ci: ['engine_cart:generate'] do
13
+ ENV['environment'] = 'test'
14
+ Rake::Task['spec'].invoke
15
+ end
16
+
17
+ task default: [:ci]
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts/annotot .js
2
+ //= link_directory ../stylesheets/annotot .css
@@ -0,0 +1,188 @@
1
+ /*
2
+ * annotationsList - current list of OA Annotations
3
+ * dfd - Deferred Object
4
+ * init()
5
+ * search(options, successCallback, errorCallback)
6
+ * create(oaAnnotation, successCallback, errorCallback)
7
+ * update(oaAnnotation, successCallback, errorCallback)
8
+ * deleteAnnotation(annotationID, successCallback, errorCallback)
9
+ *
10
+ * getAnnotationInOA(endpointAnnotation)
11
+ * getAnnotationInEndpoint(oaAnnotation)
12
+ */
13
+ (function($){
14
+
15
+ $.AnnototEndpoint = function(options) {
16
+
17
+ jQuery.extend(this, {
18
+ dfd: null,
19
+ annotationsList: [], // OA list for Mirador use
20
+ windowID: null,
21
+ eventEmitter: null
22
+ }, options);
23
+
24
+ this.init();
25
+ };
26
+
27
+ $.AnnototEndpoint.prototype = {
28
+ init: function() {},
29
+
30
+ // Search endpoint for all annotations with a given URI in options
31
+ search: function(options, successCallback, errorCallback) {
32
+ var _this = this;
33
+ _this.annotationsList = [];
34
+ options.format = 'json'
35
+
36
+ jQuery.ajax({
37
+ url: _this.endpoint,
38
+ type: 'GET',
39
+ dataType: 'json',
40
+ headers: { },
41
+ data: options, // options.uri contains the Canvas URI
42
+ contentType: "application/json; charset=utf-8",
43
+ success: function(data) {
44
+ if (typeof successCallback === "function") {
45
+ successCallback(data);
46
+ } else {
47
+ jQuery.each(data, function(index, value) {
48
+ value.endpoint = _this;
49
+ _this.annotationsList.push(_this.getAnnotationInOA(value));
50
+ });
51
+ _this.dfd.resolve(true);
52
+ }
53
+ },
54
+ error: function(data) {
55
+ if (typeof errorCallback === "function") {
56
+ errorCallback(data);
57
+ } else {
58
+ console.log("The request for annotations has caused an error for endpoint: " + options.uri);
59
+ }
60
+ }
61
+ });
62
+ },
63
+
64
+ // Delete an annotation by endpoint identifier
65
+ deleteAnnotation: function(annotationID, successCallback, errorCallback) {
66
+ var _this = this;
67
+ jQuery.ajax({
68
+ url: _this.endpoint + '/' + annotationID,
69
+ type: 'DELETE',
70
+ dataType: 'json',
71
+ headers: {
72
+ // 'X-CSRF-Token': _this.csrfToken()
73
+ },
74
+ contentType: "application/json; charset=utf-8",
75
+ success: function(data) {
76
+ if (typeof successCallback === "function") {
77
+ successCallback();
78
+ }
79
+ },
80
+ error: function(a, b) {
81
+ if (typeof errorCallback === "function") {
82
+ errorCallback();
83
+ }
84
+ }
85
+ });
86
+ },
87
+
88
+ // Update an annotation given the OA version
89
+ update: function(oaAnnotation, successCallback, errorCallback) {
90
+ var _this = this;
91
+ var annotation = _this.getAnnotationInEndpoint(oaAnnotation);
92
+
93
+ var annotationID = annotation.annotation['uuid'];
94
+
95
+ jQuery.ajax({
96
+ url: _this.endpoint + '/' + annotationID,
97
+ type: 'PATCH',
98
+ dataType: 'json',
99
+ headers: {
100
+ 'X-CSRF-Token': _this.csrfToken()
101
+ },
102
+ data: JSON.stringify(annotation),
103
+ contentType: "application/json; charset=utf-8",
104
+ success: function(data) {
105
+ if (typeof successCallback === "function") {
106
+ data.endpoint = _this;
107
+ successCallback(data);
108
+ }
109
+ },
110
+ error: function(a, b, c) {
111
+ if (typeof errorCallback === "function") {
112
+ errorCallback();
113
+ }
114
+ }
115
+ });
116
+ },
117
+
118
+ // Takes OA Annotation, gets Endpoint Annotation, and saves
119
+ // if successful, MUST return the OA rendering of the annotation
120
+ create: function(oaAnnotation, successCallback, errorCallback) {
121
+ var _this = this;
122
+ var annotation = _this.getAnnotationInEndpoint(oaAnnotation);
123
+ jQuery.ajax({
124
+ url: _this.endpoint,
125
+ type: 'POST',
126
+ headers: {
127
+ // 'X-CSRF-Token': _this.csrfToken()
128
+ },
129
+ data: JSON.stringify(annotation),
130
+ contentType: "application/json; charset=utf-8",
131
+ success: function(data) {
132
+ data.endpoint = _this;
133
+ if (typeof successCallback === "function") {
134
+ successCallback(_this.getAnnotationInOA(data));
135
+ }
136
+ },
137
+ error: function() {
138
+ if (typeof errorCallback === "function") {
139
+ errorCallback();
140
+ }
141
+ }
142
+ });
143
+ },
144
+
145
+ set: function(prop, value, options) {
146
+ if (options) {
147
+ this[options.parent][prop] = value;
148
+ } else {
149
+ this[prop] = value;
150
+ }
151
+ },
152
+
153
+ //Convert Endpoint annotation to OA
154
+ getAnnotationInOA: function(annotation) {
155
+ return annotation;
156
+ },
157
+
158
+ // Converts OA Annotation to endpoint format
159
+ getAnnotationInEndpoint: function(oaAnnotation) {
160
+ // Generate a new uuid if one is not present
161
+ if (oaAnnotation['@id'] == null) {
162
+ oaAnnotation["@id"] = Mirador.genUUID();
163
+ }
164
+
165
+ canvas = oaAnnotation.on[0].full;
166
+ var newAnno = jQuery.extend({}, oaAnnotation);
167
+ delete newAnno.endpoint
168
+ return {
169
+ annotation: {
170
+ uuid: oaAnnotation["@id"],
171
+ data: JSON.stringify(newAnno),
172
+ canvas: canvas
173
+ }
174
+ };
175
+ },
176
+
177
+ userAuthorize: function(action, annotation) {
178
+ return true; // allow all
179
+ },
180
+
181
+ csrfToken: function() {
182
+ // We need to monkey patch this since $ !== jQuery in Mirador context
183
+ return jQuery('meta[name=csrf-token]').attr('content');
184
+ },
185
+
186
+ };
187
+
188
+ }(Mirador));
@@ -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 any plugin's vendor/assets/javascripts directory 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. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,60 @@
1
+ require_dependency "annotot/application_controller"
2
+
3
+ module Annotot
4
+ class AnnotationsController < ApplicationController
5
+ before_action :set_annotation, only: %i[update destroy]
6
+
7
+ # GET /annotations
8
+ def index
9
+ @annotations = Annotation.where(canvas: annotation_search_params)
10
+ end
11
+
12
+ # POST /annotations
13
+ def create
14
+ @annotation = Annotation.new(annotation_params)
15
+
16
+ if @annotation.save
17
+ render json: @annotation.data
18
+ else
19
+ render status: :bad_request, json: {
20
+ message: 'An annotation could not be created'
21
+ }
22
+ end
23
+ end
24
+
25
+ # PATCH/PUT /annotations/1
26
+ def update
27
+ if @annotation.update(annotation_params)
28
+ render status: :ok, json: @annotation.data
29
+ else
30
+ render status: :bad_request, json: {
31
+ message: 'Annotation could not be updated.',
32
+ status: :bad_request
33
+ }
34
+ end
35
+ end
36
+
37
+ # DELETE /annotations/1
38
+ def destroy
39
+ @annotation.destroy
40
+ render status: :ok, json: {
41
+ message: 'Annotation was successfully destroyed.'
42
+ }
43
+ end
44
+
45
+ private
46
+
47
+ def set_annotation
48
+ @annotation = Annotation.find_by(id: params[:id]) || Annotation.find_by(uuid: params[:id])
49
+ raise ActiveRecord::RecordNotFound unless @annotation.present?
50
+ end
51
+
52
+ def annotation_params
53
+ params.require(:annotation).permit(:uuid, :data, :canvas)
54
+ end
55
+
56
+ def annotation_search_params
57
+ params.require(:uri)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,5 @@
1
+ module Annotot
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Annotot
2
+ module AnnotationsHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Annotot
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Annotot
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module Annotot
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: 'from@example.com'
4
+ layout 'mailer'
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ module Annotot
2
+ class Annotation < ApplicationRecord
3
+ validates :uuid, presence: true, uniqueness: true
4
+ validates :canvas, presence: true
5
+
6
+ serialize :data, JSON
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Annotot
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ <%= @annotations.map{ |a| JSON.parse(a.data )}.to_json.html_safe %>
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Annotot</title>
5
+ <%= stylesheet_link_tag "annotot/application", media: "all" %>
6
+ <%= javascript_include_tag "annotot/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,3 @@
1
+ Annotot::Engine.routes.draw do
2
+ resources :annotations, except: %i[new edit show], defaults: { format: :json }
3
+ end
@@ -0,0 +1,11 @@
1
+ class CreateAnnototAnnotations < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :annotot_annotations do |t|
4
+ t.string :uuid, index: true
5
+ t.string :canvas, index: true
6
+ t.binary :data
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ require "annotot/engine"
2
+
3
+ module Annotot
4
+ # Your code goes here...
5
+ end
@@ -0,0 +1,5 @@
1
+ module Annotot
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Annotot
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Annotot
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,9 @@
1
+ module Annotot
2
+ ##
3
+ # Install generator
4
+ class Install < Rails::Generators::Base
5
+ def add_routes
6
+ route "mount Annotot::Engine => '/'"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :annotot do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: annotot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jack Reed
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-02-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.1.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.1.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: engine_cart
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: factory_bot_rails
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: rails-controller-testing
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: rspec-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: sqlite3
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
+ description: Annotot. Open annotations in Rails.
98
+ email:
99
+ - phillipjreed@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - LICENSE
105
+ - README.md
106
+ - Rakefile
107
+ - app/assets/config/annotot_manifest.js
108
+ - app/assets/javascripts/annotot/annotot_endpoint.js
109
+ - app/assets/javascripts/annotot/application.js
110
+ - app/controllers/annotot/annotations_controller.rb
111
+ - app/controllers/annotot/application_controller.rb
112
+ - app/helpers/annotot/annotations_helper.rb
113
+ - app/helpers/annotot/application_helper.rb
114
+ - app/jobs/annotot/application_job.rb
115
+ - app/mailers/annotot/application_mailer.rb
116
+ - app/models/annotot/annotation.rb
117
+ - app/models/annotot/application_record.rb
118
+ - app/views/annotot/annotations/index.json.erb
119
+ - app/views/layouts/annotot/application.html.erb
120
+ - config/routes.rb
121
+ - db/migrate/20180215183225_create_annotot_annotations.rb
122
+ - lib/annotot.rb
123
+ - lib/annotot/engine.rb
124
+ - lib/annotot/version.rb
125
+ - lib/generators/annotot/install_generator.rb
126
+ - lib/tasks/annotot_tasks.rake
127
+ homepage: https://github.com/mejackreed/annotot
128
+ licenses:
129
+ - Apache-2.0
130
+ metadata: {}
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 2.6.11
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: Annotot. Open annotations in Rails.
151
+ test_files: []