Пример #1
0
def extract_post_1_to_subidea_1_1(request, participant2_user, reply_post_1,
                                  subidea_1_1, discussion, test_session):
    """ Links reply_post_1 to subidea_1_1 """

    from assembl.models import Extract, Keyword
    from assembl.models.idea_content_link import ExtractNatureVocabulary, ExtractActionVocabulary
    e = Extract(
        body=u"body",
        creator=participant2_user,
        owner=participant2_user,
        content=reply_post_1,
        idea_id=subidea_1_1.id,  # strange bug: Using idea directly fails
        discussion=discussion,
        extract_hash=u'extract_post_1_to_subidea_1_1',
        extract_nature=ExtractNatureVocabulary.Enum.actionable_solution,
        extract_action=ExtractActionVocabulary.Enum.give_examples)
    tags = Keyword.get_tags(['foo', 'bar'], discussion.id, test_session)
    e.tags = tags['new_tags'] + tags['tags']
    test_session.add(e)
    test_session.flush()

    def fin():
        print "finalizer extract_post_1_to_subidea_1_1"
        tags = e.tags
        e.tags = []
        for tag in tags:
            test_session.delete(tag)

        test_session.delete(e)
        test_session.flush()

    request.addfinalizer(fin)
    return e
Пример #2
0
def test_extracts_on_post(admin_user, graphql_request, discussion,
                          top_post_in_thread_phase):
    from graphene.relay import Node
    raw_id = int(Node.from_global_id(top_post_in_thread_phase)[1])
    from assembl.models import Extract, Post
    post = Post.get(raw_id)
    post.extracts.append(
        Extract(body=u"super quote",
                important=False,
                creator=admin_user,
                owner=admin_user,
                discussion=discussion,
                extract_hash=u"extract1"))
    post.extracts.append(
        Extract(body=u"super important quote",
                important=True,
                creator=admin_user,
                owner=admin_user,
                discussion=discussion,
                extract_hash=u"extract2"))
    post.db.flush()
    res = schema.execute(u"""
query Post($id: ID!) {
  post: node(id: $id) {
    ... on Post {
      extracts {
        body
        important
      }
    }
  }
}
""",
                         context_value=graphql_request,
                         variable_values={
                             "id": top_post_in_thread_phase,
                         })
    assert json.loads(json.dumps(res.data)) == {
        u'post': {
            u'extracts': [
                {
                    u'body': u'super quote',
                    u'important': False
                },
                {
                    u'body': u'super important quote',
                    u'important': True
                },
            ]
        }
    }
Пример #3
0
def delete_extract(request):
    user_id = request.authenticated_userid
    discussion_id = int(request.matchdict['discussion_id'])

    if not user_id:
        # Straight from annotator
        token = request.headers.get('X-Annotator-Auth-Token')
        if token:
            token = decode_token(token,
                                 request.registry.settings['session.secret'])
            if token:
                user_id = token['userId']
    user_id = user_id or Everyone

    extract_id = request.matchdict['id']
    extract = Extract.get_instance(extract_id)

    if not (user_has_permission(discussion_id, user_id, P_EDIT_EXTRACT) or
            (user_has_permission(discussion_id, user_id, P_EDIT_MY_EXTRACT)
             and user_id == extract.owner_id)):
        raise HTTPForbidden()

    if not extract:
        return HTTPNoContent()

    # TODO: Tombstonable extracts???
    extract.delete()
    return HTTPNoContent()
Пример #4
0
def extract_submitted_in_post_related_to_sub_idea_1_1_1(
        request, participant2_user, post_related_to_sub_idea_1_1_1,
        subidea_1_1, discussion, test_session):
    """ Create an extract in a post related to an idea."""

    from assembl.models import Extract
    from assembl.models.idea_content_link import ExtractNatureVocabulary, ExtractActionVocabulary
    new_extract = Extract(
        discussion_id=discussion.id,
        body=
        u"Commodi maiores magni rerum. Sint natus corporis in qui in ut dignissimos cumque repellendus. Reprehenderit nihil illum.",
        creator=participant2_user,
        owner=participant2_user,
        content=post_related_to_sub_idea_1_1_1,
        extract_hash=u'extract_submitted_in_post_related_to_sub_idea_1_1_1',
        extract_nature=ExtractNatureVocabulary.Enum.actionable_solution,
        extract_action=ExtractActionVocabulary.Enum.give_examples)
    test_session.add(new_extract)
    test_session.flush()

    def fin():
        print "finalizer extract_with_range_submitted_in_reply_post_1"
        test_session.delete(new_extract)
        test_session.flush()

    request.addfinalizer(fin)

    return new_extract
