コード例 #1
0
def get_settings():
    settings = get_minimal_settings()
    settings.update({
        "cookie_secret": get_cookie_secret(),
        "xsrf_cookies": truthy(tornado.options.options.xsrf),
        "debug": truthy(tornado.options.options.dev),
        "serve_traceback": truthy(tornado.options.options.dev),
        "gzip": True
    })
    return settings
コード例 #2
0
    def query(self):
        '''
        Get a list of programs.
        '''

        term = self.get_argument('term', '')
        is_editable = truthy(self.get_argument('editable', ''))

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

            query = session.query(model.Program)

            policy = user_session.policy.derive({})
            if not policy.check('surveygroup_interact_all'):
                query = filter_surveygroups(session, query,
                                            user_session.user.id, [],
                                            [model.program_surveygroup])

            # Get all programs for a survey group
            surveygroup_id = self.get_argument("surveyGroupId", None)
            if surveygroup_id:
                query = (query.join(
                    model.SurveyGroup, model.Program.surveygroups).filter(
                        model.SurveyGroup.id == surveygroup_id))

            if term != '':
                query = query.filter(
                    model.Program.title.ilike(r'%{}%'.format(term)))

            if is_editable:
                query = query.filter(model.Program.finalised_date == None)

            deleted = self.get_argument('deleted', '')
            if deleted != '':
                deleted = truthy(deleted)
                query = query.filter(model.Program.deleted == deleted)

            query = query.order_by(model.Program.created.desc())
            query = self.paginate(query)

            to_son = ToSon(r'/id$', r'/title$', r'</description$',
                           r'/deleted$', r'^/[0-9]+/error$', r'/[0-9]+$')
            sons = to_son(query.all())

        self.set_header("Content-Type", "application/json")
        self.write(json_encode(sons))
        self.finish()
コード例 #3
0
 def prepare(self):
     if (truthy(tornado.options.options.force_https)
             and 'X-Forwarded-Proto' in self.request.headers
             and self.request.headers['X-Forwarded-Proto'] != 'https'):
         # Redirect from HTTP to HTTPS when behind a load balancer on AWS.
         # http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html#x-forwarded-proto
         self.redirect(re.sub(r'^([^:]+)', 'https',
                              self.request.full_url()))
         return
コード例 #4
0
ファイル: test_util.py プロジェクト: Radhika-Envision/Upmark
 def test_truthy(self):
     self.assertTrue(truthy(True))
     self.assertTrue(truthy('True'))
     self.assertTrue(truthy('true'))
     self.assertTrue(truthy('yes'))
     self.assertTrue(truthy(1))
     self.assertTrue(truthy('1'))
     self.assertFalse(truthy('False'))
コード例 #5
0
ファイル: template.py プロジェクト: Radhika-Envision/Upmark
 def uses_old_url(self, session):
     if truthy(tornado.options.options.dev):
         return False
     if not config.get_setting(session, 'app_redirect'):
         return False
     base_url = config.get_setting(session, 'app_base_url')
     default_url = config.get_setting(session, 'app_base_url', True)
     if base_url == default_url:
         return False
     return not self.request.full_url().startswith(base_url)
コード例 #6
0
    def query(self, organisation_id):
        deleted = self.get_argument('deleted', '')
        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('submission_browse')

            query = (session.query(model.Survey).join(
                model.PurchasedSurvey).filter(
                    model.PurchasedSurvey.organisation_id == organisation_id))

            if deleted:
                deleted = truthy(deleted)
                if deleted:
                    del_filter = ((model.Survey.deleted == True) |
                                  (model.Program.deleted == True))
                else:
                    del_filter = ((model.Survey.deleted == False) &
                                  (model.Program.deleted == False))
                query = query.join(model.Program).filter(del_filter)

            if not policy.check('surveygroup_interact_all'):
                query = filter_surveygroups(session, query,
                                            user_session.user.id,
                                            [model.Program],
                                            [model.program_surveygroup])

            surveys = query.all()

            to_son = ToSon(
                r'/id$',
                r'/title$',
                r'/deleted$',
                r'/n_measures$',
                r'/program/tracking_id$',
                # Descend into list
                r'/[0-9]+$',
                r'/program$')

            sons = to_son(surveys)

        self.set_header("Content-Type", "application/json")
        self.write(json_encode(sons))
        self.finish()
