Exemplo n.º 1
0
def create():
    require(not request.authz.in_maintenance, settings.PASSWORD_LOGIN)
    data = parse_request(RoleCreateSchema)

    try:
        email = Role.SIGNATURE.loads(data.get('code'),
                                     max_age=Role.SIGNATURE_MAX_AGE)
    except BadSignature:
        return jsonify({
            'status': 'error',
            'message': gettext('Invalid code')
        }, status=400)

    role = Role.by_email(email)
    if role is not None:
        return jsonify({
            'status': 'error',
            'message': gettext('Email is already registered')
        }, status=409)

    role = Role.load_or_create(
        foreign_id='password:{}'.format(email),
        type=Role.USER,
        name=data.get('name') or email,
        email=email
    )
    role.set_password(data.get('password'))
    db.session.add(role)
    db.session.commit()
    update_role(role)
    # Let the serializer return more info about this user
    request.authz.id = role.id
    tag_request(role_id=role.id)
    return RoleSerializer.jsonify(role, status=201)
Exemplo n.º 2
0
def reconcile(collection_id=None):
    """Reconciliation API, emulates Google Refine API."""
    collection = None
    if collection_id is not None:
        collection = get_index_collection(collection_id)
    query = request.values.get('query')
    if query is not None:
        # single
        try:
            query = json.loads(query)
        except ValueError:
            query = {'query': query}
        return jsonify(reconcile_op(query, collection))

    queries = request.values.get('queries')
    if queries is not None:
        # multiple requests in one query
        try:
            qs = json.loads(queries)
            results = {}
            for k, q in qs.items():
                results[k] = reconcile_op(q, collection)
            return jsonify(results)
        except ValueError:
            raise BadRequest()
    return reconcile_index(collection)
Exemplo n.º 3
0
def index(id):
    collection = get_db_collection(id, request.authz.WRITE)
    record_audit(Audit.ACT_COLLECTION, id=id)
    roles = [r for r in Role.all_groups() if check_visible(r, request.authz)]
    q = Permission.all()
    q = q.filter(Permission.collection_id == collection.id)
    permissions = []
    for permission in q.all():
        if not check_visible(permission.role, request.authz):
            continue
        permissions.append(permission)
        if permission.role in roles:
            roles.remove(permission.role)

    # this workaround ensures that all groups are visible for the user to
    # select in the UI even if they are not currently associated with the
    # collection.
    for role in roles:
        if collection.casefile and role.is_public:
            continue
        permissions.append({
            'collection_id': collection.id,
            'write': False,
            'read': False,
            'role_id': str(role.id)
        })

    permissions = PermissionSerializer().serialize_many(permissions)
    return jsonify({
        'total': len(permissions),
        'results': permissions
    })
Exemplo n.º 4
0
def handle_es_error(err):
    log.error("ES [%s]: %r", err.error, err.info)
    return jsonify({
        'status': 'error',
        'message': gettext('There was an error during search'),
        'context': err.error
    }, status=500)
Exemplo n.º 5
0
def suggest_property():
    prefix = request.args.get('prefix', '').lower().strip()
    tag_request(prefix=prefix)
    schema = request.args.get('schema', Entity.THING)
    matches = []
    for prop in model.get(schema).properties.values():
        match = not len(prefix)
        match = prefix in prop.name.lower()
        match = match or prefix in prop.label.lower()
        if match:
            matches.append({
                'id': prop.name,
                'quid': prop.name,
                'name': prop.label,
                'r:score': 100,
                'n:type': {
                    'id': '/properties/property',
                    'name': 'Property'
                }
            })
    return jsonify({
        "code": "/api/status/ok",
        "status": "200 OK",
        "prefix": request.args.get('prefix', ''),
        "result": matches
    })
Exemplo n.º 6
0
def create_code():
    data = parse_request(RoleCodeCreateSchema)
    challenge_role(data)
    return jsonify({
        'status': 'ok',
        'message': gettext('To proceed, please check your email.')
    })
Exemplo n.º 7
0
def ingest_upload(collection_id):
    require(request.authz.can(collection_id, request.authz.WRITE))
    sync = get_flag('sync')
    meta, foreign_id = _load_metadata()
    parent_id = _load_parent(collection_id, meta)
    upload_dir = mkdtemp(prefix='aleph.upload.')
    try:
        path = None
        content_hash = None
        for storage in request.files.values():
            path = safe_filename(storage.filename, default='upload')
            path = os.path.join(upload_dir, path)
            storage.save(path)
            content_hash = checksum(path)
        document = Document.by_keys(collection_id=collection_id,
                                    parent_id=parent_id,
                                    foreign_id=foreign_id,
                                    content_hash=content_hash)
        document.update(meta)
        document.schema = Document.SCHEMA
        if content_hash is None:
            document.schema = Document.SCHEMA_FOLDER
        ingest_document(document, path,
                        role_id=request.authz.id,
                        content_hash=content_hash)
    finally:
        shutil.rmtree(upload_dir)

    if document.collection.casefile:
        # Make sure collection counts are always accurate.
        update_document(document, sync=sync)
    return jsonify({
        'status': 'ok',
        'id': stringify(document.id)
    }, status=201)
