Ejemplo n.º 1
0
def api_delete_speechparts_alignments(api_version, doc_id, user_id):
    from app.api.transcriptions.routes import get_reference_transcription

    forbid = forbid_if_nor_teacher_nor_admin_and_wants_user_data(
        current_app, user_id)
    if forbid:
        return forbid

    transcription = get_reference_transcription(doc_id)
    if transcription is None:
        return make_404(details="Transcription not found")

    try:
        # TRUNCATE
        for old_al in AlignmentDiscours.query.filter(
                AlignmentDiscours.transcription_id == transcription.id,
                AlignmentDiscours.user_id == user_id).all():
            db.session.delete(old_al)
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        print(str(e))
        return make_400(str(e))

    return make_200(data=[])
Ejemplo n.º 2
0
def api_get_alignment_translation_from_user(api_version, doc_id, user_id):
    from app.api.transcriptions.routes import get_reference_transcription
    from app.api.translations.routes import get_translation

    forbid = forbid_if_nor_teacher_nor_admin_and_wants_user_data(
        current_app, user_id)
    if forbid:
        return forbid

    transcription = get_reference_transcription(doc_id)
    if transcription is None:
        return make_404(details="No transcription available")

    translation = get_translation(doc_id=doc_id, user_id=user_id)
    if translation is None:
        return make_404(details="No translation available")

    alignments = AlignmentTranslation.query.filter(
        AlignmentTranslation.transcription_id == transcription.id,
        AlignmentTranslation.translation_id == translation.id).all()

    ptrs = [(a.ptr_transcription_start, a.ptr_transcription_end,
             a.ptr_translation_start, a.ptr_translation_end)
            for a in alignments]

    return make_200(data=ptrs)
Ejemplo n.º 3
0
def api_documents_transcriptions_alignments_discours(api_version,
                                                     doc_id,
                                                     user_id=None):
    """
    If user_id is None: get the reference translation (if any) to find the alignment
    :param api_version:
    :param doc_id:
    :param user_id:
    :return:
    """
    transcription = get_reference_transcription(doc_id)

    if transcription is None:
        return make_404()

    if user_id is None:
        user_id = transcription.user_id
    else:
        forbid = forbid_if_nor_teacher_nor_admin_and_wants_user_data(
            current_app, user_id)
        if forbid:
            return forbid

    alignments = AlignmentDiscours.query.filter(
        AlignmentDiscours.transcription_id == transcription.id,
        AlignmentDiscours.user_id == user_id).all()

    if len(alignments) == 0:
        return make_404()

    return make_200(data=[al.serialize() for al in alignments])
Ejemplo n.º 4
0
def api_delete_documents_transcriptions_alignments_images(
        api_version, doc_id, anno_id):
    """
    :param api_version:
    :param doc_id:
    :param user_id:
    :return:
    """
    transcription = get_reference_transcription(doc_id)

    if transcription is None:
        return make_404()

    manifest_url = Image.query.filter(
        Image.doc_id == doc_id).first().manifest_url

    alignments = AlignmentImage.query.filter(
        AlignmentImage.transcription_id == transcription.id,
        AlignmentImage.user_id == transcription.user_id,
        AlignmentImage.manifest_url == manifest_url,
        AlignmentImage.zone_id == anno_id).all()

    if len(alignments) > 0:
        try:
            for al in alignments:
                db.session.delete(al)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            print(str(e))
            return make_400(str(e))

    return make_200()
Ejemplo n.º 5
0
def api_post_translation_alignments(api_version, doc_id, user_id):
    """
        NB: Posting alignment has a 'TRUNCATE AND REPLACE' effect
    """
    from app.api.transcriptions.routes import get_reference_transcription
    from app.api.translations.routes import get_translation

    forbid = forbid_if_nor_teacher_nor_admin_and_wants_user_data(
        current_app, user_id)
    if forbid:
        return forbid

    transcription = get_reference_transcription(doc_id)
    if transcription is None:
        return make_404(details="Transcription not found")

    translation = get_translation(doc_id=doc_id, user_id=user_id)
    if translation is None:
        return make_404(details="Translation not found")

    data = request.get_json()
    data = data.get("data", [])
    ptrs = []
    try:
        # TRUNCATE
        for old_al in AlignmentTranslation.query.filter(
                AlignmentTranslation.transcription_id == transcription.id,
                AlignmentTranslation.translation_id == translation.id).all():
            db.session.delete(old_al)

        # INSERT
        for (ptr_transcription_start, ptr_transcription_end,
             ptr_translation_start, ptr_translation_end) in data:
            new_al = AlignmentTranslation(
                transcription_id=transcription.id,
                translation_id=translation.id,
                ptr_transcription_start=ptr_transcription_start,
                ptr_transcription_end=ptr_transcription_end,
                ptr_translation_start=ptr_translation_start,
                ptr_translation_end=ptr_translation_end)
            db.session.add(new_al)
            ptrs.append(
                (new_al.ptr_transcription_start, new_al.ptr_transcription_end,
                 new_al.ptr_translation_start, new_al.ptr_translation_end))

        db.session.commit()
    except Exception as e:
        db.session.rollback()
        print(str(e))
        return make_400(str(e))

    return make_200(data=ptrs)
