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
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
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
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
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
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