Skip to content

Commit bb828a6

Browse files
authored
Merge branch 'spring-2024' into issue-26
2 parents 5dbd43b + 8198705 commit bb828a6

12 files changed

+112
-6
lines changed

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,12 @@ docs/_build/
5858

5959
# PyBuilder
6060
target/
61+
62+
# Cache dir
63+
cache/
64+
65+
# PyCharm
66+
.idea/
67+
68+
# Old folder from v2?
69+
media/

iiify/app.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from flask_caching import Cache
99
from iiif2 import iiif, web
1010
from .resolver import ia_resolver, create_manifest, create_manifest3, getids, collection, \
11-
purify_domain, cantaloupe_resolver, create_collection3, IsCollection
11+
purify_domain, cantaloupe_resolver, create_collection3, IsCollection, create_annotations
1212
from .configs import options, cors, approot, cache_root, media_root, \
1313
cache_expr, version, image_server, cache_timeouts
1414
from urllib.parse import quote
@@ -17,7 +17,7 @@
1717
app = Flask(__name__)
1818
# disabling sorting of the output json
1919
app.config['JSON_SORT_KEYS'] = False
20-
app.config['CACHE_TYPE'] = "FileSystemCache"
20+
app.config['CACHE_TYPE'] = "FileSystemCache" if os.environ.get("FLASK_CACHE_DISABLE", None) != "true" else "NullCache"
2121
app.config['CACHE_DIR'] = "cache"
2222
cors = CORS(app) if cors else None
2323
cache = Cache(app)
@@ -191,6 +191,11 @@ def manifest3(identifier):
191191
raise excpt
192192
# abort(404)
193193

194+
@app.route('/iiif/<version>/annotations/<identifier>/<fileName>/<canvas_no>.json')
195+
@cache.cached(timeout=cache_timeouts["long"], forced_update=cache_bust)
196+
def annnotations(version, identifier, fileName, canvas_no):
197+
domain = purify_domain(request.args.get('domain', request.url_root))
198+
return ldjsonify(create_annotations(version, identifier, fileName, canvas_no, domain=domain))
194199

195200
@app.route('/iiif/<identifier>/manifest.json')
196201
@cache.cached(timeout=cache_timeouts["long"], forced_update=cache_bust)

iiify/resolver.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from .configs import options, cors, approot, cache_root, media_root, apiurl, LINKS
88
from iiif_prezi3 import Manifest, config, Annotation, AnnotationPage,AnnotationPageRef, Canvas, Manifest, ResourceItem, ServiceItem, Choice, Collection, ManifestRef, CollectionRef
9+
910
from urllib.parse import urlparse, parse_qs, quote
1011
import json
1112
import math
@@ -751,16 +752,27 @@ def create_annotations(version, identifier, fileName, canvas_no, domain=None):
751752
words = page.findall(".//WORD")
752753
count = 1
753754
for word in words:
755+
# <WORD coords="444,1353,635,1294" x-confidence="10">[David </WORD>
756+
# <WORD coords="lx,by,rx,ty" x-confidence="10">[David </WORD>
757+
# x = lx
758+
# y = ty
759+
# w = rx - lx
760+
# h = by - ty
761+
(left_x, bottom_y, right_x, top_y) = word.attrib['coords'].split(',')
762+
x = left_x
763+
y = top_y
764+
width = int(right_x) - int(left_x)
765+
height = int(bottom_y) - int(top_y)
754766
annotationPage.items.append({
755767
"id": f"https://iiif.archive.org/iiif/{identifier}/canvas/{index}/anno/{count}",
756768
"type": "Annotation",
757-
"motivation": "commenting",
769+
"motivation": "supplementing",
758770
"body": {
759771
"type": "TextualBody",
760772
"format": "text/plain",
761773
"value": word.text
762774
},
763-
"target": f"https://iiif.archive.org/iiif/{identifier}${index}/canvas#xywh={word.attrib['coords']}"
775+
"target": f"https://iiif.archive.org/iiif/{identifier}${index}/canvas#xywh={x},{y},{width},{height}"
764776
})
765777
count += 1
766778

@@ -911,7 +923,6 @@ def cantaloupe_resolver(identifier):
911923

912924
#filename = next(f for f in files if f['source'].lower() == 'derivative' \
913925
# and f['name'].endswith('_jp2.zip'))['name']
914-
print("end of logic - filename:", filename)
915926
if filename:
916927
dirpath = filename[:-4]
917928
filepath = f"{fileIdentifier}_{leaf.zfill(4)}{extension}"