Пример #5
0
def delete_extract(request):
    user_id = authenticated_userid(request)
    discussion = request.context

    if not user_id:
        # Straight from annotator
        token = request.headers.get('X-Annotator-Auth-Token')
        if token:
            token = decode_token(token,
                                 request.registry.settings['session.secret'])
            if token:
                user_id = token['userId']
        user_id = user_id or Everyone

    extract_id = request.matchdict['id']
    extract = Extract.get_instance(extract_id)
    permissions = get_permissions(user_id, discussion.id, extract)
    if P_EDIT_EXTRACT not in permissions:
        raise HTTPForbidden()

    if not extract:
        return HTTPNoContent()

    # TODO: Tombstonable extracts???
    extract.delete()
    return HTTPNoContent()
def upgrade(pyramid_env):
    with context.begin_transaction():
        op.create_table(
            'text_fragment_identifier',
            sa.Column('id', sa.Integer, primary_key=True),
            sa.Column('extract_id', sa.Integer, sa.ForeignKey('extract.id')),
            sa.Column('xpath_start', sa.String),
            sa.Column('offset_start', sa.Integer),
            sa.Column('xpath_end', sa.String),
            sa.Column('offset_end', sa.Integer)
        )
        op.add_column('extract', sa.Column('annotation_text', sa.UnicodeText))

    # Do stuff with the app's models here.
    from assembl.models import Extract
    db = Extract.db()
    with transaction.manager:
        q =  db.execute('''
            SELECT extract.id, email.subject, email.body, post.id 
            FROM extract
            JOIN email ON (email.id = extract.source_id)
            JOIN content ON (email.id = content.id)
            JOIN post ON (post.content_id = email.id)
            WHERE content.type = 'email'
            ''')
        vals = {ex_id: (sub, body, postid) for (ex_id, sub, body, postid) in q}
        for extract in db.query(Extract).options(lazyload('*')).all():
            v = vals.get(extract.id)
            if v:
                tfi = extract._infer_text_fragment_inner(*v)
                if tfi:
                    db.add(tfi)
Пример #7
0
def delete_extract(request):
    user_id = authenticated_userid(request)
    discussion_id = int(request.matchdict['discussion_id'])

    if not user_id:
        # Straight from annotator
        token = request.headers.get('X-Annotator-Auth-Token')
        if token:
            token = decode_token(
                token, request.registry.settings['session.secret'])
            if token:
                user_id = token['userId']
    user_id = user_id or Everyone

    extract_id = request.matchdict['id']
    extract = Extract.get_instance(extract_id)

    if not (user_has_permission(discussion_id, user_id, P_EDIT_EXTRACT)
        or (user_has_permission(discussion_id, user_id, P_EDIT_MY_EXTRACT)
            and user_id == extract.owner_id)):
        raise HTTPForbidden()

    if not extract:
        return HTTPNoContent()

    with transaction.manager:
        # TODO: Tombstonable extracts???
        Extract.default_db.delete(extract)
    request.response.status = HTTPNoContent.code
    return HTTPNoContent()
Пример #8
0
def put_extract(request):
    """
    Updating an Extract
    """
    extract_id = request.matchdict['id']
    user_id = authenticated_userid(request)

    updated_extract_data = json.loads(request.body)
    extract = Extract.get_instance(extract_id)
    if not extract:
        raise HTTPNotFound("Extract with id '%s' not found." % extract_id)

    extract.owner_id = user_id or get_database_id("User", extract.owner_id)
    extract.order = updated_extract_data.get('order', extract.order)
    idea_id = updated_extract_data.get('idIdea', None)
    if idea_id:
        idea = Idea.get_instance(idea_id)
        if(idea.get_discussion_id() != extract.get_discussion_id()):
            raise HTTPBadRequest(
                "Extract from discussion %s cannot be associated with an idea from a different discussion." % extract.get_discussion_id())
        extract.idea = idea
    else:
        extract.idea = None

    Extract.db.add(extract)
    #TODO: Merge ranges. Sigh.

    return {'ok': True}