コード例 #7
0
    def query(self):
        sons = []
        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            policy = user_session.policy.derive({})
            policy.verify('org_browse')

            query = session.query(model.Organisation)

            # Filter out orgs that don't share a surveygroup with this user.
            # Admins need access to orgs outside their surveygroups though.
            if not policy.check('admin'):
                query = filter_surveygroups(session, query,
                                            user_session.user.id, [],
                                            [model.organisation_surveygroup])

            # Filter down to just organisations in a particular survey group
            surveygroup_id = self.get_argument("surveyGroupId", None)
            if surveygroup_id:
                query = (query.join(
                    model.SurveyGroup, model.Organisation.surveygroups).filter(
                        model.SurveyGroup.id == surveygroup_id))

            term = self.get_argument('term', None)
            if term is not None:
                query = query.filter(
                    model.Organisation.name.ilike(r'%{}%'.format(term)))

            deleted = self.get_argument('deleted', '')
            if deleted != '':
                deleted = truthy(deleted)
                query = query.filter(model.Organisation.deleted == deleted)

            query = query.order_by(model.Organisation.name)
            query = self.paginate(query)

            to_son = ToSon(
                r'^/[0-9]+/id$',
                r'/name$',
                r'/deleted$',
                r'/locations$',
                r'/locations/0/description$',
                r'/meta$',
                r'/meta/asset_types.*$',
                # Descend into list
                r'/[0-9]+$')
            sons = to_son(query.all())
        self.set_header("Content-Type", "application/json")
        self.write(json_encode(sons))
        self.finish()