tests/test_annotations.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import unittest
2+
from flask.testing import FlaskClient
3+
from iiify.app import app
4+
5+
class TestAnnotations(unittest.TestCase):
6+
7+
def setUp(self) -> None:
8+
self.test_app = FlaskClient(app)
9+
10+
def test_v3_manifest_has_annotations(self):
11+
resp = self.test_app.get("/iiif/3/journalofexpedit00ford/manifest.json?recache=true")
12+
self.assertEqual(resp.status_code, 200)
13+
manifest = resp.json
14+
15+
count = 1
16+
for canvas in manifest['items']:
17+
self.assertTrue('annotations' in canvas, f"Expected annotations in canvas {canvas['id']}")
18+
annotations_url = f"https://localhost/iiif/3/annotations/journalofexpedit00ford/journalofexpedit00ford_djvu.xml/{count}.json"
19+
found=False
20+
for anno in canvas['annotations']:
21+
if anno['id'] == annotations_url:
22+
found=True
23+
self.assertFalse('items' in anno, "As a referenced AnnotationPage it shouldn't contain items.")
24+
self.assertTrue('type' in anno and anno['type'] == "AnnotationPage",f"Expected annotation page to have a type {anno}")
25+
26+
self.assertTrue(found, f"Expected to find {annotations_url} in {canvas['annotations']}")
27+
count += 1
28+
29+
def test_v3_annotations(self):
30+
resp = self.test_app.get("/iiif/3/annotations/journalofexpedit00ford/journalofexpedit00ford_djvu.xml/1.json?recache=true")
31+
self.assertEqual(resp.status_code, 200)
32+
annotations = resp.json
33+
34+
self.assertEqual(annotations['id'], "https://localhost/iiif/3/annotations/journalofexpedit00ford/journalofexpedit00ford_djvu.xml/1.json", "Unexpected id")
35+
self.assertEqual(annotations['@context'], "http://iiif.io/api/presentation/3/context.json", "Unexpected context")
36+
self.assertEqual(annotations['type'], "AnnotationPage", "Unexpected type, expected AnnotationPage")
37+
annotationList = annotations['items']
38+
self.assertEqual(len(annotationList), 6, "Unexpected number of annotations")
39+
40+
ids = []
41+
first=True
42+
for anno in annotationList:
43+
self.assertTrue(anno['id'] not in ids,"Duplicate ID: {anno['id']}")
44+
ids.append(anno['id'])
45+
self.assertEqual(anno['type'], "Annotation", "Expected type of Annotation")
46+
self.assertTrue("body" in anno and "target" in anno, "Body or target missing from annotation {anno}")
47+
self.assertEqual(anno['body']['type'], "TextualBody", "Expected body to be a TextualBody")
48+
self.assertEqual(anno['body']['format'], "text/plain", "Expected format to be a text/plain")
49+
self.assertEqual(anno['target'].split('#')[0], "https://iiif.archive.org/iiif/journalofexpedit00ford$0/canvas")
50+
if first:
51+
self.assertEqual(anno['target'].split('#')[1],"xywh=592,1742,460,118")
52+
self.assertEqual(anno['body']['value'],"JOURNAL ")
53+
54+
self.assertEqual(anno['motivation'], "supplementing", "Expected motivation of supplementing")
55+
first=False
56+
57+

tests/test_basic.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import os
2+
os.environ["FLASK_CACHE_DISABLE"] = "true"
3+
14
import unittest
25
from flask.testing import FlaskClient
36
from iiify.app import app
@@ -8,6 +11,7 @@ class TestBasic(unittest.TestCase):
811
def setUp(self) -> None:
912
self.test_app = FlaskClient(app)
1013

14+
1115
def test_documentation(self):
1216
resp = self.test_app.get("/iiif/documentation")
1317
self.assertEqual(resp.status_code, 200)

tests/test_cantaloupe_resolver.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import os
2+
os.environ["FLASK_CACHE_DISABLE"] = "true"
3+
14
import unittest
25
from iiify.resolver import cantaloupe_resolver
36

tests/test_collections.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import os
2+
os.environ["FLASK_ENV"] = "testing"
3+
14
import unittest
25
from flask.testing import FlaskClient
36
from iiify.app import app
4-
57
class TestCollections(unittest.TestCase):
68

79
def setUp(self) -> None:

tests/test_linking.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import os
2+
os.environ["FLASK_CACHE_DISABLE"] = "true"
3+
14
import unittest
25
from flask.testing import FlaskClient
36
from iiify.app import app

tests/test_manifests.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import os
2+
os.environ["FLASK_CACHE_DISABLE"] = "true"
3+
14
import unittest
25
from flask.testing import FlaskClient
36
from iiify.app import app

tests/test_manifests_v2.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import os
2+
os.environ["FLASK_CACHE_DISABLE"] = "true"
3+
14
import unittest
25
from flask.testing import FlaskClient
36
from iiify.app import app

0 commit comments

Comments
 (0)