Exemplo n.º 1
0
def edit(request):
    dbsession = DBSession()
    experiment = dbsession.query(Experiment).filter(Experiment.id == request.matchdict['eid']).first()
    if experiment:
        page = dbsession.query(Page).filter(and_(Page.id == request.matchdict['pid'],
                                                 Page.experiment == experiment)).first()
    else:
        page = None
    if experiment and page:
        qtgroups = dbsession.query(QuestionTypeGroup).filter(QuestionTypeGroup.parent_id == None).\
            order_by(QuestionTypeGroup.order)
        return {'experiment': experiment,
                'page': page,
                'participant': Participant(id=-1),
                'qtgroups': qtgroups,
                'crumbs': [{'title': 'Experiments',
                            'url': request.route_url('dashboard')},
                           {'title': experiment.title,
                            'url': request.route_url('experiment.view', eid=experiment.id)},
                           {'title': 'Pages',
                            'url': request.route_url('experiment.page', eid=experiment.id)},
                           {'title': '%s (%s)' % (page.title, page.name)
                            if page.title else 'No title (%s)' % page.name,
                            'url': request.route_url('experiment.page.edit', eid=experiment.id, pid=page.id)}]}
    else:
        raise HTTPNotFound()
def actions(request):
    dbsession = DBSession()
    experiment = dbsession.query(Experiment).filter(
        Experiment.id == request.matchdict['eid']).first()
    if experiment:
        return {
            'experiment':
            experiment,
            'crumbs': [{
                'title': 'Experiments',
                'url': request.route_url('dashboard')
            }, {
                'title':
                experiment.title,
                'url':
                request.route_url('experiment.view', eid=experiment.id)
            }, {
                'title':
                'Actions',
                'url':
                request.route_url('experiment.actions', eid=experiment.id)
            }]
        }
    else:
        raise HTTPNotFound()
Exemplo n.º 3
0
def delete(request):
    """Handles the "/users/{uid}/delete" URL, providing the form and backend
    functionality for deleting a :class:`~wte.models.User`. Also deletes all
    the data that is linked to that :class:`~wte.models.User`.
    """
    dbsession = DBSession()
    user = dbsession.query(User).filter(
        User.id == request.matchdict['uid']).first()
    if user:
        if user.allow('delete', request.current_user):
            if request.method == 'POST':
                try:
                    CSRFSchema().to_python(request.params,
                                           State(request=request))
                    with transaction.manager:
                        dbsession.delete(user)
                    request.session.flash('The account has been deleted',
                                          queue='info')
                    if request.current_user.has_permission('admin.users.view'):
                        raise HTTPSeeOther(request.route_url('users'))
                    else:
                        raise HTTPSeeOther(request.route_url('root'))
                except Invalid as e:
                    return {
                        'errors':
                        e.error_dict,
                        'user':
                        user,
                        'crumbs':
                        create_user_crumbs(
                            request,
                            [{
                                'title': user.display_name,
                                'url': request.route_url('user.view',
                                                         uid=user.id)
                            }, {
                                'title':
                                'Delete',
                                'url':
                                request.route_url('user.delete', uid=user.id)
                            }])
                    }
            return {
                'user':
                user,
                'crumbs':
                create_user_crumbs(
                    request,
                    [{
                        'title': user.display_name,
                        'url': request.route_url('user.view', uid=user.id)
                    }, {
                        'title': 'Delete',
                        'url': request.route_url('user.delete', uid=user.id)
                    }])
            }
        else:
            unauthorised_redirect(request)
    else:
        raise HTTPNotFound()
Exemplo n.º 4
0
def latinsquare_estimate(request):
    dbsession = DBSession()
    experiment = dbsession.query(Experiment).filter(
        Experiment.id == request.matchdict['eid']).first()
    data_set = dbsession.query(DataSet).filter(
        and_(DataSet.id == request.matchdict['did'],
             DataSet.experiment_id == request.matchdict['eid'],
             DataSet.type == 'latinsquare')).first()
    if experiment and data_set:
        try:
            params = LatinSquareEstimateSchema().to_python(
                request.params,
                State(request=request,
                      dbsession=dbsession,
                      experiment=experiment))
            count = latinsquare_estimate_count(dbsession, params['source_a'],
                                               params['mode_a'],
                                               params['source_b'],
                                               params['mode_b'])
            if count is None:
                return {'count': ''}
            else:
                return {'count': count}
        except formencode.Invalid:
            return {'count': ''}
    else:
        raise HTTPNotFound()