コード例 #8
0
    def get(self, program_id):
        '''
        Get a list of programs that share the same lineage.
        '''
        if program_id == '':
            raise errors.MethodError("Program ID is 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_view')

            query = (session.query(model.Program).filter(
                model.Program.tracking_id == program.tracking_id).order_by(
                    model.Program.created))

            if not policy.check('surveygroup_interact_all'):
                query = filter_surveygroups(session, query,
                                            user_session.user.id, [],
                                            [model.program_surveygroup])

            deleted = self.get_argument('deleted', '')
            if deleted != '':
                deleted = truthy(deleted)
                query = query.filter(model.Program.deleted == deleted)

            to_son = ToSon(
                r'/id$',
                r'/title$',
                r'/is_editable$',
                r'/deleted$',
                # Descend
                r'/[0-9]+$',
            )
            sons = to_son(query.all())

        self.set_header("Content-Type", "application/json")
        self.write(json_encode(sons))
        self.finish()
コード例 #9
0
ファイル: evaluator.py プロジェクト: SmartViking/Malang
def eval_list_comprehension(state, expr, emitters, acc):
    """
    This evaluates the list comprehension, and mutates `acc`, which should be
    a python list. `expr` is the expression on the left hand side of the pipe
    in a list comprehension (like #[<expr> | ...]). Emitters is a python tuple
    of `emitters`, which are the things on the right hand side of a list comprehension,
    seperated by commas (like #[<expr> | <emitter1> , <emitter2>, ... <emitterN> ].
    An emitter can either be `filter`, which restricts what goes into the list, or
    or an actual emitter, which is a pattern combined with an expression that
    evaluates to a list, and the pattern is pattern matched with each element of the list
    one at a time.
    """

    emitter = emitters[0]
    last_emitter = len(emitters) <= 1

    if emitter._type == 'filter':
        result = trampoline(emitter.content, state)
        if utils.truthy(result):
            if last_emitter:
                acc.append(trampoline(expr, state))
            else:
                eval_list_comprehension(state, expr, emitters[1:], acc)

    elif emitter._type == 'emitter':
        pattern = emitter.content['pattern']
        value   = trampoline(emitter.content['expr'], state)

        if value._type == 'str':
            items = (Node('str', c) for c in value.content)
        elif value._type == 'list':
            items = utils.generate_items(value)
        elif value._type == 'tuple':
            items = value.content
        elif value._type == 'number':
            items = (Node('number', n) for n in range(1, value.content+1))
        else:
            raise MalangError("Invalid emitter type ({}) in list comprehension".format(value._type), state)

        for item in items:
            temp_state = state.newenv(state.env.shallow_copy())
            patternmatch(pattern, item, temp_state)
            if last_emitter:
                acc.append(trampoline(expr, temp_state))
            else:
                eval_list_comprehension(temp_state, expr, emitters[1:], acc=acc)
コード例 #10
0
    def query(self):
        with model.session_scope() as session:
            user_session = self.get_user_session(session)
            policy = user_session.policy.derive({})
            policy.verify('custom_query_browse')

            query = session.query(model.CustomQuery)

            term = self.get_argument('term', None)
            if term is not None:
                query = query.filter(
                    model.CustomQuery.title.ilike(r'%{}%'.format(term)))

            deleted = self.get_argument('deleted', '')
            if deleted != '':
                deleted = truthy(deleted)
                query = query.filter(model.CustomQuery.deleted == deleted)

            order_by = self.get_argument('order', 'title')
            if order_by == 'title':
                order_field = model.CustomQuery.title
            elif order_by == 'modified':
                order_field = model.CustomQuery.modified
            else:
                order_field = None

            if order_field:
                if self.get_argument('desc', ''):
                    order_field = order_field.desc()
                query = query.order_by(order_field)

            query = self.paginate(query)

            to_son = ToSon(
                r'^/[0-9]+/id$',
                r'/deleted$',
                r'/title$',
                r'/description$',
                r'/modified$',
                # Descend into list
                r'/[0-9]+$',
            )
            sons = to_son(query.all())
        self.set_header("Content-Type", "application/json")
        self.write(json_encode(sons))
        self.finish()
コード例 #11
0
    def get(self, entity_id):
        '''
        Get a list of programs that some entity belongs to. For example,
        a single survey may be present in multiple programs.
        '''
        with model.session_scope() as session:
            user_session = self.get_user_session(session)

            query = (session.query(model.Program).join(self.mapper).filter(
                self.mapper.id == entity_id).order_by(model.Program.created))

            policy = user_session.policy.derive({})
            if not policy.check('surveygroup_interact_all'):
                query = filter_surveygroups(session, query,
                                            user_session.user.id, [],
                                            [model.program_surveygroup])

            deleted = self.get_argument('deleted', '')
            if deleted != '':
                deleted = truthy(deleted)
                query = query.filter(model.Program.deleted == deleted)

            programs = [
                program for program in query.all()
                if user_session.policy.derive({
                    'program': program,
                }).check('program_view')
            ]

            to_son = ToSon(
                r'/id$',
                r'/title$',
                r'/is_editable$',
                r'/created$',
                r'/deleted$',
                # Descend
                r'/[0-9]+$',
            )
            sons = to_son(programs)

        self.set_header("Content-Type", "application/json")
        self.write(json_encode(sons))
        self.finish()
コード例 #12
0
ファイル: template.py プロジェクト: Radhika-Envision/Upmark
 def dev_mode(self):
     return truthy(tornado.options.options.dev)
コード例 #13
0
ファイル: template.py プロジェクト: Radhika-Envision/Upmark
def deploy_id():
    if truthy(tornado.options.options.dev):
        return None
    else:
        return DEPLOY_ID
コード例 #14
0
ファイル: user.py プロジェクト: Radhika-Envision/Upmark
    def query(self):
        '''
        Get a list of users.
        '''

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

            organisation_id = self.get_argument("organisationId", None)
            if organisation_id:
                org = session.query(model.Organisation).get(organisation_id)
            else:
                org = None

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

            query = (
                session.query(model.AppUser)
                .join(model.Organisation))

            # Filter out users that don't share a surveygroup with the
            # requesting user.
            # Allow admins to access users outside their surveygroups though.
            if not policy.check('admin'):
                query = filter_surveygroups(
                    session, query, user_session.user.id,
                    [], [model.user_surveygroup])

            # Get all users for an organisation
            if organisation_id:
                query = query.filter(model.Organisation.id == organisation_id)

            # Get all users for a survey group
            surveygroup_id = self.get_argument("surveyGroupId", None)
            if surveygroup_id:
                query = (
                    query.join(model.SurveyGroup, model.AppUser.surveygroups)
                    .filter(model.SurveyGroup.id == surveygroup_id))

            term = self.get_argument('term', None)
            if term is not None:
                query = query.filter(
                    model.AppUser.name.ilike(r'%{}%'.format(term)))

            deleted = self.get_argument('deleted', None)
            if deleted is not None:
                deleted = truthy(deleted)

            # Filter deleted users. If organisation_id is not specified, users
            # inherit their organisation's deleted flag too.
            if deleted == True and not organisation_id:
                query = query.filter(
                    (model.AppUser.deleted == True) |
                    (model.Organisation.deleted == True))
            elif deleted == False and not organisation_id:
                query = query.filter(
                    (model.AppUser.deleted == False) &
                    (model.Organisation.deleted == False))
            elif deleted == True:
                query = query.filter(model.AppUser.deleted == True)
            elif deleted == False:
                query = query.filter(model.AppUser.deleted == False)

            query = query.order_by(model.AppUser.name)
            query = self.paginate(query)

            to_son = ToSon(
                r'/id$',
                r'/name$',
                r'/deleted$',
                # Descend into nested objects
                r'/[0-9]+$',
                r'/organisation$',
                # Exclude password from response. Not really necessary because
                # 1. it's hashed and 2. it's not in the list above. But just to
                # be safe.
                r'!password'
            )

            sons = to_son(query.all())

        self.set_header("Content-Type", "application/json")
        self.write(json_encode(sons))
        self.finish()
コード例 #15
0
    def query(self):
        '''Get a list.'''

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

        organisation_id = self.get_argument('organisationId', '')

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

            program = (session.query(model.Program).options(
                joinedload('surveygroups')).get(program_id))

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

            query = (session.query(model.Survey).filter(
                model.Survey.program_id == program_id).order_by(
                    model.Survey.title))

            deleted = self.get_argument('deleted', '')
            if deleted != '':
                deleted = truthy(deleted)
                query = query.filter(model.Survey.deleted == deleted)

            surveys = query.all()
            to_son = ToSon(
                r'/id$',
                r'/title$',
                r'/deleted$',
                r'/n_measures$',
                r'^/[0-9]+/error$',
                # Descend
                r'/[0-9]+$')
            sons = to_son(surveys)

            # Add `purchased` metadata for nominated organisation
            if organisation_id:
                org = (session.query(model.Organisation).get(organisation_id))
                policy = user_session.policy.derive({
                    'org':
                    org,
                    'surveygroups':
                    org.surveygroups,
                })
                policy.verify('surveygroup_interact')
                policy.verify('org_view')

                for son, survey in zip(sons, surveys):
                    son.purchased = survey in org.surveys

        self.set_header("Content-Type", "application/json")
        self.write(json_encode(sons))
        self.finish()
コード例 #16
0
ファイル: evaluator.py プロジェクト: SmartViking/Malang
def maval(expr, state):
    """
    This is the evaluation function. I didn't want to shadow the python builtin function `eval', so I called it
    `maval' instead. `expr' is the abstract syntax tree that has been created with Python Lex-Yacc.
    `state.env' is an Env instance, storing the identifier bindings for malang. It will be mutated inside `maval'.
    `maval' can return:
    (1) A 'Node' instance, signifying a value, it could for example return Node('number', 3), which could maybe
    be the result of evaluating the expression Node('plus', (Node('number' 2), Node('number', 1))).
    (2) A thunk (i.e. a function meant to be called later, delaying some computation).
    This is used to implement tail call elimination; `maval' can't just naively recurse deeper because python
    itself has no tail call elimination, and python's call stack would explode.
    """

    state = state.newinfonode(expr)

    T = expr._type

    if T in ('number', 'str', 'atom', 'function', 'builtin'):
        return expr

    elif T == 'uminus':
        op = trampoline(expr.content, state)
        if not op._type == 'number':
            raise MalangError("Invalid arithmetic expression", state)
        return Node('number', -op.content, infonode=expr)

    elif T in ('plus', 'minus', 'divide', 'times', 'modulo', 'pow'):

        op1, op2 = (trampoline(op, state) for op in expr.content)
        if op1._type == op2._type:
            _type = op1._type

            if _type == 'number':
                if T in ('modulo', 'divide') and op2.content == 0:
                    raise MalangError("Division or modulo by zero", state)
                else:
                    return Node('number', arithmetic_funcs[T](op1.content, op2.content), infonode=expr)
            elif _type == 'str' and T == 'plus':
                return Node('str', op1.content + op2.content, infonode=expr)
            elif _type == 'tuple' and T == 'plus':
                return Node('tuple', op1.content + op2.content, infonode=expr)
            elif _type == 'list' and T == 'plus':
                return utils.concat_malang_lists(op1, op2)

        elif T == 'times' and {op1._type, op2._type} == {'number', 'str'}:
            return Node('str', op1.content * op2.content)
        elif T == 'times' and {op1._type, op2._type} == {'number', 'tuple'}:
            return Node('tuple', op1.content * op2.content)
        elif T == 'times' and {op1._type, op2._type} == {'number', 'list'}:
            times, malanglist = (op1, op2) if op1._type == 'number' else (op2, op1)

            return utils.concat_malang_lists(*(malanglist for _ in range(times.content)))
        else:
            raise MalangError("Invalid arithmetic expression", state)


    elif T in ('eq', 'ne', 'gt', 'lt', 'ge', 'le'):
        op1, op2 = (trampoline(op, state) for op in expr.content)
        try:
            result = cmp_funcs[T](op1, op2)
        except TypeError:
            raise MalangError("Cannot compare values of types {} and {} with the {} operator"
                              .format(op1._type, op2._type, T),
                              state)
        return Node('atom', {True: 'yeah', False: 'nope'}[result], infonode=expr)

    elif T == 'tuple':
        return Node('tuple', tuple(trampoline(e, state) for e in expr.content), infonode=expr)

    elif T == 'cons':
        head, tail = (trampoline(op, state) for op in expr.content)
        if tail._type == 'list':
            return Node('list', (head, tail))
        else:
            raise MalangError("The second operand to the cons operator has to be a list", state)

    elif T == 'list-literal':
        elems = tuple(trampoline(e, state) for e in expr.content)
        return utils.transform_list_literal(elems, expr)

    elif T == 'list_comprehension':
        result = []
        leftside_expr, emitters = expr.content

        eval_list_comprehension(state, leftside_expr, emitters, acc=result)
        return utils.iter_to_malang_list(result)


    elif T == 'bind':
        pattern, e = expr.content
        val = trampoline(e, state)
        temp_env = state.env.shallow_copy()

        patternmatch(pattern, val, state.newenv(temp_env))

        # copying over the new bindings, after the patternmatch is successful, to avoid
        # 'partial' pattern matching. If I didn't use `temp_evn` in the above call to `patternmatch`
        # then evaluating `{Same, Same} := {23, 11}.` in the REPL would leave the REPL env
        # in an 'inconsistent' state. Using the temporary state means that `Same` will be
        # unbound after that code has been evaluated, because the patternmatch was unsuccessful,
        # raising an exception, thus the code below never executes.
        for name in set(temp_env.bindings) - set(state.env.bindings):
            state.env.bind(name, temp_env.bindings[name])
        return val

    elif T == 'id':
        return state.env.get(expr.content, state)

    elif T == 'module_access':
        module = trampoline(expr.content[0], state)
        if module._type != 'module':
            raise MalangError("You tried to use module access on something that wasn't a module", state)
        val = trampoline(expr.content[1], state.newenv(module.content).newreadonly(True))
        return val

    elif T == 'composition':
        f1, f2 = (trampoline(e, state) for e in expr.content)
        utils.assert_type(f1, ('builtin', 'function'), state)
        utils.assert_type(f2, ('builtin', 'function'), state)

        code = Node('program', [
            Node('program', [
                Node('fncall', (f1,
                                Node('fncall', (f2, Node('id', '@')), infonode=expr)),
                     infonode=expr
                 )
            ])
        ])

        return Node('function', {
            'code': code,
            'filename': state.filename,
            'docstring': None,
            'parent_env': state.env
        })

    elif T == 'fncall':
        func, arg = (trampoline(e, state) for e in expr.content)
        utils.assert_type(func, ('builtin', 'function'), state)
        if func._type == 'builtin':
            return func.content(arg, state)
        elif func._type == 'function':
            return thunk(maval,
                         func.content['code'],
                         state.newenv(
                             Env(parent=func.content['parent_env'], bindings={'@': arg})
                         ).newfilename(
                             func.content['filename']
                         ))

    elif T == 'func_def':
        maybe_docstring = expr.content[0].content[0].content[0]
        if maybe_docstring._type == "str":
            docstring = maybe_docstring.content
        else:
            docstring = None
        return Node('function', {'code': expr.content[0],
                                 'filename': expr.content[1],
                                 'docstring': docstring,
                                 'parent_env': state.env}, infonode=expr)

    elif T == 'program':
        start = expr.content[:-1]
        last  = expr.content[-1]
        for e in start:
            trampoline(e, state)
        return thunk(maval, last, state)

    elif T == 'case_of':
        val = trampoline(expr.content['matched_expr'], state)
        for arrow in expr.content['arrow_sequence']:
            temp_state = state.newenv(Env(parent=state.env))
            try:
                patternmatch(arrow['pattern'], val, temp_state)
            except utils.InvalidMatch:
                continue

            return thunk(maval, arrow['expr'], temp_state)
        raise MalangError("No pattern matched in case_of expression", state)

    elif T == 'if':
        test_expr, if_true, if_false = expr.content
        temp_state = state.newenv(Env(parent=state.env))
        if utils.truthy(trampoline(test_expr, temp_state)):
            return thunk(maval, if_true,  temp_state)
        else:
            return thunk(maval, if_false, temp_state)

    elif T == 'catch':
        try:
            result = trampoline(expr.content, state)
        except MalangError as e:
            return e.args[0]

        return Node('tuple', (Node('atom', 'no_throw'), result))

    elif T == 'throw':
        value = trampoline(expr.content, state)
        raise utils.Throw(value)

    elif T == 'classified':
        exposed, program = expr.content
        hidden_state = state.newenv(Env(parent=state.env))
        result = trampoline(program, hidden_state)

        for ident in exposed:
            val = hidden_state.env.get(ident.content, state)
            state.env.bind(ident.content, val)
        
        return result

    raise MalangError("Unknown expression {!r}".format(utils.AST_to_str(expr)), state)
コード例 #17
0
    def query_by_level(self, level):
        level = int(level)
        program_id = self.get_argument('programId', '')
        survey_id = self.get_argument('surveyId', '')
        term = self.get_argument('term', '')
        parent_not = self.get_argument('parent__not', None)
        deleted = self.get_argument('deleted', '')
        if deleted != '':
            deleted = truthy(deleted)
        else:
            deleted = None

        if not survey_id:
            raise errors.ModelError("Survey ID required")

        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)))
            policy = user_session.policy.derive({
                'program': survey.program,
                'survey': survey,
                'surveygroups': survey.program.surveygroups,
            })
            policy.verify('surveygroup_interact')
            policy.verify('qnode_view')

            # Use Postgres' WITH statement
            # http://www.postgresql.org/docs/9.1/static/queries-with.html
            # http://docs.sqlalchemy.org/en/rel_1_0/orm/query.html#sqlalchemy.orm.query.Query.cte
            # http://stackoverflow.com/a/28084743/320036

            # Start by selecting root nodes
            QN1 = model.QuestionNode
            start = (
                session.query(
                    QN1,
                    literal(0).label('level'),
                    array([QN1.seq]).label('path'),
                    (QN1.seq + 1).concat('.').label('pathstr'),
                    (QN1.deleted).label('any_deleted'))
                .filter(QN1.parent_id == None,
                        QN1.program_id == program_id,
                        QN1.survey_id == survey_id)
                .cte(name='root', recursive=True))

            # Now iterate down the tree to the desired level
            QN2 = aliased(model.QuestionNode, name='qnode2')
            recurse = (
                session.query(
                    QN2,
                    (start.c.level + 1).label('level'),
                    start.c.path.concat(QN2.seq).label('path'),
                    start.c.pathstr.concat(QN2.seq + 1).concat('.').label(
                        'pathstr'),
                    (start.c.any_deleted | QN2.deleted).label(
                        'any_deleted'))
                .filter(QN2.parent_id == start.c.id,
                        QN2.program_id == start.c.program_id,
                        QN2.survey_id == start.c.survey_id,
                        start.c.level <= level))

            # Combine iterated result with root
            cte = start.union_all(recurse)

            # Discard all but the lowest level
            subquery = (
                session.query(cte.c.id, cte.c.pathstr, cte.c.any_deleted)
                .filter(cte.c.level == level)
                .order_by(cte.c.path)
                .subquery())

            # Select again to get the actual qnodes
            query = (
                session.query(
                    model.QuestionNode, subquery.c.pathstr,
                    subquery.c.any_deleted)
                .filter(model.QuestionNode.program_id == program_id)
                .join(subquery,
                      model.QuestionNode.id == subquery.c.id))

            if parent_not == '':
                query = query.filter(
                    model.QuestionNode.parent_id != None)
            elif parent_not is not None:
                query = query.filter(
                    model.QuestionNode.parent_id != parent_not)

            if term != '':
                query = query.filter(
                    model.QuestionNode.title.ilike('%{}%'.format(term)))

            if deleted is not None:
                query = query.filter(subquery.c.any_deleted == deleted)

            query = self.paginate(query)

            to_son = ToSon(
                # Fields to match from any visited object
                r'/id$',
                r'/title$',
                r'/deleted$',
                r'/n_measures$'
            )
            if truthy(self.get_argument('desc', False)):
                to_son.add(r'</description$')
            if user_session.user.role == 'clerk':
                to_son.exclude(r'/total_weight$')

            sons = []
            for qnode, path, deleted in query.all():
                son = to_son(qnode)
                son['path'] = path
                son['anyDeleted'] = deleted
                sons.append(son)

        self.set_header("Content-Type", "application/json")
        self.write(json_encode(sons))
        self.finish()