Exemplo n.º 8
0
def generate(collection_id):
    data = parse_request(XrefSchema)
    collection = get_db_collection(collection_id, request.authz.WRITE)
    args = {
        "against_collection_ids": data.get("against_collection_ids")
    }
    xref_collection.apply_async([collection.id], kwargs=args, priority=5)
    return jsonify({'status': 'accepted'}, status=202)
Exemplo n.º 9
0
def _load_parent(collection_id, meta):
    """Determine the parent document for the document that is to be
    ingested."""
    parent_id = meta.get('parent_id')
    if parent_id is None:
        return
    parent = Document.by_id(parent_id, collection_id=collection_id)
    if parent is None:
        raise BadRequest(response=jsonify({
            'status': 'error',
            'message': 'Cannot load parent document'
        }, status=400))
    return parent_id
Exemplo n.º 10
0
def metadata():
    locale = get_locale()
    enable_cache(vary_user=False, vary=str(locale))
    key = cache.key('metadata', locale)
    data = cache.get_complex(key)
    if data is not None:
        return jsonify(data)

    auth = {}
    if settings.PASSWORD_LOGIN:
        auth['password_login_uri'] = url_for('sessions_api.password_login')
        auth['registration_uri'] = url_for('roles_api.create_code')
    if settings.OAUTH:
        auth['oauth_uri'] = url_for('sessions_api.oauth_init')

    data = {
        'status': 'ok',
        'maintenance': request.authz.in_maintenance,
        'app': {
            'title': settings.APP_TITLE,
            'description': settings.APP_DESCRIPTION,
            'version': __version__,
            'banner': settings.APP_BANNER,
            'ui_uri': settings.APP_UI_URL,
            'samples': settings.SAMPLE_SEARCHES,
            'logo': settings.APP_LOGO,
            'favicon': settings.APP_FAVICON,
            'locale': str(locale),
            'locales': settings.UI_LANGUAGES
        },
        'categories': Collection.CATEGORIES,
        'countries': registry.country.names,
        'languages': registry.language.names,
        'model': model,
        'auth': auth
    }
    cache.set_complex(key, data, expire=120)
    return jsonify(data)
Exemplo n.º 11
0
def openapi():
    """Generate an OpenAPI 3.0 documentation JSON file for the API."""
    enable_cache(vary_user=False)
    spec = get_openapi_spec(current_app)
    for name, view in current_app.view_functions.items():
        if name in (
                "static",
                "base_api.openapi",
                "base_api.api_v1_message",
                "sessions_api.oauth_callback",
        ):
            continue
        log.info("%s - %s", name, view.__qualname__)
        spec.path(view=view)
    return jsonify(spec.to_dict())
Exemplo n.º 12
0
def _load_metadata():
    """Unpack the common, pre-defined metadata for all the uploaded files."""
    try:
        meta = json.loads(request.form.get('meta', '{}'))
    except Exception as ex:
        raise BadRequest(str(ex))

    validate_data(meta, DocumentCreateSchema)
    foreign_id = stringify(meta.get('foreign_id'))
    if not len(request.files) and foreign_id is None:
        raise BadRequest(response=jsonify({
            'status': 'error',
            'message': 'Directories need to have a foreign_id'
        }, status=400))
    return meta, foreign_id
Exemplo n.º 13
0
def metadata():
    locale = get_locale()
    enable_cache(vary_user=False, vary=str(locale))
    key = cache.key('metadata', locale)
    data = cache.get_complex(key)
    if data is not None:
        return jsonify(data)

    auth = {}
    if settings.PASSWORD_LOGIN:
        auth['password_login_uri'] = url_for('sessions_api.password_login')
        auth['registration_uri'] = url_for('roles_api.create_code')
    if settings.OAUTH:
        auth['oauth_uri'] = url_for('sessions_api.oauth_init')

    data = {
        'status': 'ok',
        'maintenance': request.authz.in_maintenance,
        'app': {
            'title': settings.APP_TITLE,
            'version': __version__,
            'ui_uri': settings.APP_UI_URL,
            'samples': settings.SAMPLE_SEARCHES,
            'logo': settings.APP_LOGO,
            'favicon': settings.APP_FAVICON,
            'locale': str(locale),
            'locales': settings.UI_LANGUAGES
        },
        'categories': Collection.CATEGORIES,
        'countries': registry.country.names,
        'languages': registry.language.names,
        'schemata': model,
        'auth': auth
    }
    cache.set_complex(key, data, expire=120)
    return jsonify(data)