Exemplo n.º 5
0
def search(request):
    """Handles the ``/parts/{pid}/assets/search`` URL, searching
    for all :class:`~wte.models.Asset` that have a filename that
    matches the 'q' request parameter and that belong to either the
    current :class:`~wte.models.Part` or any of its ancestors.
    The current user must have the "view" permission on the current
    :class:`~wte.models.Part` to see any results.
    """
    dbsession = DBSession()
    part = dbsession.query(Part).filter(
        Part.id == request.matchdict['pid']).first()
    if part:
        if part.allow('view', request.current_user):
            assets = []
            if 'q' in request.params:
                while part is not None:
                    assets.extend([
                        asset for asset in part.assets
                        if request.params['q'] in asset.filename
                    ])
                    part = part.parent
            return [{
                'id': asset.filename,
                'value': asset.filename
            } for asset in assets]
        else:
            raise unauthorised_redirect(request)
    else:
        raise HTTPNotFound()
def view_part_tasks(request):
    """Handles the ``parts/{pid}/timed-tasks`` URL, displaying the
    :class:`~wte.models.TimedTask`\ s for the given :class:`~wte.models.Part`.

    Requires that the user has "edit" rights on the
    :class:`~wte.models.Part`.
    """
    dbsession = DBSession()
    part = dbsession.query(Part).filter(
        Part.id == request.matchdict['pid']).first()
    if part:
        if part.allow('edit', request.current_user):
            crumbs = create_part_crumbs(request, part, {
                'title': 'Edit Timed Actions',
                'url': request.current_route_url()
            })
            available_tasks = [('change_status', 'Change Status')]
            return {
                'part': part,
                'crumbs': crumbs,
                'available_tasks': available_tasks,
                'include_footer': True,
                'help': ['user', 'teacher', 'timed_actions.html']
            }
        else:
            unauthorised_redirect(request)
    else:
        raise HTTPNotFound()
Exemplo n.º 7
0
def view_asset(request):
    """Handles the ``/parts/{pid}/files/name/assets/{filename}``
    URL, sending back the correct :class:`~wte.models.Asset`.

    Requires that the user has "view" rights on the :class:`~wte.models.Part`.
    """
    dbsession = DBSession()
    part = dbsession.query(Part).filter(
        Part.id == request.matchdict['pid']).first()
    if part.type == 'page':
        part = part.parent
    asset = dbsession.query(Asset).join(Part.assets).\
        filter(and_(Asset.filename == request.matchdict['filename'],
                    Part.id == part.id)).first()
    if part and asset:
        if part.allow('view', request.current_user):
            if 'If-None-Match' in request.headers and request.headers[
                    'If-None-Match'] == asset.etag:
                raise HTTPNotModified()
            headerlist = [('Content-Type', str(asset.mimetype))]
            if asset.etag is not None:
                headerlist.append(('ETag', str(asset.etag)))
            if 'download' in request.params:
                if request.params['download'].lower() == 'true':
                    headerlist.append(
                        ('Content-Disposition',
                         str('attachment; filename="%s"' % (asset.filename))))
            return Response(body=asset.data, headerlist=headerlist)
        else:
            unauthorised_redirect(request)
    else:
        raise HTTPNotFound()
Exemplo n.º 8
0
def save_file(request):
    """Handles the ``/parts/{pid}/files/id/{fid}/save``
    URL, updating the :class:`~wte.models.Asset`'s content.

    Requires that the user has "view" rights on the :class:`~wte.models.Part`.
    It will also only update an :class:`~wte.models.Asset` belonging to the
    current :class:`~wte.models.User`.
    """
    dbsession = DBSession()
    part = dbsession.query(Part).filter(
        Part.id == request.matchdict['pid']).first()
    if part:
        if part.allow('view', request.current_user):
            progress = get_user_part_progress(dbsession, request.current_user,
                                              part)
            for user_file in progress.files:
                if user_file.id == int(request.matchdict['fid']):
                    if 'content' in request.params:
                        with transaction.manager:
                            dbsession.add(user_file)
                            user_file.data = request.params['content'].encode(
                                'utf-8')
                            user_file.etag = hashlib.sha512(
                                user_file.data).hexdigest()
                        return {'status': 'saved'}
                    else:
                        return {'status': 'no-changes'}
            raise HTTPNotFound()
        else:
            unauthorised_redirect(request)
    else:
        raise HTTPNotFound()