コード例 #18
0
    def query(self):
        '''Get list.'''
        level = self.get_argument('level', '')
        if level:
            self.query_by_level(level)
            return

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

        if root is not None and parent_id:
            raise errors.ModelError(
                "Can't specify parent ID when requesting roots")

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

            if parent_id:
                parent = (
                    session.query(model.QuestionNode)
                    .options(joinedload('survey'))
                    .options(joinedload('program'))
                    .options(joinedload('program.surveygroups'))
                    .get((parent_id, program_id)))
                if not parent:
                    raise errors.MissingDocError("No such parent category")
                if survey_id and survey_id != str(parent.survey_id):
                    raise errors.ModelError("Category is not in that survey")
                survey = parent.survey
            elif survey_id:
                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")
            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_view')

            query = (
                session.query(model.QuestionNode)
                .filter(model.QuestionNode.program_id == program_id))

            if survey_id:
                query = query.filter_by(survey_id=survey_id)

            if parent_id:
                query = query.filter_by(parent_id=parent_id)
            elif root is not None:
                query = query.filter_by(parent_id=None)

            if term:
                query = query.filter(
                    model.QuestionNode.title.ilike('%{}%'.format(term)))
            if parent_not:
                query = query.filter(
                    model.QuestionNode.parent_id != parent_not)

            if deleted:
                deleted = truthy(deleted)
                query = query.filter(model.QuestionNode.deleted == deleted)

            query = query.order_by(model.QuestionNode.seq,
                                   model.QuestionNode.deleted.desc())

            query = self.paginate(query, optional=True)

            to_son = ToSon(
                # Fields to match from any visited object
                r'/ob_type$',
                r'/id$',
                r'/title$',
                r'/group$',
                r'/seq$',
                r'/deleted$',
                r'/n_measures$',
                r'/total_weight$',
                r'^/[0-9]+/error$',
                r'/parent$',
                r'/survey$',
                r'/survey/structure.*$',
                r'/survey/program$',
                # Descend into nested objects
                r'/[0-9]+$',
            )
            if truthy(self.get_argument('desc', False)):
                to_son.add(r'</description$')
            if user_session.user.role == 'clerk':
                to_son.exclude(r'/total_weight$')

            sons = to_son(query.all())
            # test use session to keep status
            #status_session = self.get_secure_cookie('status')
            #status_ids = status_session.decode('utf8')
            #status_array = status_ids.split(',')
            #for son in sons:
            #    if son.id in status_array:
            #        son['hideDetail'] = True
            #####################################
            for son in sons:
                question=0
                ids = []
                pIds=[son.id]
                
                for pId in pIds:
                    sIds = (
                        session.query(model.QuestionNode)
                        .filter(model.QuestionNode.parent_id == pId))
                    if not sIds.first():
                         ids.append(pId)
                    else: 
                        for cid in sIds:
                            pIds.append(cid.id)
                qnodeMeasures = (
                    session.query(model.Measure, model.QnodeMeasure)
                    .filter(model.Measure.id == model.QnodeMeasure.measure_id)
                    .filter(model.QnodeMeasure.qnode_id.in_(ids)))  
                for qnodeMeasure in qnodeMeasures:
                    rt = (
                        session.query(model.ResponseType)
                        .filter(model.ResponseType.id == qnodeMeasure.Measure.response_type_id).first())
                    seq = 0
                    for p in rt.parts:
                        if "submeasure_seq" in p and p["submeasure_seq"] > question:
                            seq = p["submeasure_seq"]
                        else:
                            question += 1
                    question = question + seq
                son['nQuestion'] = question

            #    if son.id in status_array:
            #        son['hideDetail'] = True
        self.set_header("Content-Type", "application/json")
        self.write(json_encode(sons))
        self.finish()
