Beispiel #1
0
def create(context, request):
    if not context.create_view_enabled:
        raise HTTPNotFound()
    default_value_fields = list(request.GET.keys())
    formschema = dc2colander.convert(
        context.collection.schema,
        request=request,
        include_fields=context.create_include_fields,
        exclude_fields=context.create_exclude_fields,
        hidden_fields=default_value_fields,
        default_tzinfo=request.timezone(),
    )
    fs = formschema()
    fs = fs.bind(context=context, request=request)

    form_data = {}
    for f in default_value_fields:
        form_data[f] = request.GET.get(f)

    return {
        "page_title":
        "Create %s" % html.escape(
            str(context.collection.__class__.__name__.replace(
                "Collection", ""))),
        "form_title":
        "Create",
        "form":
        deform.Form(fs, buttons=("Submit", )),
        "form_data":
        form_data,
    }
Beispiel #2
0
def register(context, request):
    enabled = request.app.get_config("morpfw.new_registration.enabled", True)
    if not enabled:
        raise HTTPNotFound()
    schema = request.app.get_schemaextender(RegistrationForm)
    formschema = dc2colander.convert(schema,
                                     request=request,
                                     default_tzinfo=request.timezone())
    fs = formschema()
    fs = fs.bind(context=context, request=request)
    return {
        "form_title":
        "Register",
        "form":
        deform.Form(
            fs,
            buttons=(
                "Register",
                deform.Button(
                    "login",
                    title="Login",
                    type="link",
                    value=request.relative_url("/login"),
                ),
            ),
        ),
    }
Beispiel #3
0
 def get_form(self, formid):
     formschema = dc2colander.convert(
         self.schema, request=self.request, default_tzinfo=self.request.timezone()
     )
     fs = formschema()
     fs = fs.bind(context=self.context, request=self.request)
     return deform.Form(fs, formid=formid)
Beispiel #4
0
 def formschema(self, context, request):
     schema = self.factory(request)
     formschema = dc2colander.convert(schema,
                                      request=request,
                                      default_tzinfo=request.timezone())()
     formschema = formschema.bind(context=context, request=request)
     return formschema
Beispiel #5
0
def listing(context, request):
    column_options = []
    columns = []
    order = context.columns_order

    for c in context.columns:
        columns.append(c["title"])
        sortable = True
        if c["name"].startswith("structure:"):
            sortable = False
        column_options.append({"name": c["name"], "orderable": sortable})

    query_request_method = "GET"
    if len(context.columns) > 7:
        query_request_method = "POST"

    search_attrs = []
    for attrname, attr in context.collection.schema.__dataclass_fields__.items(
    ):
        searchable = attr.metadata.get("searchable", None)
        if searchable:
            metadata = {"required": False}
            for mf in [
                    "title",
                    "description",
                    "deform.widget",
                    "deform.widget_factory",
            ]:
                mvalue = attr.metadata.get(mf, None)
                if mvalue:
                    metadata[mf] = mvalue
            search_attrs.append(
                (attrname, attr.type, field(default=None, metadata=metadata)))

    if search_attrs:
        dc = make_dataclass("Form", search_attrs)
        formschema = dc2colander.convert(dc,
                                         request=request,
                                         default_tzinfo=request.timezone())
        search_form = deform.Form(formschema(), buttons=("Search", ))
    else:
        search_form = None

    data = _parse_dtdata(list(request.GET.items()))
    search_data = data["mfw_search"]

    return {
        "page_title": context.page_title,
        "listing_title": context.listing_title,
        "search_form": search_form,
        "search_data": search_data,
        "columns": columns,
        "column_options": json.dumps(column_options),
        "order": json.dumps(order),
        "datatable_method": query_request_method,
    }