Ejemplo n.º 6
0
def api_all_commentary(api_version, doc_id):
    if not get_doc(doc_id).is_transcription_validated:
        return make_403()

    tr = get_reference_transcription(doc_id)
    if tr is None:
        return make_404()

    commentaries = Commentary.query.filter(
        Commentary.doc_id == doc_id,
        Commentary.user_id == tr.user_id,
    ).all()

    return make_200(data=[c.serialize() for c in commentaries])
Ejemplo n.º 7
0
def get_reference_commentaries(doc_id, type_id=None):
    """

    :param type_id:
    :param doc_id:
    :return:
    """
    from app.api.transcriptions.routes import get_reference_transcription
    tr_ref = get_reference_transcription(doc_id)
    if tr_ref is None:
        return []

    if type_id is None:
        type_id = Commentary.type_id

    return Commentary.query.filter(doc_id == Commentary.doc_id,
                                   tr_ref.user_id == Commentary.user_id,
                                   type_id == Commentary.type_id).all()
Ejemplo n.º 8
0
def api_get_alignment_translation(api_version, doc_id):
    from app.api.transcriptions.routes import get_reference_transcription
    from app.api.translations.routes import get_reference_translation

    transcription = get_reference_transcription(doc_id)
    if transcription is None:
        return make_404(details="No transcription available")

    translation = get_reference_translation(doc_id)
    if translation is None:
        return make_404(details="No translation available")

    alignments = AlignmentTranslation.query.filter(
        AlignmentTranslation.transcription_id == transcription.id,
        AlignmentTranslation.translation_id == translation.id).all()

    ptrs = [(a.ptr_transcription_start, a.ptr_transcription_end,
             a.ptr_translation_start, a.ptr_translation_end)
            for a in alignments]

    return make_200(data=ptrs)
Ejemplo n.º 9
0
def view_document_translation_alignment(api_version, doc_id):
    translation = get_reference_translation(doc_id)
    transcription = get_reference_transcription(doc_id)

    if not transcription or not translation:
        return make_404()

    tr_w_notes, tl_w_notes, notes, num_al = add_notes_refs(
        transcription.serialize_for_user(transcription.user_id),
        translation.serialize_for_user(translation.user_id))

    if num_al <= 0:
        return make_404(details="Aucun alignement")

    return make_200({
        "doc_id": doc_id,
        #"transcription": Markup("".join(tr_w_notes)),
        #"translation": Markup("".join(tl_w_notes)),
        "alignments": [z for z in zip(tr_w_notes, tl_w_notes)],
        "notes": notes
    })
Ejemplo n.º 10
0
def view_document_speech_parts_alignment(api_version, doc_id, user_id=None):
    tr = get_reference_transcription(doc_id)

    if tr is None:
        return make_404()

    if user_id is None:
        user_id = tr.user_id

    alignments = AlignmentDiscours.query.filter(
        AlignmentDiscours.transcription_id == tr.id,
        AlignmentDiscours.user_id == user_id).all()

    if len(alignments) <= 0:
        return make_404(details="Aucun alignement")

    _content = add_speechparts_refs_to_text(tr.content, alignments)

    return make_200({
        "content": Markup(_content) if tr.content is not None else "",
        "notes": {"{:010d}".format(al.id): al.note
                  for al in alignments}
    })
