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()
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()
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()
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()
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()
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()
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()
def delete(request): """Handles the ``/parts/{pid}/assets/{aid}/delete`` URL, providing the UI and backend for deleting :class:`~wte.models.Asset`. Requires that the user has "edit" rights on the current :class:`~wte.models.Part`. """ dbsession = DBSession() part = dbsession.query(Part).filter( Part.id == request.matchdict['pid']).first() asset = dbsession.query(Asset).join(Part.all_assets).\ filter(and_(Asset.id == request.matchdict['aid'], Part.id == request.matchdict['pid'])).first() if part and asset: if part.allow('edit', request.current_user): crumbs = create_part_crumbs(request, part, { 'title': 'Delete Asset', 'url': request.current_route_url() }) if request.method == 'POST': try: CSRFSchema().to_python(request.params, State(request=request)) dbsession = DBSession() with transaction.manager: dbsession.add(asset) asset.parts = [] dbsession.delete(asset) dbsession.add(part) raise HTTPSeeOther( request.route_url('part.view', pid=part.id)) except formencode.Invalid as e: return { 'errors': e.error_dict, 'part': part, 'asset': asset, 'crumbs': crumbs, 'help': ['user', 'teacher', 'asset', 'delete.html'] } return { 'part': part, 'asset': asset, 'crumbs': crumbs, 'help': ['user', 'teacher', 'asset', 'delete.html'] } else: unauthorised_redirect(request) else: raise HTTPNotFound()
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 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()
def admin(request): """Handles the ``/admin`` URL, displaying all available administrative functions. """ if request.current_user.has_permission('admin'): return { 'crumbs': [{ 'title': 'Administration', 'url': request.current_route_url(), 'current': True }] } else: raise unauthorised_redirect(request)
def view(request): """Handles the "/users/{uid}" URL, showing the user's profile. """ dbsession = DBSession() user = dbsession.query(User).filter( User.id == request.matchdict['uid']).first() if user: if user.allow('view', request.current_user): return { 'user': user, 'crumbs': create_user_crumbs( request, [{ 'title': user.display_name, 'url': request.route_url('user.view', uid=user.id) }]), 'help': ['user', 'user', 'profile.html'] } else: unauthorised_redirect(request) else: raise HTTPNotFound()
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)
def content_admin(request): """Handles the ``/admin/content`` URL, displaying all available administrative functions related to the content administrations. """ if request.current_user.has_permission('admin.modules.view'): return { 'crumbs': [{ 'title': 'Administration', 'url': request.route_url('admin') }, { 'title': 'Content', 'url': request.current_route_url(), 'current': True }] } else: raise unauthorised_redirect(request)
def content_list(request): """Handles the ``/admin/content/list`` URL providing administrative access to all :class:`~wte.models.Part`\ s. """ if request.current_user.has_permission('admin.modules.view'): dbsession = DBSession() modules = dbsession.query(Part).filter(Part.parent_id == None) try: start = int(request.params['start']) except: start = 0 if 'q' in request.params and request.params['q']: modules = modules.filter(Part.title.contains(request.params['q'])) if 'status' in request.params and request.params['status']: modules = modules.filter(Part.status == request.params['status']) pages = paginate(request, 'admin.content.list', modules, start, 25) modules = modules.offset(start).limit(25) return { 'modules': modules, 'pages': pages, 'crumbs': [{ 'title': 'Administration', 'url': request.route_url('admin') }, { 'title': 'Content', 'url': request.route_url('admin.content') }, { 'title': 'All Modules', 'url': request.current_route_url(), 'current': True }] } else: raise unauthorised_redirect(request)
def add(request): """Handles the ``parts/{pid}/users/add`` URL, providing the functionality for adding a :class:`~wte.models.User` to 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): crumbs = create_part_crumbs(request, part, [{'title': 'Users', 'url': request.route_url('part.users', pid=part.id)}, {'title': 'Add', 'url': request.current_route_url()}]) users = None if 'q' in request.params: users = dbsession.query(User).outerjoin(UserPartRole).\ filter(or_(User.display_name.contains(request.params['q']), User.email.contains(request.params['q']))).\ filter(User.id.notin_(dbsession.query(User.id).join(UserPartRole). join(Part).filter(Part.id == part.id))) start = 0 if 'start' in request.params: try: start = max(0, int(request.params['start'])) except: pass if users: total_users = users.count() users = users.offset(start).limit(20).all() else: total_users = 0 pages = [] if start == 0: pages.append({'type': 'prev'}) else: pages.append({'type': 'prev', 'url': request.route_url('part.users', pid=part.id, _query=[('q', request.params['q'] if 'q' in request.params else ''), ('start', max(start - 30, 0))])}) for idx in range(0, int(math.ceil(total_users / 30.0))): if idx * 30 == start: pages.append({'type': 'current', 'label': idx + 1}) else: pages.append({'type': 'item', 'label': idx + 1, 'url': request.route_url('part.users', pid=part.id, _query=[('q', request.params['q'] if 'q' in request.params else ''), ('start', idx * 30)])}) if start + 30 >= total_users: pages.append({'type': 'next'}) else: pages.append({'type': 'next', 'url': request.route_url('part.users', pid=part.id, _query=[('q', request.params['q'] if 'q' in request.params else ''), ('start', start + 30)])}) if request.method == 'POST': try: params = AddUserSchema().to_python(request.params, State(request=request)) with transaction.manager: dbsession.add(part) for user_id in params['user_id']: if not dbsession.query(UserPartRole).\ filter(and_(UserPartRole.part_id == part.id, UserPartRole.user_id == user_id)).first(): dbsession.add(UserPartRole(user_id=user_id, part_id=part.id, role=params['role'])) raise HTTPSeeOther(request.route_url('part.users', pid=request.matchdict['pid'])) except formencode.api.Invalid as e: e.params = request.params return {'errors': e.error_dict, 'values': request.params, 'part': part, 'users': users, 'total_users': total_users, 'start': start, 'pages': pages, 'crumbs': crumbs, 'help': ['user', 'teacher', 'module', 'users.html']} return {'part': part, 'users': users, 'total_users': total_users, 'start': start, 'pages': pages, 'crumbs': crumbs, 'help': ['user', 'teacher', 'module', 'users.html']} else: unauthorised_redirect(request) else: raise HTTPNotFound()
def users(request): """Handles the ``parts/{pid}/users`` URL, displaying the :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): crumbs = create_part_crumbs(request, part, {'title': 'Users', 'url': request.current_route_url()}) try: start = int(request.params['start']) if 'start' in request.params else 0 except: start = 0 query = dbsession.query(UserPartRole).join(UserPartRole.user, UserPartRole.part).\ filter(Part.id == request.matchdict['pid']) query_params = [] if 'role' in request.params: if request.params['role'] == 'active': query = query.filter(UserPartRole.role != 'block') elif request.params['role']: query = query.filter(UserPartRole.role == request.params['role']) query_params.append(('role', request.params['role'])) else: query = query.filter(UserPartRole.role != 'block') if 'q' in request.params and request.params['q']: query = query.filter(or_(User.display_name.contains(request.params['q']), User.email.contains(request.params['q']))) query_params.append(('q', request.params['q'])) total_users = query.count() if total_users < start: start = 0 if start >= 0: users = query.offset(start).limit(30) else: users = query pages = [] if start == 0: pages.append({'type': 'prev'}) else: pages.append({'type': 'prev', 'url': request.route_url('part.users', pid=part.id, _query=query_params + [('start', max(start - 30, 0))])}) for idx in range(0, int(math.ceil(total_users / 30.0))): if idx * 30 == start: pages.append({'type': 'current', 'label': idx + 1}) else: pages.append({'type': 'item', 'label': idx + 1, 'url': request.route_url('part.users', pid=part.id, _query=query_params + [('start', idx * 30)])}) if start + 30 >= total_users: pages.append({'type': 'next'}) else: pages.append({'type': 'next', 'url': request.route_url('part.users', pid=part.id, _query=query_params + [('start', start + 30)])}) current_page = max(0, start / 30) return {'part': part, 'users': users, 'pages': pages, 'current_page': current_page, 'total_users': total_users, 'crumbs': crumbs, 'help': ['user', 'teacher', 'module', 'users.html']} else: unauthorised_redirect(request) else: raise HTTPNotFound()
def edit_part_task(request): """Handles the ``parts/{pid}/timed-tasks/{tid}/edit`` URL, providing the UI and backend for editing 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': 'Edit', 'url': request.current_route_url }]) if request.method == 'POST': try: options = [] if task.name == 'change_status': status = ['available', 'unavailable'] if part.type == 'module': status.append('archived') options.append(('target_status', formencode.validators.OneOf(status))) params = EditTimedTaskSchema(options).to_python( request.params, State(request=request)) dbsession = DBSession() with transaction.manager: dbsession.add(task) task.timestamp = datetime.combine( params['date'], params['time']) if 'options' in params and params['options']: task.options = params['options'] task.status = 'ready' dbsession.add(part) raise HTTPSeeOther( request.route_url('part.timed_task', pid=part.id)) except formencode.Invalid as e: return { 'errors': e.error_dict, 'values': request.params, '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()
def edit(request): """Handles the ``/parts/{pid}/assets/{aid}/edit`` URL, providing the UI and backend for editing :class:`~wte.models.Asset`. Requires that the user has "edit" rights on the current :class:`~wte.models.Part`. """ dbsession = DBSession() part = dbsession.query(Part).filter( Part.id == request.matchdict['pid']).first() asset = dbsession.query(Asset).join(Part.all_assets).\ filter(and_(Asset.id == request.matchdict['aid'], Part.id == request.matchdict['pid'])).first() if part and asset: if part.allow('edit', request.current_user): crumbs = create_part_crumbs( request, part, { 'title': 'Edit %s' % (asset.type.title()), 'url': request.current_route_url() }) if request.method == 'POST': try: params = EditAssetSchema().to_python( request.params, State(request=request)) dbsession = DBSession() with transaction.manager: dbsession.add(asset) asset.filename = params['filename'] if params['data'] is not None: asset.data = params['data'].file.read() asset.etag = hashlib.sha512(asset.data).hexdigest() mimetype = guess_type(params['data'].filename) if mimetype[0]: mimetype = mimetype[0] else: if params['mimetype'] != 'other': mimetype = params['mimetype'] else: mimetype = params['mimetype_other'] elif params['content'] is not None: asset.data = params['content'].encode('utf-8') asset.etag = hashlib.sha512(asset.data).hexdigest() if params['mimetype'] != 'other': mimetype = params['mimetype'] else: mimetype = params['mimetype_other'] else: if params['mimetype'] != 'other': mimetype = params['mimetype'] else: mimetype = params['mimetype_other'] asset.mimetype = mimetype dbsession.add(part) dbsession.add(asset) raise HTTPSeeOther( request.route_url('part.view', pid=part.id)) except formencode.Invalid as e: return { 'errors': e.error_dict, 'values': request.params, 'part': part, 'asset': asset, 'crumbs': crumbs, 'help': ['user', 'teacher', 'asset', 'edit.html'] } return { 'part': part, 'asset': asset, 'crumbs': crumbs, 'help': ['user', 'teacher', 'asset', 'edit.html'] } else: unauthorised_redirect(request) else: raise HTTPNotFound()
def edit(request): """Handles the "/users/{uid}/edit" URL, providing the form and backend functionality to update the user's profile. """ dbsession = DBSession() user = dbsession.query(User).filter( User.id == request.matchdict['uid']).first() if user: if user.allow('edit', request.current_user): crumbs = create_user_crumbs( request, [{ 'title': user.display_name, 'url': request.route_url('user.view', uid=user.id) }, { 'title': 'Edit', 'url': request.route_url('user.edit', uid=user.id) }]) if request.method == 'POST': try: params = EditSchema().to_python( request.params, State(dbsession=dbsession, userid=user.id, email_domains=get_config_setting( request, key='registration.domains', target_type='list', default=None), user_class=User, request=request)) with transaction.manager: dbsession.add(user) user.email = params['email'] user.display_name = params['display_name'] if params['password']: user.new_password(params['password']) options = {} if params['option']: for key, value in params['option'].items(): if isinstance(value, list): options[key] = value[-1] else: options[key] = value user.options = options raise HTTPSeeOther( request.route_url('user.view', uid=request.matchdict['uid'])) except Invalid as e: print(e) return { 'e': e.error_dict, 'values': request.params, 'user': user, 'crumbs': crumbs, 'help': ['user', 'user', 'profile.html'] } return { 'user': user, 'crumbs': crumbs, 'help': ['user', 'user', 'profile.html'] } else: unauthorised_redirect(request) else: raise HTTPNotFound()
def update(request): """Handles the ``parts/{pid}/users`` URL, applying the changes select when the user views :func:`~wte.views.user_role.action`. Requires that the user has "users" rights on the :class:`~wte.models.Part`. """ dbsession = DBSession() dbsession.add(request.current_user) 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: 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 = [] params = {} params = ActionSchema().to_python(request.params, State(request=request)) users = dbsession.query(UserPartRole).filter(UserPartRole.id.in_(params['role_id'])).all() if params['action'] == 'change_role': params = ChangeRoleSchema().to_python(request.params, State(request=request)) with transaction.manager: for role in users: dbsession.add(role) role.role = params['role'] raise HTTPSeeOther(request.route_url('part.users', pid=request.matchdict['pid'], _query=query_params)) elif params['action'] == 'remove': schema = CSRFSchema() schema.allow_extra_fields = True schema.to_python(request.params, State(request=request)) with transaction.manager: dbsession.add(part) parts = get_all_parts(part) for role in users: dbsession.add(role) for child_part in parts: progress = dbsession.query(UserPartProgress).\ filter(and_(UserPartProgress.part_id == child_part.id, UserPartProgress.user_id == role.user.id)).first() if progress: dbsession.delete(progress) dbsession.delete(role) raise HTTPSeeOther(request.route_url('part.users', pid=request.matchdict['pid'], _query=query_params)) elif params['action'] == 'block': schema = CSRFSchema() schema.allow_extra_fields = True schema.to_python(request.params, State(request=request)) with transaction.manager: for role in users: dbsession.add(role) role.role = 'block' raise HTTPSeeOther(request.route_url('part.users', pid=request.matchdict['pid'], _query=query_params)) except formencode.api.Invalid as e: return {'errors': e.error_dict, 'values': request.params, 'part': part, 'params': params, 'query_params': query_params, 'users': users, 'crumbs': crumbs, 'help': ['user', 'teacher', 'module', 'users.html']} 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()
def new(request): """Handles the ``/parts/{pid}/assets/new/{new_type}`` URL, providing the UI and backend for creating a new :class:`~wte.models.Asset`. Requires that the user has "edit" rights on the current :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': 'Add %s' % (request.matchdict['new_type'].title()), 'url': request.current_route_url() }) if request.method == 'POST': try: schema = NewAssetSchema() if request.matchdict['new_type'] == 'asset': schema.fields['data'].not_empty = True params = schema.to_python(request.params, State(request=request)) if not params['filename'] and params['data'] is None: raise formencode.Invalid( 'You must specify either a file or filename', None, None, error_dict={ 'filename': 'You must specify either a file or filename', 'data': 'You must specify either a file or filename' }) dbsession = DBSession() progress = get_user_part_progress(dbsession, request.current_user, part) with transaction.manager: dbsession.add(part) if progress: dbsession.add(progress) mimetype = 'application/binary' if params['filename'] is not None: mimetype = guess_type(params['filename']) if params['data'] is not None: mimetype = guess_type(params['data'].filename) if params['filename'] is None: params['filename'] = params['data'].filename if request.matchdict['new_type'] == 'template': new_order = [a.order for a in part.templates] elif request.matchdict['new_type'] == 'asset': new_order = [a.order for a in part.assets] elif request.matchdict['new_type'] == 'file': new_order = [a.order for a in progress.files ] if progress else [] new_order.append(0) new_order = max(new_order) + 1 new_asset = Asset( filename=params['filename'], mimetype=mimetype[0] if mimetype[0] else 'application/binary', type=request.matchdict['new_type'], order=new_order, data=params['data'].file.read() if params['data'] is not None else None, etag=hashlib.sha512( params['data'].file.read()).hexdigest() if params['data'] is not None else None) dbsession.add(new_asset) part.all_assets.append(new_asset) if request.is_xhr: request.override_renderer = 'json' dbsession.add(new_asset) dbsession.add(part) return { 'part': { 'id': part.id }, 'asset': { 'id': new_asset.id, 'filename': new_asset.filename } } else: dbsession.add(part) raise HTTPSeeOther( request.route_url('part.view', pid=part.id)) except formencode.Invalid as e: return { 'errors': e.error_dict, 'values': request.params, 'part': part, 'crumbs': crumbs, 'help': ['user', 'teacher', 'asset', 'new.html'] } return { 'part': part, 'crumbs': crumbs, 'help': ['user', 'teacher', 'asset', 'new.html'] } else: unauthorised_redirect(request) else: raise HTTPNotFound()