Пример #9
0
def delete_extract(request):
    user_id = authenticated_userid(request)
    discussion_id = int(request.matchdict['discussion_id'])

    if not user_id:
        # Straight from annotator
        token = request.headers.get('X-Annotator-Auth-Token')
        if token:
            token = decode_token(
                token, request.registry.settings['session.secret'])
            if token:
                user_id = token['userId']
    if not user_id:
        user_id = Everyone
    if not user_has_permission(discussion_id, user_id, P_DELETE_EXTRACT):
        return HTTPForbidden()

    extract_id = request.matchdict['id']
    extract = Extract.get_instance(extract_id)

    if not extract:
        return {'ok': False}

    with transaction.manager:
        Extract.db.delete(extract)

    return {'ok': True}
Пример #10
0
def extract_with_range_submitted_in_reply_post_1(request,
                                                 discussion_admin_user,
                                                 reply_post_1, subidea_1_1,
                                                 discussion, test_session):
    """ Create an extract of a given range of text in a message """

    from assembl.models import Extract, TextFragmentIdentifier, ExtractStates

    extract_body = "variable-temperature spectra indicate the onset of oxide-ion motion involving the interstitials at 130 °C, which is linked to an orthorhombic−tetragonal phase transition. For the V-doped phases, an oxide-ion conduction mechanism is observed that involves oxygen exchange between the Bi-O sublattice and rapidly rotating VO4 tetrahedral units. The more poorly conducting P-doped phase exhibits only vacancy conduction with no evidence of sublattice exchange, a result ascribed to the differing propensities of the dopants to undergo variable oxygen coordination. So I think it would be a very bad idea to allow hot beverages in coworking spaces."
    xpathStart = u"//div[@id='message-body-local:Content/%s']/" % reply_post_1.id
    xpathEnd = xpathStart
    offsetStart = 314
    offsetEnd = 958
    lang = 'en'
    extract_hash = Extract.get_extract_hash(lang, xpathStart, xpathEnd,
                                            offsetStart, offsetEnd,
                                            reply_post_1.id)
    new_extract = Extract(creator_id=discussion_admin_user.id,
                          owner_id=discussion_admin_user.id,
                          discussion_id=discussion.id,
                          body=extract_body,
                          important=True,
                          content=reply_post_1,
                          extract_state=ExtractStates.SUBMITTED.value,
                          extract_hash=extract_hash)
    new_extract.lang = lang
    test_session.add(new_extract)

    new_range = TextFragmentIdentifier(extract=new_extract,
                                       xpath_start=xpathStart,
                                       offset_start=offsetStart,
                                       xpath_end=xpathEnd,
                                       offset_end=offsetEnd)
    test_session.add(new_range)
    test_session.flush()

    def fin():
        print "finalizer extract_with_range_submitted_in_reply_post_1"
        test_session.delete(new_range)
        test_session.delete(new_extract)
        test_session.flush()

    request.addfinalizer(fin)

    return new_extract
Пример #11
0
def get_extract(request):
    extract_id = request.matchdict['id']
    extract = Extract.get_instance(extract_id)
    view_def = request.GET.get('view') or 'default'
    user_id = authenticated_userid(request) or Everyone
    permissions = request.permissions

    if extract is None:
        raise HTTPNotFound("Extract with id '%s' not found." % extract_id)

    return extract.generic_json(view_def, user_id, permissions)
Пример #12
0
def delete_extract(request):
    extract_id = request.matchdict['id']
    extract = Extract.get_instance(extract_id)

    if not extract:
        return {'ok': False}

    with transaction.manager:
        Extract.db.delete(extract)

    return {'ok': True}
Пример #13
0
def get_extract(request):
    extract_id = request.matchdict['id']
    extract = Extract.get_instance(extract_id)
    view_def = request.GET.get('view')

    if extract is None:
        raise HTTPNotFound(
            "Extract with id '%s' not found." % extract_id)

    if view_def:
        return extract.generic_json(view_def)
    else:
        return extract.serializable()
Пример #14
0
def get_extract(request):
    extract_id = request.matchdict['id']
    extract = Extract.get_instance(extract_id)
    view_def = request.GET.get('view') or 'default'
    discussion_id = int(request.matchdict['discussion_id'])
    user_id = authenticated_userid(request) or Everyone
    permissions = get_permissions(user_id, discussion_id)

    if extract is None:
        raise HTTPNotFound(
            "Extract with id '%s' not found." % extract_id)

    return extract.generic_json(view_def, user_id, permissions)