Exemplo n.º 14
0
def suggest():
    require(request.authz.logged_in)
    parser = QueryParser(request.args, request.authz, limit=10)
    if parser.prefix is None or len(parser.prefix) < 3:
        # Do not return 400 because it's a routine event.
        return jsonify({
            'status': 'error',
            'message': gettext('prefix filter is too short'),
            'results': [],
            'total': 0
        })
    # this only returns users, not groups
    q = Role.by_prefix(parser.prefix, exclude=parser.exclude)
    result = DatabaseQueryResult(request, q, parser=parser)
    return RoleSerializer.jsonify_result(result)
Exemplo n.º 15
0
def suggest_type():
    prefix = request.args.get('prefix', '').lower().strip()
    matches = []
    for schema in model:
        match = not len(prefix)
        match = match or prefix in schema.name.lower()
        match = match or prefix in schema.label.lower()
        if match and schema.matchable:
            matches.append(get_freebase_type(schema))
    return jsonify({
        "code": "/api/status/ok",
        "status": "200 OK",
        "prefix": request.args.get('prefix', ''),
        "result": matches
    })
Exemplo n.º 16
0
def handle_es_error(err):
    message = err.error
    try:
        status = int(err.status_code)
    except Exception:
        status = 500
    try:
        for cause in err.info.get('error', {}).get('root_cause', []):
            message = cause.get('reason', message)
    except Exception as ex:
        log.debug(ex)
    return jsonify({
        'status': 'error',
        'message': message
    }, status=status)
Exemplo n.º 17
0
def references(id):
    enable_cache()
    entity = get_index_entity(id, request.authz.READ)
    record_audit(Audit.ACT_ENTITY, id=id)
    results = []
    for prop, total in entity_references(entity, request.authz):
        key = ('filter:properties.%s' % prop.name, id)
        link = url_for('entities_api.index', _query=(key, ))
        results.append({
            'count': total,
            'property': prop,
            'schema': prop.schema.name,
            'results': link
        })
    return jsonify({'status': 'ok', 'total': len(results), 'results': results})
Exemplo n.º 18
0
def view(document_id):
    enable_cache()
    data = get_index_document(document_id)
    document = get_db_document(document_id)
    data['headers'] = document.headers
    # TODO: should this be it's own API? Probably so, but for that it would
    # be unclear if we should JSON wrap it, or serve plain with the correct
    # MIME type?
    if Document.SCHEMA_HTML in document.model.names:
        data['html'] = sanitize_html(document.body_raw, document.source_url)
    if Document.SCHEMA_TEXT in document.model.names:
        data['text'] = document.body_text
    if Document.SCHEMA_IMAGE in document.model.names:
        data['text'] = document.body_text
    return jsonify(data, schema=CombinedSchema)
Exemplo n.º 19
0
def _load_parent(collection, meta):
    """Determine the parent document for the document that is to be
    ingested."""
    parent_id = meta.get('parent_id')
    if parent_id is None:
        return
    parent = Document.by_id(parent_id, collection_id=collection.id)
    if parent is None:
        raise BadRequest(response=jsonify(
            {
                'status': 'error',
                'message': 'Cannot load parent document'
            },
            status=400))
    return parent
Exemplo n.º 20
0
def ingest_upload(id):
    collection = obj_or_404(Collection.by_id(id))
    require(request.authz.can_write(collection.id))
    meta, foreign_id = _load_metadata()
    parent_id = _load_parent(collection, meta)
    upload_dir = mkdtemp()
    try:
        documents = []
        for storage in request.files.values():
            path = safe_filename(storage.filename)
            path = os.path.join(upload_dir, path)
            storage.save(path)
            content_hash = checksum(path)
            document = Document.by_keys(collection=collection,
                                        parent_id=parent_id,
                                        foreign_id=foreign_id,
                                        content_hash=content_hash)
            document.mime_type = storage.mimetype
            if storage.filename:
                document.file_name = os.path.basename(storage.filename)
            document.update(meta)
            ingest_document(document, path,
                            role_id=request.authz.id)
            documents.append(document)

        if not len(request.files):
            # If there is no files uploaded, try to create an empty
            # directory instead. Maybe this should be more explicit,
            # but it seemed like the most simple way of fitting it
            # into the API.
            document = Document.by_keys(collection=collection,
                                        parent_id=parent_id,
                                        foreign_id=foreign_id)
            document.update(meta)
            ingest_document(document, upload_dir,
                            role_id=request.authz.id)
            documents.append(document)
    finally:
        shutil.rmtree(upload_dir)

    # Update child counts in index.
    if parent_id is not None:
        index_document_id.delay(parent_id)

    return jsonify({
        'status': 'ok',
        'documents': [DocumentSchema().dump(d).data for d in documents]
    })