Exemplo n.º 9
0
def view_file(request):
    """Handles the ``parts/{ptid}/pages/{pid}/users/{uid}/files/name/{filename}``
    URL, sending back the correct :class:`~wte.models.Asset`.

    Requires that the user has "view" rights on the :class:`~wte.models.Part`.
    It will also only send an :class:`~wte.models.Asset` belonging to the current
    :class:`~wte.models.User`.
    """
    dbsession = DBSession()
    part = dbsession.query(Part).filter(
        Part.id == request.matchdict['pid']).first()
    if part:
        if part.allow('view', request.current_user):
            progress = get_user_part_progress(dbsession, request.current_user,
                                              part)
            for user_file in progress.files:
                if user_file.filename == request.matchdict['filename']:
                    if 'If-None-Match' in request.headers and request.headers[
                            'If-None-Match'] == user_file.etag:
                        raise HTTPNotModified()
                    headers = [('Content-Type', str(user_file.mimetype))]
                    if user_file.etag is not None:
                        headers.append(('ETag', str(user_file.etag)))
                    if 'download' in request.params:
                        headers.append(('Content-Disposition',
                                        str('attachment; filename="%s"' %
                                            (user_file.filename))))
                    return Response(body=user_file.data, headerlist=headers)
            raise HTTPNotFound()
        else:
            unauthorised_redirect(request)
    else:
        raise HTTPNotFound()
Exemplo n.º 10
0
def transitions(request):
    dbsession = DBSession()
    experiment = dbsession.query(Experiment).filter(Experiment.id == request.matchdict['eid']).first()
    if experiment:
        page = dbsession.query(Page).filter(and_(Page.id == request.matchdict['pid'],
                                                 Page.experiment == experiment)).first()
    else:
        page = None
    if experiment and page:
        pages_questions = {}
        for tmp_page in experiment.pages:
            pages_questions[tmp_page.id] = {'page': tmp_page,
                                            'questions': dict([(q.id, q) for q in tmp_page.questions])}
        return {'experiment': experiment,
                'page': page,
                'pages_questions': pages_questions,
                'crumbs': [{'title': 'Experiments',
                            'url': request.route_url('dashboard')},
                           {'title': experiment.title,
                            'url': request.route_url('experiment.view', eid=experiment.id)},
                           {'title': 'Pages',
                            'url': request.route_url('experiment.page', eid=experiment.id)},
                           {'title': '%s (%s)' % (page.title, page.name)
                            if page.title else 'No title (%s)' % page.name,
                            'url': request.route_url('experiment.page.edit', eid=experiment.id, pid=page.id)}]}
    else:
        raise HTTPNotFound()
Exemplo n.º 11
0
def settings(request):
    dbsession = DBSession()
    experiment = dbsession.query(Experiment).filter(Experiment.id == request.matchdict['eid']).first()
    page = dbsession.query(Page).filter(and_(Page.id == request.matchdict['pid'],
                                             Page.experiment_id == request.matchdict['eid'])).first()
    if experiment and page:
        if request.method == 'POST':
            try:
                params = PageSettingsSchema().to_python(request.params,
                                                        State(request=request,
                                                              dbsession=dbsession,
                                                              experiment=experiment,
                                                              page_id=request.matchdict['pid']))
                with transaction.manager:
                    dbsession.add(page)
                    page.name = params['name']
                    page.title = params['title']
                    page.styles = params['styles']
                    page.scripts = params['scripts']
                    page['number_questions'] = params['number_questions']
                dbsession.add(page)
                dbsession.add(experiment)
                raise HTTPFound(request.route_url('experiment.page.settings', eid=experiment.id, pid=page.id))
            except formencode.Invalid as e:
                return {'experiment': experiment,
                        'page': page,
                        'crumbs': [{'title': 'Experiments',
                                    'url': request.route_url('dashboard')},
                                   {'title': experiment.title,
                                    'url': request.route_url('experiment.view', eid=experiment.id)},
                                   {'title': 'Pages',
                                    'url': request.route_url('experiment.page', eid=experiment.id)},
                                   {'title': '%s (%s)' % (page.title, page.name)
                                    if page.title else 'No title (%s)' % page.name,
                                    'url': request.route_url('experiment.page.edit',
                                                             eid=experiment.id,
                                                             pid=page.id)},
                                   {'title': 'Settings',
                                    'url': request.route_url('experiment.page.settings',
                                                             eid=experiment.id,
                                                             pid=page.id)}],
                        'values': request.params,
                        'errors': e.error_dict}
        return {'experiment': experiment,
                'page': page,
                'crumbs': [{'title': 'Experiments',
                            'url': request.route_url('dashboard')},
                           {'title': experiment.title,
                            'url': request.route_url('experiment.view', eid=experiment.id)},
                           {'title': 'Pages',
                            'url': request.route_url('experiment.page', eid=experiment.id)},
                           {'title': '%s (%s)' % (page.title, page.name)
                            if page.title else 'No title (%s)' % page.name,
                            'url': request.route_url('experiment.page.edit', eid=experiment.id, pid=page.id)},
                           {'title': 'Settings',
                            'url': request.route_url('experiment.page.settings', eid=experiment.id, pid=page.id)}]}
    else:
        raise HTTPNotFound()