Пример #15
0
def put_extract(request):
    """
    Updating an Extract
    """
    extract_id = request.matchdict['id']
    user_id = authenticated_userid(request)
    discussion = request.context

    if not user_id:
        # Straight from annotator
        token = request.headers.get('X-Annotator-Auth-Token')
        if token:
            token = decode_token(token,
                                 request.registry.settings['session.secret'])
            if token:
                user_id = token['userId']
        user_id = user_id or Everyone

    extract = Extract.get_instance(extract_id)
    if not extract:
        raise HTTPNotFound("Extract with id '%s' not found." % extract_id)
    permissions = get_permissions(user_id, discussion.id, extract)

    if P_EDIT_EXTRACT not in permissions:
        raise HTTPForbidden()

    updated_extract_data = json.loads(request.body)

    extract.owner_id = user_id or AgentProfile.get_database_id(
        extract.owner_id)
    extract.order = updated_extract_data.get('order', extract.order)
    extract.important = updated_extract_data.get('important',
                                                 extract.important)
    idea_id = updated_extract_data.get('idIdea', None)
    if idea_id:
        idea = Idea.get_instance(idea_id)
        if (idea.discussion != extract.discussion):
            raise HTTPBadRequest(
                "Extract from discussion %s cannot be associated with an idea from a different discussion."
                % extract.get_discussion_id())
        if not idea.has_permission_req(P_ASSOCIATE_EXTRACT):
            raise HTTPForbidden("Cannot associate extact with this idea")
        extract.idea = idea
    else:
        extract.idea = None

    Extract.default_db.add(extract)
    #TODO: Merge ranges. Sigh.

    return {'ok': True}
Пример #16
0
def put_extract(request):
    """
    Updating an Extract
    """
    extract_id = request.matchdict['id']
    user_id = request.authenticated_userid
    discussion_id = int(request.matchdict['discussion_id'])

    if not user_id:
        # Straight from annotator
        token = request.headers.get('X-Annotator-Auth-Token')
        if token:
            token = decode_token(token,
                                 request.registry.settings['session.secret'])
            if token:
                user_id = token['userId']
    user_id = user_id or Everyone

    updated_extract_data = json.loads(request.body)
    extract = Extract.get_instance(extract_id)
    if not extract:
        raise HTTPNotFound("Extract with id '%s' not found." % extract_id)

    if not (user_has_permission(discussion_id, user_id, P_EDIT_EXTRACT) or
            (user_has_permission(discussion_id, user_id, P_EDIT_MY_EXTRACT)
             and user_id == extract.owner_id)):
        return HTTPForbidden()

    extract.owner_id = user_id or get_database_id("User", extract.owner_id)
    extract.order = updated_extract_data.get('order', extract.order)
    extract.important = updated_extract_data.get('important',
                                                 extract.important)
    idea_id = updated_extract_data.get('idIdea', None)
    if idea_id:
        idea = Idea.get_instance(idea_id)
        if (idea.discussion != extract.discussion):
            raise HTTPBadRequest(
                "Extract from discussion %s cannot be associated with an idea from a different discussion."
                % extract.get_discussion_id())
        extract.idea = idea
    else:
        extract.idea = None

    Extract.default_db.add(extract)
    #TODO: Merge ranges. Sigh.

    return {'ok': True}
Пример #17
0
def put_extract(request):
    """
    Updating an Extract
    """
    extract_id = request.matchdict['id']
    user_id = authenticated_userid(request)
    discussion_id = int(request.matchdict['discussion_id'])

    if not user_id:
        # Straight from annotator
        token = request.headers.get('X-Annotator-Auth-Token')
        if token:
            token = decode_token(
                token, request.registry.settings['session.secret'])
            if token:
                user_id = token['userId']
    if not user_id:
        user_id = Everyone

    updated_extract_data = json.loads(request.body)
    extract = Extract.get_instance(extract_id)
    if not extract:
        raise HTTPNotFound("Extract with id '%s' not found." % extract_id)

    if not (user_has_permission(discussion_id, user_id, P_EDIT_EXTRACT)
        or (user_has_permission(discussion_id, user_id, P_EDIT_MY_EXTRACT)
            and user_id == extract.owner_id)):
        return HTTPForbidden()

    extract.owner_id = user_id or get_database_id("User", extract.owner_id)
    extract.order = updated_extract_data.get('order', extract.order)
    extract.important = updated_extract_data.get('important', extract.important)
    idea_id = updated_extract_data.get('idIdea', None)
    if idea_id:
        idea = Idea.get_instance(idea_id)
        if(idea.discussion != extract.discussion):
            raise HTTPBadRequest(
                "Extract from discussion %s cannot be associated with an idea from a different discussion." % extract.get_discussion_id())
        extract.idea = idea
    else:
        extract.idea = None

    Extract.db.add(extract)
    #TODO: Merge ranges. Sigh.

    return {'ok': True}