Beispiel #6
0
def process_register(context, request):
    enabled = request.app.get_config("morpfw.new_registration.enabled", True)
    if not enabled:
        raise HTTPNotFound()
    controls = list(request.POST.items())
    schema = request.app.get_schemaextender(RegistrationForm)
    formschema = dc2colander.convert(schema,
                                     request=request,
                                     default_tzinfo=request.timezone())
    fs = formschema()
    fs = fs.bind(context=context, request=request)
    form = deform.Form(fs)
    failed = False
    try:
        data = form.validate(controls)
    except deform.ValidationFailure as e:
        form = e
        failed = True

    if not failed:
        collection = get_user_collection(request)
        if data["password"] != data["password_validate"]:
            request.notify("error", "Password does not match",
                           "Please check your password")
            return morepath.redirect(request.relative_url("/register"))

        username = data["username"].lower()
        email = data["email"]
        if collection.get_by_username(username):
            request.notify("error", "Username already taken",
                           "Please use a different username")
            return morepath.redirect(request.relative_url("/register"))

        if collection.get_by_email(email):
            request.notify(
                "error",
                "Email already registered",
                "Log-in using your existing account",
            )
            return morepath.redirect(request.relative_url("/register"))

        del data["password_validate"]
        data["username"] = data["username"].lower()
        user = collection.create(data)

        @request.after
        def remember(response):
            """Remember the identity of the user logged in."""
            # We pass the extra info to the identity object.
            response.headers.add("Access-Control-Expose-Headers",
                                 "Authorization")
            identity = morepath.Identity(user.userid)
            request.app.remember_identity(response, request, identity)

        return morepath.redirect(request.relative_url("/"))
Beispiel #7
0
def process_create(context, request):
    if not context.create_view_enabled:
        raise HTTPNotFound()
    default_value_fields = list(request.GET.keys())
    formschema = dc2colander.convert(
        context.collection.schema,
        request=request,
        include_fields=context.create_include_fields,
        exclude_fields=context.create_exclude_fields,
        hidden_fields=default_value_fields,
        default_tzinfo=request.timezone(),
    )
    fs = formschema()
    fs = fs.bind(context=context, request=request)

    controls = list(request.POST.items())
    form = deform.Form(fs, buttons=("Submit", ))

    failed = False
    data = {}
    try:
        data = form.validate(controls)
    except deform.ValidationFailure as e:
        form = e
        failed = True
    if not failed:
        try:
            obj = context.collection.create(data, deserialize=False)
        except AlreadyExistsError as e:
            failed = True
            form_error = colander.Invalid(
                form.widget, "Object with {} already exists".format(e.message))
            form.widget.handle_error(form, form_error)

        if not failed:
            return morepath.redirect(
                request.link(context.modelui_class(request, obj, context)))

    @request.after
    def set_header(response):
        response.headers.add("X-MORP-FORM-FAILED", "True")

    return {
        "page_title":
        "Create %s" % html.escape(
            str(context.collection.__class__.__name__.replace(
                "Collection", ""))),
        "form_title":
        "Create",
        "form":
        form,
        "form_data":
        data,
    }
Beispiel #8
0
def attributes_form(context, request, mode="edit") -> deform.Form:
    schema = context.xattrprovider().schema
    formschema = dc2colander.convert(
        schema,
        request=request,
        default_tzinfo=request.timezone(),
        mode=mode,
        exclude_fields=["agreed_terms", "agreed_terms_ts"],
    )
    fs = formschema()
    fs = fs.bind(context=context, request=request)
    return deform.Form(fs, buttons=("Submit", ), formid="personalinfo-form")
Beispiel #9
0
def process_edit(context, request):
    if not context.update_view_enabled:
        raise HTTPNotFound()
    if not context.model.is_editable():
        request.notify("warning", "Readonly", "Object in readonly state")
        return morepath.redirect(request.link(context))
    formschema = dc2colander.convert(
        context.model.schema,
        request=request,
        mode="edit-process",
        include_fields=context.edit_include_fields,
        exclude_fields=context.edit_exclude_fields,
        include_schema_validators=False,
        default_tzinfo=request.timezone(),
    )
    fs = formschema()
    fs = fs.bind(context=context, request=request)
    data = context.model.data.as_dict()
    controls = list(request.POST.items())
    form = deform.Form(fs, buttons=("Submit",))

    failed = False
    try:
        data = form.validate(controls)
    except deform.ValidationFailure as e:
        form = e
        failed = True
    if not failed:
        try:
            context.model.update(data, deserialize=False)
        except ValidationError as e:
            failed = True
            for fe in e.field_errors:
                node = form
                if fe.path in form:
                    node = form[fe.path]
                node_error = colander.Invalid(node.widget, fe.message)
                node.widget.handle_error(node, node_error)
        if not failed:
            return morepath.redirect(request.link(context))

    @request.after
    def set_header(response):
        response.headers.add("X-MORP-FORM-FAILED", "True")

    return {
        "page_title": "Edit: %s" % html.escape(context.model.title()),
        "form_title": "Edit",
        "form": form,
        "form_data": data,
    }
