示例#1
0
    def map_column(
            self, mode: EditMode, request: Request, node: colander.SchemaNode,
            model: type, name: str, column: Column,
            column_type: TypeEngine) -> t.Tuple[colander.SchemaType, dict]:
        """Map non-relationship SQLAlchemy column to Colander SchemaNode.

        :return: Tuple(constructed colander.SchemaType, dict of addtional colander.SchemaNode construction arguments)
        """
        logger.debug(
            "Mapping field %s, mode %s, node %s, column %s, column type %s",
            name, mode, node, column, column_type)

        validator = None
        # Check for autogenerated columns (updated_at)
        if column.onupdate:
            if mode in (EditMode.edit, EditMode.add):
                return TypeOverridesHandling.drop, {}

        # Don't fill default values when added, as they are automatically populated
        if column.default:
            if mode == EditMode.add:
                return TypeOverridesHandling.drop, {}

        # Set unique validator
        if column.unique and (mode in (EditMode.add, EditMode.edit)):
            validator = ValidateUnique(model, mode)
        # Never add primary keys
        # NOTE: TODO: We need to preserve ids because of nesting mechanism and groupedit widget wants it id
        if column.primary_key:
            # TODO: Looks like column.autoincrement is set True by default, so we cannot use it here
            if mode in (EditMode.edit, EditMode.add):
                return TypeOverridesHandling.drop, {}
        if column.foreign_keys:

            # Handled by relationship mapper
            return TypeOverridesHandling.drop, {}

        elif isinstance(column_type, (PostgreSQLUUID, columns.UUID)):

            # UUID's cannot be edited
            if mode in (EditMode.add, EditMode.edit):
                return TypeOverridesHandling.drop, {}

            # But let's show them
            return fields.UUID(), dict(
                missing=colander.drop,
                widget=FriendlyUUIDWidget(readonly=True))
        elif isinstance(column_type, Text):
            return colander.String(), dict(
                widget=deform.widget.TextAreaWidget(), validator=validator)
        elif isinstance(column_type, JSONB):
            return JSONValue(), dict(widget=JSONWidget())
        elif isinstance(column_type, (LargeBinary, Geometry)):
            # Can't edit binary and geometry
            return TypeOverridesHandling.drop, {}
        elif isinstance(column_type, (INET, columns.INET)):
            return colander.String(), dict(validator=validator)
        else:
            # Default mapping / unknown, let the parent handle
            return TypeOverridesHandling.unknown, dict(validator=validator)
示例#2
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(JSONValue(), name="user_data", widget=JSONWidget(), description="user_data JSON properties"),
        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) -> str:
        """Title for the User object.

        :return: Title for the User object.
        """
        user = self.get_object()
        return "{friendly_name} #{id}".format(
            friendly_name=user.friendly_name,
            id=self.get_object().id
        )

    @view_config(context=UserAdmin.Resource, route_name="admin", name="show", renderer="crud/show.html", permission='view')
    def show(self):
        """User show view.

        :return: Context for template rendering.
        """
        return super(UserShow, self).show()
示例#3
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"])