예제 #1
0
def change_privilege():
    """
    Update privilege of a user.
    Requires the requester to login and be an admin.
    Example json:
    {
        "username": "******",
        "privilege": "admin",
    }
    or
    {
        "username": "******",
        "privilege": "annotator",
    }
    Valid privileges are "annotator", "admin"
    Returns:
        401 if current user is not logged in
        403 if current user is not admin
        400 if requested user is not found, privilege name is not valid
        200 if updated successfully

    """
    current_user = get_jwt_identity()
    check_user_admin_privilege(current_user)

    json = request.get_json()
    check_json(json, ('username', 'privilege'))

    username = json['username']

    user = User.query.filter_by(username=username).first()
    if user is None:
        abort(400, 'User %s not found' % username)

    privilege_map = {
        'admin': PrivilegesEnum.ADMIN,
        'annotator': PrivilegesEnum.ANNOTATOR
    }

    privilege = json['privilege']
    if privilege not in privilege_map:
        abort(400, 'Invalid privilege %s' % privilege)

    user.privileges = privilege_map[privilege]
    db.session.commit()

    return construct_msg('Privilege updated to %s successfully' %
                         privilege), 200
예제 #2
0
def update_info():
    """
    Allow user to update personal info: username, email, and password

    Example input json:
    {
        "username": "******",
        "current_password": "******",
        "email": "*****@*****.**",
        "password": "******"
    }

    Will only update provided fields. "current_password" is required.

    Raises:
        400 if new password format is incorrect
        400 if new email format is incorrect
        400 if username or email is duplicate
        401 if the current password is not correct
    """
    current_user = get_jwt_identity()
    json = request.get_json()
    user = User.query.filter_by(username=current_user).first()
    check_json(json, ['current_password'])
    if not user.verify_password(json['current_password']):
        abort(401, 'Current password incorrect')
    new_password = json.get('password', None)
    if new_password and credential_checking(new_password):
        user.set_password(new_password)

    new_email = json.get('email', None)
    if new_password and email_checking(new_email):
        user.email = new_email

    new_username = json.get('username', None)
    if new_username:
        user.username = new_username

    try:
        db.session.commit()
    except IntegrityError:
        abort(400, 'Username or email already exist')

    return construct_msg('Successfully updated'), 200
예제 #3
0
def add_label(project_id):
    """
    Add a label to the project

    Takes a json object --

    {
       "label_text": "first label",
       "label_color": "#12345"
    }

    Args:
        project_id -- ID of the project

    Returns:
        200 and json object
        {
            "msg": "Label added successfully"
        }

    """
    project = maybe_get_project(project_id)
    req = request.get_json()

    check_json(req, ['label_text', 'label_color'])

    label_name = req['label_text']
    label_color = req['label_color']
    if label_color[0] != '#' or not all(c in hexdigits
                                        for c in label_color[1:]):
        abort(400, 'Failed to add label, need color')
    label = Label(label_name=label_name, label_color=label_color)
    project.labels.append(label)
    try:
        db.session.add(label)
        db.session.commit()
    except IntegrityError:
        db.session.rollback()
        abort(400, 'Failed to add label, label name should be unique')
    return jsonify({'label_id': label.id}), 200
예제 #4
0
def request_permission(project_id):
    """ Request for specific permission to a project

        Request for specified privilege (READ_WRITE or READ_ONLY) to project
        upon receiving a `POST` request to the `/project/<project_id>/request`
        entry point. User must be signed in. User must provide a `message_type`
        to specify the privilege he or she is requesting for.

        `message_type` takes a string of two values: `r` or `rw`,
        where `r` is `READ_ONLY` and `rw` is `READ_WRITE`

        The request message will be sent to all admins of the project. Note that
        an annotator can also send a request of 'rw' permission. The decision of
        whether upgrading the ANNOTATOR to ADMIN and then granting 'rw' permission
        is left to the ADMIN.

        Must supply a jwt-token to verify user status and extract `user_id`.

        Raises:
            400 Error if message_type is not specified
            400 Error if message is not 'r' or 'rw'
            401 Error if not logged in
            404 Error if project does not exist

        Returns:
            201 if success. Will also return `project_id`.
        """

    req = request.get_json()
    check_json(req, ['message_type'])  # check missing keys

    project = Project.query.filter_by(id=project_id).first()
    if project is None:
        abort(404, 'Project with id=%s does not exist' % project_id)

    current_user = get_jwt_identity()
    user = User.query.filter_by(username=current_user).first()

    map_code_to_message_type = {
        'r': MessageTypeEnum.READ_ONLY_PERMISSION_REQUEST,
        'rw': MessageTypeEnum.READ_WRITE_PERMISSION_REQUEST,
    }

    if req['message_type'] not in map_code_to_message_type:
        abort(400, 'Not able to interpret message_type.')
    message_type = map_code_to_message_type[req['message_type']]

    # Get the list of admins to the project
    admins = []
    for permission in project.permissions:
        if permission.access_type == AccessTypeEnum.READ_WRITE:
            admins.append(permission.user)

    message = Message(type=message_type)
    try:
        db.session.add(message)
        user.sent_messages.append(message)
        for admin in admins:
            admin.received_messages.append(message)
        db.session.commit()
    except IntegrityError:
        db.session.rollback()
        abort(400, 'Create message failed.')

    return construct_msg('Message sent successfully'), 200