Exemplo n.º 12
0
def login(request):
    """Handles the "user.login" URL, checking the submitted username and
    password against the stored :class:`~pywebtools.pyramid.auth.models.User` and setting the
    necessary session variables if the login is successful.

    Uses either the ``return_to`` parameter in the request to redirect on success or
    the "user.login" redirection route, with parameter replacement "{uid}" will be replaced
    with the logged in user's identifier.
    """
    dbsession = DBSession()
    if request.current_user.logged_in:
        if 'return_to' in request.params and request.params[
                'return_to'] != request.current_route_url():
            if '_default' in active_redirects and \
                    request.params['return_to'] != request.route_url(active_redirects['_default']):
                raise HTTPSeeOther(request.params['return_to'])
        redirect(request, 'user.login', uid=request.current_user.id)
    if request.method == 'POST':
        try:
            dbsession = DBSession()
            params = LoginSchema().to_python(
                request.params,
                State(dbsession=dbsession, request=request, user_class=User))
            user = dbsession.query(User).filter(
                User.email == params['email'].lower()).first()
            request.current_user = user
            request.current_user.logged_in = True
            request.session['uid'] = user.id
            request.session.new_csrf_token()
            if 'return_to' in request.params and request.params[
                    'return_to'] != request.current_route_url():
                if '_default' in active_redirects and \
                        request.params['return_to'] != request.route_url(active_redirects['_default']):
                    raise HTTPSeeOther(request.params['return_to'])
            redirect(request, 'user.login', uid=request.current_user.id)
        except Invalid as e:
            return {
                'errors':
                e.error_dict if e.error_dict else {
                    'email': e.msg,
                    'password': e.msg
                },
                'values':
                request.params,
                'crumbs': [{
                    'title': 'Login',
                    'url': request.route_url('user.login'),
                    'current': True
                }]
            }
    return {
        'crumbs': [{
            'title': 'Login',
            'url': request.route_url('user.login'),
            'current': True
        }]
    }
Exemplo n.º 13
0
def action(request):
    """Handles the ``/users/action`` URL, applying the given action to the
    list of selected users. Requires that the current
    :class:`~wte.models.User` has the "admin.users.view"
    :class:`~wte.models.Permission`.
    """
    dbsession = DBSession()
    try:
        query_params = []
        for param in ['q', 'status', 'start']:
            if param in request.params and request.params[param]:
                query_params.append((param, request.params[param]))
        params = ActionSchema().to_python(request.params,
                                          State(request=request))
        if params['action'] != 'delete' or params['confirm']:
            with transaction.manager:
                for user in dbsession.query(User).filter(
                        User.id.in_(params['user_id'])):
                    if params['action'] == 'validate':
                        if user.status == 'unconfirmed' and user.allow(
                                'edit', request.current_user):
                            user.status = 'active'
                    elif params['action'] == 'delete':
                        if user.allow('delete', request.current_user):
                            dbsession.delete(user)
                    elif params['action'] == 'password':
                        if user.status == 'active' and user.allow(
                                'edit', request.current_user):
                            token = TimeToken(
                                user.id, 'reset_password',
                                datetime.now() + timedelta(seconds=1200))
                            dbsession.add(token)
                            dbsession.flush()
                            if 'user.password_reset' in active_callbacks:
                                active_callbacks['user.password_reset'](
                                    request, user, token)
            raise HTTPSeeOther(request.route_url('users', _query=query_params))
        else:
            return {
                'params':
                params,
                'users':
                dbsession.query(User).filter(User.id.in_(params['user_id'])),
                'query_params':
                query_params,
                'crumbs':
                create_user_crumbs(request, [{
                    'title': 'Confirm',
                    'url': request.current_route_url()
                }])
            }
    except Invalid as e:
        print(e)
        request.session.flash(
            'Please select the action you wish to apply and the users to apply it to',
            queue='error')
        raise HTTPSeeOther(request.route_url('users', _query=query_params))
Exemplo n.º 14
0
def dashboard(request):
    dbsession = DBSession()
    experiments = dbsession.query(Experiment).filter(Experiment.owned_by == request.current_user.id).\
        order_by(Experiment.title)
    return {
        'experiments': experiments,
        'crumbs': [{
            'title': 'Experiments',
            'url': request.route_url('dashboard')
        }]
    }
