class UserModelView(ModelView): can_view_details = True can_delete = False column_exclude_list = ('password', ) column_default_sort = 'id' column_filters = ( 'name', 'username', ) create_template = 'user/create.html' edit_template = 'user/edit.html' form_create_rules = [ rules.FieldSet(('username', ), 'Account'), # Header and four fields. Email field will go above phone field. rules.FieldSet(('first_name', 'last_name', 'email', 'phone'), 'Personal'), # Separate header and few fields rules.Header('Location'), rules.Field('city'), # String is resolved to form field, so there's no need to explicitly use `rules.Field` 'country', # Show macro that's included in the templates rules.Container('rule_demo.wrap', rules.Field('notes')) ] form_edit_rules = form_create_rules
class UserView(sqla.ModelView): """ This class demonstrates the use of 'rules' for controlling the rendering of forms. """ form_create_rules = [ # Header and four fields. Email field will go above phone field. rules.FieldSet(('name', 'email', 'phone'), u'个人信息'), # Separate header and few fields rules.Header(u'备注'), rules.Field('user_story'), # String is resolved to form field, so there's no need to explicitly use `rules.Field` # 'country', # Show macro from Flask-Admin lib.html (it is included with 'lib' prefix) rules.Container('rule_demo.wrap', rules.Field('notes')) ] # Use same rule set for edit page form_edit_rules = form_create_rules create_template = 'rule_create.html' edit_template = 'rule_edit.html' column_exclude_list = ('password', 'notes') # can_create = False def is_accessible(self): return flask_login.current_user.is_authenticated
class UserListView(AdminModelView): can_delete = True form_args = dict( teams=dict(validators=[DataRequired()]), first_name=dict(validators=[DataRequired()]), last_name=dict(validators=[DataRequired()]), email=dict(validators=[DataRequired()]), password=dict(validators=[DataRequired()]), ) column_labels = dict(teams='Team', roles='Role') column_list = ['first_name', 'last_name','roles','teams','email', 'active'] form_create_rules = [ rules.Field('teams'), #rules.Field('roles'), rules.Field('first_name'), rules.Field('last_name'), rules.Field('email'), rules.Field('password'), #rules.Field('active') ] form_edit_rules = form_create_rules create_template = 'rule_create.html' edit_template = 'rule_edit.html'
class UserView(MyModelView): # Restrict only the current user can see his own profile can_delete = False can_create = False def get_query(self): return self.session.query(self.model).filter(self.model.id==current_user.id) def get_count_query(self): return self.session.query(func.count('*')).filter(self.model.id==current_user.id) form_args = dict( teams=dict(validators=[DataRequired()]), first_name=dict(validators=[DataRequired()]), last_name=dict(validators=[DataRequired()]), email=dict(validators=[DataRequired()]), password=dict(validators=[DataRequired()]), ) column_labels = dict(teams='Team', roles='Role') column_list = ['first_name', 'last_name','roles','teams','email', 'active'] form_create_rules = [ rules.Field('teams'), #rules.Field('roles'), rules.Field('first_name'), rules.Field('last_name'), rules.Field('email'), rules.Field('password'), #rules.Field('active') ] form_edit_rules = form_create_rules create_template = 'rule_create.html' edit_template = 'rule_edit.html'
class TeamView(AdminModelView): can_delete = True column_list = ['name','description'] form_create_rules = [ rules.Field('name'), rules.Field('description'), rules.Field('users') ] form_edit_rules = form_create_rules create_template = 'rule_create.html' edit_template = 'rule_edit.html'
class PlatformView(DefaultView): column_default_sort = 'id' can_view_details = True can_export = True column_list = ('id', 'type', 'group', 'name', 'slug', 'country', 'links') column_searchable_list = ['name', 'slug', 'country'] column_filters = ['type', 'country', 'group'] column_editable_list = ['country', 'name', 'slug', 'group'] form_columns = ('type', 'group', 'name', 'slug', 'url', 'country', 'max_rating', 'base_score') column_formatters = {'links': count_formatter} form_rules = [ rules.FieldSet([ rules.Field('type'), rules.Field('group'), rules.Field('name'), rules.Field('country'), rules.Field('url'), ], header="Basic info"), rules.FieldSet([ rules.Field('slug'), rules.Field('max_rating'), rules.Field('base_score'), ], header="Technical info") ]
class ResetpassForm(self.form_base_class): form_widget_args = {} form_edit_rules = [ rules.Field('new_password'), rules.Field('new_password_confirm') ] _form_edit_rules = rules.RuleSet(self, form_edit_rules) action = HiddenField('') url = HiddenField('') new_password = fields.PasswordField( '新密码', [validators.required(message='密码是必填字段')]) new_password_confirm = fields.PasswordField( '密码确认', [ validators.equal_to(fieldname='new_password', message='确认密码须一致') ])
class DocumentModelView(ModelView): form_rules = [ rules.FieldSet((), u'文档详情'), rules.Field(u'title'), rules.Field(u'path'), rules.Field(u'search_column'), rules.Field(u'office'), rules.Field(u'model'), rules.Field(u'chapter'), rules.Field(u'date'), ] column_searchable_list = ('title', 'path', 'office', 'model', 'chapter', 'date') column_sortable_list = ('title', 'path', 'office', 'model', 'chapter', 'date') column_labels = dict( title=u'文档名称', path=u'存放路径', search_column=u'搜索路径', office=u'处室', model=u'机型', chapter=u'章节号', date=u'日期', ) column_descriptions = dict(search_column=u'用于程序搜索文档使用,无参考意义', )
class UserView1(sqla.ModelView): def _list_thumbnail(view, context, model, name): if not model.path: return '' return Markup('<img src="%s">' % url_for('static', filename='files/'+form.thumbgen_filename(model.path))) column_formatters = { 'path':_list_thumbnail } # Alternative way to contribute field is to override it completely. # In this case, Flask-Admin won't attempt to merge various parameters for the field. form_extra_fields = { 'path': form.ImageUploadField('Image', base_path=file_path, thumbnail_size=(100, 100, True), url_relative_path='files/') } """ This class demonstrates the use of 'rules' for controlling the rendering of forms. """ form_create_rules = [ # Header and four fields. Email field will go above phone field. rules.FieldSet(('first_name', 'last_name', 'email', 'phone','path'), 'Personal'), # Separate header and few fields rules.Header('Location'), rules.Field('city'), # String is resolved to form field, so there's no need to explicitly use `rules.Field` 'country', # Show macro that's included in the templates rules.Container('rule_demo.wrap', rules.Field('notes')) #rules.FieldSet('path') ] # Use same rule set for edit page form_edit_rules = form_create_rules create_template = 'create_user.html' edit_template = 'edit_user.html'
class UserView(sqla.ModelView): """ Esta clase demuestra el uso de 'reglas' para controlar la representación de formularios. """ form_create_rules = [ # Header y los 4 campos.. rules.FieldSet(('first_name', 'last_name', 'email', 'phone'), 'Personal'), # Separando headr y campos rules.Header('Location'), rules.Field('city'), 'country', # Mostrar macro de Flask-Admin lib.html (se incluye con el prefijo 'lib') rules.Container('rule_demo.wrap', rules.Field('notes')) ] # Use same rule set for edit page form_edit_rules = form_create_rules create_template = 'rule_create.html' edit_template = 'rule_edit.html'
class UserView(sqla.ModelView): """ This class demonstrates the use of 'rules' for controlling the rendering of forms. """ form_create_rules = [ # Header and four fields. Email field will go above phone field. rules.FieldSet(('first_name', 'last_name', 'email', 'phone'), 'Personal'), # Separate header and few fields rules.Header('Location'), rules.Field('city'), # String is resolved to form field, so there's no need to explicitly use `rules.Field` 'country', # Show macro from Flask-Admin lib.html (it is included with 'lib' prefix) rules.Container('rule_demo.wrap', rules.Field('notes')) ] # Use same rule set for edit page form_edit_rules = form_create_rules create_template = 'rule_create.html' edit_template = 'rule_edit.html'
class UserView(sqla.ModelView): """ This class demonstrates the use of 'rules' for controlling the rendering of forms. """ form_create_rules = [ # Header and four fields. Email field will go above phone field. rules.FieldSet(("first_name", "last_name", "email", "phone"), "Personal"), # Separate header and few fields rules.Header("Location"), rules.Field("city"), # String is resolved to form field, so there's no need to explicitly use `rules.Field` "country", # Show macro from Flask-Admin lib.html (it is included with 'lib' prefix) rules.Container("rule_demo.wrap", rules.Field("notes")), ] # Use same rule set for edit page form_edit_rules = form_create_rules create_template = "rule_create.html" edit_template = "rule_edit.html"
class PlatformView(DefaultView): column_default_sort = "id" can_view_details = True can_export = True column_list = ("id", "type", "group", "name", "slug", "country", "links_count") column_searchable_list = ["name", "slug", "country"] column_filters = ["type", "country", "group"] column_editable_list = ["country", "name", "slug", "group"] form_columns = ( "type", "group", "name", "slug", "url", "country", "base_score", "allow_links_overlap", "ignore_in_exports", ) form_rules = [ rules.FieldSet( [ rules.Field("type"), rules.Field("group"), rules.Field("name"), rules.Field("country"), rules.Field("url"), ], header="Basic info", ), rules.FieldSet( [ rules.Field("slug"), rules.Field("base_score"), rules.Field("allow_links_overlap"), rules.Field("ignore_in_exports"), ], header="Technical info", ), ]
class AdminModelView(ModelView): can_delete = False can_create = False def is_accessible(self): if not current_user.is_active or not current_user.is_authenticated: return False if current_user.has_role('administrator'): return True return False def _handle_view(self, name, **kwargs): """ Override builtin _handle_view in order to redirect users when a view is not accessible. """ if not self.is_accessible(): if current_user.is_authenticated: # permission denied abort(403) else: # login return redirect(url_for('security.login', next=request.url)) form_create_rules = [ CustomizableField('name', field_args={ 'readonly': True }), rules.Field('description'), rules.Field('users'), ] form_edit_rules = form_create_rules create_template = 'rule_create.html' edit_template = 'rule_edit.html'
class UserView(AdminModelView): """ This class demonstrates the use of 'rules' for controlling the rendering of forms. """ form_create_rules = [ # Header and four fields. Email field will go above phone field. rules.FieldSet(('username', 'email', 'password'), 'Personal'), # Separate header and few fields rules.FieldSet(('last_login_at', 'current_login_at', 'last_login_ip', 'current_login_ip', 'login_count'), 'login'), rules.Field('active'), rules.Field('confirmed_at'), rules.Field('roles'), # String is resolved to form field, so there's no need to explicitly use `rules.Field` # Show macro that's included in the templates # rules.Container('rule_demo.wrap', rules.Field('notes')) ] # Use same rule set for edit page form_edit_rules = form_create_rules create_template = 'admin/create_user.html' edit_template = 'admin/edit_user.html'
def create_form_rules(self): create_form_rules = [ rules.Header('Personal Info'), rules.Field('team'), rules.Field('name'), rules.Header('Project Info'), rules.Field('project_name'), rules.Field('version'), rules.Field('SVN'), #rules.Field('submitted_at'), rules.Field('notes'), rules.Header('Reviewers'), rules.Field('reviewer1'), rules.Field('reviewer2'), #rules.Field('reviewers'), ] return create_form_rules '''
def test_form_rules(): app, db, admin = setup() Model1, _ = create_models(db) db.create_all() view = CustomModelView(Model1, db.session, form_rules=('test2', 'test1', rules.Field('test4'))) admin.add_view(view) client = app.test_client() rv = client.get('/admin/model1/new/') eq_(rv.status_code, 200) data = rv.data.decode('utf-8') pos1 = data.find('Test1') pos2 = data.find('Test2') pos3 = data.find('Test3') pos4 = data.find('Test4') ok_(pos1 > pos2) ok_(pos4 > pos1) ok_(pos3 == -1)
def test_form_rules(): app, db, admin = setup() Model1, _ = create_models(db) db.create_all() view = CustomModelView(Model1, db.session, form_rules=("test2", "test1", rules.Field("test4"))) admin.add_view(view) client = app.test_client() rv = client.get("/admin/model1/new/") eq_(rv.status_code, 200) data = rv.data.decode("utf-8") pos1 = data.find("Test1") pos2 = data.find("Test2") pos3 = data.find("Test3") pos4 = data.find("Test4") ok_(pos1 > pos2) ok_(pos4 > pos1) ok_(pos3 == -1)
class ToolModelView(ModelView): can_create = False can_edit = False form_rules = [ rules.FieldSet((), u'工具详情'), rules.Field(u'project_title'), rules.Field(u'size'), rules.Field(u'name'), rules.Field(u'description'), rules.Field(u'number'), rules.Header(u'校验'), rules.Field(u'belong'), ] column_editable_list = ('size', ) column_searchable_list = ('project_title', ) column_sortable_list = ('project_title', 'name') column_exclude_list = ('belong', ) column_labels = dict(project_title=u'项目', name=u'名称', size=u'尺寸', number=u'数量', description=u'备注', belong=u'校验') column_descriptions = dict(project_title=u'''工具所用于的拆装项目, 请保证 "Belong"列的内容与项目名一致(例如 "737更换滑行灯工具"对应 "<"Object 737更换滑行灯工具">"), 保证录入工具和拆装项目匹配''', number=u'若不填,系统默认为 1', name=u'工具的名称', size=u'工具的大小或者尺寸')
class RegistrationRequestView(OrgRequestViewMixin, CustomWithInlineFormsModelView): column_searchable_list = [ 'status', 'ticket_id', 'org_id', 'actual_name', 'email' ] column_list = [ 'id', 'submitted_on', 'modified_on', 'status', 'ticket_id', 'org_id', 'actual_name', 'email', 'email_notification_language', ] column_descriptions = { 'terms_version': 'The version of the legal terms accepted by the client.', 'terms_lang': 'The language variant of the legal terms accepted by the client.', } form_extra_fields = { org_request_helpers.ACTIONS_FIELD_NAME: org_request_helpers.ACTIONS_FIELD_FOR_REGISTRATION, } form_columns = [ 'id', 'submitted_on', 'modified_on', 'status', 'ticket_id', 'org_group', org_request_helpers.ACTIONS_FIELD_NAME, 'org_id', 'actual_name', 'email', 'submitter_title', 'submitter_firstname_and_surname', 'csr', 'email_notification_language', 'email_notification_addresses', 'asns', 'fqdns', 'ip_networks', 'terms_version', 'terms_lang', ] form_widget_args = { # Let it be visible but inactive. (State changes # can be made only with the custom buttons which # fill out the target-status-dedicated invisible # input; that input and those buttons are provided # by `org_request_helpers.ACTIONS_FIELD...` # -- see `form_extra_fields` below.) 'status': { 'disabled': True }, 'terms_version': { 'readonly': True }, 'terms_lang': { 'readonly': True }, } form_rules = [ rules.Header('Registration request consideration'), rules.Field('status'), rules.Field('ticket_id'), rules.Field('org_group'), rules.Field(org_request_helpers.ACTIONS_FIELD_NAME), rules.Header('Basic and access-related data'), rules.Field('org_id'), rules.Field('actual_name'), rules.Field('email'), rules.Field('submitter_title'), rules.Field('submitter_firstname_and_surname'), rules.Field('csr'), rules.Header('"Inside" event criteria'), rules.Field('asns'), rules.Field('fqdns'), rules.Field('ip_networks'), rules.Header('E-mail notifications preferences'), rules.Field('email_notification_language'), rules.Field('email_notification_addresses'), rules.Header('Legal information'), rules.Field('terms_version'), rules.Field('terms_lang'), ] org_request_handler_kit = org_request_helpers.registration_request_handler_kit inline_models = [ RegistrationRequestEMailNotificationAddress, RegistrationRequestASN, RegistrationRequestFQDN, RegistrationRequestIPNetwork, ]
class NodeView(ModelView): column_list = [ 'cluster', 'fqdn', 'ip', 'maintenance_mode', 'wipe_root_disk_next_boot', 'credentials', 'ignition_config', ] list_template = 'admin/node_list.html' details_template = 'admin/node_details.html' form_excluded_columns = [ 'credentials', 'target_config_version', 'active_config_version', 'active_ignition_config', ] column_formatters = { 'credentials': macro('render_credentials'), 'ignition_config': macro('render_ignition_config'), } column_labels = { 'ip': "Public IP", 'fqdn': "Fully Qualified Domain Name", 'maintenance_mode': "Maintenance mode", 'coreos_autologin': "******", 'root_disk': "Root disk device", 'wipe_root_disk_next_boot': "Wipe root disk on next boot", 'root_disk_size_sectors': "Size of root partition (in sectors)", 'linux_consoles': "Linux console devices", 'disable_ipv6': "Disable IPv6 in Linux kernel", 'is_etcd_server': "etcd server", 'is_k8s_schedulable': "Kubernetes schedulable", 'is_k8s_master': "Kubernetes master", 'mountpoints': 'Additional mountpoints', 'addresses': 'Additional IP addresses', } column_descriptions = { 'maintenance_mode': "If this is enabled, node will be booted in minimal CoreOS environment without " "touching root partition.", 'coreos_autologin': "******" "for debugging. Don't enable in production.", 'root_disk': "First partition of this disk will be wiped on every boot. CoreOS will use it to store " "volatile data.", 'wipe_root_disk_next_boot': "If this is set, node's root disk partition table will be wiped on next boot. " "This option will be automatically disabled on next provisiton report.", 'root_disk_size_sectors': "Used during root disk wiping. (Typically one sector is 512 bytes.)", 'linux_consoles': "Passed to kernel as `console` arguments. (Separate by comma.)", 'disable_ipv6': "Passed to kernel as `ipv6.disable=1` argument.", 'is_etcd_server': "Run etcd server on this node and connect other nodes to it.", 'is_k8s_schedulable': "Run kubelet on this node and register it as schedulable.", 'is_k8s_master': "Run kubelet on this node and add persistent kube-apiserver, kube-controller-manager, " "kube-scheduler pods to it.", } # TODO: with `inline_models` `on_model_change` doesn't get called pre save inline_models_disabled = [ (models.Mountpoint, { 'column_descriptions': { 'what': 'Device to mount.', 'where': 'Mount path.', 'wanted_by': 'WantedBy systemd unit.', } }), (models.Address, { 'column_descriptions': { 'interface': 'Network interface.', 'ip': 'IP address.', } }), ] form_rules = [ rules.Field('cluster'), rules.Field('ip'), rules.Field('fqdn'), rules.FieldSet([ 'maintenance_mode', 'coreos_autologin', 'root_disk', 'wipe_root_disk_next_boot', 'root_disk_size_sectors', 'linux_consoles', 'disable_ipv6', 'mountpoints', 'addresses', ], 'Boot'), rules.FieldSet([ 'is_etcd_server', 'is_k8s_schedulable', 'is_k8s_master', ], 'Components'), ] def _issue_creds(self, model): with self.session.no_autoflush: ca_creds = model.cluster.ca_credentials creds = models.CredentialsData() creds.cert, creds.key = pki.issue_certificate( 'system:node:' + model.fqdn, ca_cert=ca_creds.cert, ca_key=ca_creds.key, organizations=['system:nodes'], san_dns=model.certificate_alternative_dns_names, san_ips=model.certificate_alternative_ips, certify_days=10000, is_web_server=True, is_web_client=True) self.session.add(creds) model.credentials = creds def on_model_change(self, form, model, is_created): if is_created: self._issue_creds(model) model.active_ignition_config = '' else: model.target_config_version += 1 @expose('/reissue-credentials', methods=['POST']) def reissue_creds_view(self): model = self.get_one(request.args.get('id')) model.target_config_version += 1 self._issue_creds(model) self.session.add(model) self.session.commit() return_url = get_redirect_target() or self.get_url('.index_view') flash('The credentials successfully reissued', 'success') return redirect(return_url) @expose('/active-ignition.json') def active_ignition_config_view(self): node = self.get_one(request.args.get('id')) if not node.active_ignition_config: abort(404) data = json.loads(node.active_ignition_config) data = json.dumps(data, indent=2) return Response(data, mimetype='application/json') @expose('/target-ignition.json') def target_ignition_config_view(self): node = self.get_one(request.args.get('id')) response = config_renderer.ignition.render(node, indent=True) return Response(response, mimetype='application/json')
class IdentityView(ModelView): column_list = [ 'issuer', 'name', 'status', ] list_template = 'admin/identity_list.html' column_formatters = { 'status': macro('render_status'), } form_excluded_columns = [ 'name', 'issues', 'pairs', ] form_extra_fields = { 'subj_cn': fields.StringField('CN', description='Common Name', validators=required), 'subj_c': fields.StringField('C', description='Country'), 'subj_o': fields.StringField('O', description='Organization'), 'subj_ou': fields.StringField('OU', description='Organizational Unit'), 'subj_dnq': fields.StringField('', description='Distinguished name qualifier'), 'subj_st': fields.StringField('ST', description='State or province name'), 'subj_sn': fields.StringField('', description='Serial number'), 'cert_validate_since': fields.DateTimeField('Valid since', description='Not valid before', validators=required, default=default_since), 'cert_validate_till': fields.DateTimeField('Valid till', description='Not valid after', validators=required, default=default_till), 'cert_ca_path_length': fields.IntegerField('CA path length', default=0), 'san_ips': InlineFieldList(fields.StringField('IP', [validators.IPAddress()]), 'IP', description='IP address'), 'san_dns_names': InlineFieldList(fields.StringField('DNS'), 'DNS', description='DNS names'), 'ku_web_server_auth': fields.BooleanField('Web server auth', description='TLS Web Server Authentication'), 'ku_web_client_auth': fields.BooleanField('Web client auth', description='TLS Web Client Authentication'), 'key_size': fields.IntegerField('Size', default=2048), 'key_public_exponent': fields.IntegerField('Public exponent', default=65537), } form_rules = [ rules.Field('issuer'), rules.FieldSet([ 'cert_validate_since', 'cert_validate_till', 'cert_ca_path_length', ], 'Certificate settings'), rules.FieldSet([ 'subj_cn', 'subj_c', 'subj_o', 'subj_ou', 'subj_dnq', 'subj_st', 'subj_sn', ], 'Subject'), rules.FieldSet([ 'san_ips', 'san_dns_names', ], 'Subject Alternative Names'), rules.FieldSet([ 'ku_web_server_auth', 'ku_web_client_auth', ], 'Key Usage'), rules.FieldSet([ 'key_size', 'key_public_exponent', ], 'Key Settings'), ] def create_model(self, *args, **kwargs): with self.session.no_autoflush: return super().create_model(*args, **kwargs) def on_model_change(self, form, model, is_created): data = x509.CertInfo(form.data) if data.issuer: pair = models.Pair( *x509.issue_certificate(data, data.issuer.pair.as_tuple)) else: pair = models.Pair(*x509.issue_certificate(data)) model.pair = pair model.name = data.subj_cn @expose('/reissue/', methods=['POST']) def reissue_view(self): model = self.get_one(request.values.get('id')) info = x509.load_certificate_info(model.pair.as_tuple, reissue=True) if model.issuer: pair = models.Pair( *x509.issue_certificate(info, model.issuer.pair.as_tuple)) else: pair = models.Pair(*x509.issue_certificate(info)) model.pair = pair self.session.commit() return_url = get_redirect_target() or self.get_url('.index_view') flash('The identity certificate was successfully reissued', 'success') return redirect(return_url) def edit_form(self, obj=None): if obj: info = x509.load_certificate_info(obj.pair.as_tuple, reissue=True) for k, v in info.as_dict().items(): if not hasattr(obj, k): setattr(obj, k, v) return super().edit_form(obj) @expose('/details/') def details_view(self): model = self.get_one(request.values.get('id')) return_url = get_redirect_target() or self.get_url('.index_view') return redirect( self.get_url('pair.details_view', id=model.pair.id, url=return_url)) @expose('/import/', methods=['GET', 'POST']) def import_view(self): return_url = get_redirect_target() or self.get_url('.index_view') form = ImportForm(get_form_data()) if self.validate_form(form): pair_tuple = form.data['cert'].encode( 'ascii'), form.data['key'].encode('ascii') info = x509.load_certificate_info(pair_tuple) if not x509.does_keys_match(pair_tuple): flash('Failed to import identity: keys does not match.', 'error') return redirect(return_url) identity = models.Identity() identity.name = info.subj_cn if not info.self_signed: def find_issuer(): for issuer in models.Identity.query.filter_by( name=info.issuer_cn): cert_chain = issuer.get_cert_chain() try: x509.verify_certificate_chain( pair_tuple[0], cert_chain) except x509.InvalidCertificate: pass else: return issuer identity.issuer = find_issuer() if not identity.issuer: flash( 'Failed to import identity: issuer identity not found.', 'error') return redirect(return_url) self.session.add(identity) pair = models.Pair(*pair_tuple) pair.identity = identity self.session.add(pair) try: self.session.commit() except IntegrityError: flash( 'Failed to import identity: identity with same name already exists.', 'error') return redirect(return_url) flash('Identity was successfully imported.', 'success') return redirect(self.get_save_return_url(identity, is_created=True)) return self.render('admin/identity_import.html', form=form, return_url=return_url)
class OrgConfigUpdateRequestView(OrgRequestViewMixin, CustomWithInlineFormsModelView): column_searchable_list = ['status', 'ticket_id', 'org_id'] column_list = [ 'id', 'submitted_on', 'modified_on', 'status', 'ticket_id', 'org_id', ] form_extra_fields = { org_request_helpers.ACTIONS_FIELD_NAME: org_request_helpers.ACTIONS_FIELD_FOR_ORG_CONFIG_UPDATE, } form_columns = [ 'id', 'submitted_on', 'modified_on', 'status', 'ticket_id', 'org_id', 'requesting_user_login', 'additional_comment', org_request_helpers.ACTIONS_FIELD_NAME, 'actual_name_upd', 'actual_name', 'email_notification_enabled_upd', 'email_notification_enabled', 'email_notification_language_upd', 'email_notification_language', 'email_notification_addresses_upd', 'email_notification_addresses', 'email_notification_times_upd', 'email_notification_times', 'asns_upd', 'asns', 'fqdns_upd', 'fqdns', 'ip_networks_upd', 'ip_networks', ] form_widget_args = { # Let it be visible but inactive. (State changes # can be made only with the custom buttons which # fill out the target-status-dedicated invisible # input; that input and those buttons are provided # by `org_request_helpers.ACTIONS_FIELD...` # -- see `form_extra_fields` below.) 'status': { 'disabled': True }, 'org_id': { 'readonly': True }, 'requesting_user_login': { 'readonly': True }, 'additional_comment': { 'readonly': True }, } form_rules = [ rules.Header('Org config update request consideration'), rules.Field('status'), rules.Field('ticket_id'), rules.Field('org_id'), rules.Field('requesting_user_login'), rules.Field('additional_comment'), rules.Field(org_request_helpers.ACTIONS_FIELD_NAME), rules.Header('Updates of basic data'), rules.Field('actual_name_upd'), rules.Field('actual_name'), rules.Header('Updates of "Inside" event criteria'), rules.Field('asns_upd'), rules.Field('asns'), rules.Field('fqdns_upd'), rules.Field('fqdns'), rules.Field('ip_networks_upd'), rules.Field('ip_networks'), rules.Header('Updates of e-mail notifications preferences'), rules.Field('email_notification_enabled_upd'), rules.Field('email_notification_enabled'), rules.Field('email_notification_language_upd'), rules.Field('email_notification_language'), rules.Field('email_notification_addresses_upd'), rules.Field('email_notification_addresses'), rules.Field('email_notification_times_upd'), rules.Field('email_notification_times'), ] org_request_handler_kit = org_request_helpers.org_config_update_request_handler_kit inline_models = [ OrgConfigUpdateRequestEMailNotificationAddress, OrgConfigUpdateRequestEMailNotificationTime, OrgConfigUpdateRequestASN, OrgConfigUpdateRequestFQDN, OrgConfigUpdateRequestIPNetwork, ]
class NodeView(ModelView): column_list = [ 'cluster', 'fqdn', 'ip', 'maintenance_mode', 'credentials', 'config', ] list_template = 'admin/node_list.html' details_template = 'admin/node_details.html' form_excluded_columns = [ 'credentials', 'target_config_version', 'active_config_version', 'provisions', 'disks', ] column_formatters = { 'credentials': macro('render_credentials'), 'config': macro('render_config'), } column_labels = { 'ip': "Public IP", 'fqdn': "Fully Qualified Domain Name", 'maintenance_mode': "Maintenance mode", 'debug_boot': "Debug boot", 'coreos_autologin': "******", 'linux_consoles': "Linux console devices", 'disable_ipv6': "Disable IPv6 in Linux kernel", 'is_etcd_server': "etcd server", 'is_k8s_schedulable': "Kubernetes schedulable", 'is_k8s_master': "Kubernetes master", 'mountpoints': 'Additional mountpoints', 'addresses': 'Additional IP addresses', } column_descriptions = { 'maintenance_mode': "If this is enabled, node will be booted in minimal CoreOS environment without " "touching root partition.", 'debug_boot': "Forward all system journal messages to kmsg for troubleshooting.", 'coreos_autologin': "******" "for debugging. Don't enable in production.", 'linux_consoles': "Passed to kernel as `console` arguments. (Separate by comma.)", 'disable_ipv6': "Passed to kernel as `ipv6.disable=1` argument.", 'is_etcd_server': "Run etcd server on this node and connect other nodes to it.", 'is_k8s_schedulable': "Run kubelet on this node and register it as schedulable.", 'is_k8s_master': "Run kubelet on this node and add persistent kube-apiserver, kube-controller-manager, " "kube-scheduler pods to it.", } inline_models = [ (models.Mountpoint, { 'column_descriptions': { 'what': 'Device to mount.', 'where': 'Mount path.', 'wanted_by': 'WantedBy systemd unit.', 'is_persistent': 'Use this partition to store critical data that should survive reboots.', } }), (models.Address, { 'column_descriptions': { 'interface': 'Network interface.', 'ip': 'IP address.', } }), ] form_rules = [ rules.Field('cluster'), rules.Field('ip'), rules.Field('fqdn'), rules.FieldSet([ 'maintenance_mode', 'debug_boot', 'coreos_autologin', 'linux_consoles', 'disable_ipv6', 'mountpoints', 'addresses', 'additional_kernel_cmdline', ], 'Boot'), rules.FieldSet([ 'is_etcd_server', 'is_k8s_schedulable', 'is_k8s_master', ], 'Components'), ] # without this, Node is saved to database before on_model_change() gets called # and this happens only when there is inline_models def create_model(self, *args, **kwargs): with self.session.no_autoflush: return super().create_model(*args, **kwargs) def _issue_creds(self, model): with self.session.no_autoflush: ca_creds = model.cluster.ca_credentials creds = models.CredentialsData() creds.cert, creds.key = pki.issue_certificate('system:node:' + model.fqdn, ca_cert=ca_creds.cert, ca_key=ca_creds.key, organizations=['system:nodes'], san_dns=model.certificate_alternative_dns_names, san_ips=model.certificate_alternative_ips, certify_days=10000, is_web_server=True, is_web_client=True) self.session.add(creds) model.credentials = creds def on_model_change(self, form, model, is_created): if is_created: self._issue_creds(model) else: model.target_config_version += 1 def on_model_delete(self, model): model.mountpoints.delete() model.addresses.delete() def after_model_delete(self, model): models.CredentialsData.query.filter_by(id=model.credentials_id).delete() @expose('/reissue-credentials', methods=['POST']) def reissue_creds_view(self): model = self.get_one(request.args.get('id')) model.target_config_version += 1 self._issue_creds(model) self.session.add(model) self.session.commit() return_url = get_redirect_target() or self.get_url('.index_view') flash('The credentials successfully reissued', 'success') return redirect(return_url) @expose('/target-ignition.json') def target_ignition_config_view(self): node = self.get_one(request.args.get('id')) response = config_renderer.ignition.render(node, indent=True) return Response(response, mimetype='application/json') @expose('/target.ipxe') def target_ipxe_config_view(self): node = self.get_one(request.args.get('id')) response = config_renderer.ipxe.render(node, request.url_root) return Response(response, mimetype='text/plain')
READ_ONLY = {'readonly': True} class Form(FlaskForm): """Base class to customize wtforms""" _translations = Translations() Meta = AutoAttrMeta def _get_translations(self): return self._translations class CallableValidator(object): """ Takes a callable and validates using it """ def __init__(self, function, message=None): self.function = function self.message = message def __call__(self, form, field): validation = self.function(form, field) if validation is not None: raise ValidationError(self.message or validation) validators.CallableValidator = CallableValidator rules.csrf_token = rules.Field( 'csrf_token', render_field='quokka_macros.render_hidden_field')
class EntityView(CustomWithInlineFormsModelView): model_form_converter = ModelWithShortTimeFieldConverter can_view_details = True # essential to display PK column in the "list" view column_display_pk = True column_searchable_list = [ 'full_name', 'short_name', 'email', 'city', 'sector_label', 'ticket_id', ] column_list = [ 'full_name', 'short_name', 'email', 'city', 'sector_label', 'ticket_id', ] form_columns = [ # official data: 'id', 'full_name', 'short_name', 'verified', 'email', 'address', 'city', 'postal_code', 'public_essential_service', 'sector', 'ticket_id', 'internal_id', 'extra_ids', 'additional_information', 'asns', 'fqdns', 'ip_networks', 'alert_email', 'contact_points', 'dependant_entities', 'org', ] form_rules = [ rules.Header('Basic data'), rules.Field('full_name'), rules.Field('short_name'), rules.Field('verified'), rules.Field('email'), rules.Field('address'), rules.Field('city'), rules.Field('postal_code'), rules.Header('Supplementary data'), rules.Field('public_essential_service'), rules.Field('sector'), rules.Field('ticket_id'), rules.Field('internal_id'), rules.Field('extra_ids'), rules.Field('additional_information'), rules.Header('Own network data'), rules.Field('asns'), rules.Field('fqdns'), rules.Field('ip_networks'), rules.Header('Contact data'), rules.Field('alert_email'), rules.Field('contact_points'), rules.Header('Dependant entities'), rules.Field('dependant_entities'), rules.Header('Related n6 client Org'), rules.Field('org'), ] inline_models = [ EntityExtraId, EntityASN, EntityFQDN, EntityIPNetwork, EntityContactPointInlineFormAdmin(EntityContactPoint, db_session), DependantEntity, ]
class OrgView(ShowInlineStringPKModelView): # create_modal = True # edit_modal = True model_form_converter = OrgModelConverter column_descriptions = { 'org_id': 'Organization identifier', } can_view_details = True # essential to display PK column in the "list" view column_display_pk = True column_searchable_list = ['org_id'] column_list = [ 'org_id', 'full_access', # 'stream_api_enabled', # 'email_notifications_enabled', # 'email_notifications_business_days_only', 'access_to_inside', 'access_to_threats', 'access_to_search', ] form_columns = [ 'org_id', 'org_groups', 'users', 'full_access', 'access_to_inside', # 'inside_max_days_old', # 'inside_request_parameters', 'inside_subsources', 'inside_ex_subsources', 'inside_subsource_groups', 'inside_ex_subsource_groups', 'access_to_threats', # 'threats_max_days_old', # 'threats_request_parameters', 'threats_subsources', 'threats_ex_subsources', 'threats_subsource_groups', 'threats_ex_subsource_groups', 'access_to_search', # 'search_max_days_old', # 'search_request_parameters', 'search_subsources', 'search_ex_subsources', 'search_subsource_groups', 'search_ex_subsource_groups', # other options/notifications settings # 'stream_api_enabled', # 'email_notifications_enabled', # 'email_notifications_addresses', # 'email_notifications_times', # 'email_notifications_language', # 'email_notifications_business_days_only', 'inside_filter_asns', 'inside_filter_ccs', 'inside_filter_fqdns', 'inside_filter_ip_networks', 'inside_filter_urls', ] form_rules = [ rules.Header('Basic options for organization'), rules.Field('org_id'), rules.Field('org_groups'), rules.Field('full_access'), rules.Header('Users'), rules.Field('users'), rules.Header('"Inside" resource'), rules.Field('access_to_inside'), # rules.Field('inside_max_days_old'), # rules.Field('inside_request_parameters'), rules.Field('inside_subsources'), rules.Field('inside_ex_subsources'), rules.Field('inside_subsource_groups'), rules.Field('inside_ex_subsource_groups'), rules.Header('"Threats" resource'), rules.Field('access_to_threats'), # rules.Field('threats_max_days_old'), # rules.Field('threats_request_parameters'), rules.Field('threats_subsources'), rules.Field('threats_ex_subsources'), rules.Field('threats_subsource_groups'), rules.Field('threats_ex_subsource_groups'), rules.Header('"Search" resource'), rules.Field('access_to_search'), # rules.Field('search_max_days_old'), # rules.Field('search_request_parameters'), rules.Field('search_subsources'), rules.Field('search_ex_subsources'), rules.Field('search_subsource_groups'), rules.Field('search_ex_subsource_groups'), # rules.Header('Other options'), # rules.Field('stream_api_enabled'), # rules.Field('email_notifications_enabled'), # rules.Field('email_notifications_addresses'), # rules.Field('email_notifications_times'), # rules.Field('email_notifications_language'), # rules.Field('email_notifications_business_days_only'), rules.Header('Criteria for "Inside" (n6filter)'), rules.Field('inside_filter_asns'), rules.Field('inside_filter_ccs'), rules.Field('inside_filter_fqdns'), rules.Field('inside_filter_ip_networks'), rules.Field('inside_filter_urls'), ] inline_models = [ UserInlineFormAdmin(User), EMailNotificationAddress, NotificationTimeInlineFormAdmin(EMailNotificationTime), InsideFilterASN, InsideFilterCC, InsideFilterFQDN, InsideFilterIPNetwork, InsideFilterURL, ]
def edit_form_rules(self): if not has_app_context() or current_user.has_role('reviewer1'): edit_form_rules = [ rules.Header('Personal Info'), rules.Field('team'), rules.Field('name'), rules.Header('Project Info'), rules.Field('project_name'), rules.Field('version'), rules.Field('SVN'), #rules.Field('submitted_at'), CustomizableField('notes', field_args={'readonly': False}), rules.Header('Reviewers'), CustomizableField('reviewer1', field_args={'readonly': True}), rules.Field('comment1'), CustomizableField('reviewer2', field_args={'readonly': True}), CustomizableField('comment2', field_args={'readonly': True}), CustomizableField('review1', field_args={'readonly': True}), #rules.Field('reviewers'), ] if not has_app_context() or current_user.has_role('reviewer2'): edit_form_rules = [ rules.Header('Personal Info'), rules.Field('team'), rules.Field('name'), rules.Header('Project Info'), rules.Field('project_name'), rules.Field('version'), rules.Field('SVN'), #rules.Field('submitted_at'), CustomizableField('notes', field_args={'readonly': False}), rules.Header('Reviewers'), CustomizableField('reviewer1', field_args={'readonly': False}), CustomizableField('comment1', field_args={'readonly': True}), CustomizableField('reviewer2', field_args={'readonly': False}), rules.Field('comment2'), CustomizableField('review2', field_args={'readonly': True}), #rules.Field('reviewers'), ] if not has_app_context() or current_user.has_role('user'): edit_form_rules = [ rules.Header('Personal Info'), CustomizableField('team', field_args={'readonly': True}), CustomizableField('name', field_args={'readonly': True}), rules.Header('Project Info'), CustomizableField('project_name', field_args={'readonly': False}), #rules.Field('project_name'), CustomizableField('version', field_args={'readonly': False}), #rules.Field('version'), rules.Field('SVN'), #rules.Field('submitted_at'), rules.Field('notes'), rules.Header('Reviewers'), rules.Field('reviewer1'), #CustomizableField('reviewer1', field_args={ # 'readonly': not self.model.approve #}), CustomizableField('comment1', field_args={'readonly': True}), rules.Field('reviewer2'), CustomizableField('comment2', field_args={'readonly': True}), #rules.Field('reviewers'), #CustomizableField('review2', field_args={ # 'readonly': True #}), ] if not has_app_context() or current_user.has_role( 'superuser') or current_user.has_role('administrator'): edit_form_rules = [ rules.Header('Personal Info'), rules.Field('team'), rules.Field('name'), rules.Header('Project Info'), rules.Field('project_name'), rules.Field('version'), rules.Field('SVN'), #rules.Field('submitted_at'), rules.Field('notes'), rules.Header('Reviewers'), CustomizableField('reviewer1', field_args={'readonly': False}), CustomizableField('comment1', field_args={'readonly': False}), rules.Field('review1'), CustomizableField('reviewer2', field_args={'readonly': False}), CustomizableField('comment2', field_args={'readonly': False}), rules.Field('review2'), rules.Field('comment3'), rules.Field('approve'), #rules.Field('reviewers'), ] ''' if not has_app_context() or current_user.has_role('superuser'): edit_form_rules.append('approve') if not has_app_context() or current_user.has_role('reviewer1'): edit_form_rules.append('review1') if not has_app_context() or current_user.has_role('reviewer2'): edit_form_rules.append('review2') ''' return edit_form_rules
class OrgView(CustomWithInlineFormsModelView): # create_modal = True # edit_modal = True model_form_converter = ModelWithShortTimeFieldConverter column_descriptions = { 'org_id': "Organization's identifier (domain name).", } can_view_details = True # essential to display PK column in the "list" view column_display_pk = True column_searchable_list = ['org_id'] column_list = [ 'org_id', 'actual_name', 'full_access', # 'stream_api_enabled', # 'email_notification_enabled', # 'email_notification_business_days_only', 'access_to_inside', 'access_to_threats', 'access_to_search', ] form_columns = [ 'org_id', 'actual_name', 'org_groups', 'users', 'entity', 'full_access', 'stream_api_enabled', # authorization: 'access_to_inside', 'inside_subsources', 'inside_off_subsources', 'inside_subsource_groups', 'inside_off_subsource_groups', 'access_to_threats', 'threats_subsources', 'threats_off_subsources', 'threats_subsource_groups', 'threats_off_subsource_groups', 'access_to_search', 'search_subsources', 'search_off_subsources', 'search_subsource_groups', 'search_off_subsource_groups', # notification settings: 'email_notification_enabled', 'email_notification_addresses', 'email_notification_times', 'email_notification_language', 'email_notification_business_days_only', # filter-related options: 'inside_filter_asns', 'inside_filter_ccs', 'inside_filter_fqdns', 'inside_filter_ip_networks', 'inside_filter_urls', ] form_rules = [ rules.Header('Organization basic data'), rules.Field('org_id'), rules.Field('actual_name'), rules.Field('full_access'), rules.Field('stream_api_enabled'), rules.Header('Groups and users'), rules.Field('org_groups'), rules.Field('users'), rules.Header('"Inside" access zone'), rules.Field('access_to_inside'), rules.Field('inside_subsources'), rules.Field('inside_off_subsources'), rules.Field('inside_subsource_groups'), rules.Field('inside_off_subsource_groups'), rules.Header('"Threats" access zone'), rules.Field('access_to_threats'), rules.Field('threats_subsources'), rules.Field('threats_off_subsources'), rules.Field('threats_subsource_groups'), rules.Field('threats_off_subsource_groups'), rules.Header('"Search" access zone'), rules.Field('access_to_search'), rules.Field('search_subsources'), rules.Field('search_off_subsources'), rules.Field('search_subsource_groups'), rules.Field('search_off_subsource_groups'), rules.Header('E-mail notification settings'), rules.Field('email_notification_enabled'), rules.Field('email_notification_addresses'), rules.Field('email_notification_times'), rules.Field('email_notification_language'), rules.Field('email_notification_business_days_only'), rules.Header('"Inside" event criteria (checked by n6filter)'), rules.Field('inside_filter_asns'), rules.Field('inside_filter_ccs'), rules.Field('inside_filter_fqdns'), rules.Field('inside_filter_ip_networks'), rules.Field('inside_filter_urls'), rules.Header('Related entity'), rules.Field('entity'), ] inline_models = [ UserInlineFormAdmin(User), EMailNotificationAddress, NotificationTimeInlineFormAdmin(EMailNotificationTime), InsideFilterASN, InsideFilterCC, InsideFilterFQDN, InsideFilterIPNetwork, InsideFilterURL, ]
class UserView(MyModelView): #id, username, confirmed, email, __password_hash, role_id, location, about_me, member_since, last_seen can_view_details = True # show a modal dialog with records details form_widget_args = {'id': {'readonly': True}} column_list = [ 'id', 'role_id', 'username', 'confirmed', 'email', 'location', 'about_me', 'member_since', 'last_seen' ] column_auto_select_related = True column_searchable_list = [ 'id', 'role_id', 'username', 'confirmed', 'email', 'location', 'about_me', 'member_since', 'last_seen' ] column_editable_list = [ 'username', 'confirmed', 'email', 'location', 'about_me', 'member_since', ] column_default_sort = [('username', False), ('last_seen', False)] # sort on multiple columns # custom filter: each filter in the list is a filter operation (equals, not equals, etc) # filters with the same name will appear as operations under the same filter column_filters = [ 'username', FilterEqual(column=User.username, name='User Name'), #FilterLastNameBrown(column=User.last_name, name='Last Name', # options=(('1', 'Yes'), ('0', 'No'))), 'member_since', 'email', 'confirmed', 'last_seen', 'location', ] # column_formatters = {'phone_number': phone_number_formatter} # setup edit forms so that only posts created by this user can be selected as 'featured' form_create_rules = [ # Header and four fields. Email field will go above phone field. rules.FieldSet(('username', 'email', 'role', 'confirmed', 'member_since', 'last_seen'), 'Personal'), # Separate header and few fields rules.Header('Location'), rules.Field('location'), # String is resolved to form field, so there's no need to explicitly use `rules.Field` # Show macro that's included in the templates rules.Container('rule_demo.wrap', rules.Field('about_me')) ] form_edit_rules = form_create_rules create_template = 'admin/create_user.html' edit_template = 'admin/edit_user.html' def edit_form(self, obj): return self._filtered_roles(super(UserView, self).edit_form(obj)) def _filtered_roles(self, form): form.role.query_factory = lambda: Role.query.filter( Role.permission == form._obj.id).all() return form