Skip to content

Commit

Permalink
Text annotation functions
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexanderWatzinger committed Sep 16, 2024
1 parent b4f3468 commit a2d7079
Show file tree
Hide file tree
Showing 9 changed files with 234 additions and 40 deletions.
8 changes: 4 additions & 4 deletions openatlas/api/endpoints/iiif.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from openatlas.api.resources.api_entity import ApiEntity
from openatlas.api.resources.util import get_license_url, get_license_name
from openatlas.models.annotation import Annotation
from openatlas.models.annotation import AnnotationImage
from openatlas.models.entity import Entity


Expand Down Expand Up @@ -111,7 +111,7 @@ def get(image_id: int) -> Response:

@staticmethod
def build_annotation_list(image_id: int) -> dict[str, Any]:
annotations_ = Annotation.get_by_file(image_id)
annotations_ = AnnotationImage.get_by_file(image_id)
return {
"@context": "https://iiif.io/api/presentation/2/context.json",
"@id": url_for(
Expand All @@ -129,10 +129,10 @@ class IIIFAnnotation(Resource):
def get(annotation_id: int) -> Response:
return jsonify(
IIIFAnnotation.build_annotation(
Annotation.get_by_id(annotation_id)))
AnnotationImage.get_by_id(annotation_id)))

@staticmethod
def build_annotation(annotation: Annotation) -> dict[str, Any]:
def build_annotation(annotation: AnnotationImage) -> dict[str, Any]:
entity_link = ''
if annotation.entity_id:
entity = ApiEntity.get_by_id(annotation.entity_id)
Expand Down
74 changes: 64 additions & 10 deletions openatlas/database/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from flask import g

SELECT = """
ANNOTATION_IMAGE_SELECT = \
"""
SELECT
id,
image_id,
Expand All @@ -14,20 +15,50 @@
FROM web.annotation_image
"""

ANNOTATION_TEXT_SELECT = \
"""
SELECT
id,
source_id,
entity_id,
link_start,
link_end,
user_id,
text,
created
FROM web.annotation_text
"""

def get_by_id(id_: int) -> dict[str, Any]:
g.cursor.execute(SELECT + ' WHERE id = %(id)s;', {'id': id_})

def get_annotation_image_by_id(id_: int) -> dict[str, Any]:
g.cursor.execute(
ANNOTATION_IMAGE_SELECT + ' WHERE id = %(id)s;',
{'id': id_})
return dict(g.cursor.fetchone()) if g.cursor.rowcount else {}


def get_annotation_text_by_id(id_: int) -> dict[str, Any]:
g.cursor.execute(
ANNOTATION_TEXT_SELECT + ' WHERE id = %(id)s;',
{'id': id_})
return dict(g.cursor.fetchone()) if g.cursor.rowcount else {}


def get_by_file(image_id: int) -> list[dict[str, Any]]:
def get_annotation_image_by_file(image_id: int) -> list[dict[str, Any]]:
g.cursor.execute(
SELECT + ' WHERE image_id = %(image_id)s;',
ANNOTATION_IMAGE_SELECT + ' WHERE image_id = %(image_id)s;',
{'image_id': image_id})
return [dict(row) for row in g.cursor.fetchall()]


def get_orphaned_annotations() -> list[dict[str, Any]]:
def get_annotation_text_by_source(source_id: int) -> list[dict[str, Any]]:
g.cursor.execute(
ANNOTATION_TEXT_SELECT + ' WHERE source_id = %(source_id)s;',
{'source_id': source_id})
return [dict(row) for row in g.cursor.fetchall()]


def get_annotation_image_orphans() -> list[dict[str, Any]]:
g.cursor.execute(
"""
SELECT
Expand All @@ -47,7 +78,7 @@ def get_orphaned_annotations() -> list[dict[str, Any]]:
return [dict(row) for row in g.cursor.fetchall()]


def insert(data: dict[str, Any]) -> None:
def insert_annotation_image(data: dict[str, Any]) -> None:
g.cursor.execute(
"""
INSERT INTO web.annotation_image (
Expand All @@ -66,7 +97,7 @@ def insert(data: dict[str, Any]) -> None:
data)


def update(data: dict[str, Any]) -> None:
def update_annotation_image(data: dict[str, Any]) -> None:
g.cursor.execute(
"""
UPDATE web.annotation_image
Expand All @@ -76,17 +107,40 @@ def update(data: dict[str, Any]) -> None:
data)


