def post(self, pid, sid): """ Create a new annotation on an existing session """ helpers.abort_if_invalid_parameters(pid, sid) helpers.abort_if_unauthorized(Project.query.get(pid)) # Text and optionally, a list of tags (i.e. codes): json_data = request.get_json(force=True, silent=True) helpers.abort_if_invalid_json(json_data) schema = UserAnnotationSchema() helpers.abort_if_errors_in_validation( errors=schema.validate(json_data)) user = User.query.filter_by(email=get_jwt_identity()).first() user_annotation = UserAnnotationModel( content=json_data['content'], start_interval=json_data['start_interval'], end_interval=json_data['end_interval'], user_id=user.id, session_id=sid) if json_data.get('tags', None): user_annotation.tags.extend([ Tags.query.filter_by(id=cid).first() for cid in json_data['tags'] ]) db.session.add(user_annotation) db.session.commit() InterviewSession.email_participants(user, sid) fcm.notify_participants_user_commented(pid, sid) return custom_response(200, data=schema.dump(user_annotation))
def put(self, token): """ Updates an unconfirmed user record* and accepts the membership invite. *i.e. someone created through a Gabber or when invited """ token_data = self.validate_token(token) data = helpers.jsonify_request_or_abort() helpers.abort_if_errors_in_validation( ProjectInviteWithToken().validate(data)) user = User.query.get(token_data['user_id']) user.fullname = data['fullname'] user.set_password(data['password']) user.registered = True membership = Membership.query.filter_by( project_id=token_data['project_id'], user_id=user.id).first() # Makes sure that they can only be confirmed once if membership.confirmed and user.verified: return custom_response(400, errors=['MEMBERSHIP_CONFIRMED']) user.verified = True membership.confirmed = True db.session.commit() return custom_response(200, data=create_jwt_access(user.email))
def post(self, pid, mid=None): """ An administrator or staff member of a project invited a user Mapped to: /api/projects/<int:id>/membership/invites/ """ admin, data = self.validate_and_get_data(pid) helpers.abort_if_errors_in_validation(AddMemberSchema().validate(data)) email = data['email'].lower() user = User.query.filter_by(email=email).first() # Note: If the user is not known an unregistered user is created. # This is similar to how users are created after a Gabber session. if not user: # TODO: use the project default language?! user = User.create_unregistered_user(data['fullname'], email, 1) # The user cannot be added to the same project multiple times if not user.is_project_member(pid): membership = Membership(uid=user.id, pid=pid, rid=role_id(data['role']), confirmed=user.registered) db.session.add(membership) db.session.commit() project = Project.query.get(pid) client = MailClient(user.lang) if user.registered or user.verified: client.invite_registered(user, admin.fullname, project) else: client.invite_unregistered(user, admin.fullname, project) else: return custom_response(400, errors=['membership.MEMBER_EXISTS']) return custom_response(200, data=ProjectMemberWithAccess().dump(membership))
def create_comment(project_id, session_id, annotation_id, comment_id=None): """ CREATE a comment within a session to an annotation, however, if comment_id is provided, then the comment is a comment on a comment, rather than on an annotation. """ helpers.abort_if_invalid_parameters(project_id, session_id) user = helpers.abort_if_unauthorized(Project.query.get(project_id)) if comment_id: helpers.abort_if_unknown_comment(comment_id, annotation_id) data = helpers.jsonify_request_or_abort() schema = UserAnnotationCommentSchema() helpers.abort_if_errors_in_validation(schema.validate(data)) # Note: comment_id can be null, which represents that it is a parent comment = CommentsModel(data['content'], comment_id, user.id, annotation_id) db.session.add(comment) db.session.commit() # Determine which type of comment the response is to: nested or a root comment if comment_id: _comment = CommentsModel.query.filter_by(parent_id=comment_id).first() else: _comment = RootComment.query.get(annotation_id) parent_user_id = _comment.user_id usr = User.query.get(parent_user_id) if user.id != usr.id: InterviewSession.email_commentor(usr, project_id, session_id) fcm.notify_participants_user_commented(project_id, session_id) return custom_response(200, data=schema.dump(comment))
def put(self, pid, mid=None): admin, data = self.validate_and_get_data(pid) helpers.abort_if_errors_in_validation( EditMemberSchema().validate(data)) membership = Membership.query.get(data['id']) membership.role_id = role_id(data['role']) db.session.commit() return custom_response(200, data=ProjectMemberWithAccess().dump(membership))
def post(self): """ CREATE a project where sessions can be created """ current_user = get_jwt_identity() user = User.query.filter_by(email=current_user).first() helpers.abort_if_unknown_user(user) # Force request to JSON, and fail silently if that fails the data is None. json_data = helpers.jsonify_request_or_abort() schema = ProjectPostSchema() helpers.abort_if_errors_in_validation(schema.validate(json_data)) data = schema.dump(json_data) from ..utils import amazon # TODO: we currently only support creating English projects english_lang = SupportedLanguage.query.filter_by(code='en').first() project = ProjectModel( default_lang=english_lang. id, # TODO: this should be the one they selected, but for now is EN creator=user.id, image=amazon.upload_base64(data['image']), is_public=data['privacy'] == 'public') admin_role = Roles.query.filter_by(name='administrator').first().id membership = Membership(uid=user.id, pid=project.id, rid=admin_role, confirmed=True) project.members.append(membership) db.session.add(project) db.session.flush() Project().add_codebook(project.id, json_data['codebook']) content = json_data['content'].get('en', None) if not content: return custom_response(400, errors=['projects.UNSUPPORTED_LANGUAGE']) project.content.extend([ ProjectLanguage(pid=project.id, lid=english_lang.id, description=content['description'], title=content['title']) ]) project.topics.extend([ TopicLanguage(project_id=project.id, lang_id=english_lang.id, text=t['text']) for t in content['topics'] ]) db.session.commit() return custom_response(201, data=ProjectModelSchema().dump(project))
def put(self, pid): """ The project to UPDATE: expecting a whole Project object to be sent. """ helpers.abort_on_unknown_project_id(pid) user = User.query.filter_by(email=get_jwt_identity()).first() helpers.abort_if_unknown_user(user) helpers.abort_if_not_admin_or_staff(user, pid) json_data = helpers.jsonify_request_or_abort() json_data['id'] = pid json_data['creator'] = user.id schema = ProjectModelSchema() errors = schema.validate(json_data) helpers.abort_if_errors_in_validation(errors) # When the project is updated, only the image data (base-64) is sent if it has changed. if json_data.get('image', None): from ..utils import amazon json_data['image'] = amazon.upload_base64(json_data['image']) project = ProjectModel.query.get(pid) # TODO: it's unclear why schema.load does not load image correctly, hence needing to manually set it. project.image = json_data['image'] if json_data.get( 'image', None) else project.image project.is_public = json_data['privacy'] == 'public' # Loads project data: relations are not loaded in their own schemas data = schema.load(json_data, instance=project) self.add_codebook(project.id, json_data['codebook']) # Note: it may be better to move this to schema's pre-load for language, content in json_data['content'].items(): # As the title may have changed, we must create a new slug content['slug'] = slugify(content['title']) # Overrides the title/description for the specific language that has changed plang = ProjectLanguageSchema().load( content, instance=data.content.filter_by(id=content['id']).first()) for topic in content['topics']: # Updates the topic if it changes, otherwise adds a new topic if 'id' in topic: TopicLanguageSchema().load(topic, instance=data.content.filter_by( id=topic['id']).first()) else: new_topic = TopicLanguage(project_id=project.id, lang_id=plang.lang_id, text=topic['text']) db.session.add(new_topic) # Changes are stored in memory; if error occurs, wont be left with half-changed state. db.session.commit() return custom_response(200, schema.dump(data))
def put(token): """ Lets a user update their consent for a gabber session. """ consent_id = SessionConsent.validate_token(token) data = helpers.jsonify_request_or_abort() helpers.abort_if_errors_in_validation(ConsentType().validate(data)) consent = SessionConsentModel.query.get(consent_id) consent.type = data['consent'] db.session.commit() return custom_response(200)