Exemplo n.º 15
0
def delete_part_task(request):
    """Handles the ``parts/{pid}/timed-tasks/{tid}/delete`` URL, providing the UI
    and backend for deleting an existing :class:`~wte.models.TimedTask` that
    belongs to a :class:`~wte.models.Part`.

    Requires that the user has "edit" rights on the
    :class:`~wte.models.Part`.
    """
    dbsession = DBSession()
    part = dbsession.query(Part).filter(
        Part.id == request.matchdict['pid']).first()
    task = dbsession.query(TimedTask).filter(
        TimedTask.id == request.matchdict['tid']).first()
    if part and task:
        if part.allow('edit', request.current_user):
            crumbs = create_part_crumbs(
                request, part,
                [{
                    'title': 'Timed Actions',
                    'url': request.route_url('part.timed_task', pid=part.id)
                }, {
                    'title': 'Delete',
                    'url': request.current_route_url
                }])
            if request.method == 'POST':
                try:
                    CSRFSchema().to_python(request.params,
                                           State(request=request))
                    dbsession = DBSession()
                    with transaction.manager:
                        dbsession.delete(task)
                    dbsession.add(part)
                    raise HTTPSeeOther(
                        request.route_url('part.timed_task', pid=part.id))
                except formencode.Invalid as e:
                    return {
                        'errors': e.error_dict,
                        'part': part,
                        'task': task,
                        'crumbs': crumbs,
                        'include_footer': True,
                        'help': ['user', 'teacher', 'timed_actions.html']
                    }
            return {
                'part': part,
                'task': task,
                'crumbs': crumbs,
                'include_footer': True,
                'help': ['user', 'teacher', 'timed_actions.html']
            }
        else:
            unauthorised_redirect(request)
    else:
        raise HTTPNotFound()
Exemplo n.º 16
0
def new_part_task(request):
    """Handles the ``parts/{pid}/timed-tasks/new`` URL, providing the UI and
    backend for creating a new :class:`~wte.models.TimedTask`\ s for
    a given :class:`~wte.models.Part`.

    Requires that the user has "edit" rights on the
    :class:`~wte.models.Part`.
    """
    dbsession = DBSession()
    part = dbsession.query(Part).filter(
        Part.id == request.matchdict['pid']).first()
    if part:
        if part.allow('edit', request.current_user):
            crumbs = create_part_crumbs(request, part, {
                'title': 'Timed Actions',
                'url': request.current_route_url()
            })
            available_tasks = [('change_status', 'Change Status')]
            if request.method == 'POST':
                try:
                    params = NewTimedTaskSchema().to_python(
                        request.params, State(request=request))
                    with transaction.manager:
                        title = 'Unknown Task'
                        if params['name'] == 'change_status':
                            title = 'Change Status'
                        new_task = TimedTask(name=params['name'],
                                             part_id=part.id,
                                             title=title,
                                             status='new')
                        dbsession.add(new_task)
                    dbsession.add(part)
                    dbsession.add(new_task)
                    raise HTTPSeeOther(
                        request.route_url('part.timed_task.edit',
                                          pid=part.id,
                                          tid=new_task.id))
                except formencode.Invalid as e:
                    return {
                        'errors': e.error_dict,
                        'values': request.params,
                        'part': part,
                        'crumbs': crumbs,
                        'available_tasks': available_tasks,
                        'include_footer': True,
                        'help': ['user', 'teacher', 'timed_actions.html']
                    }
            return {
                'part': part,
                'crumbs': crumbs,
                'available_tasks': available_tasks,
                'include_footer': True,
                'help': ['user', 'teacher', 'timed_actions.html']
            }
        else:
            unauthorised_redirect(request)
    else:
        raise HTTPNotFound()
Exemplo n.º 17
0
def initialise_database(args):
    settings = get_appsettings(args.configuration)
    setup_logging(args.configuration)
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    if args.drop_existing:
        Base.metadata.drop_all(engine)
    Base.metadata.create_all(engine)
    dbsession = DBSession()
    with transaction.manager:
        user = User(email='*****@*****.**',
                    display_name='Admin',
                    status='active')
        user.new_password('password')
        group = PermissionGroup(title='Site administrator')
        group.permissions.append(
            Permission(name='admin.users.view', title='View all users'))
        group.permissions.append(
            Permission(name='admin.users.edit', title='Edit all users'))
        group.permissions.append(
            Permission(name='admin.users.delete', title='Delete all users'))
        group.permissions.append(
            Permission(name='admin.users.permissions',
                       title='Edit all user\'s permissions'))
        user.permission_groups.append(group)
        group = PermissionGroup(title='Developer')
        group.permissions.append(
            Permission(name='experiment.create',
                       title='Create new experiments'))
        user.permission_groups.append(group)
        dbsession.add(user)
        group = PermissionGroup(title='Content administrator')
        group.permissions.append(
            Permission(name='experiment.view', title='View all experiments'))
        group.permissions.append(
            Permission(name='experiment.edit', title='Edit all experiments'))
        group.permissions.append(
            Permission(name='experiment.delete',
                       title='Delete all experiments'))
        dbsession.add(group)
        question_types = load(QuestionTypeIOSchema(many=True),
                              json.loads(resource_string('ess',
                                                         'scripts/templates/default_question_types.json').\
            decode('utf-8')))
        dbsession.add_all(question_types)
    alembic_config = config.Config(args.configuration, ini_section='app:main')
    alembic_config.set_section_option('app:main', 'script_location',
                                      'ess:migrations')
    command.stamp(alembic_config, "head")