def upgrade(pyramid_env):
    from assembl.models import Extract, TextFragmentIdentifier, Content, Post
    db = Extract.db()
    reg = re.compile(r"^//div\[@id='message-([0-9]+)'\](.*)")
    with transaction.manager:
        db.query(TextFragmentIdentifier).filter_by(extract=None).delete()
        for tfi in db.query(TextFragmentIdentifier).join(
                Extract, Content, Post).all():
            xpo = tfi.xpath_start
            print xpo
            match = reg.match(xpo)
            if match:
                id, remainder = match.groups()
                uri = Post.uri_generic(id)
                xp = "//div[@id='message-%s']%s" % (
                    uri, remainder)
                print xp
                tfi.xpath_start = tfi.xpath_end = xp
Пример #19
0
def _get_extracts_real(request, view_def='default', ids=None, user_id=None):
    discussion = request.discussion
    user_id = user_id or Everyone
    all_extracts = discussion.db.query(Extract).filter(
        Extract.discussion_id == discussion.id)
    if ids:
        ids = [Extract.get_database_id(id) for id in ids]
        all_extracts = all_extracts.filter(Extract.id.in_(ids))

    all_extracts = all_extracts.options(joinedload_all(Extract.content))
    all_extracts = all_extracts.options(
        joinedload_all(Extract.selectors).joinedload(
            AnnotationSelector.extract, innerjoin=True))
    permissions = request.permissions

    return [
        extract.generic_json(view_def, user_id, permissions)
        for extract in all_extracts
    ]
Пример #20
0
def extract_post_1_to_subidea_1_1(
        request, participant2_user, reply_post_1,
        subidea_1_1, discussion, test_session):
    """ Links reply_post_1 to subidea_1_1 """
    from assembl.models import Extract
    e = Extract(
        body=u"body",
        creator=participant2_user,
        owner=participant2_user,
        content=reply_post_1,
        idea_id=subidea_1_1.id,  # strange bug: Using idea directly fails
        discussion=discussion)
    test_session.add(e)
    test_session.flush()

    def fin():
        print "finalizer extract_post_1_to_subidea_1_1"
        test_session.delete(e)
        test_session.flush()
    request.addfinalizer(fin)
    return e
def upgrade(pyramid_env):
    from assembl.models import Extract, Mailbox
    db = Mailbox.db()
    with transaction.manager:
        for mb in db.query(Mailbox).all():
            Mailbox.reprocess_content(mb)
    db = Extract.db()
    with transaction.manager:
        q = db.execute('''
            SELECT extract.id, email.subject, email.body, post.id
            FROM extract
            JOIN email ON (email.id = extract.source_id)
            JOIN content ON (email.id = content.id)
            JOIN post ON (post.content_id = email.id)
            WHERE content.type = 'email'
            ''')
        vals = {ex_id: (sub, body, postid) for (ex_id, sub, body, postid) in q}
        for extract in db.query(Extract).options(lazyload('*')).all():
            v = vals.get(extract.id)
            if v:
                tfi = extract._infer_text_fragment_inner(*v)
                if tfi:
                    db.add(tfi)