Beispiel #10
0
def process_login(context, request):
    controls = list(request.POST.items())
    schema = request.app.get_schemaextender(LoginForm)
    formschema = dc2colander.convert(schema,
                                     request=request,
                                     default_tzinfo=request.timezone())
    fs = formschema()
    fs = fs.bind(context=context, request=request)
    form = deform.Form(fs)
    failed = False
    try:
        data = form.validate(controls)
    except deform.ValidationFailure as e:
        form = e
        failed = True

    if not failed:
        username = data["username"].lower()
        password = data["password"]
        collection = request.get_collection("morpfw.pas.user")

        if not collection.authenticate(username, password):
            request.notify("error", "Invalid Login",
                           "Please check your username / password")
            return morepath.redirect(request.relative_url("/login"))

        @request.after
        def remember(response):
            """Remember the identity of the user logged in."""
            # We pass the extra info to the identity object.
            response.headers.add("Access-Control-Expose-Headers",
                                 "Authorization")
            u = collection.get_by_username(username)
            identity = morepath.Identity(u.userid)
            request.app.remember_identity(response, request, identity)

        came_from = request.GET.get("came_from", "")
        if came_from:
            came_from = urllib.parse.unquote(came_from)
        else:
            came_from = request.relative_url("/")
        return morepath.redirect(came_from)

    request.notify("error", "Invalid Login",
                   "Please check your username / password")

    return morepath.redirect(request.relative_url("/login"))
Beispiel #11
0
def preview(context, request):
    formschema = dc2colander.convert(
        context.model.schema,
        request=request,
        include_fields=context.view_include_fields,
        exclude_fields=context.view_exclude_fields,
        default_tzinfo=request.timezone(),
    )

    fs = formschema()
    fs = fs.bind(context=context, request=request)
    form = deform.Form(fs)
    form_data = context.model.data.as_dict()
    return form.render(appstruct=form_data,
                       readonly=True,
                       request=request,
                       context=context)
Beispiel #12
0
def delete(context, request):
    if not context.delete_view_enabled:
        raise HTTPNotFound()
    formschema = dc2colander.convert(
        context.model.schema,
        request=request,
        include_fields=context.view_include_fields,
        exclude_fields=context.view_exclude_fields,
        default_tzinfo=request.timezone(),
    )
    data = context.model.data.as_dict()
    return {
        "page_title": "Delete Confirmation",
        "form_title": "Are you sure you want to delete this?",
        "form": deform.Form(formschema()),
        "form_data": data,
    }
Beispiel #13
0
def _dt_result_render(context, request, columns, objs):
    rows = []
    collection = context.collection
    formschema = dc2colander.convert(collection.schema,
                                     request=request,
                                     default_tzinfo=request.timezone())
    for o in objs:
        row = []
        fs = formschema()
        fs = fs.bind(context=o, request=request)
        form = deform.Form(fs)
        brefs = o.backreferences()
        if not request.permits(o, crudperms.View):
            for c in columns:
                row.append("<i>Restricted</i>")
            rows.append(row)
            continue

        for c in columns:
            if c["name"].startswith("structure:"):
                row.append(context.get_structure_column(o, request, c["name"]))
            elif c["name"].startswith("backreference:"):
                brefname = c["name"].replace("backreference:", "")
                brefdata = o.resolve_backreference(brefs[brefname])
                if brefdata:
                    row.append(
                        '<a href="%s">%s</a>' %
                        (request.link(brefdata[0].ui()), brefdata[0].title()))
                else:
                    row.append("")
            else:
                field = form[c["name"]]
                value = o.data[c["name"]]
                if value is None:
                    value = colander.null
                row.append(
                    field.render(value,
                                 readonly=True,
                                 request=request,
                                 context=o))
        rows.append(row)
    return rows
Beispiel #14
0
def login(context, request):
    schema = request.app.get_schemaextender(LoginForm)
    formschema = dc2colander.convert(schema,
                                     request=request,
                                     default_tzinfo=request.timezone())
    fs = formschema()
    fs = fs.bind(context=context, request=request)
    buttons = ["Login"]
    if request.app.get_config("morpfw.new_registration.enabled", True):
        buttons.append(
            deform.Button(
                "register",
                title="Register",
                type="link",
                value=request.relative_url("/register"),
            ))
    return {
        "form_title": "Login",
        "form": deform.Form(fs, buttons=buttons),
    }
Beispiel #15
0
    def process_form(self):
        request = self.request
        formschema = dc2colander.convert(
            self.schema, request=self.request, default_tzinfo=request.timezone()
        )
        fs = formschema()
        fs = fs.bind(context=self.context, request=self.request)
        controls = request.POST.items()
        form = deform.Form(fs, formid=request.POST.get("__formid__"))
        failed = False
        try:
            data = form.validate(controls)
        except deform.ValidationFailure as e:
            form = e
            failed = True
            data = controls

        if not failed:
            self.sessiondata = data

        return {"form": form, "failed": failed, "data": data}