Exemplo n.º 21
0
def _load_parent(collection, meta):
    """Determine the parent document for the document that is to be
    ingested."""
    parent = ensure_dict(meta.get("parent"))
    parent_id = meta.get("parent_id", parent.get("id"))
    if parent_id is None:
        return
    parent = Document.by_id(parent_id, collection=collection)
    if parent is None:
        raise BadRequest(
            response=jsonify(
                {"status": "error", "message": "Cannot load parent document"},
                status=400,
            )
        )
    return parent
Exemplo n.º 22
0
def permissions_update(id):
    # TODO: consider using a list to bundle permission writes
    collection = get_collection(id, request.authz.WRITE)
    data = parse_request(schema=PermissionSchema)
    role = Role.all().filter(Role.id == data['role']['id']).first()
    if role is None or not check_visible(role):
        raise BadRequest()

    perm = update_permission(role,
                             collection,
                             data['read'],
                             data['write'])
    return jsonify({
        'status': 'ok',
        'updated': PermissionSchema().dump(perm)
    })
Exemplo n.º 23
0
def suggest_type():
    prefix = request.args.get('prefix', '').lower().strip()
    tag_request(prefix=prefix)
    matches = []
    for schema in model:
        match = not len(prefix)
        match = match or prefix in schema.name.lower()
        match = match or prefix in schema.label.lower()
        if match and schema.matchable:
            matches.append(get_freebase_type(schema))
    return jsonify({
        "code": "/api/status/ok",
        "status": "200 OK",
        "prefix": request.args.get('prefix', ''),
        "result": matches
    })
Exemplo n.º 24
0
def password_login():
    """Provides email and password authentication."""
    data = parse_request(LoginSchema)
    role = Role.by_email(data.get('email'))
    if role is None or not role.has_password:
        return Unauthorized("Authentication has failed.")

    if not role.check_password(data.get('password')):
        return Unauthorized("Authentication has failed.")

    update_role(role)
    db.session.commit()
    return jsonify({
        'status': 'ok',
        'token': create_token(role)
    })
Exemplo n.º 25
0
def references(entity_id):
    enable_cache()
    entity = get_index_entity(entity_id, request.authz.READ)
    tag_request(collection_id=entity.get('collection_id'))
    results = []
    for prop, total in entity_references(entity, request.authz):
        results.append({
            'count': total,
            'property': prop,
            'schema': prop.schema.name,
        })
    return jsonify({
        'status': 'ok',
        'total': len(results),
        'results': results
    })
Exemplo n.º 26
0
def password_login():
    """Provides email and password authentication."""
    require(settings.PASSWORD_LOGIN)
    data = parse_request(LoginSchema)
    role = Role.by_email(data.get('email'))
    if role is None or not role.has_password:
        raise BadRequest(gettext("Invalid user or password."))

    if not role.check_password(data.get('password')):
        raise BadRequest(gettext("Invalid user or password."))

    db.session.commit()
    update_role(role)
    authz = Authz.from_role(role)
    request.authz = authz
    return jsonify({'status': 'ok', 'token': authz.to_token(role=role)})
Exemplo n.º 27
0
def references(entity_id):
    enable_cache()
    entity = get_index_entity(entity_id, request.authz.READ)
    record_audit(Audit.ACT_ENTITY, id=entity_id)
    results = []
    for prop, total in entity_references(entity, request.authz):
        results.append({
            'count': total,
            'property': prop,
            'schema': prop.schema.name,
        })
    return jsonify({
        'status': 'ok',
        'total': len(results),
        'results': results
    })
Exemplo n.º 28
0
def tags(entity_id):
    """
    ---
    get:
      summary: Get entity tags
      description: >-
        Get tags for the entity with id `entity_id`. Tags include the query
        string to make a search by that particular tag.
      parameters:
      - in: path
        name: entity_id
        required: true
        schema:
          type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                allOf:
                - $ref: '#/components/schemas/QueryResponse'
                properties:
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/EntityTag'
      tags:
      - Entity
    """
    enable_cache()
    entity = get_index_entity(entity_id, request.authz.READ)
    tag_request(collection_id=entity.get("collection_id"))
    results = []
    for (field, value, total) in entity_tags(entity, request.authz):
        qvalue = quote(value.encode("utf-8"))
        key = ("filter:%s" % field, qvalue)
        qid = query_string([key])
        results.append({
            "id": qid,
            "value": value,
            "field": field,
            "count": total
        })
    results.sort(key=lambda p: p["count"], reverse=True)
    return jsonify({"status": "ok", "total": len(results), "results": results})