예제 #5
0
def update_user_permission(project_id):
    """ Grant a user with specified privilege to project

        Grant a user with specified privilege (READ_WRITE or READ_ONLY) to
        project
        upon receiving a `PUT`request to the `/project/<project_id>/permissions`
        entry point. User must be signed in as an ADMIN and have READ_WRITE
        permission to the project. User must provide a `username` to specify the
        user that will be granted permissions, and `access_type` to specify the
        type of privilege to grant.

        `access_type` takes a string of two values: `r` or `rw`, where `r` is
        `READ_ONLY` and `rw` is `READ_WRITE`

        Only user with `ADMIN` privilege can have `READ_WRITE` access to
        projects.
        That is, the user indicated by `username` should have an `ADMIN`
        privilege
        (as opposed to `ANNOTATOR` privilege)

        Must supply a jwt-token to verify user status and extract `user_id`.

        Raises:
            400 Error if username or access_type is not specified
            400 Error if access_type is not 'r' or 'rw'
            401 Error if not logged in
            401 Error if user is not an ADMIN
            401 Error if user does not have privilege to update permission
            403 Error if user indicated by `username` has only ANNOTATOR
            privilege
                but `access_type` is 'rw'
            404 Error if user with user_name does not exist

        Returns:
            201 if success. Will also return `project_id`.
        """

    project = maybe_get_project(project_id)  # check privilege and get project

    req = request.get_json()
    check_json(req, ('username', 'access_type'))  # check missing keys

    username = req['username']
    user = User.query.filter_by(username=username).first()
    if user is None:
        abort(404, 'User with username=%s not found' % username)

    map_code_to_access_type = {
        'r': AccessTypeEnum.READ_ONLY,
        'rw': AccessTypeEnum.READ_WRITE,
    }
    if req['access_type'] not in map_code_to_access_type:
        abort(400, 'Not able to interpret access_type.')
    access_type = map_code_to_access_type[req['access_type']]

    # Check if user has already had some sort of permission to the project
    permission = ProjectPermission.query.filter(
        (ProjectPermission.user_id == user.id)
        & (ProjectPermission.project_id == project_id)).first()
    if permission is not None:
        permission.access_type = access_type
        db.session.commit()
        return construct_msg('Permission updated successfully'), 200

    new_permission = ProjectPermission(access_type=access_type)
    project.permissions.append(new_permission)
    user.project_permissions.append(new_permission)
    try:
        db.session.add(new_permission)
        db.session.commit()
    except IntegrityError:
        db.session.rollback()
        abort(400, 'Update permission failed.')

    return construct_msg('Permission added successfully'), 201
예제 #6
0
def create_project():
    """ Create a new project by the user currently signed in

    Create a new project entry in the database and a new folder in the
    filesystem
    to hold image dataset upon receiving a `POST`request to the `/project` entry
    point. User must be signed in as an ADMIN and must provide a `project name`
    to create a new project.

    Must supply a jwt-token to verify user status and extract `user_id`.
    `project name` must be unique.

    Raises:
        400 Error if project name is not specified
        401 Error if not logged in
        401 Error if user is not an ADMIN
        400 Error if project name already exists in the database


    Returns:
        201 if success. Will also return `project_id`.
    """

    req = request.get_json()
    check_json(req, ['project_name'])

    # check user identity and privilege
    identity = get_jwt_identity()
    user = check_user_admin_privilege(identity)

    project_name = req['project_name']
    user_id = user.id
    project = Project(project_name=project_name, created_by=user_id)

    try:
        db.session.add(project)
        db.session.flush()  # To make sure no duplicates exist in db
    except IntegrityError:
        db.session.rollback()
        abort(
            400, 'Duplicate project name. '
            'Please provide a different project name.')
    else:
        # if able to add project to db, try add project_permission
        # creator is granted with READ_WRITE privilege
        project_permission = ProjectPermission(
            access_type=AccessTypeEnum.READ_WRITE,
            user_id=user_id,
            project_id=project.id)
        user.project_permissions.append(project_permission)
        project.permissions.append(project_permission)
        try:
            db.session.add(project_permission)
        except DatabaseError:
            db.session.rollback()
            abort(400, 'Cannot update project permission for user.')

    db.session.commit()

    # create project directory
    project_dir = os.path.join(app.config['STATIC_STORAGE_DIR'],
                               str(project.id))
    if not os.path.exists(project_dir):
        os.makedirs(project_dir)

    return jsonify({
        'msg': 'project added successfully',
        'project_id': project.id
    }), 201