def delete(id_: int) -> None:
def delete_annotation_image(id_: int) -> None:
g.cursor.execute(
'DELETE FROM web.annotation_image WHERE id = %(id)s;',
{'id': id_})


def remove_entity(annotation_id: int, entity_id: int) -> None:
def remove_entity_from_annotation_image(
annotation_id: int,
entity_id: int) -> None:
g.cursor.execute(
"""
UPDATE web.annotation_image
SET entity_id = NULL
WHERE id = %(annotation_id)s AND entity_id = %(entity_id)s;
""",
{'annotation_id': annotation_id, 'entity_id': entity_id})


def insert_annotation_text(data: dict[str, Any]) -> None:
g.cursor.execute(
"""
INSERT INTO web.annotation_text (
source_id,
entity_id,
link_start,
link_end,
user_id,
text
) VALUES (
%(source_id)s,
%(entity_id)s,
%(link_start)s,
%(link_end)s,
%(user_id)s,
%(text)s);
""",
data)
6 changes: 6 additions & 0 deletions openatlas/display/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,12 @@ class SourceDisplay(BaseDisplay):
def add_button_network(self) -> None:
pass

def add_button_others(self) -> None:
self.buttons.append(
button(
_('annotation'),
url_for('annotation_text_insert', id_=self.entity.id)))

