Пример #1
0
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()
Пример #2
0
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()
Пример #3
0
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()
Пример #4
0
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)
Пример #5
0
class AssetSchema(colander.Schema):

    #: Human readable name
    name = colander.SchemaNode(colander.String())

    #:  The network this asset is in
    network = colander.SchemaNode(
        UUIDForeignKeyValue(model=AssetNetwork, match_column="id"),
        widget=defer_widget_values(deform.widget.SelectWidget,
                                   available_networks),
    )

    #: Symbol how this asset is presented in tickers
    symbol = colander.SchemaNode(colander.String())

    description = colander.SchemaNode(colander.String(), missing="")

    #: Markdown page telling about this asset
    long_description = colander.SchemaNode(colander.String(),
                                           description="Markdown formatted",
                                           missing="",
                                           widget=deform.widget.TextAreaWidget(
                                               rows=20, cols=80))

    #: Ethereum address
    external_id = colander.SchemaNode(colander.String(),
                                      title="Address",
                                      validator=validate_ethereum_address,
                                      missing=None,
                                      description="0x hex string format")

    #: Number of units avaialble
    supply = colander.SchemaNode(colander.Decimal(), missing=None)

    #: What kind of asset is this
    asset_class = colander.SchemaNode(
        EnumValue(AssetClass),
        widget=deform.widget.SelectWidget(values=enum_values(AssetClass)))

    #: Workflow state of this asset
    state = colander.SchemaNode(
        EnumValue(AssetState),
        widget=deform.widget.SelectWidget(values=enum_values(AssetState)))

    other_data = colander.SchemaNode(
        JSONValue(),
        widget=JSONWidget(),
        description="JSON bag of attributes of the object",
        missing=dict)

    def dictify(self, obj: Asset) -> dict:
        """Serialize SQLAlchemy model instance to nested dictionary appstruct presentation."""

        appstruct = dictify(self,
                            obj,
                            excludes=("long_description", "external_id"))

        # Convert between binary storage and human readable hex presentation
        appstruct["long_description"] = obj.other_data.pop(
            "long_description", "")

        if obj.external_id:
            appstruct["external_id"] = bin_to_eth_address(obj.external_id)
        else:
            appstruct["external_id"] = ""

        return appstruct

    def objectify(self, appstruct: dict, obj: Asset):
        """Store the dictionary data from the form submission on the object."""

        objectify(self,
                  appstruct,
                  obj,
                  excludes=("long_description", "external_id"))

        if not obj.other_data:
            # When creating the object JSON value may be None
            # instead of empty dict
            obj.other_data = {}

        # Special case of field stored inside JSON bag
        obj.other_data["long_description"] = appstruct["long_description"]

        # Convert between binary storage and human readable hex presentation
        if appstruct["external_id"]:
            obj.external_id = eth_address_to_bin(appstruct["external_id"])