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