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, }
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"), ), ), ), }
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)
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
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, }
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("/"))
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, }
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")
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, }
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"))
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)
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, }
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
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), }
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}
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, }
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, }
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)
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, }
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, }
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
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, }