annotot 0.2.1 → 0.7.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.
- checksums.yaml +5 -5
- data/README.md +71 -1
- data/app/assets/javascripts/annotot/annotot_endpoint.js +10 -8
- data/app/controllers/annotot/annotations_controller.rb +13 -3
- data/app/controllers/annotot/application_controller.rb +1 -1
- data/app/models/annotot/annotation.rb +12 -0
- data/app/views/annotot/annotations/pages.json.jbuilder +4 -0
- data/app/views/annotot/annotations/show.json.erb +1 -0
- data/config/routes.rb +2 -1
- data/lib/annotot/version.rb +1 -1
- data/lib/generators/annotot/install_generator.rb +5 -0
- data/lib/tasks/annotot_tasks.rake +59 -4
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f30142a82474f3723a5d0e041a7b26bce696b1aa975d6b4dc3da81b7cc89ad43
|
4
|
+
data.tar.gz: 1f3d9a4ebb62364cb8ca4a2eea465abc6e4a461b397a61949afe4380c0c2f200
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bfbefc765005d29ab2ec2810941692a93a2d02111701c86648ba9e08efd4b21ee6f639ebf6ea209a185777e7b8020d013b1244c34dedbaff4a3b48ee5dd39421
|
7
|
+
data.tar.gz: 0a93107a49bf745413b4f515e6ceb072d62159f9c5d47919bf615b7b22eef27e4e1af984cf10ea647a0664491552f5f58dbcd666562a0bd3dccf784bf7442059
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
Need to persist annotations quick and easily? Annotot, the original mini annotation API is for you. Don't annotate, annotot instead.
|
5
5
|
|
6
|
-
h/t @
|
6
|
+
h/t [@eefahy](https://github.com/eefahy) for the inspiration and name
|
7
7
|
|
8
8
|

|
9
9
|
|
@@ -30,6 +30,76 @@ annotationEndpoint: {
|
|
30
30
|
|
31
31
|
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).
|
32
32
|
|
33
|
+
## API
|
34
|
+
|
35
|
+
Annotot by default mounts itself at `/`. Though [this can be changed](http://guides.rubyonrails.org/engines.html#mounting-the-engine). All API endpoints are relative to its mount location.
|
36
|
+
|
37
|
+
| Path / Url | HTTP Verb | Path | Controller#Action |
|
38
|
+
| --- | --- | --- | --- |
|
39
|
+
| [annotations_path](#annotationspath) | GET | /annotations(.:format) | annotot/annotations#index {:format=>:json} |
|
40
|
+
| | POST | /annotations(.:format) | annotot/annotations#create {:format=>:json} |
|
41
|
+
| [lists_annotations_path](#listsannotationspath) | GET | /annotations/lists(.:format) | annotot/annotations#lists {:format=>:json} |
|
42
|
+
| [annotation_path](#annotationpath) | PATCH | /annotations/:id(.:format) | annotot/annotations#update {:format=>:json} |
|
43
|
+
| | PUT | /annotations/:id(.:format) | annotot/annotations#update {:format=>:json}
|
44
|
+
| | DELETE | /annotations/:id(.:format) | annotot/annotations#destroy {:format=>:json}
|
45
|
+
|
46
|
+
---
|
47
|
+
|
48
|
+
### annotations_path
|
49
|
+
`GET` - Return annotations for a given canvas
|
50
|
+
|
51
|
+
Parameters:
|
52
|
+
|
53
|
+
| Name | Required? | Description |
|
54
|
+
| --- | --- | --- |
|
55
|
+
| uri | yes | Canvas uri for which to return annotations
|
56
|
+
|
57
|
+
`POST` - Create a new annotation
|
58
|
+
|
59
|
+
Parameters:
|
60
|
+
|
61
|
+
| Name | Required? | Description |
|
62
|
+
| --- | --- | --- |
|
63
|
+
| annotation | yes | object containing creation parameters
|
64
|
+
| annotation.uuid | no | uuid for annotation
|
65
|
+
| annotation.data | no | annotation body data as string
|
66
|
+
| annotation.canvas | no | canvas to place the annotation on
|
67
|
+
|
68
|
+
---
|
69
|
+
|
70
|
+
### lists_annotations_path
|
71
|
+
`GET` - Return an AnnotationList of annotations for a given canvas
|
72
|
+
|
73
|
+
Parameters:
|
74
|
+
|
75
|
+
| Name | Required? | Description |
|
76
|
+
| --- | --- | --- |
|
77
|
+
| uri | yes | Canvas uri for which to return annotations
|
78
|
+
|
79
|
+
---
|
80
|
+
|
81
|
+
### annotation_path
|
82
|
+
`PATCH`, `PUT` - Update an annotation
|
83
|
+
|
84
|
+
Parameters:
|
85
|
+
|
86
|
+
| Name | Required? | Description |
|
87
|
+
| --- | --- | --- |
|
88
|
+
| id | yes | Canvas uri or Rails ActiveRecord id for annotation to update
|
89
|
+
| annotation | yes | object containing creation parameters
|
90
|
+
| annotation.uuid | no | uuid for annotation
|
91
|
+
| annotation.data | no | annotation body data as string
|
92
|
+
| annotation.canvas | no | canvas to place the annotation on
|
93
|
+
|
94
|
+
`DELETE` - Delete an annotation
|
95
|
+
|
96
|
+
Parameters:
|
97
|
+
|
98
|
+
| Name | Required? | Description |
|
99
|
+
| --- | --- | --- |
|
100
|
+
| id | yes | Canvas uri or Rails ActiveRecord id for annotation to delete
|
101
|
+
|
102
|
+
|
33
103
|
## Installation
|
34
104
|
Add this line to your application's Gemfile:
|
35
105
|
|
@@ -31,7 +31,7 @@
|
|
31
31
|
search: function(options, successCallback, errorCallback) {
|
32
32
|
var _this = this;
|
33
33
|
_this.annotationsList = [];
|
34
|
-
options.format = 'json'
|
34
|
+
options.format = 'json';
|
35
35
|
|
36
36
|
jQuery.ajax({
|
37
37
|
url: _this.endpoint,
|
@@ -65,7 +65,7 @@
|
|
65
65
|
deleteAnnotation: function(annotationID, successCallback, errorCallback) {
|
66
66
|
var _this = this;
|
67
67
|
jQuery.ajax({
|
68
|
-
url: _this.endpoint + '/' + annotationID,
|
68
|
+
url: _this.endpoint + '/' + encodeURIComponent(annotationID),
|
69
69
|
type: 'DELETE',
|
70
70
|
dataType: 'json',
|
71
71
|
headers: {
|
@@ -89,11 +89,11 @@
|
|
89
89
|
update: function(oaAnnotation, successCallback, errorCallback) {
|
90
90
|
var _this = this;
|
91
91
|
var annotation = _this.getAnnotationInEndpoint(oaAnnotation);
|
92
|
-
|
93
|
-
var annotationID = annotation.annotation
|
92
|
+
|
93
|
+
var annotationID = annotation.annotation.uuid;
|
94
94
|
|
95
95
|
jQuery.ajax({
|
96
|
-
url: _this.endpoint + '/' + annotationID,
|
96
|
+
url: _this.endpoint + '/' + encodeURIComponent(annotationID),
|
97
97
|
type: 'PATCH',
|
98
98
|
dataType: 'json',
|
99
99
|
headers: {
|
@@ -158,13 +158,15 @@
|
|
158
158
|
// Converts OA Annotation to endpoint format
|
159
159
|
getAnnotationInEndpoint: function(oaAnnotation) {
|
160
160
|
// Generate a new uuid if one is not present
|
161
|
-
|
161
|
+
// condition needs to be set to check for "falsy" values
|
162
|
+
// !oaAnnotation['@id'] should match null and undefined
|
163
|
+
if (!oaAnnotation['@id']) {
|
162
164
|
oaAnnotation["@id"] = Mirador.genUUID();
|
163
165
|
}
|
164
|
-
|
166
|
+
|
165
167
|
canvas = oaAnnotation.on[0].full;
|
166
168
|
var newAnno = jQuery.extend({}, oaAnnotation);
|
167
|
-
delete newAnno.endpoint
|
169
|
+
delete newAnno.endpoint;
|
168
170
|
return {
|
169
171
|
annotation: {
|
170
172
|
uuid: oaAnnotation["@id"],
|
@@ -2,18 +2,26 @@ require_dependency "annotot/application_controller"
|
|
2
2
|
|
3
3
|
module Annotot
|
4
4
|
class AnnotationsController < ApplicationController
|
5
|
-
before_action :set_annotation, only: %i[update destroy]
|
5
|
+
before_action :set_annotation, only: %i[update destroy show]
|
6
6
|
|
7
7
|
# GET /annotations
|
8
8
|
def index
|
9
9
|
@annotations = Annotation.where(canvas: annotation_search_params)
|
10
10
|
end
|
11
11
|
|
12
|
+
# GET /annotations
|
13
|
+
def show; end
|
14
|
+
|
12
15
|
# Get /annotations/lists
|
13
16
|
def lists
|
14
17
|
@annotations = Annotation.where(canvas: annotation_search_params)
|
15
18
|
end
|
16
19
|
|
20
|
+
# Get /annotations/pages
|
21
|
+
def pages
|
22
|
+
@annotations = Annotation.where(canvas: annotation_search_params)
|
23
|
+
end
|
24
|
+
|
17
25
|
# POST /annotations
|
18
26
|
def create
|
19
27
|
@annotation = Annotation.new(annotation_params)
|
@@ -50,7 +58,9 @@ module Annotot
|
|
50
58
|
private
|
51
59
|
|
52
60
|
def set_annotation
|
53
|
-
@annotation = Annotation.
|
61
|
+
@annotation = Annotot::Annotation.retrieve_by_id_or_uuid(
|
62
|
+
CGI.unescape(params[:id])
|
63
|
+
)
|
54
64
|
raise ActiveRecord::RecordNotFound unless @annotation.present?
|
55
65
|
end
|
56
66
|
|
@@ -59,7 +69,7 @@ module Annotot
|
|
59
69
|
end
|
60
70
|
|
61
71
|
def annotation_search_params
|
62
|
-
params.require(:uri)
|
72
|
+
CGI.unescape(params.require(:uri))
|
63
73
|
end
|
64
74
|
end
|
65
75
|
end
|
@@ -4,5 +4,17 @@ module Annotot
|
|
4
4
|
validates :canvas, presence: true
|
5
5
|
|
6
6
|
serialize :data, JSON
|
7
|
+
|
8
|
+
##
|
9
|
+
# Used to differentiate between a numeric id and a uuid. Rails will trim a
|
10
|
+
# uuid with leading numbers eg '123a'.to_i => 123
|
11
|
+
# @param [String] identifier
|
12
|
+
def self.retrieve_by_id_or_uuid(identifier)
|
13
|
+
if identifier =~ /\A\d+\z/
|
14
|
+
find_by(id: identifier)
|
15
|
+
else
|
16
|
+
find_by(uuid: identifier)
|
17
|
+
end
|
18
|
+
end
|
7
19
|
end
|
8
20
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= JSON.parse(@annotation.data).to_json.html_safe %>
|
data/config/routes.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
Annotot::Engine.routes.draw do
|
2
|
-
resources :annotations, except: %i[new edit
|
2
|
+
resources :annotations, path: '/', except: %i[new edit], defaults: { format: :json } do
|
3
3
|
collection do
|
4
4
|
get 'lists'
|
5
|
+
get 'pages'
|
5
6
|
end
|
6
7
|
end
|
7
8
|
end
|
data/lib/annotot/version.rb
CHANGED
@@ -1,4 +1,59 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require 'json'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
namespace :annotot do
|
5
|
+
desc 'Import annotation list from path'
|
6
|
+
task :import_file, [:url_path] => :environment do |_t, args|
|
7
|
+
path = Pathname.new(args.url_path)
|
8
|
+
puts "Importing annotations from #{path}"
|
9
|
+
anno_list = JSON.parse(File.read(path))
|
10
|
+
puts "#{anno_list['resources'].length} resources found"
|
11
|
+
touch_count = 0
|
12
|
+
anno_list['resources'].map do |resource|
|
13
|
+
uuid = resource['@id']
|
14
|
+
selector = resource['on'].first['selector']
|
15
|
+
canvas = resource['on'].first['full']
|
16
|
+
|
17
|
+
##
|
18
|
+
# Annotation appears to be Mirador 2.6.0 compatible
|
19
|
+
if resource['on'].first['@type'] == 'oa:SpecificResource' && selector['@type'] == 'oa:Choice'
|
20
|
+
if selector['default']['@type'] == 'oa:FragmentSelector' && selector['item']['@type'] == 'oa:SvgSelector'
|
21
|
+
touch_count += 1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Annotation needs to be updated to a single fragment selector
|
27
|
+
if resource['on'].first['@type'] == 'oa:SpecificResource' && selector['@type'] == 'oa:FragmentSelector'
|
28
|
+
new_on = "#{canvas}##{selector['value']}"
|
29
|
+
resource['on'] = new_on
|
30
|
+
touch_count += 1
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Annotation only has an SvgSelector and in an non-compliant format
|
35
|
+
if selector['@type'] == 'oa:SvgSelector'
|
36
|
+
item = selector.deep_dup
|
37
|
+
# Fix missing quotes in SVG
|
38
|
+
item['value'] = item['value'].gsub('xmlns=http://www.w3.org/2000/svg', 'xmlns="http://www.w3.org/2000/svg"')
|
39
|
+
selector['@type'] = 'oa:Choice'
|
40
|
+
selector['default'] = {
|
41
|
+
'@type' => 'oa:FragmentSelector',
|
42
|
+
'value' => 'xywh=0,0,0,0'
|
43
|
+
}
|
44
|
+
selector.delete('value')
|
45
|
+
selector['item'] = item
|
46
|
+
resource['on'].first['selector'] = selector.deep_dup
|
47
|
+
touch_count += 1
|
48
|
+
end
|
49
|
+
|
50
|
+
anno_json = resource.to_json
|
51
|
+
anno = Annotot::Annotation.find_or_create_by(uuid: uuid)
|
52
|
+
anno.update!(
|
53
|
+
canvas: canvas,
|
54
|
+
data: anno_json
|
55
|
+
)
|
56
|
+
end
|
57
|
+
puts "Updated #{touch_count} annotations"
|
58
|
+
end
|
59
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: annotot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jack Reed
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 5.1
|
19
|
+
version: '5.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 5.1
|
26
|
+
version: '5.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: engine_cart
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -117,6 +117,8 @@ files:
|
|
117
117
|
- app/models/annotot/application_record.rb
|
118
118
|
- app/views/annotot/annotations/index.json.erb
|
119
119
|
- app/views/annotot/annotations/lists.json.jbuilder
|
120
|
+
- app/views/annotot/annotations/pages.json.jbuilder
|
121
|
+
- app/views/annotot/annotations/show.json.erb
|
120
122
|
- app/views/layouts/annotot/application.html.erb
|
121
123
|
- config/routes.rb
|
122
124
|
- db/migrate/20180215183225_create_annotot_annotations.rb
|
@@ -144,8 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
146
|
- !ruby/object:Gem::Version
|
145
147
|
version: '0'
|
146
148
|
requirements: []
|
147
|
-
|
148
|
-
rubygems_version: 2.6.11
|
149
|
+
rubygems_version: 3.1.2
|
149
150
|
signing_key:
|
150
151
|
specification_version: 4
|
151
152
|
summary: Annotot. Open annotations in Rails.
|