def add_data(self) -> None:
super().add_data()
self.data[_('artifact')] = [
Expand Down
22 changes: 20 additions & 2 deletions openatlas/forms/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ class Form(FlaskForm):
return Form()


def get_annotation_form(
def get_annotation_image_form(
image_id: int,
entity: Optional[Entity] = None,
insert: Optional[bool] = True) -> FlaskForm:
insert: Optional[bool] = True) -> Any:
class Form(FlaskForm):
text = TextAreaField(_('annotation'))
if insert:
Expand All @@ -82,6 +82,24 @@ class Form(FlaskForm):
return Form()


def get_annotation_text_form(
source_id: int,
entity: Optional[Entity] = None,
insert: Optional[bool] = True) -> Any:
class Form(FlaskForm):
text = TextAreaField(_('annotation'))
if insert:
pass
setattr(
Form,
'entity',
TableField(
Entity.get_by_id(source_id).get_linked_entities('P67', sort=True),
entity))
setattr(Form, 'save', SubmitField(_('save')))
return Form()


def get_table_form(classes: list[str], excluded: list[int]) -> str:
entities = Entity.get_by_class(classes, types=True, aliases=True)
table = Table([''] + g.table_headers[classes[0]], order=[[2, 'asc']])
Expand Down
84 changes: 73 additions & 11 deletions openatlas/models/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from openatlas.database import annotation as db


class Annotation:
class AnnotationImage:
def __init__(self, data: dict[str, Any]) -> None:
self.id = data['id']
self.image_id = data['image_id']
Expand All @@ -21,38 +21,100 @@ def update(
self,
entity_id: Optional[int] = None,
text: Optional[str] = None) -> None:
db.update({'id': self.id, 'entity_id': entity_id, 'text': text})
db.update_annotation_image({
'id': self.id,
'entity_id': entity_id,
'text': text})

def delete(self) -> None:
db.delete(self.id)
db.delete_annotation_image(self.id)

@staticmethod
def get_by_id(id_: int) -> Annotation:
return Annotation(db.get_by_id(id_))
def get_by_id(id_: int) -> AnnotationImage:
return AnnotationImage(db.get_annotation_image_by_id(id_))

@staticmethod
def get_by_file(image_id: int) -> list[Annotation]:
return [Annotation(row) for row in db.get_by_file(image_id)]
def get_by_file(image_id: int) -> list[AnnotationImage]:
return [
AnnotationImage(row) for row
in db.get_annotation_image_by_file(image_id)]

@staticmethod
def get_orphaned_annotations() -> list[Annotation]:
return [Annotation(row) for row in db.get_orphaned_annotations()]
def get_orphaned_annotations() -> list[AnnotationImage]:
return [
AnnotationImage(row) for row in db.get_annotation_image_orphans()]

@staticmethod
def remove_entity_from_annotation(
annotation_id: int,
entity_id: int) -> None:
db.remove_entity(annotation_id, entity_id)
db.remove_entity_from_annotation_image(annotation_id, entity_id)

@staticmethod
def insert(
image_id: int,
coordinates: str,
entity_id: Optional[int] = None,
text: Optional[str] = None) -> None:
db.insert({
db.insert_annotation_image({
'image_id': image_id,
'user_id': current_user.id,
'entity_id': entity_id or None,
'coordinates': coordinates,
'text': text})


class AnnotationText:
def __init__(self, data: dict[str, Any]) -> None:
self.id = data['id']
self.source_id = data['source_id']
self.entity_id = data['entity_id']
self.link_start = data['link_start']
self.link_start = data['link_end']
self.user_id = data['user_id']
self.text = data['text']
self.created = data['created']

# def update(
# self,
# entity_id: Optional[int] = None,
# text: Optional[str] = None) -> None:
# db.update_annotation_image({
# 'id': self.id,
# 'entity_id': entity_id,
# 'text': text})
#
# def delete(self) -> None:
# db.delete_annotation_image(self.id)
#
# @staticmethod
# def get_by_id(id_: int) -> AnnotationText:
# return AnnotationText(db.get_annotation_image_by_id(id_))
#

@staticmethod
def get_by_source(source_id: int) -> list[AnnotationText]:
return [
AnnotationText(row) for row
in db.get_annotation_text_by_source(source_id)]
#
# @staticmethod
# def remove_entity_from_annotation(
# annotation_id: int,
# entity_id: int) -> None:
# db.remove_entity_from_annotation_image(annotation_id, entity_id)

@staticmethod
def insert(
source_id: int,
link_start: int,
link_end: int,
entity_id: Optional[int] = None,
text: Optional[str] = None) -> None:
db.insert_annotation_text({
'source_id': source_id,
'user_id': current_user.id,
'entity_id': entity_id or None,
'link_start': link_start,
'link_end': link_end,
'text': text})
File renamed without changes.
1 change: 1 addition & 0 deletions openatlas/templates/annotate_text.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Annotate text
8 changes: 4 additions & 4 deletions openatlas/views/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
ApiForm, ContentForm, FrontendForm, GeneralForm, LogForm, MailForm,
MapForm, ModulesForm, SimilarForm, TestMailForm)
from openatlas.forms.util import get_form_settings, set_form_settings
from openatlas.models.annotation import Annotation
from openatlas.models.annotation import AnnotationImage
from openatlas.models.checks import (
entities_linked_to_itself, invalid_cidoc_links, invalid_dates,
orphaned_subunits, orphans as get_orphans, similar_named,
Expand Down Expand Up @@ -563,7 +563,7 @@ def orphans() -> str:
if is_authorized('editor') else ''])

# Orphaned annotations
for annotation in Annotation.get_orphaned_annotations():
for annotation in AnnotationImage.get_orphaned_annotations():
file = Entity.get_by_id(annotation.image_id)
entity = Entity.get_by_id(annotation.entity_id)
tabs['orphaned_annotations'].table.rows.append([
Expand Down Expand Up @@ -650,7 +650,7 @@ def admin_file_delete(filename: str) -> Response:
@app.route('/admin/annotation/delete/<int:id_>')
@required_group('editor')
def admin_annotation_delete(id_: int) -> Response:
annotation = Annotation.get_by_id(id_)
annotation = AnnotationImage.get_by_id(id_)
annotation.delete()
flash(_('annotation deleted'), 'info')
return redirect(f"{url_for('orphans')}#tab-orphaned-annotations")
Expand All @@ -671,7 +671,7 @@ def admin_annotation_relink(image_id: int, entity_id: int) -> Response:
def admin_annotation_remove_entity(
annotation_id: int,
entity_id: int) -> Response:
Annotation.remove_entity_from_annotation(annotation_id, entity_id)
AnnotationImage.remove_entity_from_annotation(annotation_id, entity_id)
flash(_('entity removed from annotation'), 'info')
return redirect(f"{url_for('orphans')}#tab-orphaned-annotations")

Expand Down
Loading

0 comments on commit a2d7079

Please sign in to comment.