Ejemplo n.º 11
0
def api_post_documents_transcriptions_alignments_discours(
        api_version, doc_id, user_id):
    """
        {
            "data": [
                    {
                        "speech_part_type_id" : 1,
                        "ptr_start": 1,
                        "ptr_end": 20,
                        "note": "aaa"
                    },
                    {
                        "speech_part_type_id" : 2,
                        "ptr_start": 21,
                        "ptr_end": 450,
                        "note": "bb"
                    }
            ]
        }

        :param user_id:
        :param api_version:
        :param doc_id:
        :return:
        """
    """
           NB: Posting alignment has a 'TRUNCATE AND REPLACE' effect
       """

    forbid = forbid_if_nor_teacher_nor_admin_and_wants_user_data(
        current_app, user_id)
    if forbid:
        return forbid

    transcription = get_reference_transcription(doc_id)
    if transcription is None:
        return make_404(details="Transcription not found")

    data = request.get_json()
    data = data.get("data", [])
    ptrs = []
    try:
        # TRUNCATE
        for old_al in AlignmentDiscours.query.filter(
                AlignmentDiscours.transcription_id == transcription.id,
                AlignmentDiscours.user_id == user_id).all():
            db.session.delete(old_al)

        # INSERT
        for d in data:
            new_al = AlignmentDiscours(
                transcription_id=transcription.id,
                speech_part_type_id=d["speech_part_type_id"],
                ptr_start=d["ptr_start"],
                ptr_end=d["ptr_end"],
                user_id=user_id,
                note=d.get('note', None))
            db.session.add(new_al)
            ptrs.append({
                'id': new_al.id,
                'ptr_start': new_al.ptr_start,
                'ptr_end': new_al.ptr_end,
                'note': new_al.note,
                'speech_part_type_id': new_al.speech_part_type_id
            })

        db.session.commit()
    except Exception as e:
        db.session.rollback()
        print(str(e))
        return make_400(str(e))

    return make_200(data=ptrs)
Ejemplo n.º 12
0
def api_documents_put_annotation(api_version, doc_id, zone_id):
    """
    expected format:

    {
        "manifest_url": "https://../manifest20.json",
        "canvas_idx": 0,
        // In case there are multiple images on a canvas, optionnal, default is 0
        "img_idx": 0,
        "zone_type_id": 2,
        "fragment': "620,128,788,159",
        "svg': "620,128,788,159, ...",

        // in case of a COMMENTING motivation, the text content is embedded within the annotation,
        // optionnal, default is none
        "note": "Ceci est une majuscule"

        // in case of a DESCRIBING motivation, the text content is a segment of the transcription
        "ptr_start" : 3
        "ptr_end" : 131
    }

    :param api_version:
    :param doc_id:
    :return:
    """
    data = request.get_json()

    try:
        doc = Document.query.filter(Document.id == doc_id).first()

        url = data['manifest_url']
        canvas_idx = data['canvas_idx']
        doc_id = doc.id
        img_idx = data.get('img_idx', 0)

        note = data.get('note', None)
        ptr_start = data.get('ptr_start', None)
        ptr_end = data.get('ptr_end', None)

        if note is not None and (ptr_start is not None or ptr_end is not None):
            raise Exception('ambiguous annotation type')

        img_zone = ImageZone.query.with_for_update(nowait=True).filter(
            ImageZone.zone_id == zone_id,
            ImageZone.manifest_url == url,
            ImageZone.canvas_idx == canvas_idx,
            ImageZone.img_idx == img_idx,
            ImageZone.user_id == doc.user_id
        ).one()

        img_zone.zone_id = int(zone_id)
        img_zone.note = note
        img_zone.zone_type_id = data.get('zone_type_id', 2)
        img_zone.fragment = data.get('fragment', None)
        img_zone.svg = data.get('svg', None)

        db.session.flush()
        #db.session.add(img_zone)

        tr = get_reference_transcription(doc_id)
        if tr is None:
            raise Exception('There is no reference transcription to use in this annotation')

        print('finding existing al')
        al = AlignmentImage.query.filter(
            AlignmentImage.transcription_id == tr.id,
            AlignmentImage.manifest_url == url,
            AlignmentImage.canvas_idx == canvas_idx,
            AlignmentImage.img_idx == img_idx,
            AlignmentImage.zone_id == zone_id
        ).first()

        if ptr_start is not None and ptr_end is not None:
            if al is None:
                print('new al')
                note = None
                new_al = AlignmentImage(
                    transcription_id=tr.id,
                    user_id=doc.user_id,
                    zone_id=zone_id,
                    manifest_url=url,
                    canvas_idx=canvas_idx,
                    img_idx=img_idx,
                    ptr_transcription_start=ptr_start,
                    ptr_transcription_end=ptr_end
                )
                db.session.add(new_al)
            else:
                print('update al')
                al.ptr_transcription_start = ptr_start
                al.ptr_transcription_end = ptr_end
                db.session.add(al)
        else:
            # let's check if there is an old al to delete
            if al is not None:
                print("delete old al")
                db.session.delete(al)

        #db.session.add(img_zone)
        db.session.commit()
    except Exception as e:
        print(data, str(e))
        db.session.rollback()
        return make_400(details="Cannot update this annotation: %s" % str(e))

    return make_200(data=img_zone.serialize())
