class UserSetPassword(admin_views.Edit): """Set the user password. Use the CRUD edit form with one field to set the user password. """ includes = [ colander.SchemaNode(colander.String(), name='password', widget=deform.widget.CheckedPasswordWidget(css_class="password-widget")), ] form_generator = SQLAlchemyFormGenerator(includes=includes) def save_changes(self, form: deform.Form, appstruct: dict, obj: User): # Set hashed password user_registry = get_user_registry(self.request) user_registry.set_password(obj, appstruct["password"]) # Drop session kill_user_sessions(self.request, obj, "password_change") def do_success(self): messages.add(self.request, kind="success", msg="Password changed.", msg_id="msg-password-changed") # Redirect back to view page after edit page has succeeded return HTTPFound(self.request.resource_url(self.context, "show")) @view_config(context=UserAdmin.Resource, route_name="admin", name="set-password", renderer="crud/edit.html", permission='edit') def set_password(self): return super(admin_views.Edit, self).edit()
class Show(crud_views.Show): """Default show view for model admin.""" base_template = "admin/base.html" form_generator = SQLAlchemyFormGenerator() resource_buttons = [ TraverseLinkButton(id="edit", name="Edit", view_name="edit", permission="edit"), TraverseLinkButton(id="delete", name="Delete", view_name="delete", permission="delete"), TraverseLinkButton( id="shell", name="Shell", view_name="shell", permission="shell", tooltip= "Open IPython Notebook shell and have this item prepopulated in obj variable.", feature="notebook"), ] @view_config(context=ModelAdmin.Resource, name="show", renderer="crud/show.html", route_name="admin", permission='view') def show(self): # We override this method just to define admin route_name traversing return super(Show, self).show()
class UserShow(admin_views.Show): """Show one user.""" resource_buttons = admin_views.Show.resource_buttons + [TraverseLinkButton(id="set-password", name="Set password", view_name="set-password")] includes = ["id", "uuid", "enabled", "created_at", "updated_at", "username", colander.SchemaNode(colander.String(), name='full_name'), "email", "last_login_at", "last_login_ip", colander.SchemaNode(colander.String(), name="registration_source", missing=colander.drop), colander.SchemaNode(colander.String(), name="social"), colander.SchemaNode(GroupSet(), name="groups", widget=defer_widget_values(deform.widget.CheckboxChoiceWidget, group_vocabulary, css_class="groups")) ] form_generator = SQLAlchemyFormGenerator(includes=includes) def get_title(self): return "{} #{}".format(self.get_object().friendly_name, self.get_object().id) @view_config(context=UserAdmin.Resource, route_name="admin", name="show", renderer="crud/show.html", permission='view') def show(self): return super(UserShow, self).show()
class UserEdit(admin_views.Edit): """Edit one user in admin interface.""" includes = [ "enabled", colander.SchemaNode(colander.String(), name='username'), # Make username required field colander.SchemaNode(colander.String(), name='full_name', missing=""), "email", colander.SchemaNode(GroupSet(), name="groups", widget=defer_widget_values(deform.widget.CheckboxChoiceWidget, group_vocabulary, css_class="groups")) ] form_generator = SQLAlchemyFormGenerator(includes=includes) def save_changes(self, form:deform.Form, appstruct:dict, user:User): """Save the user edit and reflect if we need to drop user session.""" enabled_changes = appstruct["enabled"] != user.enabled email_changes = appstruct["email"] != user.email username_changes = appstruct["username"] != user.username super(UserEdit, self).save_changes(form, appstruct, user) # Notify authentication system to drop all sessions for this user if enabled_changes: kill_user_sessions(self.request, user, "enabled_change") elif email_changes: kill_user_sessions(self.request, user, "email_change") elif username_changes: kill_user_sessions(self.request, user, "username_change") def get_title(self): return "{} #{}".format(self.get_object().friendly_name, self.get_object().id) @view_config(context=UserAdmin.Resource, route_name="admin", name="edit", renderer="crud/edit.html", permission='edit') def edit(self): return super(UserEdit, self).edit()
class UserAdd(admin_views.Add): """CRUD add part for creating new users.""" #: TODO: Not sure how we should manage with explicit username - it's not used for login so no need to have a point to ask includes = [ # "username", --- usernames are never exposed anymore colander.SchemaNode(colander.String(), name="email", validator=validate_unique_user_email), "full_name", colander.SchemaNode(colander.String(), name='password', widget=deform.widget.CheckedPasswordWidget(css_class="password-widget")), colander.SchemaNode(GroupSet(), name="groups", widget=defer_widget_values(deform.widget.CheckboxChoiceWidget, group_vocabulary, css_class="groups")) ] form_generator = SQLAlchemyFormGenerator(includes=includes) def get_form(self): # TODO: Still not sure how handle nested values on the automatically generated add form. But here we need it for groups to appear return self.create_form(EditMode.add, buttons=("add", "cancel",)) def initialize_object(self, form, appstruct, obj: User): password = appstruct.pop("password") form.schema.objectify(appstruct, obj) hasher = self.request.registry.getUtility(IPasswordHasher) obj.hashed_password = hasher.hash_password(password) # Users created through admin are useable right away, so activate the user obj.activated_at = now()
class UserAdd(admin_views.Add): """CRUD add part for creating new users.""" #: TODO: Not sure how we should manage with explicit username - it's not used for login so no need to have a point to ask includes = [ # "username", --- usernames are never exposed anymore colander.SchemaNode(colander.String(), name="email", validator=validate_unique_user_email), "full_name", colander.SchemaNode(colander.String(), name='password', widget=deform.widget.CheckedPasswordWidget(css_class="password-widget")), colander.SchemaNode(GroupSet(), name="groups", widget=defer_widget_values(deform.widget.CheckboxChoiceWidget, group_vocabulary, css_class="groups")) ] form_generator = SQLAlchemyFormGenerator(includes=includes) def get_form(self): # TODO: Still not sure how handle nested values on the automatically generated add form. But here we need it for groups to appear return self.create_form(EditMode.add, buttons=("add", "cancel",)) def add_object(self, obj): """Flush newly created object to persist storage.""" # Users created through admin are useable right away obj.activated_at = now() super(UserAdd, self).add_object(obj)
class Add(crud_views.Add): """Default add view for model admin.""" base_template = "admin/base.html" form_generator = SQLAlchemyFormGenerator() @view_config(context=ModelAdmin, name="add", renderer="crud/add.html", route_name="admin", permission='add') def add(self): # We override this method just to define admin route_name traversing return super(Add, self).add()
class Edit(crud_views.Edit): """Default edit vie for model admin.""" base_template = "admin/base.html" form_generator = SQLAlchemyFormGenerator() @view_config(context=ModelAdmin.Resource, name="edit", renderer="crud/edit.html", route_name="admin", permission='edit') def edit(self): # We override this method just to define admin route_name traversing return super(Edit, self).edit()
class GroupEdit(admin_views.Edit): includes = [ "name", "description" ] form_generator = SQLAlchemyFormGenerator(includes=includes) @view_config(context=GroupAdmin.Resource, route_name="admin", name="edit", renderer="crud/edit.html", permission='edit') def edit(self): return super(GroupEdit, self).edit()
class GroupAdd(admin_views.Add): includes = [ "name", "description" ] form_generator = SQLAlchemyFormGenerator(includes=includes) @view_config(context=GroupAdmin, route_name="admin", name="add", renderer="crud/add.html", permission='add') def add(self): return super(GroupAdd, self).add()
class GroupShow(admin_views.Show): includes = ["id", "name", "description", "created_at", "updated_at"] form_generator = SQLAlchemyFormGenerator(includes=includes) @view_config(context=GroupAdmin.Resource, route_name="admin", name="show", renderer="crud/show.html", permission='view') def show(self): return super(GroupShow, self).show()
class GroupEdit(admin_views.Edit): """Edit one group in admin interface.""" includes = [ "name", "description" ] form_generator = SQLAlchemyFormGenerator(includes=includes) @view_config(context=GroupAdmin.Resource, route_name="admin", name="edit", renderer="crud/edit.html", permission='edit') def edit(self): """Group edit view.. :return: Context for template rendering. """ return super(GroupEdit, self).edit()
class GroupAdd(admin_views.Add): """Create new Group.""" includes = [ "name", "description" ] form_generator = SQLAlchemyFormGenerator(includes=includes) @view_config(context=GroupAdmin, route_name="admin", name="add", renderer="crud/add.html", permission='add') def add(self): """Group add view.. :return: Context for template rendering. """ return super(GroupAdd, self).add()