Exemplo n.º 29
0
def content(entity_id):
    """
    ---
    get:
      summary: Get the content of an entity
      description: >
        Return the text and/or html content of the entity with id `entity_id`
      parameters:
      - in: path
        name: entity_id
        required: true
        schema:
          type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  headers:
                    type: object
                  html:
                    type: string
                  text:
                    type: string
                type: object
          description: OK
        '404':
          description: Not Found
      tags:
      - Entity
    """
    enable_cache()
    entity = get_index_entity(entity_id, request.authz.READ, excludes=['text'])
    tag_request(collection_id=entity.get('collection_id'))
    proxy = model.get_proxy(entity)
    html = proxy.first('bodyHtml', quiet=True)
    source_url = proxy.first('sourceUrl', quiet=True)
    encoding = proxy.first('encoding', quiet=True)
    html = sanitize_html(html, source_url, encoding=encoding)
    headers = proxy.first('headers', quiet=True)
    headers = registry.json.unpack(headers)
    return jsonify({
        'headers': headers,
        'text': proxy.first('bodyText', quiet=True),
        'html': html
    })
Exemplo n.º 30
0
def statistics():
    """Get a summary of the data acessible to the current user.
    ---
    get:
      summary: System-wide user statistics.
      description: >
        Get a summary of the data acessible to the current user.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
      tags:
      - System
    """
    enable_cache()
    collections = request.authz.collections(request.authz.READ)
    for collection_id in collections:
        resolver.queue(request, Collection, collection_id)
    resolver.resolve(request)

    # Summarise stats. This is meant for display, so the counting is a bit
    # inconsistent between counting all collections, and source collections
    # only.
    schemata = defaultdict(int)
    countries = defaultdict(int)
    categories = defaultdict(int)
    for collection_id in collections:
        data = resolver.get(request, Collection, collection_id)
        if data is None or data.get('casefile'):
            continue
        categories[data.get('category')] += 1
        things = get_collection_things(collection_id)
        for schema, count in things.items():
            schemata[schema] += count
        for country in data.get('countries', []):
            countries[country] += 1

    return jsonify({
        'collections': len(collections),
        'schemata': dict(schemata),
        'countries': dict(countries),
        'categories': dict(categories),
        'things': sum(schemata.values()),
    })
Exemplo n.º 31
0
def suggest():
    """
    ---
    get:
      summary: Suggest users matching a search prefix
      description: >-
        For a given `prefix`, suggest matching user accounts. For
        security reasons, the prefix must be more than three
        characters long.
      parameters:
      - in: query
        name: prefix
        required: true
        schema:
          type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                allOf:
                - $ref: '#/components/schemas/QueryResponse'
                properties:
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/Role'
      tags:
      - Role
    """
    require(request.authz.logged_in)
    parser = QueryParser(request.args, request.authz, limit=10)
    if parser.prefix is None or len(parser.prefix) < 3:
        # Do not return 400 because it's a routine event.
        return jsonify({
            "status": "error",
            "message": gettext("prefix filter is too short"),
            "results": [],
            "total": 0,
        })
    # this only returns users, not groups
    exclude = ensure_list(parser.excludes.get("id"))
    q = Role.by_prefix(parser.prefix, exclude=exclude)
    result = DatabaseQueryResult(request, q, parser=parser)
    return RoleSerializer.jsonify_result(result)
Exemplo n.º 32
0
def ingest_upload(id):
    collection = get_db_collection(id, request.authz.WRITE)
    meta, foreign_id = _load_metadata(collection)
    parent_id = _load_parent(collection, meta)
    upload_dir = mkdtemp(prefix='aleph.upload.')
    try:
        documents = []
        for storage in request.files.values():
            path = safe_filename(storage.filename, default='upload')
            path = os.path.join(upload_dir, path)
            storage.save(path)
            content_hash = checksum(path)
            document = Document.by_keys(collection=collection,
                                        parent_id=parent_id,
                                        foreign_id=foreign_id,
                                        content_hash=content_hash)
            document.update(meta)
            ingest_document(document, path, role_id=request.authz.id)
            documents.append(document)

        if not len(request.files):
            # If there is no files uploaded, try to create an empty
            # directory instead. Maybe this should be more explicit,
            # but it seemed like the most simple way of fitting it
            # into the API.
            document = Document.by_keys(collection=collection,
                                        parent_id=parent_id,
                                        foreign_id=foreign_id)
            document.schema = Document.SCHEMA_FOLDER
            document.update(meta)
            ingest_document(document,
                            None,
                            role_id=request.authz.id,
                            shallow=True)
            documents.append(document)
    finally:
        shutil.rmtree(upload_dir)

    # Update child counts in index.
    if parent_id is not None:
        index_document_id.apply_async([parent_id], priority=1)

    return jsonify({
        'status':
        'ok',
        'documents': [CombinedSchema().dump(d).data for d in documents]
    })