Ejemplo n.º 13
0
def api_documents_post_annotation(api_version, doc_id):
    """
    expected format:

    {
        "manifest_url": "https://../manifest20.json",
        "canvas_idx": 0,
        // In case there are multiple images on a canvas, optionnal, default is 0
        "img_idx": 0,
        "zone_type_id": 2,

        "fragment": "620,128,788,159",  // FragmentSelector
        "svg": "<svg ...>"              // SvgSelector

        // in case of a COMMENTING motivation, the text content is embedded within the annotation,
        // optionnal, default is none
        "note": "Ceci est une majuscule"

        // in case of a DESCRIBING motivation, the text content is a segment of the transcription
        "ptr_start" : 3
        "ptr_end" : 131
    }

    :param api_version:
    :param doc_id:
    :return:
    """
    data = request.get_json()

    try:
        doc = Document.query.filter(Document.id == doc_id).first()

        url = data['manifest_url']
        canvas_idx = data['canvas_idx']
        doc_id = doc.id
        img_idx = data.get('img_idx', 0)

        note = data.get('note', None)
        ptr_start = data.get('ptr_start', None)
        ptr_end = data.get('ptr_end', None)

        if note is not None and (ptr_start is not None or ptr_end is not None):
            raise Exception('ambiguous annotation type')

        # test if the image is in db first
        if Image.query.filter(
                Image.manifest_url == url,
                Image.canvas_idx == canvas_idx,
                Image.doc_id == doc_id,
                Image.img_idx == img_idx
        ).first() is None:
            raise Exception('image unknown: %s', [url, canvas_idx, doc_id, img_idx])

        # compute relative zone id
        last_zone = ImageZone.query.filter(
            ImageZone.manifest_url == url,
            ImageZone.canvas_idx == canvas_idx,
            ImageZone.img_idx == img_idx
        ).order_by(ImageZone.zone_id.desc()).first()

        if last_zone is None:
            new_zone_id = 1
        else:
            new_zone_id = int(last_zone.zone_id) + 1

        new_anno = ImageZone(
            zone_id=new_zone_id,
            manifest_url=url,
            canvas_idx=canvas_idx,
            img_idx=img_idx,
            user_id=doc.user_id,
            zone_type_id=data['zone_type_id'],

            svg=data.get('svg', None),
            fragment=data.get('fragment', None),
            note=note
        )
        db.session.add(new_anno)

        if ptr_start is not None and ptr_end is not None:
            tr = get_reference_transcription(doc_id)
            if tr is None:
                raise Exception('There is no reference transcription use in this annotation')

            al = AlignmentImage.query.filter(
                AlignmentImage.transcription_id == tr.id,
                AlignmentImage.manifest_url == url,
                AlignmentImage.canvas_idx == canvas_idx,
                AlignmentImage.img_idx == img_idx,
                AlignmentImage.ptr_transcription_start == ptr_start,
                AlignmentImage.ptr_transcription_end == ptr_end
            ).first()

            if al is not None:
                raise Exception('this alignment already exists: %s', [tr.id, ptr_start, ptr_end])

            new_al = AlignmentImage(
                transcription_id=tr.id,
                user_id=doc.user_id,
                zone_id=new_zone_id,
                manifest_url=url,
                canvas_idx=canvas_idx,
                img_idx=img_idx,
                ptr_transcription_start=ptr_start,
                ptr_transcription_end=ptr_end
            )

            db.session.add(new_al)

        db.session.commit()
    except Exception as e:
        print(data, str(e))
        db.session.rollback()
        return make_400(details="Cannot build this new annotation: %s" % str(e))

    return make_201(data=new_anno.serialize())