Пример #22
0
def post_extract(request):
    """
    Create a new extract.
    """
    extract_data = json.loads(request.body)
    discussion_id = int(request.matchdict['discussion_id'])
    user_id = request.authenticated_userid
    if not user_id:
        # Straight from annotator
        token = request.headers.get('X-Annotator-Auth-Token')
        if token:
            token = decode_token(
                token, request.registry.settings['session.secret'])
            if token:
                user_id = token['userId']
    user_id = user_id or Everyone
    if not user_has_permission(discussion_id, user_id, P_ADD_EXTRACT):
        #TODO: maparent:  restore this code once it works:
        #return HTTPForbidden(result=ACLDenied(permission=P_ADD_EXTRACT))
        return HTTPForbidden()
    if not user_id or user_id == Everyone:
        # TODO: Create an anonymous user.
        raise HTTPServerError("Anonymous extracts are not implemeted yet.")
    content = None
    uri = extract_data.get('uri')
    important = extract_data.get('important', False)
    annotation_text = None
    if uri:
        # Straight from annotator
        annotation_text = extract_data.get('text')
    else:
        target = extract_data.get('target')
        if not (target or uri):
            raise HTTPBadRequest("No target")

        target_class = sqla.get_named_class(target.get('@type'))
        if issubclass(target_class, Post):
            post_id = target.get('@id')
            post = Post.get_instance(post_id)
            if not post:
                raise HTTPNotFound(
                    "Post with id '%s' not found." % post_id)
            content = post
        elif issubclass(target_class, Webpage):
            uri = target.get('url')
    if uri and not content:
        content = Webpage.get_instance(uri)
        if not content:
            # TODO: maparent:  This is actually a singleton pattern, should be
            # handled by the AnnotatorSource now that it exists...
            source = AnnotatorSource.default_db.query(AnnotatorSource).filter_by(
                discussion_id=discussion_id).filter(
                cast(AnnotatorSource.name, Unicode) == 'Annotator').first()
            if not source:
                source = AnnotatorSource(
                    name='Annotator', discussion_id=discussion_id)
            content = Webpage(url=uri, discussion_id=discussion_id)
    extract_body = extract_data.get('quote', '')

    idea_id = extract_data.get('idIdea', None)
    if idea_id:
        idea = Idea.get_instance(idea_id)
        if(idea.discussion.id != discussion_id):
            raise HTTPBadRequest(
                "Extract from discussion %s cannot be associated with an idea from a different discussion." % extract.get_discussion_id())
    else:
        idea = None

    ranges = extract_data.get('ranges', [])
    extract_hash = Extract.get_extract_hash(
        None,
        u"".join([r['start'] for r in ranges]),
        u"".join([r['end'] for r in ranges]),
        u"".join([r['startOffset'] for r in ranges]),
        u"".join([r['endOffset'] for r in ranges]),
        content.id
        )
    new_extract = Extract(
        creator_id=user_id,
        owner_id=user_id,
        discussion_id=discussion_id,
        body=extract_body,
        idea=idea,
        important=important,
        annotation_text=annotation_text,
        content=content,
        extract_hash=extract_hash
    )
    Extract.default_db.add(new_extract)
    for range_data in ranges:
        range = TextFragmentIdentifier(
            extract=new_extract,
            xpath_start=range_data['start'],
            offset_start=range_data['startOffset'],
            xpath_end=range_data['end'],
            offset_end=range_data['endOffset'])
        TextFragmentIdentifier.default_db.add(range)

    Extract.default_db.flush()

    return {'ok': True, '@id': new_extract.uri()}
Пример #23
0
def post_extract(request):
    """
    Create a new extract.
    """
    extract_data = json.loads(request.body)
    discussion = request.context
    db = discussion.db
    user_id = authenticated_userid(request)
    if not user_id:
        # Straight from annotator
        token = request.headers.get('X-Annotator-Auth-Token')
        if token:
            token = decode_token(token,
                                 request.registry.settings['session.secret'])
            if token:
                user_id = token['userId']
        user_id = user_id or Everyone
        permissions = get_permissions(user_id, discussion_id)
    else:
        permissions = request.permissions
    if P_ADD_EXTRACT not in permissions:
        #TODO: maparent:  restore this code once it works:
        #raise HTTPForbidden(result=ACLDenied(permission=P_ADD_EXTRACT))
        raise HTTPForbidden()
    if not user_id or user_id == Everyone:
        # TODO: Create an anonymous user.
        raise HTTPServerError("Anonymous extracts are not implemeted yet.")
    content = None
    uri = extract_data.get('uri')
    important = extract_data.get('important', False)
    annotation_text = extract_data.get('text')
    target = extract_data.get('target')
    if not uri:
        # Extract from an internal post
        if not target:
            raise HTTPBadRequest("No target")

        target_class = sqla.get_named_class(target.get('@type'))
        if issubclass(target_class, Post):
            post_id = target.get('@id')
            post = Post.get_instance(post_id)
            if not post:
                raise HTTPNotFound("Post with id '%s' not found." % post_id)
            content = post
        elif issubclass(target_class, Webpage):
            uri = target.get('url')
    if uri and not content:
        content = Webpage.get_instance(uri)
        if not content:
            # TODO: maparent:  This is actually a singleton pattern, should be
            # handled by the AnnotatorSource now that it exists...
            source = db.query(AnnotatorSource).filter_by(
                discussion=discussion).filter(
                    cast(AnnotatorSource.name, Unicode) ==
                    'Annotator').first()
            if not source:
                source = AnnotatorSource(name='Annotator',
                                         discussion=discussion)
                db.add(source)
            content = Webpage(url=uri, discussion=discussion)
            db.add(content)
    extract_body = extract_data.get('quote', None)

    idea_id = extract_data.get('idIdea', None)
    if idea_id:
        idea = Idea.get_instance(idea_id)
        if (idea.discussion.id != discussion.id):
            raise HTTPBadRequest(
                "Extract from discussion %s cannot be associated with an idea from a different discussion."
                % extract.get_discussion_id())
        if not idea.has_permission_req(P_ASSOCIATE_EXTRACT):
            raise HTTPForbidden("Cannot associate extact with this idea")
    else:
        idea = None

    new_extract = Extract(creator_id=user_id,
                          owner_id=user_id,
                          discussion=discussion,
                          idea=idea,
                          important=important,
                          annotation_text=annotation_text,
                          content=content)
    db.add(new_extract)

    for range_data in extract_data.get('ranges', []):
        range = TextFragmentIdentifier(extract=new_extract,
                                       body=extract_body,
                                       xpath_start=range_data['start'],
                                       offset_start=range_data['startOffset'],
                                       xpath_end=range_data['end'],
                                       offset_end=range_data['endOffset'])
        db.add(range)
    db.flush()

    return {'ok': True, '@id': new_extract.uri()}