Exemplo n.º 33
0
def tags(entity_id):
    """
    ---
    get:
      summary: Get entity tags
      description: >-
        Get tags for the entity with id `entity_id`. Tags include the query
        string to make a search by that particular tag.
      parameters:
      - in: path
        name: entity_id
        required: true
        schema:
          type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                allOf:
                - $ref: '#/components/schemas/QueryResponse'
                properties:
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/EntityTag'
      tags:
      - Entity
    """
    enable_cache()
    entity = get_index_entity(entity_id, request.authz.READ)
    tag_request(collection_id=entity.get('collection_id'))
    results = []
    for (field, value, total) in entity_tags(entity, request.authz):
        qvalue = quote(value.encode('utf-8'))
        key = ('filter:%s' % field, qvalue)
        results.append({
            'id': query_string([key]),
            'value': value,
            'field': field,
            'count': total,
        })

    results.sort(key=lambda p: p['count'], reverse=True)
    return jsonify({'status': 'ok', 'total': len(results), 'results': results})
Exemplo n.º 34
0
def statistics(collection_id):
    """
    ---
    get:
      summary: Get a summary of collection contents
      description: >
        Get a listing of the most common entity types and attributes in the
        given collection. The result is cached and can be somewhat out of
        sync with the real numbers.
      parameters:
      - description: The collection ID.
        in: path
        name: collection_id
        required: true
        schema:
          minimum: 1
          type: integer
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  schema:
                    type: object
                  names:
                    type: object
                  addresses:
                    type: object
                  countries:
                    type: object
                  languages:
                    type: object
                  phones:
                    type: object
                  emails:
                    type: object
                  ibans:
                    type: object
      tags:
      - Collection
    """
    collection = get_db_collection(collection_id, request.authz.READ)
    return jsonify(get_collection_stats(collection.id))
Exemplo n.º 35
0
def password_login():
    """Provides email and password authentication."""
    data = parse_request(schema=LoginSchema)
    q = Role.by_email(data.get('email'))
    q = q.filter(Role.password_digest != None)  # noqa
    role = q.first()

    if role is None:
        return Unauthorized("Authentication has failed.")

    if not role.check_password(data.get('password')):
        return Unauthorized("Authentication has failed.")

    return jsonify({
        'status': 'ok',
        'token': create_token(role)
    })
Exemplo n.º 36
0
def references(entity_id):
    enable_cache()
    entity = get_index_entity(entity_id, request.authz.READ)
    tag_request(collection_id=entity.get('collection_id'))
    record_audit(Audit.ACT_ENTITY, id=entity_id)
    results = []
    for prop, total in entity_references(entity, request.authz):
        results.append({
            'count': total,
            'property': prop,
            'schema': prop.schema.name,
        })
    return jsonify({
        'status': 'ok',
        'total': len(results),
        'results': results
    })
Exemplo n.º 37
0
def tags(entity_id):
    enable_cache()
    entity = get_index_entity(entity_id, request.authz.READ)
    tag_request(collection_id=entity.get('collection_id'))
    results = []
    for (field, value, total) in entity_tags(entity, request.authz):
        qvalue = quote(value.encode('utf-8'))
        key = ('filter:%s' % field, qvalue)
        results.append({
            'id': query_string([key]),
            'value': value,
            'field': field,
            'count': total,
        })

    results.sort(key=lambda p: p['count'], reverse=True)
    return jsonify({'status': 'ok', 'total': len(results), 'results': results})
Exemplo n.º 38
0
def _load_metadata():
    """Unpack the common, pre-defined metadata for all the uploaded files."""
    try:
        meta = json.loads(request.form.get("meta", "{}"))
    except Exception as ex:
        raise BadRequest(str(ex))

    validate(meta, "DocumentIngest")
    foreign_id = stringify(meta.get("foreign_id"))
    if not len(request.files) and foreign_id is None:
        raise BadRequest(
            response=jsonify(
                {"status": "error", "message": "Directories need to have a foreign_id"},
                status=400,
            )
        )
    return meta, foreign_id
Exemplo n.º 39
0
def references(entity_id):
    """
    ---
    get:
      summary: Get entity references
      description: >-
        Get the schema-wise aggregation of references to the entity with id
        `entity_id`. This can be used to find and display adjacent entities.
      parameters:
      - in: path
        name: entity_id
        required: true
        schema:
          type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                allOf:
                - $ref: '#/components/schemas/QueryResponse'
                properties:
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/EntityReference'
      tags:
      - Entity
    """
    enable_cache()
    entity = get_index_entity(entity_id, request.authz.READ)
    tag_request(collection_id=entity.get('collection_id'))
    results = []
    for prop, total in entity_references(entity, request.authz):
        results.append({
            'count': total,
            'property': prop,
            'schema': prop.schema.name,
        })
    return jsonify({
        'status': 'ok',
        'total': len(results),
        'results': results
    })