Beispiel #16
0
def xattredit(context, request):
    if not context.update_view_enabled:
        raise HTTPNotFound()
    if not context.model.is_editable():
        request.notify("warning", "Readonly", "Object in readonly state")
        return morepath.redirect(request.link(context))

    xattrprovider = context.model.xattrprovider()
    if xattrprovider:
        xattrformschema = dc2colander.convert(
            xattrprovider.schema, request=request, default_tzinfo=request.timezone()
        )
    else:
        raise HTTPNotFound()

    data = xattrprovider.as_dict()
    return {
        "page_title": "Edit: %s" % html.escape(context.model.title()),
        "form_title": "Edit Extended Attributes",
        "form": deform.Form(xattrformschema(), buttons=("Submit",)),
        "form_data": data,
    }
Beispiel #17
0
def process_xattredit(context, request):
    if not context.update_view_enabled:
        raise HTTPNotFound()
    if not context.model.is_editable():
        request.notify("warning", "Readonly", "Object in readonly state")
        return morepath.redirect(request.link(context))

    xattrprovider = context.model.xattrprovider()
    if xattrprovider:
        xattrformschema = dc2colander.convert(
            xattrprovider.schema, request=request, default_tzinfo=request.timezone()
        )
    else:
        raise HTTPNotFound()

    fs = xattrformschema()
    fs = fs.bind(context=context, request=request)
    data = xattrprovider.as_dict()
    controls = list(request.POST.items())
    form = deform.Form(fs, buttons=("Submit",))

    failed = False
    try:
        data = form.validate(controls)
    except deform.ValidationFailure as e:
        form = e
        failed = True
    if not failed:
        # FIXME: model update should allow datetime object
        xattrprovider.update(data)
        return morepath.redirect(request.link(context))

    return {
        "page_title": "Edit: %s" % html.escape(context.model.title()),
        "form_title": "Edit",
        "form": form,
        "form_data": data,
    }
Beispiel #18
0
    def render_column(self, record, name):
        if getattr(self, "_render_column", None) is None:
            formschema = dc2colander.convert(
                self.collection.schema,
                request=self.request,
                default_tzinfo=self.request.timezone(),
            )

            def render_column(rec, colname):
                fs = formschema()
                fs = fs.bind(context=rec, request=self.request)
                form = deform.Form(fs)
                field = form[colname]
                value = rec[colname]
                if value is None:
                    value = colander.null
                return field.render(value,
                                    readonly=True,
                                    request=self.request,
                                    context=rec)

            self._render_column = render_column
        return self._render_column(record, name)
Beispiel #19
0
def edit(context, request):
    if not context.update_view_enabled:
        raise HTTPNotFound()
    if not context.model.is_editable():
        request.notify("warning", "Readonly", "Object in readonly state")
        return morepath.redirect(request.link(context))
    formschema = dc2colander.convert(
        context.model.schema,
        request=request,
        mode="edit",
        include_fields=context.edit_include_fields,
        exclude_fields=context.edit_exclude_fields,
        default_tzinfo=request.timezone(),
    )
    data = context.model.data.as_dict()
    fs = formschema()
    fs = fs.bind(context=context, request=request)
    return {
        "page_title": "Edit: %s" % html.escape(context.model.title()),
        "form_title": "Edit",
        "form": deform.Form(fs, buttons=("Submit",)),
        "form_data": data,
    }
Beispiel #20
0
def listing(context, request):
    page = int(request.GET.get("page", 0))
    query = None
    formschema = dc2colander.convert(SearchForm, request=request)()
    formschema = formschema.bind(request=request, context=context)
    form = deform.Form(formschema, buttons=("Submit", ), method="GET")
    data = {}
    if "__formid__" in request.GET:
        controls = list(request.GET.items())
        failed = False
        try:
            data = form.validate(controls)
        except deform.ValidationFailure as e:
            form = e
            failed = True

        if not failed:
            signal = data["signal"]
            state = data["state"]
            if signal:
                query = rulez.field["signal"] == signal
            if state:
                if query is None:
                    query = rulez.field["state"] == state
                else:
                    query = rulez.and_(query, rulez.field["state"] == state)
    batch = CollectionBatching(request,
                               context.collection,
                               query=query,
                               pagesize=5,
                               pagenumber=page)
    return {
        "batch": batch,
        "search_form": form,
        "search_data": data,
    }
