class RegistroUsuario(ModelSoftlogView): route_base = '/registeruser' list_widget = ListWidget base_order = ('username', 'asc') base_permissions = ['Listar', 'Visualizar', 'Excluir'] list_title = lazy_gettext('List of Registration Requests') show_title = lazy_gettext('Show Registration') list_columns = ['username', 'registration_date', 'email'] show_exclude_columns = ['password'] search_exclude_columns = ['password']
class Menus(ModelSoftlogView): route_base = '/viewmenus' base_permissions = ['Listar'] list_widget = ListWidget base_order = ('name', 'asc') start_empty = False list_title = lazy_gettext('List View Menus') show_title = lazy_gettext('Show View Menu') add_title = lazy_gettext('Add View Menu') edit_title = lazy_gettext('Edit View Menu') label_columns = {'name': lazy_gettext('Name')}
class TipoPermissoes(ModelSoftlogView): route_base = '/permissions' base_permissions = ['Listar'] list_widget = ListWidget start_empty = False base_order = ('name', 'asc') list_title = lazy_gettext('List Base Permissions') show_title = lazy_gettext('Show Base Permission') add_title = lazy_gettext('Add Base Permission') edit_title = lazy_gettext('Edit Base Permission') label_columns = {'name': lazy_gettext('Name')}
class RedefinirSenha(SimpleFormView): """ View for reseting all users password """ route_base = '/resetpassword' form = ResetPasswordForm form_title = lazy_gettext('Reset Password Form') redirect_url = '/' message = lazy_gettext('Password Changed') def form_post(self, form): pk = request.args.get('pk') self.appbuilder.sm.reset_password(pk, form.password.data) flash(as_unicode(self.message), 'info')
class RedefinirMinhaSenha(SimpleFormView): """ View for resetting own user password """ route_base = '/resetmypassword' form = ResetPasswordForm form_title = lazy_gettext('Reset Password Form') redirect_url = '/' message = lazy_gettext('Password Changed') def form_post(self, form): self.appbuilder.sm.reset_password(g.user.id, form.password.data) flash(as_unicode(self.message), 'info')
class GruposUsuario(ModelSoftlogView): route_base = '/roles' list_widget = ListWidget base_order = ('name', 'asc') start_empty = False list_title = lazy_gettext('List Roles') show_title = lazy_gettext('Show Role') add_title = lazy_gettext('Add Role') edit_title = lazy_gettext('Edit Role') label_columns = { 'name': lazy_gettext('Name'), 'permissions': lazy_gettext('Permissions') } list_columns = ['name', 'permissions'] order_columns = ['name'] @action("Clonar Grupo", lazy_gettext('Copy Role'), lazy_gettext('Copy the selected roles?'), icon='fa-copy', single=False) def copy_role(self, items): self.update_redirect() for item in items: new_role = item.__class__() new_role.name = item.name new_role.permissions = item.permissions new_role.name = new_role.name + ' copiar' self.datamodel.add(new_role) return redirect(self.get_redirect())
class FilterNotStartsWith(BaseFilter): name = lazy_gettext('Not Starts with') def apply(self, query, value): query, field = get_field_setup_query(query, self.model, self.column_name) return query.filter(~field.like(value + '%'))
class FilterNotContains(BaseFilter): name = lazy_gettext('Not Contains') def apply(self, query, value): query, field = get_field_setup_query(query, self.model, self.column_name) return query.filter(~field.like('%' + value + '%'))
class FilterEndsWith(BaseFilter): name = lazy_gettext('Ends with') def apply(self, query, value): query, field = get_field_setup_query(query, self.model, self.column_name) return query.filter(field.like('%' + value))
class FilterRelationOneToManyNotEqual(FilterRelation): name = lazy_gettext('No Relation') def apply(self, query, value): query, field = get_field_setup_query(query, self.model, self.column_name) rel_obj = self.datamodel.get_related_obj(self.column_name, value) return query.filter(field != rel_obj)
class FilterSmaller(BaseFilter): name = lazy_gettext('Smaller than') def apply(self, query, value): query, field = get_field_setup_query(query, self.model, self.column_name) value = set_value_to_type(self.datamodel, self.column_name, value) return query.filter(field < value)
class FilterNotEqual(BaseFilter): name = lazy_gettext('Not Equal to') def apply(self, query, value): query, field = get_field_setup_query(query, self.model, self.column_name) value = set_value_to_type(self.datamodel, self.column_name, value) return query.filter(field != value)
class FilterRelationManyToManyEqual(FilterRelation): name = lazy_gettext('Relation as Many') def apply(self, query, value): query, field = get_field_setup_query(query, self.model, self.column_name) rel_obj = self.datamodel.get_related_obj(self.column_name, value) return query.filter(field.contains(rel_obj))
class StringConexoesView(ModelSoftlogView): route_base = '/databases_tenancy' base_permissions = ['Listar', 'Visualizar'] list_columns = ['banco_dados', 'host', 'port'] list_title = lazy_gettext('List Base Permissions') show_title = lazy_gettext('Show Base Permission') add_title = lazy_gettext('Add Base Permission') edit_title = lazy_gettext('Edit Base Permission') label_columns = { 'id_string_conexao': lazy_gettext('Id'), 'banco_dados': lazy_gettext('DataBase'), 'usuario': lazy_gettext('User'), 'senha': lazy_gettext('Password'), 'port': lazy_gettext('Port'), 'host': lazy_gettext('Host') }
class UsuarioInformacoes(SimpleFormView): form = UserInfoEdit form_title = lazy_gettext('Edit User Information') redirect_url = '/' message = lazy_gettext('User information changed') def form_get(self, form): item = self.appbuilder.sm.get_user_by_id(g.user.id) # fills the form generic solution for key, value in form.data.items(): form_field = getattr(form, key) form_field.data = getattr(item, key) def form_post(self, form): form = self.form.refresh(request.form) item = self.appbuilder.sm.get_user_by_id(g.user.id) form.populate_obj(item) self.appbuilder.sm.update_user(item) flash(as_unicode(self.message), 'info')
class UsuarioEstatisticas(DirectByChartView): chart_title = lazy_gettext('User Statistics') label_columns = { 'username': lazy_gettext('User Name'), 'login_count': lazy_gettext('Login count'), 'fail_login_count': lazy_gettext('Failed login count') } search_columns = UserModelView.search_columns definitions = [{ 'label': 'Login Count', 'group': 'username', 'series': ['login_count'] }, { 'label': 'Failed Login Count', 'group': 'username', 'series': ['fail_login_count'] }]
class AuthView(BaseView): route_base = '' login_template = '' invalid_login_message = lazy_gettext('Invalid login. Please try again.') title = lazy_gettext('Sign In') @expose('/login/', methods=['GET', 'POST']) def login(self): pass @expose('/logout/') def logout(self): logout_user() return redirect(self.appbuilder.get_url_for_index) @expose('/relogin/', methods=['GET', 'POST']) def relogin(self): pass
class Permissoes(ModelSoftlogView): route_base = '/permissionviews' base_permissions = ['Listar'] list_widget = ListWidget start_empty = False list_title = lazy_gettext('List Permissions on Views/Menus') show_title = lazy_gettext('Show Permission on Views/Menus') add_title = lazy_gettext('Add Permission on Views/Menus') edit_title = lazy_gettext('Edit Permission on Views/Menus') label_columns = { 'permission': lazy_gettext('Permission'), 'view_menu': lazy_gettext('View/Menu') } list_columns = ['permission', 'view_menu']
class BaseRegisterUser(PublicFormView): """ Make your own user registration view and inherit from this class if you want to implement a completely different registration process. If not, just inherit from RegisterUserDBView or RegisterUserOIDView depending on your authentication method. then override SecurityManager property that defines the class to use:: from flask.ext.appbuilder.security.registerviews import RegisterUserDBView class MyRegisterUserDBView(BaseRegisterUser): email_template = 'register_mail.html' ... class MySecurityManager(SecurityManager): registeruserdbview = MyRegisterUserDBView When instantiating AppBuilder set your own SecurityManager class:: appbuilder = AppBuilder(app, db.session, security_manager_class=MySecurityManager) """ route_base = '/register' email_template = 'appbuilder/general/security/register_mail.html' """ The template used to generate the email sent to the user """ email_subject = lazy_gettext('Account activation') """ The email subject sent to the user """ activation_template = 'appbuilder/general/security/activation.html' """ The activation template, shown when the user is activated """ message = lazy_gettext('Registration sent to your email') """ The message shown on a successful registration """ error_message = lazy_gettext( 'Not possible to register you at the moment, try again later') """ The message shown on an unsuccessful registration """ false_error_message = lazy_gettext('Registration not found') """ The message shown on an unsuccessful registration """ form_title = lazy_gettext('Fill out the registration form') """ The form title """ def send_email(self, register_user): """ Method for sending the registration Email to the user """ try: from flask_mail import Mail, Message except: log.error("Install Flask-Mail to use User registration") return False mail = Mail(self.appbuilder.get_app) msg = Message() msg.subject = self.email_subject url = url_for('.activation', _external=True, activation_hash=register_user.registration_hash) msg.html = self.render_template(self.email_template, url=url, username=register_user.username, first_name=register_user.first_name, last_name=register_user.last_name) msg.recipients = [register_user.email] try: mail.send(msg) except Exception as e: log.error("Send email exception: {0}".format(str(e))) return False return True def add_registration(self, username, first_name, last_name, email, password=''): """ Add a registration request for the user. :rtype : RegisterUser """ register_user = self.appbuilder.sm.add_register_user( username, first_name, last_name, email, password) if register_user: if self.send_email(register_user): flash(as_unicode(self.message), 'info') return register_user else: flash(as_unicode(self.error_message), 'danger') self.appbuilder.sm.del_register_user(register_user) return None @expose('/activation/<string:activation_hash>') def activation(self, activation_hash): """ Endpoint to expose an activation url, this url is sent to the user by email, when accessed the user is inserted and activated """ reg = self.appbuilder.sm.find_register_user(activation_hash) if not reg: log.error( c.LOGMSG_ERR_SEC_NO_REGISTER_HASH.format(activation_hash)) flash(as_unicode(self.false_error_message), 'danger') return redirect(self.appbuilder.get_url_for_index) if not self.appbuilder.sm.add_user( username=reg.username, email=reg.email, first_name=reg.first_name, last_name=reg.last_name, role=self.appbuilder.sm.find_role( self.appbuilder.sm.auth_user_registration_role), hashed_password=reg.password): flash(as_unicode(self.error_message), 'danger') return redirect(self.appbuilder.get_url_for_index) else: self.appbuilder.sm.del_register_user(reg) return self.render_template(self.activation_template, username=reg.username, first_name=reg.first_name, last_name=reg.last_name, appbuilder=self.appbuilder) def add_form_unique_validations(self, form): datamodel_user = self.appbuilder.sm.get_user_datamodel datamodel_register_user = self.appbuilder.sm.get_register_user_datamodel if len(form.username.validators) == 1: form.username.validators.append(Unique(datamodel_user, 'username')) form.username.validators.append( Unique(datamodel_register_user, 'username')) if len(form.email.validators) == 2: form.email.validators.append(Unique(datamodel_user, 'email')) form.email.validators.append( Unique(datamodel_register_user, 'email'))
class BaseInterface(object): """ Base class for all data model interfaces. Sub class it to implement your own interface for some data engine. """ obj = None filter_converter_class = None """ when sub classing override with your own custom filter converter """ """ Messages to display on CRUD Events """ add_row_message = lazy_gettext('Added Row') edit_row_message = lazy_gettext('Changed Row') delete_row_message = lazy_gettext('Deleted Row') delete_integrity_error_message = lazy_gettext( 'Associated data exists, please delete them first') add_integrity_error_message = lazy_gettext( 'Integrity error, probably unique constraint') edit_integrity_error_message = lazy_gettext( 'Integrity error, probably unique constraint') general_error_message = lazy_gettext('General Error') """ Tuple with message and text with severity type ex: ("Added Row", "info") """ message = () def __init__(self, obj): self.obj = obj def _get_attr_value(self, item, col): if not hasattr(item, col): # it's an inner obj attr try: return reduce(getattr, col.split('.'), item) except Exception as e: return '' if hasattr(getattr(item, col), '__call__'): # its a function return getattr(item, col)() else: # its an attribute return getattr(item, col) def get_filters(self, search_columns=None): search_columns = search_columns or [] return Filters(self.filter_converter_class, self, search_columns) def get_values_item(self, item, show_columns): return [self._get_attr_value(item, col) for col in show_columns] def _get_values(self, lst, list_columns): """ Get Values: formats values for list template. returns [{'col_name':'col_value',....},{'col_name':'col_value',....}] :param lst: The list of item objects from query :param list_columns: The list of columns to include """ retlst = [] for item in lst: retdict = {} for col in list_columns: retdict[col] = self._get_attr_value(item, col) retlst.append(retdict) return retlst def get_values(self, lst, list_columns): """ Get Values: formats values for list template. returns [{'col_name':'col_value',....},{'col_name':'col_value',....}] :param lst: The list of item objects from query :param list_columns: The list of columns to include """ for item in lst: retdict = {} for col in list_columns: retdict[col] = self._get_attr_value(item, col) yield retdict def get_values_json(self, lst, list_columns): """ Converts list of objects from query to JSON """ result = [] for item in self.get_values(lst, list_columns): for key, value in list(item.items()): if isinstance(value, datetime.datetime) or isinstance( value, datetime.date): value = value.isoformat() item[key] = value if isinstance(value, list): item[key] = [str(v) for v in value] result.append(item) return result """ Returns the models class name useful for auto title on views """ @property def model_name(self): return self.obj.__class__.__name__ """ Next methods must be overridden """ def query(self, filters=None, order_column='', order_direction='', page=None, page_size=None): pass def is_image(self, col_name): return False def is_file(self, col_name): return False def is_gridfs_file(self, col_name): return False def is_gridfs_image(self, col_name): return False def is_string(self, col_name): return False def is_text(self, col_name): return False def is_integer(self, col_name): return False def is_numeric(self, col_name): return False def is_float(self, col_name): return False def is_boolean(self, col_name): return False def is_date(self, col_name): return False def is_datetime(self, col_name): return False def is_relation(self, prop): return False def is_relation_col(self, col): return False def is_relation_many_to_one(self, prop): return False def is_relation_many_to_many(self, prop): return False def is_relation_one_to_one(self, prop): return False def is_relation_one_to_many(self, prop): return False def is_nullable(self, col_name): return True def is_unique(self, col_name): return False def is_pk(self, col_name): return False def is_fk(self, col_name): return False def get_max_length(self, col_name): return -1 def get_min_length(self, col_name): return -1 """ ----------------------------------------- FUNCTIONS FOR CRUD OPERATIONS ----------------------------------------- """ def add(self, item): """ Adds object """ raise NotImplementedError def edit(self, item): """ Edit (change) object """ raise NotImplementedError def delete(self, item): """ Deletes object """ raise NotImplementedError def get_col_default(self, col_name): pass def get_keys(self, lst): """ return a list of pk values from object list """ pk_name = self.get_pk_name() return [getattr(item, pk_name) for item in lst] def get_pk_name(self, item): """ Returns the primary key name """ raise NotImplementedError def get_pk_value(self, item): return getattr(item, self.get_pk_name()) def get(self, pk, filter=None): """ return the record from key, you can optionally pass filters if pk exits on the db but filters exclude it it will return none. """ pass def get_related_model(self, prop): raise NotImplementedError def get_related_interface(self, col_name): """ Returns a BaseInterface for the related model of column name. :param col_name: Column name with relation :return: BaseInterface """ raise NotImplementedError def get_related_obj(self, col_name, value): raise NotImplementedError def get_related_fk(self, model): raise NotImplementedError def get_columns_list(self): """ Returns a list of all the columns names """ return [] def get_user_columns_list(self): """ Returns a list of user viewable columns names """ return self.get_columns_list() def get_search_columns_list(self): """ Returns a list of searchable columns names """ return [] def get_order_columns_list(self, list_columns=None): """ Returns a list of order columns names """ return [] def get_relation_fk(self, prop): pass
class UserModelView(ModelSoftlogView): route_base = '/users' list_widget = ListWidget start_empty = False list_title = lazy_gettext('List Users') show_title = lazy_gettext('Show User') add_title = lazy_gettext('Add User') edit_title = lazy_gettext('Edit User') base_order = ("first_name", "asc") label_columns = { 'get_full_name': lazy_gettext('Full Name'), 'first_name': lazy_gettext('First Name'), 'last_name': lazy_gettext('Last Name'), 'username': lazy_gettext('User Name'), 'password': lazy_gettext('Password'), 'active': lazy_gettext('Is Active?'), 'email': lazy_gettext('EMail'), 'roles': lazy_gettext('Role'), 'last_login': lazy_gettext('Last login'), 'login_count': lazy_gettext('Login count'), 'fail_login_count': lazy_gettext('Failed login count'), 'created_on': lazy_gettext('Created on'), 'created_by': lazy_gettext('Created by'), 'changed_on': lazy_gettext('Changed on'), 'changed_by': lazy_gettext('Changed by') } description_columns = { 'first_name': lazy_gettext('Write the user first name or names'), 'last_name': lazy_gettext('Write the user last name'), 'username': lazy_gettext( 'Username valid for authentication on DB or LDAP, unused for OID auth' ), 'password': lazy_gettext( 'Please use a good password policy, this application does not check this for you' ), 'active': lazy_gettext( 'It\'s not a good policy to remove a user, just make it inactive'), 'email': lazy_gettext('The user\'s email, this will also be used for OID auth'), 'roles': lazy_gettext( 'The user role on the application, this will associate with a list of permissions' ), 'conf_password': lazy_gettext('Please rewrite the user\'s password to confirm') } list_columns = [ 'nome_usuario', 'last_name', 'username', 'email', 'active', 'roles' ] show_fieldsets = [ (lazy_gettext('User info'), { 'fields': ['username', 'active', 'roles', 'login_count'] }), (lazy_gettext('Personal Info'), { 'fields': ['first_name', 'last_name', 'email'], 'expanded': True }), (lazy_gettext('Audit Info'), { 'fields': [ 'last_login', 'fail_login_count', 'created_on', 'created_by', 'changed_on', 'changed_by' ], 'expanded': False }), ] user_show_fieldsets = [ (lazy_gettext('User info'), { 'fields': ['username', 'active', 'roles', 'login_count'] }), (lazy_gettext('Personal Info'), { 'fields': ['first_name', 'last_name', 'email'], 'expanded': True }), ] search_exclude_columns = ['password'] add_columns = [ 'nome_usuario', 'last_name', 'username', 'active', 'email', 'roles' ] edit_columns = [ 'nome_usuario', 'last_name', 'username', 'active', 'email', 'roles' ] user_info_title = lazy_gettext("Your user information") @expose('/userinfo/') @has_access def userinfo(self): item = self.datamodel.get(g.user.id, self._base_filters) widgets = self._get_show_widget( g.user.id, item, show_fieldsets=self.user_show_fieldsets) self.update_redirect() return self.render_template(self.show_template, title=self.user_info_title, widgets=widgets, appbuilder=self.appbuilder) @action('userinfoedit', lazy_gettext("Edit User"), "", "fa-edit", multiple=False) def userinfoedit(self, item): return redirect( url_for(self.appbuilder.sm.userinfoeditview.__name__ + '.this_form_get'))
class Usuarios(UserModelView): """ View that add DB specifics to User view. Override to implement your own custom view. Then override userdbmodelview property on SecurityManager """ add_form_extra_fields = { 'password': PasswordField( lazy_gettext('Password'), description=lazy_gettext( 'Please use a good password policy, this application does not check this for you' ), validators=[validators.DataRequired()], widget=BS3PasswordFieldWidget()), 'conf_password': PasswordField(lazy_gettext('Confirm Password'), description=lazy_gettext( 'Please rewrite the user\'s password to confirm'), validators=[ EqualTo('password', message=lazy_gettext('Passwords must match')) ], widget=BS3PasswordFieldWidget()) } add_columns = [ 'nome_usuario', 'last_name', 'username', 'active', 'email', 'roles', 'password', 'conf_password' ] @expose('/show/<pk>', methods=['GET']) @has_access @permission_name("Visualizar") def show(self, pk): actions = {} actions['resetpasswords'] = self.actions.get('resetpasswords') item = self.datamodel.get(pk, self._base_filters) if not item: abort(404) widgets = self._get_show_widget(pk, item, actions=actions) self.update_redirect() return self.render_template(self.show_template, pk=pk, title=self.show_title, widgets=widgets, appbuilder=self.appbuilder, related_views=self._related_views) @expose('/userinfo/') @has_access @permission_name("InformacaoUsuario") def userinfo(self): actions = {} actions['resetmypassword'] = self.actions.get('resetmypassword') actions['userinfoedit'] = self.actions.get('userinfoedit') item = self.datamodel.get(g.user.id, self._base_filters) widgets = self._get_show_widget( g.user.id, item, actions=actions, show_fieldsets=self.user_show_fieldsets) self.update_redirect() return self.render_template( self.show_template, title=self.user_info_title, widgets=widgets, appbuilder=self.appbuilder, ) @action('resetmypassword', lazy_gettext("Reset my password"), "", "fa-lock", multiple=False) @permission_name("RedefinirMinhaSenha") def resetmypassword(self, item): return redirect( url_for(self.appbuilder.sm.resetmypasswordview.__name__ + '.this_form_get')) @action('resetpasswords', lazy_gettext("Reset Password"), "", "fa-lock", multiple=False) @permission_name("RedefinirSenha") def resetpasswords(self, item): return redirect( url_for(self.appbuilder.sm.resetpasswordview.__name__ + '.this_form_get', pk=item.id)) def pre_update(self, item): item.changed_on = datetime.datetime.now() item.changed_by_fk = g.user.id def pre_add(self, item): item.password = generate_password_hash(item.password)