コード例 #19
0
    def query(self):
        '''Get a list.'''
        term = self.get_argument('term', '')
        program_id = self.get_argument('programId', '')
        survey_id = self.get_argument('surveyId', '')
        approval = self.get_argument('approval', '')
        tracking_id = self.get_argument('trackingId', '')
        deleted = self.get_argument('deleted', '')
        organisation_id = self.get_argument('organisationId', '')

        with model.session_scope() as session:
            user_session = self.get_user_session(session)
            if user_session.user.role in {'clerk', 'org_admin'}:
                if not organisation_id:
                    organisation_id = user_session.org.id

            if organisation_id:
                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('submission_browse')

            else:
                policy = user_session.policy.derive({})
                policy.verify('submission_browse_any')

            query = session.query(model.Submission)

            if term:
                query = query.filter(
                    model.Submission.title.ilike(r'%{}%'.format(term)))

            if program_id:
                query = query.filter(model.Submission.program_id == program_id)

            if survey_id:
                query = query.filter(model.Submission.survey_id == survey_id)

            if approval:
                approval_set = self.approval_set(approval)
                log.debug('Approval set: %s', approval_set)
                query = query.filter(
                    model.Submission.approval.in_(approval_set))

            if organisation_id:
                query = query.filter(
                    model.Submission.organisation_id == organisation_id)

            if tracking_id:
                query = query.join(model.Program)
                query = query.filter(model.Program.tracking_id == tracking_id)

            if deleted:
                deleted = truthy(deleted)
                query = query.filter(model.Submission.deleted == deleted)

            if not policy.check('surveygroup_interact_all'):
                query = filter_surveygroups(
                    session, query, user_session.user.id,
                    [model.Organisation, model.Program], [
                        model.organisation_surveygroup,
                        model.program_surveygroup
                    ])

            query = query.order_by(model.Submission.created.desc())
            query = self.paginate(query)

            to_son = ToSon(
                r'/id$',
                r'/title$',
                r'/name$',
                r'/approval$',
                r'/created$',
                r'/deleted$',
                r'/program/tracking_id$',
                r'^/[0-9]+/error$',
                # Descend
                r'/[0-9]+$',
                r'/organisation$',
                r'/survey$',
                r'/program$')
            sons = to_son(query.all())

        self.set_header("Content-Type", "application/json")
        self.write(json_encode(sons))
        self.finish()
コード例 #20
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)