Exemplo n.º 18
0
def content_regenerate(request):
    """Handles the ``/admin/content/regenerate`` URL, regenerating the
    ``compiled_content`` attribute for all :class:`~wte.models.Part`\ s.
    """
    if request.current_user.has_permission('admin.modules.edit'):
        if request.method == 'POST':
            dbsession = DBSession()
            with transaction.manager:
                for part in dbsession.query(Part):
                    if part.content:
                        part.compiled_content = compile_rst(
                            part.content, request, part)
            request.session.flash('Regeneration complete', queue='info')
        raise HTTPSeeOther(request.route_url('admin.content'))
    else:
        raise unauthorised_redirect(request)
Exemplo n.º 19
0
 def wrapper(f, *args, **kwargs):
     request = request_from_args(*args)
     if 'uid' in request.session:
         dbsession = DBSession()
         user = dbsession.query(User).filter(
             User.id == request.session['uid']).first()
         if user:
             user.logged_in = True
             request.current_user = user
         else:
             request.current_user = User()
             request.current_user.logged_in = False
     else:
         request.current_user = User()
         request.current_user.logged_in = False
     return f(*args, **kwargs)
Exemplo n.º 20
0
def export(request):
    dbsession = DBSession()
    experiment = dbsession.query(Experiment).filter(Experiment.id == request.matchdict['eid']).first()
    page = dbsession.query(Page).filter(and_(Page.id == request.matchdict['pid'],
                                             Page.experiment_id == request.matchdict['eid'])).first()
    if experiment and page:
        try:
            CSRFSchema().to_python(request.params, State(request=request))
            request.response.headers['Content-Disposition'] = 'attachment; filename="%s.json"' % page.name
            return PageIOSchema(include_data=('questions', 'questions.q_type', 'questions.q_type.parent',
                                              'questions.q_type.q_type_group', 'questions.q_type.q_type_group.parent',
                                              'questions.q_type.parent.q_type_group',
                                              'questions.q_type.parent.q_type_group.parent')).dump(page).data
        except formencode.Invalid:
            raise HTTPFound(request.route_url('experiment.page.edit', eid=experiment.id, pid=page.id))
    else:
        raise HTTPNotFound()
Exemplo n.º 21
0
def import_experiment(request):
    if request.method == 'POST':
        try:
            params = ImportExperimentSchema().to_python(
                request.params, State(request=request))
            dbsession = DBSession()
            with transaction.manager:
                experiment, errors = ExperimentIOSchema(include_schemas=[s for s in all_io_schemas
                                                                         if s != ExperimentIOSchema]).\
                    loads(params['source'].file.read().decode('utf-8'))
                if errors:
                    raise formencode.Invalid(
                        '. '.join([
                            '%s: %s' % (e['source']['pointer'], e['detail'])
                            for e in errors['errors']
                        ]), None, None)
                for page in experiment.pages:
                    replace_questions(page, dbsession)
                experiment.owner = request.current_user
                experiment.external_id = uuid.uuid1().hex,
                experiment.status = 'develop'
                dbsession.add(experiment)
                dbsession.flush()
                for latin_square in experiment.latin_squares:
                    fix_latinsquare(latin_square, experiment.data_sets)
                for page in experiment.pages:
                    for transition in page.next:
                        fix_transition(transition, experiment.pages)
            dbsession.add(experiment)
            raise HTTPFound(
                request.route_url('experiment.view', eid=experiment.id))
        except formencode.Invalid as e:
            return {
                'crumbs': [{
                    'title': 'Experiments',
                    'url': request.route_url('dashboard')
                }, {
                    'title': 'Import',
                    'url': request.route_url('experiment.import')
                }],
                'errors': {
                    'source': str(e)
                },
                'values':
                request.params
            }
    return {
        'crumbs': [{
            'title': 'Experiments',
            'url': request.route_url('dashboard')
        }, {
            'title': 'Import',
            'url': request.route_url('experiment.import')
        }]
    }