Пример #24
0
def post_extract(request):
    """
    Create a new extract.
    """
    extract_data = json.loads(request.body)
    discussion_id = int(request.matchdict['discussion_id'])
    user_id = authenticated_userid(request)
    if not user_id:
        # Straight from annotator
        token = request.headers.get('X-Annotator-Auth-Token')
        if token:
            token = decode_token(
                token, request.registry.settings['session.secret'])
            if token:
                user_id = token['userId']
    if not user_id:
        user_id = Everyone
    if not user_has_permission(discussion_id, user_id, P_ADD_EXTRACT):
        #TODO: maparent:  restore this code once it works:
        #return HTTPForbidden(result=ACLDenied(permission=P_ADD_EXTRACT))
        return HTTPForbidden()
    if user_id == Everyone:
        # TODO: Create an anonymous user.
        raise HTTPServerError("Anonymous extracts are not implemeted yet.")
    content = None
    uri = extract_data.get('uri')
    annotation_text = None
    if uri:
        # Straight from annotator
        annotation_text = extract_data.get('text')
    else:
        target = extract_data.get('target')
        if not (target or uri):
            raise HTTPClientError("No target")

        target_type = target.get('@type')
        if target_type == 'email':
            post_id = target.get('@id')
            post = Post.get_instance(post_id)
            if not post:
                raise HTTPNotFound(
                    "Post with id '%s' not found." % post_id)
            content = post
        elif target_type == 'webpage':
            uri = target.get('url')
    if uri and not content:
        content = Webpage.get_instance(uri)
        if not content:
            # TODO: maparent:  This is actually a singleton pattern, should be
            # handled by the AnnotatorSource now that it exists...
            source = AnnotatorSource.db.query(AnnotatorSource).filter_by(
                discussion_id=discussion_id).filter(
                cast(AnnotatorSource.name, Unicode) == 'Annotator').first()
            if not source:
                source = AnnotatorSource(
                    name='Annotator', discussion_id=discussion_id,
                    type='source')
            content = Webpage(url=uri, discussion_id=discussion_id)
    extract_body = extract_data.get('quote', '')
    new_extract = Extract(
        creator_id=user_id,
        owner_id=user_id,
        discussion_id=discussion_id,
        body=extract_body,
        annotation_text=annotation_text,
        content=content
    )
    Extract.db.add(new_extract)

    for range_data in extract_data.get('ranges', []):
        range = TextFragmentIdentifier(
            extract=new_extract,
            xpath_start=range_data['start'],
            offset_start=range_data['startOffset'],
            xpath_end=range_data['end'],
            offset_end=range_data['endOffset'])
        TextFragmentIdentifier.db.add(range)
    Extract.db.flush()

    return {'ok': True, 'id': new_extract.uri()}