Beispiel #21
0
def view(context, request):
    result = base_view(context, request)
    result["references"] = []
    for refname, ref in context.model.references().items():
        refmodel = context.model.resolve_reference(ref)
        if refmodel:
            refmodelui = refmodel.ui()
            refdata = base_view(refmodelui, request)
            refdata["name"] = ref.name
            refdata["title"] = ref.get_title(request)
            refdata["content"] = refmodelui
            result["references"].append(refdata)

    result["single_backreferences"] = []
    result["backreferences"] = []
    for refname, bref in context.model.backreferences().items():
        columns = []
        column_options = []
        collectionui = bref.collection(request).ui()
        ref = bref.get_reference(request)
        for col in collectionui.columns:
            columns.append(col["title"])
            column_options.append(col)
        columns_order = collectionui.columns_order
        create_default = {bref.reference_name: context[ref.attribute]}
        create_default_qs = urlencode(create_default)
        create_link = request.link(collectionui,
                                   "+create?%s" % create_default_qs)
        modal_create_link = request.link(
            collectionui, "+modal-create?%s" % create_default_qs)
        datatable_method = "GET"
        if len(columns) > 7:
            datatable_method = "POST"
        brefdata = {
            "name":
            bref.name,
            "title":
            bref.get_title(request),
            "single_reference":
            bref.single_reference,
            "datatable_url":
            request.link(
                context,
                "backreference-search.json?backreference_name={}".format(
                    bref.name),
            ),
            "datatable_method":
            datatable_method,
            "columns":
            columns,
            "column_options":
            json.dumps(column_options),
            "columns_order":
            json.dumps(columns_order),
            "create_link":
            create_link,
            "modal_create_link":
            modal_create_link,
        }

        if bref.single_reference:
            content = context.model.resolve_backreference(bref)
            if content:
                item = content[0]
                itemui = item.ui()
                formschema = dc2colander.convert(
                    item.schema,
                    request=request,
                    include_fields=itemui.view_include_fields,
                    exclude_fields=itemui.view_exclude_fields,
                    default_tzinfo=request.timezone(),
                )
                fs = formschema()
                fs = fs.bind(context=item, request=request)
                brefdata["form"] = deform.Form(fs)
                brefdata["form_data"] = item.as_dict()
                brefdata["content"] = item.ui()
            result["single_backreferences"].append(brefdata)
        else:
            result["backreferences"].append(brefdata)

    return result
Beispiel #22
0
def base_view(context, request):
    formschema = dc2colander.convert(
        context.model.schema,
        request=request,
        include_fields=context.view_include_fields,
        exclude_fields=context.view_exclude_fields,
        default_tzinfo=request.timezone(),
    )

    xattrprovider = context.model.xattrprovider()
    if xattrprovider:
        xattrformschema = dc2colander.convert(
            xattrprovider.schema,
            request=request,
            default_tzinfo=request.timezone(),
            exclude_fields=["agreed_terms", "agreed_terms_ts"],
        )
    else:
        xattrformschema = None
    data = context.model.data.as_dict()
    sm = context.model.statemachine()

    metadataschema = dc2colander.convert(
        morpfw.Schema,
        request=request,
        exclude_fields=["blobs", "xattrs"],
        default_tzinfo=request.timezone(),
    )
    # FIXME: widget override should be part of dc2colander
    for f in metadataschema.__all_schema_nodes__:
        if f.name == "creator":
            f.widget = ReferenceWidget("morpfw.pas.user",
                                       term_field="username",
                                       value_field="uuid")
    if sm:
        triggers = [
            i for i in sm._machine.get_triggers(sm.state)
            if not i.startswith("to_")
        ]
    else:
        triggers = None

    fs = formschema()
    fs = fs.bind(context=context, request=request)

    mfs = metadataschema(widget=deform.widget.FormWidget(
        readonly_template="readonly/form_inline",
        readonly_item_template="readonly/mapping_item_inline",
    ))
    mfs = mfs.bind(context=context, request=request)

    xfs = None
    if xattrprovider:
        xfs = xattrformschema()
        xfs = xfs.bind(context=context, request=request)

    return {
        "page_title": "View: %s" % html.escape(context.model.title()),
        "form_title": "View",
        "content": context,
        "metadataform": deform.Form(mfs),
        "form": deform.Form(fs),
        "form_data": data,
        "xattrform": deform.Form(xfs) if xattrprovider else None,
        "xattrform_data": xattrprovider.as_dict() if xattrprovider else None,
        "readonly": True,
        "transitions": triggers,
    }