Ejemplo n.º 14
0
def api_documents_annotations(api_version, doc_id, zone_id):
    """

    :param canvas_name:
    :param api_version:
    :param doc_id:
    :param zone_id:
    :return:
    """

    from app.api.transcriptions.routes import get_reference_transcription
    tr = get_reference_transcription(doc_id)
    if tr is None:
        return make_404()
    try:
        manifest = make_manifest(api_version, doc_id)
        sequence = manifest["sequences"][0]

        img = Image.query.filter(Image.doc_id == doc_id).first()

        # select annotations zones
        img_zone = ImageZone.query.filter(
            ImageZone.zone_id == zone_id,
            ImageZone.manifest_url == img.manifest_url
        ).one()

        res_uri = current_app.with_url_prefix(request.path)

        # if the note content is empty, then you need to fetch a transcription segment
        img_al = None
        if img_zone.note is None:
            try:
                img_al = AlignmentImage.query.filter(
                    AlignmentImage.transcription_id == tr.id,
                    AlignmentImage.zone_id == img_zone.zone_id,
                    AlignmentImage.user_id == tr.user_id,
                    AlignmentImage.manifest_url == img.manifest_url
                ).one()
                note_content = tr.content[img_al.ptr_transcription_start:img_al.ptr_transcription_end]
            except NoResultFound:
                return make_404(details="This transcription zone has no text fragment attached to it".format(doc_id))
        # else it is a mere image note
        else:
            note_content = img_zone.note

        # TODO: gerer erreur si pas d'image dans le canvas
        canvas = sequence["canvases"][img_zone.canvas_idx]
        img_json = canvas["images"][img_zone.img_idx]
        url = current_app.with_url_prefix(url_for("api_bp.api_documents_manifest", api_version=1.0, doc_id=doc_id))
        new_annotation = make_annotation(
            url,
            canvas["@id"],
            img_json.get('fragment', None),
            img_json.get('svg', None),
            res_uri,
            note_content,
            format="text/html"
        )
        return new_annotation

    except Exception as e:
        print(str(e))
        return make_400(str(e))
Ejemplo n.º 15
0
def api_documents_annotations_list_by_canvas(api_version, doc_id, motivation, canvas_idx):
    """
    """
    user = current_app.get_current_user()
    doc = Document.query.filter(Document.id == doc_id).first()

    if user.is_anonymous and doc.is_published is False:
        annotation_list = make_annotation_list(request.base_url, [])
        return annotation_list

    try:
        manifest = make_manifest(api_version, doc_id)
        sequence = manifest["sequences"][0]
        canvas = sequence["canvases"][int(canvas_idx)]

        annotations = []
        img = Image.query.filter(Image.doc_id == doc_id).first()
        img = Image.query.filter(Image.manifest_url == img.manifest_url, Image.doc_id == doc_id,
                                 Image.canvas_idx == canvas_idx).first()

        # TODO s'il y a plusieurs images dans un seul et même canvas ?
        #img_json = canvas["images"][0]
        kwargs = {
            "doc_id": doc_id,
            "api_version": api_version
        }

        manifest_url = current_app.with_url_prefix(
            url_for("api_bp.api_documents_manifest", api_version=1.0, doc_id=doc_id))

        for img_zone in [zone for zone in img.zones]:
            kwargs["zone_id"] = img_zone.zone_id
            res_uri = current_app.with_url_prefix(url_for("api_bp.api_documents_annotations", **kwargs))

            print(img_zone, img_zone.zone_type.label)
            if img_zone.zone_type.label == "describing":
                from app.api.transcriptions.routes import get_reference_transcription
                tr = get_reference_transcription(doc_id)
                if tr is None:
                    annotation_list = make_annotation_list(request.base_url, [])
                    return annotation_list

                img_al = AlignmentImage.query.filter(
                    AlignmentImage.transcription_id == tr.id,
                    AlignmentImage.manifest_url == img_zone.manifest_url,
                    AlignmentImage.canvas_idx == img_zone.canvas_idx,
                    AlignmentImage.img_idx == img_zone.img_idx,
                    AlignmentImage.zone_id == img_zone.zone_id
                ).first()

                # is there a text segment bound to this image zone?
                if img_al is not None:
                    text_content = tr.content[img_al.ptr_transcription_start:img_al.ptr_transcription_end]
                else:
                    text_content = ""

            else:
                text_content = img_zone.note

            new_annotation = make_annotation(
                manifest_url,
                canvas["@id"],
                img_zone.fragment,
                img_zone.svg,
                res_uri,
                content=text_content,
                format="text/html"
            )
            annotations.append(new_annotation)
        annotation_list = make_annotation_list(request.base_url, annotations)
        return annotation_list

    except Exception as e:
        print(str(e))
        return make_400(str(e))