class OyChangePasswordForm(Form): old_password = PasswordField( label=lazy_gettext("Old Password"), validators=[password_required], render_kw=dict(required=True), ) password = PasswordField( label=lazy_gettext("Password"), description=lazy_gettext("Not less than 6 characters"), validators=[password_required, password_length], render_kw=dict(required=True), ) password_confirm = PasswordField( label=lazy_gettext("Re-Type Password"), validators=[EqualTo("password", message="RETYPE_PASSWORD_MISMATCH")], render_kw=dict(required=True), ) def __init__(self, user, *args, **kwargs): self.user = user super(OyChangePasswordForm, self).__init__(*args, **kwargs) def validate(self): if not super(OyChangePasswordForm, self).validate(): return False if not verify_and_update_password(self.old_password.data, self.user): self.old_password.errors.append(gettext("Incorrect Password")) return False if self.old_password.data.strip() == self.password.data.strip(): self.password.errors.append( gettext("The new password is the same as the old password") ) return False return True
def get_list_row_actions(self): actions = super().get_list_row_actions() if self.can_edit: actions = [a for a in actions if not isinstance(a, EditRowAction)] actions.insert( 0, LinkRowAction( "fa fa-pencil", url=self._get_edit_view_endpoint, title=lazy_gettext("Edit record"), ), ) if self.can_delete: actions = [a for a in actions if not isinstance(a, OyDeleteRowAction)] actions.insert( 0, LinkRowAction( "fa fa-trash", url=self._get_delete_endpoint, title=lazy_gettext("Delete record"), ), ) actions.extend( [ TemplateLinkRowAction( template_name="oy.add_child_row_action", title=lazy_gettext("Add child"), ), TemplateLinkRowAction( template_name="oy.children_row_action", title=gettext("Show children"), ), ] ) return actions
def __init__(self, app=None, auto_register_modules=False, **kwargs): index_view = kwargs.pop( "index_view", OyIndexView( name=lazy_gettext("Dashboard Home"), menu_icon_type="fa", menu_icon_value="fa-dashboard", template="admin/oy/index.html", ), ) self.auto_register_modules = auto_register_modules defaults = { "name": lazy_gettext("Dashboard"), "template_mode": "bootstrap3", # "base_template": "oy_admin/master.html", "index_view": index_view, "category_icon_classes": { "Settings": "fa fa-cog", "Pages": "fa fa-file-text-o", "Users": "fa fa-users", }, } for k, v in defaults.items(): kwargs.setdefault(k, v) super(OyAdmin, self).__init__(app, **kwargs)
def last_edited_by(cls): return db.relationship( "User", foreign_keys=[cls.editor_id], info=dict(label=lazy_gettext("Author"), description=lazy_gettext("")), )
def register_admin(app, admin): admin.add_view( ImageAdmin( Image, db.session, name=lazy_gettext("image"), verbose_name=lazy_gettext("images"), endpoint="image_admin", url="media/images/", menu_icon_type="fa", menu_icon_value="fa-photo", menu_order=500, )) admin.add_view( GenericMediaAdmin( Document, db.session, name=lazy_gettext("document"), verbose_name=lazy_gettext("documents"), endpoint="document_admin", url="media/documents/", menu_icon_type="fa", menu_icon_value="fa-file", menu_order=400, ))
def provide_core_settings(app): return [ Field( name="title", type="text", label=lazy_gettext("Site Title"), description=lazy_gettext("The site Title"), default=app.name.title(), ) ]
def register_admin(app, admin): admin.add_view( RedirectsAdmin( Redirect, db.session, name=lazy_gettext("redirect"), verbose_name=lazy_gettext("redirects"), menu_icon_type="fa", menu_icon_value="fa-refresh", menu_order=300, ))
def register_admin(app, admin): admin.add_view( UserAdmin( User, db.session, name=lazy_gettext("user account"), verbose_name=lazy_gettext("user accounts"), endpoint="users", menu_icon_type="fa", menu_icon_value="fa-users", menu_order=100, ))
def register_admin(app, admin): admin.add_view( RichTextPageAdmin( RichTextPage, db.session, name=lazy_gettext("Rich Text page"), verbose_name=lazy_gettext("Rich Text pages"), menu_icon_type="fa", menu_icon_value="fa-newspaper-o", menu_order=700, ) )
def register_admin(app, admin): admin.add_view( FormAdmin( Form, db.session, name=lazy_gettext("form"), verbose_name=lazy_gettext("forms"), menu_icon_type="fa", menu_icon_value="fa-wpforms", menu_order=600, ) )
def __str__(self): readable_filetypes = [] for ft in self.filetypes: readable_filetypes.append(SUPPORTED_FILE_TYPES.get(ft, ft)) return (self.message + " " + lazy_gettext( "Please make sure you uploaded one of the following file types:") + " " + ", ".join([str(ft) for ft in readable_filetypes]))
def editor_id(cls): return db.Column( db.Integer, db.ForeignKey("user.id"), nullable=True, info=dict(label=lazy_gettext("Author")), )
def __init__(self): super().__init__( "fa fa-trash", ".delete_confirm", title=lazy_gettext("Delete record"), id_arg="pk", )
class OyRecoverPasswordForm(ForgotPasswordForm): submit = None email = EmailField( label=lazy_gettext("Your registered email address"), validators=[data_required()], render_kw=dict(required=True), )
def form_rules(self): rv = [ "user_name", "email", rules.NestedRule([ rules.HTML("<h4>" + lazy_gettext("Change Password") + "</h4>"), "old_password", "new_password", "new_password_confirm", ]), rules.HTML("<h4>" + lazy_gettext("Profile Details") + "</h4>"), ] for fn, _, __ in self.get_profile_fields(): rv.append(_wrap_field(fn)) if current_user.has_role("admin"): rv.extend(["active", "roles"]) return rv
def get_form(self): form = super().get_form() rv = dict( old_password=PasswordField(label=lazy_gettext("Old Password")), new_password=PasswordField(label=lazy_gettext("New Password")), new_password_confirm=PasswordField( label=lazy_gettext("Confirm New Password")), ) idarg = None if not request else request.args.get("id") user = None if not idarg else self.get_one(idarg) for fn, cf, kw in self.get_profile_fields(): if user is not None: kw["default"] = user.profile.get(fn) rv[_wrap_field(fn)] = cf(**kw) for k, v in rv.items(): setattr(form, k, v) return form
class ChildPageTypeForm(FlaskForm): parent_pk = HiddenField(validators=[InputRequired()]) url = HiddenField(default=self.get_save_return_url(self.model)) page_type = SelectField( validators=[InputRequired()], label=lazy_gettext("Select the type of the child page "), default="", choices=self._get_pchild_form_choices, )
class Form(Page): __contenttype__ = "form" id = db.Column(db.Integer, db.ForeignKey("page.id"), primary_key=True) submit_text = db.Column( db.String(255), info=dict( label=lazy_gettext("Submit button text"), description=lazy_gettext("Text of the submit button in the form"), ), ) submit_message = db.Column( db.UnicodeText, info=dict( label=lazy_gettext("After Submit Message"), description=lazy_gettext( "A Message to display for the user after submitting the form"), ), ) fields = db.relationship(Field, backref="form")
class OyLoginForm(EmailFormMixin, PasswordFormMixin, LoginForm): def __init__(self, *a, **kw): super(OyLoginForm, self).__init__(*a, **kw) self.lang.choices = current_app.config["SUPPORTED_LOCALES"].items() lang = SelectField( label=lazy_gettext("Choose interface language"), validators=[data_required()], render_kw=dict(required=True), )
def uploaded_file(cls): depot_args = dict(cls.__depot_args__) filters = depot_args.pop("filters", []) allowed_files = getattr(cls, "__allowed_file_types__", []) if allowed_files: filters.insert(0, FileTypeCheckFilter(filetypes=allowed_files)) return db.Column( UploadedFileField(filters=filters, **depot_args), nullable=False, info=dict(label=lazy_gettext("Select a file")), )
class RichTextPage(OyExtBase): module_args = dict( name="oy.contrib.richtext_page", import_name="oy.contrib.richtext_page", template_folder="templates", viewable_name=lazy_gettext("Rich Text Page"), ) def init_app(self, app): app.add_contenttype_handler("richtext_page", RichTextPageView)
class GenericMedia(Titled, TimeStampped, UserRelated, Tagged): file_id = db.Column( db.String(64), unique=True, nullable=False, index=True, default=lambda: token_urlsafe(NUMBYTES), ) description = db.Column(db.Text, nullable=True, info=dict(lable=lazy_gettext("Description"))) __depot_args__ = {"upload_storage": "media_storage"} @declared_attr def uploaded_file(cls): depot_args = dict(cls.__depot_args__) filters = depot_args.pop("filters", []) allowed_files = getattr(cls, "__allowed_file_types__", []) if allowed_files: filters.insert(0, FileTypeCheckFilter(filetypes=allowed_files)) return db.Column( UploadedFileField(filters=filters, **depot_args), nullable=False, info=dict(label=lazy_gettext("Select a file")), ) def before_insert(self, mapper, connection): tbl = mapper.mapped_table sel = db.select([tbl.c.id]) token = token_urlsafe(14) while connection.scalar( db.func.count(sel.where(tbl.c.file_id == token))): token = token_urlsafe(NUMBYTES) filename, ext = os.path.splitext(self.uploaded_file.filename) self.file_id = f"{slugify(filename)}-{token}{ext}" @classmethod def get_upload_storage(cls): return (db.inspect(cls).get_property( "uploaded_file").columns[0].type._upload_storage) @staticmethod def deserialize_instance(module, model, **attrs): """Custom logic for constructing object from json when adding demo data.""" with db.session.no_autoflush: file = open( os.path.join(module.root_path, "fixtures", attrs["uploaded_file"]), "rb") attrs["uploaded_file"] = file obj = original_deserialize_instance(module, model, **attrs) file.close() return obj
class Profile(ImmutableProxiedDictMixin, db.Model, TimeStampped): id = db.Column(db.Integer, primary_key=True) user_id = db.Column( db.Integer, db.ForeignKey("user.id"), unique=True, nullable=False, info=dict(label=lazy_gettext("User")), ) user = db.relationship( User, backref=backref("profile", uselist=False, cascade="all, delete-orphan"), single_parent=True, info=dict(label=lazy_gettext("User"), description=lazy_gettext("")), ) extras = db.relationship( "ProfileExtras", collection_class=attribute_mapped_collection("key") ) _proxied = association_proxy("extras", "value") def __repr__(self): return f"<{self.user.user_name}: Profile()>"
class Role(db.Model, RoleMixin): id = db.Column(db.Integer(), primary_key=True) name = db.Column( db.String(80), unique=True, info=dict( label=lazy_gettext("Name"), description=lazy_gettext("A name to identify this role"), ), ) description = db.Column( db.Unicode(255), info=dict( label=lazy_gettext("Description"), description=lazy_gettext("A simple summary about this role."), ), ) def __str__(self): return self.name def __repr__(self): return f"<Role(name='{self.name}'>"
def get_list_row_actions(self): actions = super().get_list_row_actions() if self.can_delete: actions = [a for a in actions if not isinstance(a, DeleteRowAction)] actions.append(OyDeleteRowAction()) if hasattr(self, "get_preview_url"): actions.append( LinkRowAction( icon_class="fa fa-eye", url=lambda v, i, r: self.get_preview_url(r), title=lazy_gettext("Preview in site"), ) ) return actions
class OyRegisterForm(RegisterForm): user_name = StringField( label=lazy_gettext("User Name"), description=lazy_gettext("Should be UNIQUE"), validators=[data_required(), unique_username], render_kw=dict(required=True), ) email = EmailField( label=lazy_gettext("User Email"), description=lazy_gettext( "An active email address, a confirmation link will be sent to it." ), validators=[email_required, email_validator, unique_user_email], render_kw=dict(required=True), ) password = PasswordField( label=lazy_gettext("Password"), description=lazy_gettext("Not less than 6 characters"), validators=[password_required, password_length], render_kw=dict(required=True), ) password_confirm = PasswordField( label=lazy_gettext("Re-Type Password"), validators=[EqualTo("password", message="RETYPE_PASSWORD_MISMATCH")], render_kw=dict(required=True), ) roles = QuerySelectMultipleField( label=lazy_gettext("User Roles"), allow_blank=True, blank_text=lazy_gettext("No Roles"), query_factory=lambda: Role.query, ) send_confirmation = BooleanField( label=lazy_gettext("Require email confirmation"), description=lazy_gettext( "we will not activate this account untill the user confirms his/her email address" ), default=True, )
def unique_username(form, field): from oy.boot.security import user_datastore if user_datastore.get_user(field.data) is not None: raise ValidationError(lazy_gettext("User name already exists"))
class FormAdmin(PageAdmin): column_extra_row_actions = [ EndpointLinkRowAction( icon_class="fa fa-download", endpoint=".export_entries", title=lazy_gettext("Export Entries as CSV"), id_arg="pk", ), EndpointLinkRowAction( icon_class="fa fa-table", endpoint=".view_entries", title=lazy_gettext("View Entries"), id_arg="pk", ), ] form_excluded_columns = list(PageAdmin.form_excluded_columns) + [ "author", "created", "updated", "entries", ] form_columns = list(PageAdmin.form_columns) form_columns.insert(6, "fields") form_columns.insert(7, "submit_text") form_columns.insert(8, "submit_message") form_overrides = {"submit_message": CkeditorTextAreaField} inline_models = [ ( Field, dict( form_columns=[ "id", "name", "label", "description", "type", "choices", "default", "required", "max_length", ], form_extra_fields={ "type": SelectField( label=Field.type.info["label"], description=Field.type.info["description"], choices=field_type_choices, ) }, ), ) ] @expose("/export-entries/<int:pk>") def export_entries(self, pk): """Taken from Flask-Admin with some modifications, no shame!""" form = self.get_one(str(pk)) filename = "attachment; filename=%s" % _gen_csv_file_name(form) class Echo(object): """ An object that implements just the write method of the file-like interface. """ def write(self, value): """ Write the value by returning it, instead of storing in a buffer. """ return value writer = csv.writer(Echo()) def generate(): # Append the column titles at the beginning titles = [csv_encode("date")] + [ csv_encode(field.name) for field in form.fields ] yield writer.writerow(titles) for entry in form.entries: vals = [csv_encode(entry.created.isoformat())] + [ csv_encode(_process_field_value(field)) for field in entry.fields ] yield writer.writerow(vals) return Response( stream_with_context(generate()), headers={"Content-Disposition": filename}, mimetype="text/csv", ) @expose("/view-entries/<int:pk>") def view_entries(self, pk): """View form entries""" form = self.get_one(str(pk)) entries = FormEntry.query.filter_by(form=form) paginator = paginate_with_args(entries) return self.render( "oy_admin/form-entries.html", form=form, paginator=paginator, val_proc=_process_field_value, )
""" import os.path import fleep from tempfile import SpooledTemporaryFile from PIL import Image from depot.io.utils import file_from_content, INMEMORY_FILESIZE from depot.fields.interfaces import FileFilter from depot.fields.upload import UploadedFile from depot.io.interfaces import FileStorage from oy.models import db from oy.babel import lazy_gettext # See fleep supported file types <https://github.com/floyernick/fleep-py> SUPPORTED_FILE_TYPES = { "raster-image": lazy_gettext("Image Files"), "raw-image": lazy_gettext("Raw Image Files"), "3d-image": lazy_gettext("3D Image Files"), "vector-image": lazy_gettext("Vector Image Files"), "video": lazy_gettext("Video Files"), "audio": lazy_gettext("Audio Files"), "document": lazy_gettext("Documents"), "executable": lazy_gettext("Executable Files"), "system": lazy_gettext("System Files"), "database": lazy_gettext("Database Files"), "archive": lazy_gettext("Archives"), "font": lazy_gettext("Font Files"), } class UnsupportedFileTypeError(IOError):
def __init__(self, filetypes, message=None): self.filetypes = filetypes self.message = message or lazy_gettext("Unsupported file type.")