Beispiel #1
0
    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))
Beispiel #2
0
    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))
Beispiel #3
0
    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))
Beispiel #4
0
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))
Beispiel #5
0
 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))
Beispiel #6
0
    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))
Beispiel #7
0
    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))
Beispiel #8
0
 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)