Exemplo n.º 40
0
def status():
    require(request.authz.logged_in)
    status = get_active_collection_status()
    active_collections = status.pop('datasets')
    active_foreign_ids = set(active_collections.keys())
    collections = request.authz.collections(request.authz.READ)
    results = []
    for fid in active_foreign_ids:
        collection = Collection.by_foreign_id(fid)
        if collection is None:
            continue
        if collection.id in collections:
            result = active_collections[fid]
            result['collection'] = collection.to_dict()
            result['id'] = fid
            results.append(result)
    status['results'] = results
    return jsonify(status)
Exemplo n.º 41
0
def content(entity_id):
    enable_cache()
    entity = get_index_entity(entity_id, request.authz.READ)
    tag_request(collection_id=entity.get('collection_id'))
    for entity in entities_by_ids([entity_id],
                                  schemata=entity.get('schema'),
                                  excludes=['text']):
        proxy = model.get_proxy(entity)
        html = sanitize_html(proxy.first('bodyHtml', quiet=True),
                             proxy.first('sourceUrl', quiet=True))
        headers = proxy.first('headers', quiet=True)
        headers = registry.json.unpack(headers)
        return jsonify({
            'headers': headers,
            'text': proxy.first('bodyText', quiet=True),
            'html': html
        })
    return ('', 404)
Exemplo n.º 42
0
def suggest_entity():
    """Suggest API, emulates Google Refine API."""
    prefix = request.args.get('prefix', '')
    args = {
        'prefix': prefix,
        'filter:schemata': request.args.getlist('type'),
        'filter:collection_id': request.args.getlist('filter:collection_id')
    }
    parser = SearchQueryParser(args, request.authz)
    query = EntitiesQuery(parser)
    result = query.search()
    matches = list(entity_matches(result))
    return jsonify({
        "code": "/api/status/ok",
        "status": "200 OK",
        "prefix": prefix,
        "result": matches
    })
Exemplo n.º 43
0
def content(entity_id):
    enable_cache()
    entity = get_index_entity(entity_id, request.authz.READ)
    tag_request(collection_id=entity.get('collection_id'))
    for entity in entities_by_ids([entity_id],
                                  schemata=entity.get('schema'),
                                  excludes=['text']):
        proxy = model.get_proxy(entity)
        record_audit(Audit.ACT_ENTITY, id=entity_id)
        html = sanitize_html(proxy.first('bodyHtml', quiet=True),
                             proxy.first('sourceUrl', quiet=True))
        headers = proxy.first('headers', quiet=True)
        headers = registry.json.unpack(headers)
        return jsonify({
            'headers': headers,
            'text': proxy.first('bodyText', quiet=True),
            'html': html
        })
    return ('', 404)
Exemplo n.º 44
0
def password_login():
    """Provides email and password authentication."""
    data = parse_request(LoginSchema)
    role = Role.by_email(data.get('email'))
    if role is None or not role.has_password:
        return Unauthorized("Authentication has failed.")

    if not role.check_password(data.get('password')):
        return Unauthorized("Authentication has failed.")

    db.session.commit()
    update_role(role)
    authz = Authz.from_role(role)
    request.authz = authz
    record_audit(Audit.ACT_LOGIN)
    return jsonify({
        'status': 'ok',
        'token': authz.to_token(role=role)
    })
Exemplo n.º 45
0
def statistics():
    """Get a summary of the data acessible to the current user."""
    enable_cache()
    collections = request.authz.collections(request.authz.READ)
    for collection_id in collections:
        resolver.queue(request, Collection, collection_id)
    for role_id in request.authz.roles:
        resolver.queue(request, Role, role_id)
    resolver.resolve(request)

    # Summarise stats. This is meant for display, so the counting is a bit
    # inconsistent between counting all collections, and source collections
    # only.
    schemata = defaultdict(int)
    countries = defaultdict(int)
    categories = defaultdict(int)
    for collection_id in collections:
        data = resolver.get(request, Collection, collection_id)
        if data is None or data.get('casefile'):
            continue
        categories[data.get('category')] += 1
        for schema, count in data.get('schemata', {}).items():
            schemata[schema] += count
        for country in data.get('countries', []):
            countries[country] += 1

    # Add a users roles to the home page:
    groups = []
    for role_id in request.authz.roles:
        data = resolver.get(request, Role, role_id)
        if data is None or data.get('type') != Role.GROUP:
            continue
        groups.append(RoleSerializer().serialize(data))

    return jsonify({
        'collections': len(collections),
        'schemata': dict(schemata),
        'countries': dict(countries),
        'categories': dict(categories),
        'groups': groups,
        'things': sum(schemata.values()),
    })
