def delete_project(project_id): """ Delete a project with specified project id. Doesn't require a body Args: project_id -- The ID of the project Raises: 401 if * The project doesn't exist * Currently logged in user is not admin of this project (read write access) Returns: 200 and a json object -- { 'msg': 'Project deleted successfully' } """ project = maybe_get_project(project_id) # check privilege and get project # Delete the whole image directory shutil.rmtree( os.path.join(app.config['STATIC_STORAGE_DIR'], str(project.id))) db.session.delete(project) db.session.commit() return construct_msg('Project deleted successfully'), 200
def upload_image(project_id): """ Upload image to a project Args: project_id: The id of the project """ project = maybe_get_project(project_id) if 'image' in request.files: file = request.files['image'] project = project image = Image(project_id=project.id) try: image.save_image_to_project(file) except IOError: abort(400, 'Unable to save image') project.images.append(image) try: db.session.add(image) db.session.commit() except IntegrityError: db.session.rollback() abort(400, 'Failed to add image') return construct_msg('Image added successfully'), 200 else: abort(400, 'Missing \'image\' in request')
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 upload_zip(project_id): """ Upload zip file of images to project Args: project_id -- id of project to upload zip file to Returns: HTTP status code and message of zip file upload """ def filter_condition(name): split = name.lower().split('.') return split and split[-1] in VALID_IMG_EXTENSIONS project = maybe_get_project(project_id) project_dir = get_project_dir(project) if 'zip' in request.files: file = request.files['zip'] extension = parse_and_validate_file_extension(file.filename, {'zip'}) new_file_name = '%s.%s' % (str(uuid.uuid4()), extension) zip_path = os.path.join(project_dir, new_file_name) file.save(zip_path) zip_file = ZipFile(zip_path) image_names = zip_file.namelist() name_map = {} for image_name in filter(filter_condition, image_names): if image_name in name_map: continue image = Image(project_id=project.id) image.save_empty_image(image_name) project.images.append(image) try: db.session.add(image) db.session.commit() except IntegrityError: db.session.rollback() abort(400, 'Failed to add image') name_map[image_name] = image.image_storage_path zip_file.close() multiprocessing.Process(target=unzip_process, args=(zip_path, name_map)).start() return ( construct_msg('Zip uploaded successfully, please wait for unzip'), 200) else: abort(400, 'Missing \'zip\' in request')
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 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 upload_annotation(): """ Upload annotation resource Args: None Returns: HTTP status code on if annotation was uploaded successfully """ req = request.get_json() fields_to_check = ['project_id', 'image_id', 'labels'] for field_to_check in fields_to_check: if field_to_check not in req: abort(400, 'Missing %s in json' % field_to_check) project = maybe_get_project_read_only(req['project_id']) image = Image.query.filter_by( id=req['image_id'], project_id=project.id).first() if not image: abort(400, 'Invalid image id') # Validate labels labels = req['labels'] fields_to_check = ['label_id'] for label_obj in labels: for field_to_check in fields_to_check: if field_to_check not in label_obj: abort(400, 'Missing %s in label' % field_to_check) label_id = label_obj['label_id'] label = Label.query.filter_by( id=label_id, project_id=project.id).first() if not label: abort( 400, 'label id %d not in project %s' % (label_id, project.project_name)) current_user = get_jwt_identity() user = User.query.filter_by(username=current_user).first() for label_obj in labels: data = str.encode(json.dumps(label_obj)) label_id = label_obj['label_id'] label = Label.query.filter_by( id=label_id, project_id=project.id).first() annotation = Annotation.query.filter_by( label_id=label_id, image_id=image.id).first() if annotation: annotation.data = data else: annotation = Annotation( data=data, image_id=image.id, label_id=label_id, vector=b'') project.annotations.append(annotation) image.is_annotated = True image.annotations.append(annotation) label.annotations.append(annotation) user.annotations.append(annotation) annotation.added_at = dt.datetime.utcnow() image.modified_at = dt.datetime.utcnow() project.modified_at = dt.datetime.utcnow() db.session.commit() return construct_msg('Annotation saved successfully'), 200