Ejemplo n.º 1
0
    def post(self, ob_type, object_ids):
        object_ids = object_ids.split(',')

        if not ob_type:
            raise errors.ModelError(
                "Object type required when creating a subscription")

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            ob = get_ob(session, ob_type, object_ids)
            if not ob:
                raise errors.MissingDocError("No such object")

            act = Activities(session)
            subscription = act.subscribe(user_session.user, ob)
            subscription.subscribed = self.request_son.get('subscribed', False)

            policy = user_session.policy.derive({
                'user':
                subscription.user,
                'survey':
                self.get_survey(ob),
                'submission':
                self.get_submission(ob),
            })
            policy.verify('subscription_add')

            session.flush()
            subscription_id = str(subscription.id)

        self.get('', subscription_id)
Ejemplo n.º 2
0
    def post(self, user_id):
        '''
        Create a new user.
        '''
        if user_id:
            raise errors.MethodError("Can't use POST for existing users.")

        try:
            user_input_schema(self.request_son)
        except voluptuous.error.Invalid as e:
            raise errors.ModelError.from_voluptuous(e)

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            org = (
                session.query(model.Organisation)
                .get(self.request_son['organisation']['id']))
            if not org:
                raise errors.ModelError("No such organisation")

            user = model.AppUser(organisation=org)

            try:
                assign_surveygroups(user_session, user, self.request_son)
            except ValueError as e:
                raise errors.ModelError(str(e))

            policy = user_session.policy.derive({
                'org': user.organisation,
                'user': user,
                'target': self.request_son,
                'surveygroups': user.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('user_add')
            policy.verify('user_change_role')
            self.check_password(self.request_son.password)

            self._update(user, self.request_son, session)
            session.add(user)

            # Need to flush so object has an ID to record action against.
            session.flush()

            act = Activities(session)
            act.record(user_session.user, user, ['create'])
            act.ensure_subscription(
                user_session.user, user, user.organisation, self.reason)
            act.subscribe(user, user.organisation)
            self.reason("New user subscribed to organisation")

            user_id = user.id
        self.get(user_id)
Ejemplo n.º 3
0
    def query(self, ob_type, object_ids):
        with model.session_scope() as session:
            ob = get_ob(session, ob_type, object_ids)
            if not ob:
                raise errors.MissingDocError("No such object")

            user_session = self.get_user_session(session)
            act = Activities(session)
            subscription_map = {
                tuple(sub.ob_refs): sub.subscribed
                for sub in act.subscriptions(user_session.user, ob)
            }
            subscription_id_map = {
                tuple(sub.ob_refs): sub.id
                for sub in act.subscriptions(user_session.user, ob)
            }

            lineage = [{
                'id':
                subscription_id_map.get(tuple(item.ob_ids), None),
                'title':
                item.ob_title,
                'ob_type':
                item.ob_type,
                'ob_ids':
                item.ob_ids,
                'subscribed':
                subscription_map.get(tuple(item.ob_ids), None)
            } for item in ob.action_lineage]

            to_son = ToSon(
                r'/id$',
                r'/title$',
                r'/subscribed$',
                r'/ob_type$',
                r'/ob_ids/?.*$',
                r'/[0-9]+$',
            )
            sons = to_son(lineage)

        self.set_header("Content-Type", "application/json")
        self.write(json_encode(sons))
        self.finish()
Ejemplo n.º 4
0
    def delete(self, user_id):
        if not user_id:
            raise errors.MethodError("User ID required")

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            user = session.query(model.AppUser).get(user_id)
            if not user:
                raise errors.MissingDocError("No such user")

            policy = user_session.policy.derive({
                'org': user.organisation,
                'user': user,
                'surveygroups': user.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('user_del')

            act = Activities(session)
            if not user.deleted:
                act.record(user_session.user, user, ['delete'])
            act.ensure_subscription(
                user_session.user, user, user.organisation, self.reason)

            user.deleted = True

        self.finish()
Ejemplo n.º 5
0
    def delete(self, organisation_id):
        if not organisation_id:
            raise errors.MethodError("Organisation ID required")

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            org = session.query(model.Organisation).get(organisation_id)
            if not org:
                raise errors.MissingDocError("No such organisation")

            policy = user_session.policy.derive({
                'org':
                org,
                'surveygroups':
                org.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('org_del')

            act = Activities(session)
            if not org.deleted:
                act.record(user_session.user, org, ['delete'])
            act.ensure_subscription(user_session.user, org, org, self.reason)

            org.deleted = True

        self.finish()
Ejemplo n.º 6
0
    def _update_state(self, program_id, editable):
        '''
        Just update the state of the program (not title etc.)
        '''
        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            program = session.query(model.Program).get(program_id)
            if not program:
                raise errors.MissingDocError("No such program")

            policy = user_session.policy.derive({
                'program': program,
            })

            if editable:
                program.finalised_date = None
                policy.verify('program_edit')
            else:
                policy.verify('program_edit')
                program.finalised_date = datetime.datetime.utcnow()

            act = Activities(session)
            if session.is_modified(program):
                act.record(user_session.user, program, ['state'])
            act.ensure_subscription(user_session.user, program, program,
                                    self.reason)
        self.get(program_id)
Ejemplo n.º 7
0
    def post(self, query_id):
        if query_id:
            raise errors.MethodError("Can't use POST for existing query.")

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            custom_query = model.CustomQuery()
            self.update(custom_query, self.request_son)
            self.update_auto(custom_query, user_session.user)
            session.add(custom_query)

            policy = user_session.policy.derive({
                'custom_query': custom_query,
            })
            policy.verify('custom_query_add')

            session.flush()
            act = Activities(session)
            act.record(user_session.user, custom_query, ['create'])
            act.ensure_subscription(user_session.user, custom_query,
                                    custom_query, self.reason)

            query_id = str(custom_query.id)

        self.get(query_id)
Ejemplo n.º 8
0
    def delete(self, submission_id):
        if submission_id == '':
            raise errors.MethodError("Submission ID required")

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            submission = (session.query(model.Submission).get(submission_id))
            if not submission:
                raise errors.MissingDocError("No such submission")

            policy = user_session.policy.derive({
                'org':
                submission.organisation,
                'surveygroups':
                submission.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('submission_del')

            act = Activities(session)
            if not submission.deleted:
                act.record(user_session.user, submission, ['delete'])
            act.ensure_subscription(user_session.user, submission,
                                    submission.organisation, self.reason)

            submission.deleted = True

        self.finish()
Ejemplo n.º 9
0
    def delete(self, response_type_id):
        '''Delete'''

        program_id = self.get_argument('programId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            response_type = (session.query(model.ResponseType).get(
                (response_type_id, program_id)))
            if not response_type:
                raise errors.MissingDocError("No such response type")

            policy = user_session.policy.derive({
                'program':
                response_type.program,
                'surveygroups':
                response_type.program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('response_type_del')

            session.delete(response_type)
            # No need for survey update: delete will fail if any measures are
            # using this RT

            act = Activities(session)
            act.record(user_session.user, response_type, ['delete'])
            act.ensure_subscription(user_session.user, response_type,
                                    response_type.program, self.reason)

        self.set_header("Content-Type", "text/plain")
        self.finish()
Ejemplo n.º 10
0
    def delete(self, program_id):
        '''
        Delete an existing program.
        '''
        if not program_id:
            raise errors.MethodError("Program ID required")

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            program = session.query(model.Program).get(program_id)
            if not program:
                raise errors.MissingDocError("No such program")

            policy = user_session.policy.derive({
                'program':
                program,
                'surveygroups':
                program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('program_del')

            act = Activities(session)
            if not program.deleted:
                act.record(user_session.user, program, ['delete'])
            act.ensure_subscription(user_session.user, program, program,
                                    self.reason)

            program.deleted = True

        self.finish()
Ejemplo n.º 11
0
    def put(self, response_type_id):
        '''Update existing'''

        program_id = self.get_argument('programId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            response_type = (session.query(model.ResponseType).get(
                (response_type_id, program_id)))
            if not response_type:
                raise errors.MissingDocError("No such response type")

            policy = user_session.policy.derive({
                'program':
                response_type.program,
                'surveygroups':
                response_type.program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('response_type_edit')

            if 'name' in self.request_son:
                rt_by_name = (session.query(model.ResponseType).filter(
                    model.ResponseType.program_id == program_id).filter(
                        model.ResponseType.name ==
                        self.request_son.name).first())
                if rt_by_name and rt_by_name != response_type:
                    raise errors.ModelError(
                        "'" + self.request_son.name +
                        "' as a response type of that name already exists")

            try:
                self._update(response_type, self.request_son)
            except ResponseTypeError as e:
                raise errors.ModelError(str(e))
            except voluptuous.error.Error as e:
                raise errors.ModelError(str(e))
            except Exception as e:
                raise errors.ModelError(str(e))

            verbs = []
            # Check if modified now to avoid problems with autoflush later
            if session.is_modified(response_type):
                verbs.append('update')
                calculator = Calculator.structural()
                for measure in response_type.measures:
                    for qnode_measure in measure.qnode_measures:
                        calculator.mark_measure_dirty(qnode_measure)
                calculator.execute()

            act = Activities(session)
            act.record(user_session.user, response_type, verbs)
            act.ensure_subscription(user_session.user, response_type,
                                    response_type.program, self.reason)

        self.get(response_type_id)
Ejemplo n.º 12
0
    def put(self, survey_id):
        '''Update existing.'''
        if not survey_id:
            raise errors.MethodError("Survey ID required")

        program_id = self.get_argument('programId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            survey = (session.query(model.Survey).options(
                joinedload('program')).options(
                    joinedload('program.surveygroups')).get(
                        (survey_id, program_id)))
            if not survey:
                raise errors.MissingDocError("No such survey")

            ## set only last level indexing_form 1 if no value, remove other level indexing_form
            levels = len(self.request_son.structure.levels)

            for i, l in enumerate(self.request_son.structure.levels):
                if i + 1 != levels and l.indexing_from:
                    del l.indexing_from
                if i + 1 == levels and (
                    (not l.indexing_from and l.indexing_from != 0) or
                    (not isinstance(l.indexing_from, Number))
                        or l.indexing_from < 0):
                    l.indexing_from = 1

            self._update(survey, self.request_son)

            policy = user_session.policy.derive({
                'program':
                survey.program,
                'survey':
                survey,
                'surveygroups':
                survey.program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('survey_edit')

            verbs = []
            if session.is_modified(survey):
                verbs.append('update')

            if survey.deleted:
                survey.deleted = False
                verbs.append('undelete')

            act = Activities(session)
            act.record(user_session.user, survey, verbs)
            act.ensure_subscription(user_session.user, survey, survey.program,
                                    self.reason)

        self.get(survey_id)
Ejemplo n.º 13
0
    def post(self, response_type_id):
        '''Create new'''
        if response_type_id:
            raise errors.ModelError("Can't specify ID when creating")

        program_id = self.get_argument('programId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            program = session.query(model.Program).get(program_id)
            if not program:
                raise errors.MissingDocError("No such program")

            policy = user_session.policy.derive({
                'program':
                program,
                'surveygroups':
                program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('response_type_add')

            rt_by_name = (session.query(model.ResponseType).filter(
                model.ResponseType.program_id == program_id).filter(
                    model.ResponseType.name == self.request_son.name).first())
            if rt_by_name:
                raise errors.ModelError(
                    "'" + self.request_son.name +
                    "' as a response type of that name already exists")

            response_type = model.ResponseType(program=program)
            session.add(response_type)
            try:
                self._update(response_type, self.request_son)
            except ResponseTypeError as e:
                raise errors.ModelError(str(e))
            except voluptuous.error.Error as e:
                raise errors.ModelError(str(e))

            try:
                session.flush()
            except sqlalchemy.exc.IntegrityError as e:
                raise errors.ModelError.from_sa(e)

            response_type_id = str(response_type.id)
            # No need for survey update: RT is not being used yet

            act = Activities(session)
            act.record(user_session.user, response_type, ['create'])
            act.ensure_subscription(user_session.user, response_type,
                                    response_type.program, self.reason)
        self.get(response_type_id)
Ejemplo n.º 14
0
    def post(self, survey_id):
        '''Create new.'''
        if survey_id:
            raise errors.MethodError("Can't use POST for existing object")

        program_id = self.get_argument('programId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            program = (session.query(model.Program).options(
                joinedload('surveygroups')).get(program_id))
            if not program:
                raise errors.ModelError("No such program")

            ## set only last level indexing_form 1 if no value, remove other level indexing_form
            levels = len(self.request_son.structure.levels)

            for i, l in enumerate(self.request_son.structure.levels):
                if i + 1 != levels and l.indexing_from:
                    del l.indexing_from
                if i + 1 == levels and (
                    (not l.indexing_from and l.indexing_from != 0) or
                    (not isinstance(l.indexing_from, Number))
                        or l.indexing_from < 0):
                    l.indexing_from = 1

            survey = model.Survey(program=program)
            self._update(survey, self.request_son)
            session.add(survey)

            # Need to flush so object has an ID to record action against.
            session.flush()

            policy = user_session.policy.derive({
                'program':
                program,
                'survey':
                survey,
                'surveygroups':
                program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('survey_add')

            act = Activities(session)
            act.record(user_session.user, survey, ['create'])
            act.ensure_subscription(user_session.user, survey, survey.program,
                                    self.reason)

            survey_id = str(survey.id)

        self.get(survey_id)
Ejemplo n.º 15
0
    def put(self, organisation_id):
        '''
        Update an existing organisation.
        '''
        if not organisation_id:
            raise errors.MethodError(
                "Can't use PUT for new organisations (no ID).")

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            org = session.query(model.Organisation).get(organisation_id)
            if not org:
                raise errors.MissingDocError("No such organisation")

            try:
                groups_changed = assign_surveygroups(user_session, org,
                                                     self.request_son)
            except ValueError as e:
                raise errors.ModelError(str(e))

            policy = user_session.policy.derive({
                'org':
                org,
                'surveygroups':
                org.surveygroups,
            })
            policy.verify('org_edit')

            # Check that user shares a common surveygroup with this org.
            # Admins need permission to edit orgs outside their surveygroups
            # though.
            if not policy.check('admin'):
                policy.verify('surveygroup_interact')

            old_locations = list(org.locations)
            self._update(org, self.request_son)

            verbs = []
            if (session.is_modified(org) or org.locations != old_locations
                    or groups_changed or session.is_modified(org.meta)):
                verbs.append('update')

            if org.deleted:
                org.deleted = False
                verbs.append('undelete')

            act = Activities(session)
            act.record(user_session.user, org, verbs)
            act.ensure_subscription(user_session.user, org, org, self.reason)

        self.get(organisation_id)
Ejemplo n.º 16
0
    def delete(self, qnode_id):
        '''Delete existing.'''

        if not qnode_id:
            raise errors.MethodError("Question node ID required")

        program_id = self.get_argument('programId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            qnode = (
                session.query(model.QuestionNode)
                .options(joinedload('program'))
                .options(joinedload('program.surveygroups'))
                .get((qnode_id, program_id)))
            if not qnode:
                raise errors.MissingDocError("No such question node")
            log.debug("deleting: %s", qnode)

            program = qnode.program
            survey = qnode.survey
            parent = qnode.parent

            policy = user_session.policy.derive({
                'program': program,
                'survey': survey,
                'surveygroups': program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('qnode_del')

            act = Activities(session)
            if not qnode.deleted:
                act.record(user_session.user, qnode, ['delete'])
            act.ensure_subscription(
                user_session.user, qnode, qnode.program, self.reason)

            qnode.deleted = True

            calculator = Calculator.structural()
            if parent:
                parent.children.reorder()
                calculator.mark_qnode_dirty(parent)
            else:
                survey.qnodes.reorder()
                calculator.mark_survey_dirty(survey)
            calculator.execute()

        self.finish()
Ejemplo n.º 17
0
    def put(self, query_id):
        if not query_id:
            raise errors.MethodError("Can't use PUT for new query.")

        with model.session_scope(version=True) as session:
            custom_query = session.query(model.CustomQuery).get(query_id)
            if custom_query is None:
                raise errors.MissingDocError("No such query")

            user_session = self.get_user_session(session)
            policy = user_session.policy.derive({
                'custom_query': custom_query,
            })
            policy.verify('custom_query_edit')

            self.check_concurrent_write(custom_query)
            if not self.should_save_new_version(custom_query,
                                                user_session.user):
                custom_query.version_on_update = False

            self.update(custom_query, self.request_son)

            verbs = []
            if session.is_modified(custom_query):
                verbs.append('update')
                self.update_auto(custom_query, user_session.user)
            else:
                custom_query.version_on_update = False

            if custom_query.deleted:
                custom_query.deleted = False
                verbs.append('undelete')

            session.flush()
            act = Activities(session)
            act.record(user_session.user, custom_query, verbs)
            act.ensure_subscription(user_session.user, custom_query,
                                    custom_query, self.reason)

            query_id = str(custom_query.id)

        self.get(query_id)
Ejemplo n.º 18
0
    def post(self, organisation_id):
        '''
        Create a new organisation.
        '''
        if organisation_id:
            raise errors.MethodError(
                "Can't use POST for existing organisation.")

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            org = model.Organisation()

            try:
                assign_surveygroups(user_session, org, self.request_son)
            except ValueError as e:
                raise errors.ModelError(str(e))

            self._update(org, self.request_son)
            session.add(org)

            # Need to flush so object has an ID to record action against.
            session.flush()

            policy = user_session.policy.derive({
                'org':
                org,
                'surveygroups':
                org.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('org_add')

            act = Activities(session)
            act.record(user_session.user, org, ['create'])
            act.ensure_subscription(user_session.user, org, org, self.reason)

            organisation_id = str(org.id)
        self.get(organisation_id)
Ejemplo n.º 19
0
    def delete(self, query_id):
        if not query_id:
            raise errors.MethodError("Query ID required")

        with model.session_scope(version=False) as session:
            custom_query = session.query(model.CustomQuery).get(query_id)
            if custom_query is None:
                raise errors.MissingDocError("No such query")

            user_session = self.get_user_session(session)
            policy = user_session.policy.derive({
                'custom_query': custom_query,
            })
            policy.verify('custom_query_del')

            act = Activities(session)
            if not custom_query.deleted:
                act.record(user_session.user, custom_query, ['delete'])
            act.ensure_subscription(user_session.user, custom_query,
                                    custom_query, self.reason)

            custom_query.deleted = True

        self.get(query_id)
Ejemplo n.º 20
0
    def delete(self, survey_id):
        if not survey_id:
            raise errors.MethodError("Survey ID required")

        program_id = self.get_argument('programId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            survey = (session.query(model.Survey).options(
                joinedload('program')).options(
                    joinedload('program.surveygroups')).get(
                        (survey_id, program_id)))
            if not survey:
                raise errors.MissingDocError("No such survey")

            policy = user_session.policy.derive({
                'program':
                survey.program,
                'survey':
                survey,
                'surveygroups':
                survey.program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('survey_del')

            act = Activities(session)
            if not survey.deleted:
                act.record(user_session.user, survey, ['delete'])
            act.ensure_subscription(user_session.user, survey, survey.program,
                                    self.reason)

            survey.deleted = True

        self.finish()
Ejemplo n.º 21
0
    def put(self, submission_id):
        '''Update existing.'''
        if submission_id == '':
            raise errors.MethodError("Submission ID required")

        approval = self.get_argument('approval', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            submission = session.query(model.Submission).get(submission_id)
            if not submission:
                raise errors.MissingDocError("No such submission")

            policy = user_session.policy.derive({
                'org':
                submission.organisation,
                'approval':
                approval,
                'surveygroups':
                submission.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('submission_edit')

            current_level = 0
            verbs = []
            if approval:
                self.check_approval_down_one(session, submission, approval)
                current_level = APPROVAL_STATES.index(submission.approval)
                if approval != submission.approval:
                    verbs.append('state')
                submission.approval = approval
            self._update(submission, self.request_son)
            if session.is_modified(submission):
                verbs.append('update')

            # update measures approval state, when save edited submission no approval, so here should not
            if approval != '':
                approval_level = APPROVAL_STATES.index(approval)
                if 'state' in verbs and approval_level > current_level:
                    approval_level = approval_level - 1
                    responses = (session.query(model.Response).filter(
                        model.Response.submission_id == submission.id,
                        model.Response.approval ==
                        APPROVAL_STATES[approval_level]))
                    for response in responses:
                        # update = updater(response, error_factory=errors.ModelError)
                        # update('title', son)
                        response.approval = approval
                        try:
                            calculator = Calculator.scoring(submission)
                            calculator.mark_measure_dirty(
                                response.qnode_measure)
                            calculator.execute()
                        except ResponseTypeError as e:
                            raise errors.ModelError(str(e))

                        act = Activities(session)
                        act.record(user_session.user, response, verbs)
                        act.ensure_subscription(user_session.user, response,
                                                response.submission,
                                                self.reason)

            if submission.deleted:
                submission.deleted = False
                verbs.append('undelete')

            act = Activities(session)
            act.record(user_session.user, submission, verbs)
            act.ensure_subscription(user_session.user, submission,
                                    submission.organisation, self.reason)

        self.get(submission_id)
Ejemplo n.º 22
0
    def post(self, submission_id):
        '''Create new.'''
        if submission_id:
            raise errors.MethodError("Can't use POST for existing object")

        program_id = self.get_argument('programId', '')
        if not program_id:
            raise errors.ModelError("Program ID is required")

        survey_id = self.get_argument('surveyId', '')
        if not survey_id:
            raise errors.ModelError("Survey ID is required")

        organisation_id = self.get_argument('organisationId', '')
        if not organisation_id:
            raise errors.ModelError("Organisation ID is required")

        # Source submission ID
        duplicate_id = self.get_argument('duplicateId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            org = session.query(model.Organisation).get(organisation_id)
            if not org:
                raise errors.ModelError("No such organisation")

            survey = session.query(model.Survey).get((survey_id, program_id))
            if not survey:
                raise errors.ModelError("No such survey")

            if duplicate_id:
                source_submission = (session.query(
                    model.Submission).get(duplicate_id))
                if not source_submission:
                    raise errors.MissingDocError(
                        "Source submission (for duplication) not found")
                if source_submission.organisation != org:
                    raise errors.ModelError(
                        "Can't duplicate a submission across two "
                        "organisations: '%s' and '%s'" %
                        (source_submission.organisation.name, org.name))
            else:
                source_submission = None

            submission = model.Submission(program=survey.program,
                                          survey=survey,
                                          organisation=org,
                                          approval='draft')
            self._update(submission, self.request_son)
            session.add(submission)

            surveygroups = submission.surveygroups
            if source_submission:
                surveygroups &= source_submission.surveygroups

            policy = user_session.policy.derive({
                'org': org,
                'survey': survey,
                'surveygroups': surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('submission_add')

            session.flush()
            submission_id = str(submission.id)

            if source_submission:
                yield SubmissionHandler.executor.submit(
                    self.duplicate, submission, source_submission, session)

            act = Activities(session)
            act.record(user_session.user, submission, ['create'])
            act.ensure_subscription(user_session.user, submission,
                                    submission.organisation, self.reason)

        self.get(submission_id)
Ejemplo n.º 23
0
    def put(self, submission_id, qnode_id):
        '''Save (create or update).'''

        approval = self.get_argument('approval', '')
        relevance = self.get_argument('relevance', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            submission = (
                session.query(model.Submission)
                .get(submission_id))
            if not submission:
                raise errors.MissingDocError("No such submission")

            policy = user_session.policy.derive({
                'org': submission.organisation,
                'submission': submission,
                'approval': approval,
                'index': APPROVAL_STATES.index,
                'surveygroups': submission.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('rnode_edit')

            rnode = (
                session.query(model.ResponseNode)
                .get((submission_id, qnode_id)))

            verbs = []

            if not rnode:
                qnode = (
                    session.query(model.QuestionNode)
                    .get((qnode_id, submission.program.id)))
                if qnode is None:
                    raise errors.MissingDocError("No such question node")
                rnode = model.ResponseNode.from_qnode(
                    qnode, submission, create=True)

            importance = self.request_son.get('importance')
            if importance is not None:
                if int(importance) <= 0:
                    self.request_son['importance'] = None
                elif int(importance) > 5:
                    self.request_son['importance'] = 5
            urgency = self.request_son.get('urgency')
            if urgency is not None:
                if int(urgency) <= 0:
                    self.request_son['urgency'] = None
                elif int(urgency) > 5:
                    self.request_son['urgency'] = 5
            self._update(rnode, self.request_son)
            if session.is_modified(rnode):
                verbs.append('update')
            session.flush()

            if approval:
                policy.verify('submission_response_approval')
                yield self.set_approval(
                    session, rnode, approval, user_session)
                verbs.append('state')
            if relevance:
                yield self.set_relevance(
                    session, rnode, relevance, user_session)
                verbs.append('update')

            try:
                calculator = Calculator.scoring(submission)
                calculator.mark_qnode_dirty(rnode.qnode)
                calculator.execute()
            except ResponseTypeError as e:
                raise errors.ModelError(str(e))

            act = Activities(session)
            act.record(user_session.user, rnode, verbs)
            act.ensure_subscription(
                user_session.user, rnode, rnode.submission,
                self.reason)

        self.get(submission_id, qnode_id)
Ejemplo n.º 24
0
    def post(self, activity_id):
        if activity_id:
            raise errors.ModelError("Can't specify ID for new activity")

        if len(self.request_son.message) < 3:
            raise errors.ModelError("Message is too short")

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            if self.request_son.to == 'org':
                org = user_session.org
                if not org:
                    raise errors.ModelError('No such organisation')
            elif self.request_son.to == 'all':
                org = None
            else:
                raise errors.ModelError('Unrecognised recipient')

            activity = model.Activity(
                subject=user_session.user,
                verbs=['broadcast'],
                message=self.request_son.message,
                sticky=self.request_son.sticky,
            )

            try:
                assign_surveygroups(user_session, activity, self.request_son)
            except ValueError as e:
                raise errors.ModelError(str(e))

            if org:
                desc = org.action_descriptor
                activity.ob_type = desc.ob_type
                activity.ob_ids = desc.ob_ids
                activity.ob_refs = desc.ob_refs
                policy = user_session.policy.derive({
                    'surveygroups':
                    org.surveygroups,
                })
                policy.verify('surveygroup_interact')
            else:
                activity.ob_type = None
                activity.ob_ids = []
                activity.ob_refs = []

            session.add(activity)
            session.flush()

            policy = user_session.policy.derive({
                'activity': activity,
                'org': org,
            })
            policy.verify('post_add')

            son = ActivityHandler.TO_SON(activity)

            act = Activities(session)
            if org:
                act.ensure_subscription(user_session.user, org, org,
                                        self.reason)

        self.set_header("Content-Type", "application/json")
        self.write(json_encode(son))
        self.finish()
Ejemplo n.º 25
0
    def fetch_activities(self, from_date, until_date, include_sticky):
        start_super = perf()
        timing = []
        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            act = Activities(session)
            sticky_flags = {'filter'}
            if include_sticky:
                sticky_flags.update({'include', 'at_top'})

            start = perf()
            query = act.timeline_query(user_session.user,
                                       from_date,
                                       until_date,
                                       sticky_flags=sticky_flags)
            duration = perf() - start
            timing.append("Query construction took %gs" % duration)

            start = perf()
            activities = query.all()
            duration = perf() - start
            timing.append("Query execution took %gs" % duration)

            # Use hand-written serialisation code, because the reflection done
            # in ToSon is too slow for this large number of items.
            # (5ms vs 300ms)
            start = perf()
            user_sons = {}
            activity_sons = []
            for a in activities:
                a_son = {
                    'id': str(a.id),
                    'created': a.created.timestamp(),
                    'message': a.message,
                    'obIds': [str(id_) for id_ in a.ob_ids],
                    'obType': a.ob_type,
                    'sticky': a.sticky,
                    'verbs': list(a.verbs),
                }
                user = a.subject
                if user in user_sons:
                    user_son = user_sons[user]
                else:
                    user_son = {
                        'id': str(user.id),
                        'name': user.name,
                    }
                    user_sons[a.subject] = user_son

                if a.ob_type == 'organisation':
                    a_son['org_id'] = str(a.ob_ids[0])

                a_son['subject'] = user_son
                activity_sons.append(a_son)

            son = {
                'from': from_date.timestamp(),
                'until': until_date.timestamp(),
                'actions': activity_sons
            }
            duration = perf() - start
            timing.append("Serialization took %gs" % duration)

        duration = perf() - start_super
        timing.append("Total: %gs" % duration)

        return son, timing
Ejemplo n.º 26
0
    def post(self, qnode_id):
        '''Create new.'''

        if qnode_id:
            raise errors.MethodError("Can't use POST for existing object")

        program_id = self.get_argument('programId', '')
        survey_id = self.get_argument('surveyId', '')
        parent_id = self.get_argument('parentId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            program = (
                session.query(model.Program)
                .options(joinedload('surveygroups'))
                .get(program_id))
            if not program:
                raise errors.ModelError("No such program")

            qnode = model.QuestionNode(program=program)
            self._update(session, qnode, self.request_son)
            log.debug("new: %s", qnode)

            if survey_id:
                survey = (
                    session.query(model.Survey)
                    .get((survey_id, program_id)))
                if not survey:
                    raise errors.ModelError("No such survey")
            else:
                survey = None
            log.debug("survey: %s", survey)

            if parent_id:
                parent = (
                    session.query(model.QuestionNode)
                    .get((parent_id, program_id)))
                if not parent:
                    raise errors.ModelError("Parent does not exist")
                if not survey:
                    survey = parent.survey
                elif parent.survey != survey:
                    raise errors.ModelError(
                        "Parent does not belong to that survey")
            else:
                parent = None

            qnode.survey = survey

            if parent:
                log.debug("Appending to parent")
                parent.children.append(qnode)
                parent.children.reorder()
                log.debug("committing: %s", parent.children)
            elif survey:
                log.debug("Appending to survey")
                survey.qnodes.append(qnode)
                survey.qnodes.reorder()
                log.debug("committing: %s", survey.qnodes)
            else:
                raise errors.ModelError("Parent or survey ID required")

            # Need to flush so object has an ID to record action against.
            session.flush()

            policy = user_session.policy.derive({
                'program': qnode.program,
                'survey': qnode.survey,
                'surveygroups': qnode.program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('qnode_add')

            calculator = Calculator.structural()
            calculator.mark_qnode_dirty(qnode)
            calculator.execute()

            qnode_id = str(qnode.id)

            act = Activities(session)
            act.record(user_session.user, qnode, ['create'])
            act.ensure_subscription(
                user_session.user, qnode, qnode.program, self.reason)

        self.get(qnode_id)
Ejemplo n.º 27
0
    def put(self, qnode_id):
        '''Update existing.'''

        if not qnode_id:
            self.ordering()
            return

        program_id = self.get_argument('programId', '')
        parent_id = self.get_argument('parentId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            qnode = (
                session.query(model.QuestionNode)
                .options(joinedload('program'))
                .options(joinedload('program.surveygroups'))
                .get((qnode_id, program_id)))
            if not qnode:
                raise errors.MissingDocError("No such question node")

            policy = user_session.policy.derive({
                'program': qnode.program,
                'survey': qnode.survey,
                'surveygroups': qnode.program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('qnode_edit')

            self._update(session, qnode, self.request_son)

            verbs = []
            if session.is_modified(qnode):
                verbs.append('update')

            calculator = Calculator.structural()
            if parent_id and str(qnode.parent_id) != parent_id:
                # Change parent
                old_parent = qnode.parent
                new_parent = (
                    session.query(model.QuestionNode)
                    .get((parent_id, program_id)))
                if new_parent.survey != qnode.survey:
                    raise errors.ModelError("Can't move to different survey")
                if not new_parent:
                    raise errors.ModelError("No such question node")
                old_parent.children.remove(qnode)
                old_parent.children.reorder()
                new_parent.children.append(qnode)
                new_parent.children.reorder()
                calculator.mark_qnode_dirty(old_parent)
                calculator.mark_qnode_dirty(qnode)
                self.reason("Moved from %s to %s" % (
                    old_parent.title, new_parent.title))
                verbs.append('relation')

            if qnode.deleted:
                # Get a reference to the collection before changing the
                # deleted flag - otherwise, if a query is needed to
                # instantiate the collection, it will seem as if the object
                # is already in the collection and insert will not work as
                # expected.
                if qnode.parent:
                    collection = qnode.parent.children
                else:
                    collection = qnode.survey.qnodes
                qnode.deleted = False
                collection.insert(qnode.seq, qnode)
                collection.reorder()
                calculator.mark_qnode_dirty(qnode)
                verbs.append('undelete')

            calculator.execute()

            act = Activities(session)
            act.record(user_session.user, qnode, verbs)
            act.ensure_subscription(
                user_session.user, qnode, qnode.program, self.reason)

        self.get(qnode_id)
Ejemplo n.º 28
0
    def ordering(self):
        '''Change the order of all children in a parent's collection.'''

        program_id = self.get_argument('programId', '')
        survey_id = self.get_argument('surveyId', '')
        parent_id = self.get_argument('parentId', '')
        root = self.get_argument('root', None)

        #if parent_id and root is None:
        if parent_id is None and root is None: 
            raise errors.ModelError(
                "Parent ID required, or specify 'root=' for root nodes")
        if root is not None and parent_id:
            raise errors.ModelError(
                "Can't specify both 'root=' and parent ID")
            if not survey_id:
                raise errors.ModelError(
                    "Survey ID is required for operating on root nodes")

        son = json_decode(self.request.body)

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            act = Activities(session)
            if parent_id:
                parent = (
                    session.query(model.QuestionNode)
                    .get((parent_id, program_id)))
                if not parent:
                    raise errors.MissingDocError(
                        "Parent question node does not exist")
                survey = parent.survey
                if survey_id and survey_id != str(survey.id):
                    raise errors.MissingDocError(
                        "Parent does not belong to that survey")
                log.debug("Reordering children of: %s", parent)
                reorder(parent.children, son)
                act.record(user_session.user, parent, ['reorder_children'])
                act.ensure_subscription(
                    user_session.user, parent, parent.program, self.reason)

            elif root is not None:
                survey = (
                    session.query(model.Survey)
                    .get((survey_id, program_id)))
                if not survey:
                    raise errors.MissingDocError("No such survey")
                log.debug("Reordering children of: %s", survey)
                reorder(survey.qnodes, son)
                act.record(
                    user_session.user, survey, ['reorder_children'])
                act.ensure_subscription(
                    user_session.user, survey, survey.program, self.reason)

            else:
                raise errors.ModelError(
                    "Survey or parent ID required")

            policy = user_session.policy.derive({
                'program': survey.program,
                'survey': survey,
                'surveygroups': survey.program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('qnode_edit')

        self.query()
Ejemplo n.º 29
0
    def post(self, program_id):
        '''
        Create a new program.
        '''
        if program_id:
            raise errors.MethodError("Can't use POST for existing program.")

        duplicate_id = self.get_argument('duplicateId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            program = model.Program()
            self._update(program, self.request_son)
            session.add(program)

            try:
                assign_surveygroups(user_session, program, self.request_son)
            except ValueError as e:
                raise errors.ModelError(str(e))

            policy = user_session.policy.derive({
                'program':
                program,
                'surveygroups':
                program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('program_add')

            # Need to flush so object has an ID to record action against.
            session.flush()

            act = Activities(session)

            if duplicate_id:
                source_program = (session.query(
                    model.Program).get(duplicate_id))
                if not source_program:
                    raise errors.MissingDocError(
                        "Source program does not exist")

                policy = user_session.policy.derive({
                    'program':
                    source_program,
                    'surveygroups':
                    source_program.surveygroups,
                })
                policy.verify('surveygroup_interact')
                policy.verify('program_view')

                yield self.duplicate_structure(source_program, program,
                                               session)
                source_program.finalised_date = datetime.datetime.utcnow()
                act.record(user_session.user, source_program, ['state'])

            act.record(user_session.user, program, ['create'])
            act.ensure_subscription(user_session.user, program, program,
                                    self.reason)

            program_id = program.id

        self.get(program_id)
Ejemplo n.º 30
0
    def put(self, program_id):
        '''
        Update an existing program.
        '''
        if program_id == '':
            raise errors.MethodError("Can't use PUT for new program (no ID).")

        editable = self.get_argument('editable', '')
        if editable != '':
            self._update_state(program_id, truthy(editable))
            return

        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            program = session.query(model.Program).get(program_id)
            if not program:
                raise errors.MissingDocError("No such program")

            try:
                groups_changed = assign_surveygroups(user_session, program,
                                                     self.request_son)
            except ValueError as e:
                raise errors.ModelError(str(e))

            policy = user_session.policy.derive({
                'program':
                program,
                'surveygroups':
                program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('program_edit')

            if not program.is_editable:
                raise errors.MethodError("This program is closed for editing")

            calculator = Calculator.structural()
            if self.request_son['has_quality'] != program.has_quality:
                # Recalculate stats for surveys. This will trigger the
                # recalculation of the submissions in the recalculation
                # daemon.
                for survey in program.surveys:
                    calculator.mark_survey_dirty(survey)

            self._update(program, self.request_son)

            calculator.execute()

            verbs = []
            if session.is_modified(program) or groups_changed:
                verbs.append('update')

            if program.deleted:
                program.deleted = False
                verbs.append('undelete')

            act = Activities(session)
            act.record(user_session.user, program, verbs)
            act.ensure_subscription(user_session.user, program, program,
                                    self.reason)
        self.get(program_id)