Exemplo n.º 46
0
def suggest_entity():
    """Suggest API, emulates Google Refine API."""
    prefix = request.args.get('prefix', '')
    tag_request(prefix=prefix)
    types = request.args.getlist('type') or Entity.THING
    args = {
        'prefix': prefix,
        'filter:schemata': types,
        'filter:collection_id': request.args.getlist('filter:collection_id')
    }
    parser = SearchQueryParser(args, request.authz)
    query = EntitiesQuery(parser)
    result = query.search()
    matches = list(entity_matches(result))
    return jsonify({
        "code": "/api/status/ok",
        "status": "200 OK",
        "prefix": prefix,
        "result": matches
    })
Exemplo n.º 47
0
def reconcile_index(collection=None):
    domain = settings.APP_UI_URL.strip('/')
    label = settings.APP_TITLE
    suggest_query = []
    schemata = list(model)
    if collection is not None:
        label = '%s (%s)' % (collection.get('label'), label)
        suggest_query.append(('filter:collection_id', collection.get('id')))
        schemata = [model.get(s) for s in collection.get('schemata').keys()]
    return jsonify({
        'name': label,
        'identifierSpace': 'http://rdf.freebase.com/ns/type.object.id',
        'schemaSpace': 'http://rdf.freebase.com/ns/type.object.id',
        'view': {'url': entity_url('{{id}}')},
        'preview': {
            'url': entity_url('{{id}}'),
            'width': 800,
            'height': 400
        },
        'suggest': {
            'entity': {
                'service_url': domain,
                'service_path': url_for('reconcile_api.suggest_entity',
                                        _query=suggest_query,
                                        _authorize=True,
                                        _relative=True)
            },
            'type': {
                'service_url': domain,
                'service_path': url_for('reconcile_api.suggest_type',
                                        _relative=True)
            },
            'property': {
                'service_url': domain,
                'service_path': url_for('reconcile_api.suggest_property',
                                        _relative=True)
            }
        },
        'defaultTypes': [get_freebase_type(s) for s in schemata if s.matchable]
    })
Exemplo n.º 48
0
def tags(entity_id):
    enable_cache()
    entity = get_index_entity(entity_id, request.authz.READ)
    tag_request(collection_id=entity.get('collection_id'))
    record_audit(Audit.ACT_ENTITY, id=entity_id)
    results = []
    for (field, value, total) in entity_tags(entity, request.authz):
        qvalue = quote(value.encode('utf-8'))
        key = ('filter:%s' % field, qvalue)
        results.append({
            'id': query_string([key]),
            'value': value,
            'field': field,
            'count': total,
        })

    results.sort(key=lambda p: p['count'], reverse=True)
    return jsonify({
        'status': 'ok',
        'total': len(results),
        'results': results
    })
Exemplo n.º 49
0
def healthz():
    return jsonify({'status': 'ok'})
Exemplo n.º 50
0
def handle_bad_request(err):
    return jsonify({
        'status': 'error',
        'message': err.description
    }, status=400)
Exemplo n.º 51
0
def handle_authz_error(err):
    return jsonify({
        'status': 'error',
        'message': gettext('You are not authorized to do this.'),
        'roles': request.authz.roles
    }, status=403)
Exemplo n.º 52
0
def handle_not_found_error(err):
    return jsonify({
        'status': 'error',
        'message': gettext('This path does not exist.')
    }, status=404)
Exemplo n.º 53
0
def handle_server_error(err):
    log.exception("%s: %s", type(err).__name__, err)
    return jsonify({
        'status': 'error',
        'message': gettext('Internal server error.')
    }, status=500)
Exemplo n.º 54
0
def handle_invalid_data(err):
    return jsonify({
        'status': 'error',
        'message': str(err),
        'errors': err.errors
    }, status=400)
Exemplo n.º 55
0
def api_v1_message(path):
    return jsonify({
        'status': 'error',
        'message': gettext('/api/1/ is deprecated, please use /api/2/.')
    }, status=410)
Exemplo n.º 56
0
def mark_read():
    require(request.authz.logged_in)
    role = Role.by_id(request.authz.id)
    role.notified_at = datetime.utcnow()
    db.session.commit()
    return jsonify({'status': 'ok'}, status=202)
Exemplo n.º 57
0
def handle_jwt_expired(err):
    return jsonify({
        'status': 'error',
        'errors': gettext('Access token is invalid.')
    }, status=401)