Exemplo n.º 22
0
def reorder_page(request):
    dbsession = DBSession()
    experiment = dbsession.query(Experiment).filter(Experiment.id == request.matchdict['eid']).first()
    if experiment:
        page = dbsession.query(Page).filter(and_(Page.id == request.matchdict['pid'],
                                                 Page.experiment == experiment)).first()
    else:
        page = None
    if experiment and page:
        try:
            params = ReorderSchema().to_python(request.params, State(request=request))
            with transaction.manager:
                visible_idx = 1
                for idx, qid in enumerate(params['item']):
                    question = dbsession.query(Question).filter(and_(Question.id == qid,
                                                                     Question.page == page)).first()
                    if question is not None:
                        dbsession.add(question.q_type)
                        question.order = idx
                        if question['frontend', 'visible'] and question['frontend', 'title']:
                            question['frontend', 'question_number'] = visible_idx
                            visible_idx = visible_idx + 1
            return {'status': 'ok'}
        except formencode.Invalid:
            return {'status': 'error'}
    else:
        raise HTTPNotFound()
Exemplo n.º 23
0
def crossref_role(name,
                  rawtext,
                  text,
                  lineno,
                  inliner,
                  options={},
                  content=[]):
    """The :func:`~wte.text_formatter.docutils_ext.crossref_role` function
    implements an additional docutils role that handles cross-references
    between :class:`~wte.models.Part`\ s.

    Usage in ReST is \:crossref\:\`part_id\` or \:crossref\:\`link text
    <part_id>\`.
    """
    request = inliner.document.settings.pyramid_request
    result = []
    messages = []
    text = utils.unescape(text)
    match = re.match(CROSSREF_PATTERN, text)
    if match:
        groups = match.groups()
        target_id = groups[0] if groups[0] else groups[2]
        dbsession = DBSession()
        part = dbsession.query(Part).filter(Part.id == target_id).first()
        if part:
            result.append(
                nodes.reference(rawtext,
                                groups[1] if groups[1] else part.title,
                                internal=False,
                                refuri=request.route_url('part.view',
                                                         pid=target_id)))
        else:
            messages.append(
                inliner.reporter.warning(
                    'There is no target to link to for "%s"' % (text),
                    line=lineno))
            result.append(inliner.problematic(rawtext, rawtext, messages[0]))
    else:
        messages.append(
            inliner.reporter.error(
                'No valid link target identifier could be identified in "%s"' %
                (text),
                line=lineno))
        result.append(inliner.problematic(rawtext, rawtext, messages[0]))
    return result, messages
Exemplo n.º 24
0
def check_answers(request):
    """Handles the "/parts/{pid}/quiz/check_answers" URL, checking whether a
    :class:`~wte.models.QuizAnswer` exists and if so, returning whether it was
    answered correctly and what the answer was.

    The response does not distinguish between initial or finally correct, but will return
    the last answer the user provided.
    """
    try:
        params = CheckAnswerSchema().to_python(request.params,
                                               State(request=request))
        dbsession = DBSession()
        quiz = dbsession.query(Quiz).filter(
            and_(Quiz.part_id == request.matchdict['pid'],
                 Quiz.name == params['quiz'])).first()
        if quiz:
            answer = dbsession.query(QuizAnswer).filter(
                and_(QuizAnswer.user_id == request.current_user.id,
                     QuizAnswer.quiz_id == quiz.id,
                     QuizAnswer.question == params['question'])).first()
            if answer:
                if answer.initial_correct:
                    return {
                        'status': 'correct',
                        'answer': json.loads(answer.initial_answer)
                    }
                elif answer.final_correct:
                    return {
                        'status': 'correct',
                        'answer': json.loads(answer.final_answer)
                    }
                elif answer.final_correct is None:
                    return {
                        'status': 'incorrect',
                        'answer': json.loads(answer.initial_answer)
                    }
                else:
                    return {
                        'status': 'incorrect',
                        'answer': json.loads(answer.final_answer)
                    }
        return {'status': 'unanswered'}
    except Invalid as e:
        return {'status': 'error', 'errors': e.error_dict}
Exemplo n.º 25
0
    def has_permission(self, permission):
        """Checks whether the user has been granted the given ``permission``,
        either directly or via a :class:`~pywebtools.pyramid.auth.models.PermissionGroup`.

        :param permission: The permission to check for
        :type permission: `unicode`
        :return: ``True`` if the user has the permission, ``False`` otherwise
        :rtype: `bool`
        """
        if hasattr(self, '_permissions'):
            return permission in self._permissions
        else:
            dbsession = DBSession()
            direct_perm = dbsession.query(Permission.name).join(
                User, Permission.users).filter(User.id == self.id)
            group_perm = dbsession.query(Permission.name).join(PermissionGroup, Permission.permission_groups).\
                join(User, PermissionGroup.users).filter(User.id == self.id)
            self._permissions = [p[0] for p in direct_perm.union(group_perm)]
            return self.has_permission(permission)
