Source code for gazette.views.users

from io import BytesIO
from morepath import redirect
from morepath.request import Response
from onegov.core.crypto import random_password
from import Private
from import Secret
from onegov.core.templates import render_template
from onegov.gazette import _
from onegov.gazette import GazetteApp
from onegov.gazette.forms import EmptyForm
from onegov.gazette.forms import UserForm
from onegov.gazette.forms.user import ExportUsersForm
from onegov.gazette.layout import Layout
from onegov.gazette.layout import MailLayout
from onegov.user import User
from onegov.user import UserCollection
from onegov.user import UserGroup
from onegov.user.utils import password_reset_url
from sedate import utcnow
from webob.exc import HTTPForbidden
from xlsxwriter import Workbook

from typing import TYPE_CHECKING
    from onegov.core.types import RenderData
    from onegov.gazette.request import GazetteRequest
    from webob import Response as BaseResponse

[docs] def view_users( self: UserCollection, request: 'GazetteRequest' ) -> 'RenderData': """ View the users. Publishers can see editors, admins can see editors and publishers. Admins are never shown. """ layout = Layout(self, request) roles = [ ( _("Editors"), self.for_filter(role='member').query().order_by( User.username ).all() ) ] if request.is_secret(self): roles.append( ( _("Publishers"), self.for_filter(role='editor').query().order_by( User.username ).all() ) ) return { 'layout': layout, 'roles': roles, 'title': _('Users'), 'export':, name='export'), 'new_user':, name='new-user') }
@GazetteApp.form( model=UserCollection, name='new-user', template='', permission=Private, form=UserForm )
[docs] def create_user( self: UserCollection, request: 'GazetteRequest', form: UserForm ) -> 'RenderData | BaseResponse': """ Create a new publisher or editor. This view is visible for admins and publishers. """ layout = Layout(self, request) if form.submitted(request): assert is not None user = self.add(, random_password(16),, ) form.update_model(user) user.modified = user.timestamp() url = password_reset_url( user, request,, name='reset-password') ) assert is not None subject=request.translate(_("User account created")), receivers=(user.username, ),['transactional']['sender'], content=render_template( '', request, { 'title': request.translate(_("User account created")), 'model': None, 'url': url, 'layout': MailLayout(self, request) } ) ) request.message(_("User added."), 'success') return redirect(layout.manage_users_link) return { 'layout': layout, 'form': form, 'title': _("New User"), 'cancel': layout.manage_users_link }
@GazetteApp.form( model=User, name='edit', template='', permission=Private, form=UserForm )
[docs] def edit_user( self: User, request: 'GazetteRequest', form: UserForm ) -> 'RenderData | BaseResponse': """ Edit the role, name and email of a user. Publishers may only edit members. Admins can not be edited. """ layout = Layout(self, request) if self.role != 'member' and not request.is_secret(self): raise HTTPForbidden() if form.submitted(request): form.update_model(self) self.logout_all_sessions( request.message(_("User modified."), 'success') return redirect(layout.manage_users_link) if not form.errors: form.apply_model(self) return { 'layout': layout, 'form': form, 'title': self.title, 'subtitle': _("Edit User"), 'cancel': layout.manage_users_link }
@GazetteApp.form( model=User, name='delete', template='', permission=Private, form=EmptyForm )
[docs] def delete_user( self: User, request: 'GazetteRequest', form: EmptyForm ) -> 'RenderData | BaseResponse': """ Delete a user. Publishers may only edit members. Admins can not be deleted. """ layout = Layout(self, request) if self.role != 'member' and not request.is_secret(self): raise HTTPForbidden() # FIXME: backrefs created across module boundaries if self.official_notices or self.changes: # type:ignore[attr-defined] request.message( _("There are official notices linked to this user!"), 'warning' ) if form.submitted(request): collection = UserCollection(request.session) # FIXME: Why are we re-fetching the user to check its role? user = collection.by_username(self.username) assert user is not None if user.role != 'admin': self.logout_all_sessions( collection.delete(self.username) request.message(_("User deleted."), 'success') return redirect(layout.manage_users_link) return { 'message': _( 'Do you really want to delete "${item}"?', mapping={'item': self.title} ), 'layout': layout, 'form': form, 'title': self.title, 'subtitle': _("Delete User"), 'button_text': _("Delete User"), 'button_class': 'alert', 'cancel': layout.manage_users_link }
@GazetteApp.html( model=UserCollection, name='sessions', template='', permission=Secret )
[docs] def view_user_sessions( self: UserCollection, request: 'GazetteRequest' ) -> 'RenderData': """ View all open browser sessions. This view is only visible by an admin. """ layout = Layout(self, request) return { 'layout': layout, 'title': _('Sessions'), 'users': self.query().all() }
@GazetteApp.form( model=User, name='clear-sessions', template='', permission=Secret, form=EmptyForm )
[docs] def clear_user_sessions( self: User, request: 'GazetteRequest', form: EmptyForm ) -> 'RenderData | BaseResponse': """ Closes all open browser sessions. This view is only visible by an admin. """ layout = Layout(self, request) cancel = UserCollection(request.session), name='sessions' ) if form.submitted(request): self.logout_all_sessions( return redirect(cancel) return { 'message': _("Do you really clear all active sessions?"), 'layout': layout, 'form': form, 'title': self.title, 'subtitle': _("Clear Sessions"), 'button_text': _("Clear Sessions"), 'button_class': 'alert', 'cancel': cancel }
@GazetteApp.form( model=UserCollection, name='export', permission=Private, form=ExportUsersForm, template='' )
[docs] def export_users( self: UserCollection, request: 'GazetteRequest', form: ExportUsersForm ) -> 'RenderData | Response': """ Export all users as XLSX. The exported file can be re-imported using the import-editors command line command. """ if form.submitted(request): output = BytesIO() workbook = Workbook(output) for role, name in ( ('member', request.translate(_("Editors"))), ('editor', request.translate(_("Publishers"))) ): worksheet = workbook.add_worksheet() = name worksheet.write_row(0, 0, ( request.translate(_("Group")), request.translate(_("Name")), request.translate(_("E-Mail")) )) users = self.query().filter(User.role == role) group_ids = if group_ids: users = users.filter(User.group_id.in_(group_ids)) users = users.join(, isouter=True) users = users.order_by(, User.realname, User.username ) for index, user in enumerate(users.all()): worksheet.write_row(index + 1, 0, ( if else '', user.realname or '', user.username or '' )) workbook.close() response = Response() response.content_type = ( 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ) response.content_disposition = 'inline; filename={}-{}.xlsx'.format( request.translate(_("Users")).lower(), utcnow().strftime('%Y%m%d%H%M') ) response.body = return response return { 'form': form, 'layout': Layout(self, request), 'title': _('Export Users'), 'button_text': _('Export'), 'callout': _('Export users by groups or leave empty ' 'for un unfiltered export.') }