Exemplo n.º 26
0
def main(global_config, **settings):
    """Constructs, initialises, and returns the Web Teaching Environment's
    ``WSGIApplication``.
    """
    # Init Database
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    check_database_version(DB_VERSION)
    # Init configuration
    config = Configurator(settings=settings)
    config.include('kajiki.integration.pyramid')
    # Init routes
    config.add_static_view('static', 'static', cache_max_age=3600)
    views.init(config, settings)
    # Init docutils
    text_formatter.init(settings)

    config.scan()
    return config.make_wsgi_app()
Exemplo n.º 27
0
def action(request):
    """Handles the ``parts/{pid}/users/action`` URL, loads the interface for changing
    :class:`~wte.models.User` registered for a :class:`~wte.models.Part`.

    Requires that the user has "users" rights on the
    :class:`~wte.models.Part`.
    """
    dbsession = DBSession()
    part = dbsession.query(Part).filter(Part.id == request.matchdict['pid']).first()
    if part:
        if part.allow('users', request.current_user):
            query_params = []
            for param in ['q', 'role', 'start']:
                if param in request.params and request.params[param]:
                    query_params.append((param, request.params[param]))
            try:
                params = ActionSchema().to_python(request.params,
                                                  State(request=request))
            except formencode.api.Invalid:
                request.session.flash('Please select the action you wish to apply ' +
                                      'and the users you wish to apply it to', queue='error')
                raise HTTPSeeOther(request.route_url('part.users', pid=part.id, _query=query_params))
            crumbs = create_part_crumbs(request,
                                        part,
                                        [{'title': 'Users',
                                         'url': request.route_url('part.users', pid=part.id)},
                                         {'title': 'Update',
                                          'url': request.current_route_url()}])
            users = dbsession.query(UserPartRole).filter(UserPartRole.id.in_(params['role_id'])).all()
            return {'part': part,
                    'params': params,
                    'query_params': query_params,
                    'users': users,
                    'crumbs': crumbs,
                    'help': ['user', 'teacher', 'module', 'users.html']}
        else:
            unauthorised_redirect(request)
    else:
        raise HTTPNotFound()
Exemplo n.º 28
0
def list_experiments(request):
    dbsession = DBSession()
    experiments = dbsession.query(Experiment)
    query_params = []
    if 'q' in request.params and request.params['q'].strip():
        experiments = experiments.filter(
            Experiment.title.like('%%%s%%' % request.params['q'].strip()))
        query_params.append(('q', request.params['q'].strip()))
    start = 0
    if 'start' in request.params:
        try:
            start = int(request.params['start'])
        except ValueError:
            pass
    experiments = experiments.offset(start).limit(10)
    pages = paginate(request,
                     'experiment.list',
                     experiments,
                     start,
                     10,
                     query_params=query_params)
    return {'experiments': experiments, 'pages': pages}
Exemplo n.º 29
0
def reorder_transition(request):
    dbsession = DBSession()
    experiment = dbsession.query(Experiment).filter(Experiment.id == request.matchdict['eid']).first()
    if experiment:
        page = dbsession.query(Page).filter(and_(Page.id == request.matchdict['pid'],
                                                 Page.experiment == experiment)).first()
    else:
        page = None
    if experiment and page:
        try:
            params = ReorderSchema().to_python(request.params, State(request=request))
            with transaction.manager:
                for idx, tid in enumerate(params['item']):
                    transition = dbsession.query(Transition).filter(and_(Transition.id == tid,
                                                                         Transition.source == page)).first()
                    if transition is not None:
                        transition.order = idx
            return {'status': 'ok'}
        except formencode.Invalid:
            return {'status': 'error'}
    else:
        raise HTTPNotFound()
Exemplo n.º 30
0
def users(request):
    """Handles the ``/users`` URL, displaying all users if the current
    :class:`~pywebtools.pyramid.auth.models.User` has the "admin.users.view"
    :class:`~pywebtools.pyramid.auth.models.Permission`.
    """
    dbsession = DBSession()
    users = dbsession.query(User)
    query_params = []
    if 'q' in request.params and request.params['q']:
        users = users.filter(
            or_(User.display_name.contains(request.params['q']),
                User.email.contains(request.params['q'])))
        query_params.append(('q', request.params['q']))
    if 'status' in request.params and request.params['status']:
        query_params.append(('status', request.params['status']))
        if request.params['status'] == 'confirmed':
            users = users.filter(User.status == 'active')
        else:
            users = users.filter(User.status != 'active')
    start = 0
    if 'start' in request.params:
        try:
            start = int(request.params['start'])
        except ValueError:
            pass
    users = users.order_by(User.display_name)
    pages = paginate(request,
                     'users',
                     users,
                     start,
                     25,
                     query_params=query_params)
    users = users.offset(start).limit(25)
    return {
        'users': users,
        'pages': pages,
        'crumbs': create_user_crumbs(request, [])
    }