Beispiel #1
0
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
Beispiel #2
0
class ConferenceUser(UserModelView, ConferenceAdmin):
    column_list = ['number', 'name', 'is_public', 'is_locked',
                   'participant_count', 'invited_participant_count']
    form_create_rules = form_edit_rules = [
        rules.FieldSet(
            ('number', 'name', 'conference_profile'),
            _('Basic Settings')
        ),
        rules.FieldSet(
            ('is_public', 'public_participant_profile'),
            _('Open Access')
        ),
        rules.FieldSet(
            (rules.Macro('conference_participants_link'),),
            _('Participants')
        ),
    ]

    @expose('/details/')
    def details_view(self):
        conf = Conference.query.get_or_404(request.args.get('id', 0))
        self._template_args['confbridge_participants'] = \
            confbridge_list_participants(conf.number)
        self._template_args['confbridge'] = confbridge_get(conf.number)
        return super(ModelView, self).details_view()
Beispiel #3
0
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")
    ]
Beispiel #4
0
class CompanyView(AdminView):
    form = CompanyForm
    column_list = ['id'] + [
        'equipement', 'transport', 'restauration', 'badges', 'programme'
    ]
    export_types = [
        'equipement', 'transport', 'restauration', 'badges', 'programme',
        'secteurs'
    ]
    form_rules = [
        rules.FieldSet(('id', 'password', 'name', 'pole', 'zone'), 'Profil'),
        rules.FieldSet(
            ('equipement', 'restauration', 'badges', 'programme', 'transport'),
            'Suivi'),
        rules.FieldSet(('acompte', ), 'Finances'),
        rules.FieldSet(('size', 'duration', 'equiped', 'emplacement'),
                       'Equipement'),
    ]
    can_export = True
    can_delete = False
    column_searchable_list = ['id']
    column_sortable_list = ['id']
    column_filters = (FilterField(column='pole',
                                  name='pole',
                                  options=(('fra', 'Entreprises France'),
                                           ('si', 'Section Internationale'),
                                           ('cm', 'Carrefour Maghrebin'),
                                           ('school', 'Ecoles'),
                                           ('startup', 'Start-Up'))),
                      FilterField(column='zone',
                                  name='zone',
                                  options=[["zone{}".format(i)] * 2
                                           for i in range(1, 10)]),
                      FilterField(column='duration',
                                  name='jours',
                                  options=[('wed', 'Mercredi'),
                                           ('thu', 'Jeudi')]))
    column_labels = dict(id='Identifiant')
    column_formatters = dict(id=formatter)

    @expose('/export/<export_type>/')
    def export(self, export_type):
        return _export(self, export_type)

    def _on_model_change(self, form, model, is_created):
        if is_created:
            model['sections'] = {
                'furnitures': {},
                'catering': {
                    'wed': {},
                    'thu': {}
                },
                'events': {},
                'persons': [],
                'transports': [],
                'profile': {
                    'stand': {},
                    'facturation': {}
                }
            }
Beispiel #5
0
class UserAdminView(CustomBaseView):

    column_list = ['id', 'email', 'username', 'join_time']
    column_details_exclude_list = ['password', 'avatar_hash']
    column_editable_list = ['email', 'username']
    column_searchable_list = ['email', 'username']
    column_sortable_list = ['id', 'join_time']
    column_default_sort = 'id'

    form_excluded_columns = ['password_hash', 'avatar_hash']
    form_rules = [
        rules.FieldSet(
            ('email', 'username', 'name'),
            'Basic Informations',
        ),
        'about_me',
        'location',
        rules.FieldSet(
            ('role', ),
            'Roles',
        ),
        'is_active',
    ]
    form_widget_args = {
        'is_active': {
            'column_class': 'form-check',
            'class': 'form-check-input',
            'label_class': 'form-check-label',
        }
    }
Beispiel #6
0
class UserAdminView(ModelView, ActionsMixin):
    column_searchable_list = ('username', )
    column_sortable_list = ('username', 'admin')
    column_exclude_list = ('password', )
    form_excluded_columns = ('password', )

    # form_edit_rules = ('username', 'admin',)
    form_edit_rules = (rules.Header('Edit info for:'), 'username', 'admin',
                       'notes', rules.Header('Reset Password'), 'new_password',
                       'confirm')
    # form_create_rules = ('username', 'admin', 'email', 'notes', 'password')

    form_create_rules = (
        rules.FieldSet(('username', 'notes', 'email'), 'Personal'),
        rules.FieldSet(('admin', 'password'), 'Permission'),
    )

    def is_accessible(self):
        return current_user.is_authenticated and current_user.is_admin()

    def inaccessible_callback(self, name, *kwargs):
        return redirect(url_for('home', next=request.url))

    def scaffold_form(self):
        form_class = super(UserAdminView, self).scaffold_form()
        form_class.password = PasswordField('Password')
        form_class.new_password = PasswordField('New Password')
        form_class.confirm = PasswordField('Confirm_ New Password')
        return form_class

    def create_model(self, form):
        model = self.model(form.username.data, form.password.data,
                           form.admin.data)
        form.populate_obj(model)
        model.password = bcrypt.generate_password_hash(form.password.data)
        self.session.add(model)
        self._on_model_change(form, model, True)
        self.session.commit()

    form_overrides = dict(notes=CKTextAreaField)
    create_template = 'edit.html'
    edit_template = 'edit.html'

    def update_model(self, form, model):
        form.populate_obj(model)
        if form.new_password.data:
            if form.new_password.data != form.confirm.data:
                flash('Passwords must match!!!')
                return
            model.password = bcrypt.generate_password_hash(
                form.new_password.data)
        self.session.add(model)
        self._on_model_change(form, model, False)
        self.session.commit()
Beispiel #7
0
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
Beispiel #8
0
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'用于程序搜索文档使用,无参考意义', )
Beispiel #9
0
def test_rule_field_set():
    app, db, admin = setup()

    Model1, _ = create_models(db)
    db.create_all()

    view = CustomModelView(
        Model1,
        db.session,
        form_create_rules=(rules.FieldSet(["test2", "test1", "test4"],
                                          "header"), ),
    )
    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")
    ok_("<h3>header</h3>" in data)
    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)
Beispiel #10
0
def test_rule_field_set():
    app, db, admin = setup()

    Model1, _ = create_models(db)
    db.create_all()

    view = CustomModelView(Model1,
                           db.session,
                           form_create_rules=(rules.FieldSet(
                               ['test2', 'test1', 'test4'], 'header'), ))
    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')
    ok_('<h3>header</h3>' in data)
    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)
Beispiel #11
0
class CommitteeMeetingView(EventView):
    column_list = ('date', 'title', 'committee', 'featured')
    column_labels = {
        'committee': 'Committee',
    }
    column_sortable_list = (
        'date',
        ('committee', 'committee.name'),
    )
    column_default_sort = (Event.date, True)
    column_searchable_list = ('committee.name', 'title')
    column_filters = ['committee.name', 'date']
    column_export_exclude_list = ['summary', 'body']
    form_edit_rules = ('committee', 'title', 'date', 'chairperson', 'featured',
                       'public_participation', 'bills', 'summary', 'body',
                       'files',
                       rules.FieldSet([
                           'actual_start_time', 'actual_end_time', 'attendance'
                       ], 'Member Attendance Record'))
    form_create_rules = form_edit_rules
    form_args = {
        'summary': {
            'default': '<p>Report of the meeting to follow.</p>'
        },
        'committee': {
            'validators': [data_required()]
        },
        'files': {
            'widget': widgets.InlineFileWidget()
        },
    }
    form_widget_args = {
        'body': {
            'class': 'ckeditor'
        },
        'summary': {
            'class': 'ckeditor'
        }
    }
    form_ajax_refs = {'bills': {'fields': ('title', ), 'page_size': 50}}
    inline_models = [
        InlineFile(EventFile),
        InlineCommitteeMeetingAttendance(CommitteeMeetingAttendance),
    ]

    def on_model_change(self, form, model, is_created):
        super(CommitteeMeetingView,
              self).on_model_change(form, model, is_created)
        # make sure the new times are timezone aware
        for attr in ['actual_start_time', 'actual_end_time']:
            if getattr(model, attr):
                setattr(model, attr, getattr(model, attr).replace(tzinfo=SAST))

        if model.committee.ad_hoc:
            # reset the active flag on this ad-hoc committee?
            self.session.flush()
            model.committee.reset_active()
class StaticPageModelView(CKEditorMixin, OrderableModelViewMixin, SecureModelView):

    column_list = ["name"]
    form_overrides = {"text": CKTextAreaField}
    form_rules = [rules.FieldSet(["name", "text"])]
    column_labels = {
        "name": "Name",
        "text": "Text",
    }
Beispiel #13
0
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",
        ),
    ]
Beispiel #14
0
def generate_rules(enabled: list, disabled: list):
    ''' Returns list of enable\disable rules for views. '''

    form_edit_rules = [rules.FieldSet(enabled)]

    for field in disabled:
        disabled_field = CustomizableField(field,
                                           field_args={'disabled': True})
        form_edit_rules.append(disabled_field)

    return form_edit_rules
class UserModelView(SuperuserModelView):
    """ModelView for user management."""
    column_list = ["username", "role", "email"]

    form_rules = [
        rules.FieldSet(("username", "role", "email", "password"))
    ]

    form_extra_fields = {
        "password": PasswordField("Password")
    }
Beispiel #16
0
class CategoryAdminView(CustomBaseView):

    column_list = ['id', 'name', 'level', 'create_time']
    column_editable_list = ['name']
    column_sortable_list = ['name', 'create_time']
    column_default_sort = 'id'
    column_filters = ['name']
    column_searchable_list = ['name']

    form_columns = [
        'name', 'level', 'parent', 'posts', 'is_nav', 'description'
    ]
    form_excluded_columns = ['create_time']
    form_args = {
        'name': {
            'validators': [DataRequired()],
        },
    }
    form_rules = [
        rules.FieldSet(
            ('name', ),
            'Information',
        ), 'description',
        rules.FieldSet(
            ('parent', 'level'),
            'Classification',
        ),
        rules.FieldSet(
            ('posts', ),
            'Inclusion',
        ), 'is_nav'
    ]
    form_widget_args = {
        'is_nav': {
            'column_class': 'form-check',
            'class': 'form-check-input',
            'label_class': 'form-check-label',
        }
    }
Beispiel #17
0
class PostBlogModelView(ModelView):

    # can_delete = False  # disable model deletion
    # page_size = 50  # the number of entries to display on the list view

    # column_exclude_list = ['comments','timestamp']

    # column_searchable_list = ('headline',)
    # column_filters = ('category', 'headline','body')

    #form_create_rules = ('category', 'tags','comments','headline','body','timestamp','timestamp','author')

    #form_create_rules = [
    # Header and four fields. Email field will go above phone field.
    #rules.FieldSet(('headline', 'body', ), 'Blog'),
    # Separate header and few fields
    #rules.Header('Author'),
    #rules.Field('author'),
    # 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('admin/rule_dm.wrap', rules.Field('timestamp'))
    #]

    # Use same rule set for edit page
    #form_edit_rules = form_create_rules

    # form_args = {
    # 'headline':{
    # 'label':'Title'
    # },
    # 'body':{
    # 'label':'Blog Html'
    # }
    # }
    #add additional args
    # form_widget_args = {
    # 'body': {
    # 'rows': 10,
    # 'style': 'color: black',
    # 'id':'editor1'
    # }
    # }

    form_create_rules = (
        rules.FieldSet(('headline', 'body', 'timestamp'), 'Blogsr rel'),
        #rules.FieldSet(('category', 'tags', 'comments'), 'Permission'),
    )

    create_template = 'blog_create.html'
Beispiel #18
0
class ReportMgmtViewAdmin(ReportModel):
    can_delete = False
    create_template = "no_rbac/report_create_form.html"
    edit_template = "no_rbac/report_edit_form.html"
    form_rules = [
        rules.FieldSet(("report_id", "schedule_timezone"), ""),
        rules.FieldSet(
            ("report_title", "description", "owner_name", "owner_email",
             "subscribers"),
            "General",
        ),
        rules.FieldSet(
            ("schedule_type", "schedule_time", "schedule_week_day",
             "schedule_custom"),
            "Schedule",
        ),
        rules.FieldSet(("tests", ), "Tests"),
    ]

    # We're doing this to hide the view from the main
    # menu and keep access in the /reports/ endpoint
    def is_visible(self):
        return False
Beispiel #19
0
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'
Beispiel #20
0
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'
Beispiel #21
0
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'
Beispiel #22
0
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 ProdutoView(ModelView):
    column_list = ('codigo', 'nome', 'valor', 'quantidade')
    column_editable_list = ('nome', 'valor', 'quantidade')
    form_args = {
        'nome': {
            'label': 'Nome',
            'validators': [required()]
        },
        'codigo': {
            'label': 'Codigo',
            'validators': [required()]
        },
        'valor': {
            'label': 'Preço',
            'validators': [required()]
        },
        'quantidade': {
            'label': 'Quantidade',
            'validators': [required()]
        }
    }
    form_edit_rules = [rules.FieldSet(('nome', 'valor', 'quantidade'))]
Beispiel #24
0
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"
Beispiel #25
0
class CarAdmin(ModelView):
    form_rules = [
        rules.FieldSet(('desc', 'cartype', rules.HTML('<br><br>'), 'comment'),
                       'Details')
    ]
    form_widget_args = {
        'cartype': {
            'style': 'color: black'
        },
        'desc': {
            'style': 'color: black',
            #'readonly': True
        },
        'comment': {
            'rows': 4,
            'style': 'color: red',
        }
    }
    form_overrides = dict(cartype=RadioField)
    form_args = dict(cartype=dict(
        choices=[('Compact',
                  'Compact'), ('Mid-size',
                               'Mid-size'), ('Pickup-Truck', 'Pickup Truck')]))
Beispiel #26
0
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'工具的大小或者尺寸')
Beispiel #27
0
class ParticipantProfileAdmin(ModelView, AuthBaseView):
    """Class that repesents confbridge user profiles"""
    column_list = ['name', 'legend']
    column_formatters = {
        'legend': lambda v, c, m, n: legend_formatter(v, c, m, n),
    }
    can_view_details = True
    form_args = {
        'name': {
            'validators': [Required()]
        },
        'music_on_hold_class': {
            'validators': [Required()]
        }
    }
    form_create_rules = form_edit_rules = [
        'name',
        rules.FieldSet((
            'admin',
            'marked',
            'pin',
            'startmuted',
            'quiet',
            'wait_marked',
            'end_marked',
            'music_on_hold_when_empty',
            'music_on_hold_class',
        ), _('Basic')),
        rules.FieldSet((
            'announce_user_count',
            'announce_user_count_all',
            'announce_only_user',
            'announcement',
            'announce_join_leave',
        ), _('Announcements')),
        rules.FieldSet((
            'dsp_drop_silence',
            'dsp_talking_threshold',
            'dsp_silence_threshold',
            'talk_detection_events',
            'denoise',
            'jitterbuffer',
            'dtmf_passthrough',
        ), _('Voice Processing'))
    ]
    column_labels = {
        'name': _('Profile Name'),
        'legend': _('Legend'),
    }
    """ # I'don want to tranlate asterisk profile setting names
        'admin': _('Admin'),
        'marked': _('Marked'),
        'pin': _('PIN'),
        'startmuted': _('Start Muted'),
        'quiet': _('Quiet'),
        'wait_marked': _('Wait Marked'),
        'end_marked': _('End Marked'),
        'music_on_hold_when_empty': _('Music On Hold When Empty'),
        'music_on_hold_class': _(''),
    """
    column_descriptions = {
        'admin':
        _('Sets if the user is an Admin or not. By default, no.'),
        'marked':
        _('Sets if the user is Marked or not. By default, no.'),
        'startmuted':
        _('Sets if the user should start out muted. By default, no.'),
        'pin':
        _('Sets if the user must enter a PIN before joining the conference. The user will be prompted for the PIN.'
          ),
        'startmuted':
        _('Sets if the user should start out muted. By default, no.'),
        'quiet':
        _('When set, enter/leave prompts and user introductions are not played. By default, no.'
          ),
        'wait_marked':
        _('Sets if the user must wait for another marked user to enter before joining the conference. By default, no.'
          ),
        'end_marked':
        _('If enabled, every user with this option in their profile will be removed from the conference when the last marked user exists the conference.'
          ),
        'dtmf_passthrough':
        _('Whether or not DTMF received from users should pass through the conference to other users. By default, no.'
          ),
        'music_on_hold_when_empty':
        _('Sets whether music on hold should be played when only one person is in the conference or when the user is waiting on a marked user to enter the conference. By default, off.'
          ),
        'music_on_hold_class':
        _('Sets the music on hold class to use for music on hold.'),
        'announce_user_count':
        _('Sets if the number of users in the conference should be announced to the caller. By default, no.'
          ),
        'announce_user_count_all':
        _('Choices: yes, no, integer. Sets if the number of users should be announced to all other users in the conference when someone joins. When set to a number, the announcement will only occur once the user count is above the specified number'
          ),
        'announce_only_user':
        _('Sets if the only user announcement should be played when someone enters an empty conference. By default, yes.'
          ),
        'announcement':
        _('If set, the sound file specified by filename will be played to the user, and only the user, upon joining the conference bridge.'
          ),
        'announce_join_leave':
        _('When enabled, this option prompts the user for their name when entering the conference. After the name is recorded, it will be played as the user enters and exists the conference. By default, no.'
          ),
        'dsp_drop_silence':
        _('Drops what Asterisk detects as silence from entering into the bridge. Enabling this option will drastically improve performance and help remove the buildup of background noise from the conference. This option is highly recommended for large conferences, due to its performance improvements.'
          ),
        'dsp_talking_threshold':
        _("""The time, in milliseconds, by default 160, of sound above what the DSP has established as base-line silence for a user, before that user is considered to be talking. This value affects several options:
Audio is only mixed out of a user's incoming audio stream if talking is detected. If this value is set too loose, the user will hear themselves briefly each time they begin talking until the DSP has time to establish that they are in fact talking.
When talker detection AMI events are enabled, this value determines when talking has begun, which causes AMI events to fire. If this value is set too tight, AMI events may be falsely triggered by variants in the background noise of the caller.
The drop_silence option depends on this value to determine when the user's audio should be mixed into the bridge after periods of silence. If this value is too loose, the beginning of a user's speech will get cut off as they transition from silence to talking."""
          ),
        'dsp_silence_threshold':
        _("""The time, in milliseconds, by default 2500, of sound falling within what the DSP has established as the baseline silence, before a user is considered to be silent. The best way to approach this option is to set it slightly above the maximum amount of milliseconds of silence a user may generate during natural speech. This value affects several operations:
When talker detection AMI events are enabled, this value determines when the user has stopped talking after a period of talking. If this value is set too low, AMI events indicating that the user has stopped talking may get faslely sent out when the user briefly pauses during mid sentence.
The drop_silence option depends on this value to determine when the user's audio should begin to be dropped from the bridge, after the user stops talking. If this value is set too low, the user's audio stream may sound choppy to other participants."""
          ),
        'talk_detection_events':
        _('Sets whether or not notifications of when a user begins and ends talking should be sent out as events over AMI. By default, no.'
          ),
        'denoise':
        _('Whether or not a noise reduction filter should be applied to the audio before mixing. By default, off. This requires codec_speex to be built and installed. Do not confuse this option with drop_silence. denoise is useful if there is a lot of background noise for a user, as it attempts to remove the noise while still preserving the speech. This option does not remove silence from being mixed into the conference and does come at the cost of a slight performance hit.'
          ),
        'jitterbuffer':
        _("Whether or not to place a jitter buffer on the caller's audio stream before any audio mixing is performed. This option is highly recommended, but will add a slight delay to the audio and will incur a slight performance penalty. This option makes use of the JITTERBUFFER dialplan function's default adaptive jitter buffer. For a more fine-tuned jitter buffer, disable this option and use the JITTERBUFFER dialplan function on the calling channel, before it enters the ConfBridge application."
          ),
    }

    def is_accessible(self):
        return super(
            AuthBaseView,
            self).is_accessible() and current_user.has_role('admin') or False
Beispiel #28
0
class ConferenceAdmin(MyModelView, AuthBaseView):
    """
    This is active conference started in a room.
    """
    form_base_class = ConferenceForm
    can_view_details = True
    details_template = 'conference_details.html'
    edit_template = 'conference_edit.html'
    create_template = 'conference_create.html'

    column_list = [
        'number', 'name', 'is_public', 'is_locked', 'participant_count',
        'invited_participant_count', 'user'
    ]
    column_labels = {
        'number': _('Conference Number'),
        'name': _('Conference Name'),
        'participant_count': _('Participants'),
        'invited_participant_count': _('Invited Participants'),
        'online_participant_count': _('Participants Online'),
        'is_locked': _('Locked'),
        'is_public': _('Public'),
        'conference_profile': _('Conference Profile'),
        'public_participant_profile': _('Public Participant Profile'),
    }

    form_create_rules = form_edit_rules = [
        rules.FieldSet(('number', 'name', 'conference_profile'),
                       _('Basic Settings')),
        rules.FieldSet(('is_public', 'public_participant_profile', 'user'),
                       _('Open Access')),
        rules.FieldSet((rules.Macro('conference_participants_link'), ),
                       _('Participants')),
    ]

    column_formatters = {
        'legend': lambda v, c, m, n: legend_formatter(v, c, m, n),
    }

    form_args = {
        'number': dict(validators=[Required(), is_number]),
        'name': dict(validators=[Required()]),
        'conference_profile': dict(validators=[Required()]),
        'public_participant_profile': dict(validators=[Required()]),
    }

    def is_accessible(self):
        return super(
            AuthBaseView,
            self).is_accessible() and current_user.has_role('admin') or False

    @expose('/details/')
    def details_view(self):
        conf = Conference.query.get_or_404(request.args.get('id', 0))
        self._template_args['confbridge_participants'] = \
            confbridge_list_participants(conf.number)
        self._template_args['confbridge'] = confbridge_get(conf.number)
        return super(ModelView, self).details_view()

    @expose('/contacts/', methods=['POST'])
    def add_contacts(self):
        if request.method == 'POST':
            if not request.form.get('conference') or not request.form.get(
                    'profile'):
                flash('You must select Conference and Profile')
                if current_user.has_role('admin'):
                    return redirect(url_for('contact_admin.index_view'))
                else:
                    return redirect(url_for('contact_user.index_view'))

            conference = Conference.query.filter_by(
                id=request.form['conference']).first_or_404()

            profile = ParticipantProfile.query.filter_by(
                id=request.form['profile']).first_or_404()

            contacts = Contact.query.filter(
                Contact.id.in_(request.form['ids'].split(',')))

            for c in contacts:
                if Participant.query.filter_by(phone=c.phone,
                                               conference=conference).first():
                    flash(gettext('%(contact)s is already there.', contact=c))
                    continue
                p = Participant(phone=c.phone,
                                name=c.name,
                                user=current_user,
                                profile=profile,
                                conference=conference)
                flash(gettext('%(contact)s added.', contact=c))

                db.session.add(p)
            db.session.commit()

        return redirect(url_for('.edit_view', id=conference.id))

    @expose('/<int:conf_id>/invite_guest')
    def invite_guest(self, conf_id):
        conf = Conference.query.get_or_404(conf_id)
        phone = request.args.get('phone', None)
        if phone and phone.isdigit():
            originate(conf.number,
                      phone,
                      bridge_options=conf.conference_profile.
                      get_confbridge_options(),
                      user_options=conf.public_participant_profile.
                      get_confbridge_options())
            flash(
                gettext('Number %(phone)s is called for conference.',
                        phone=phone))
        time.sleep(1)
        return redirect(url_for('.details_view', id=conf_id))

    @expose('/<int:conf_id>/invite_participants')
    def invite_participants(self, conf_id):
        conf = Conference.query.get_or_404(conf_id)
        conf.invite_participants()
        flash(gettext('All the participants where invited to the conference'))
        time.sleep(1)
        return redirect(url_for('.details_view', id=conf.id))

    @expose('/kick/<conf_id>')
    @expose('/kick/<conf_id>/channel/<path:channel>')
    def kick(self, conf_id, channel=None):
        conf = Conference.query.filter_by(id=conf_id).first_or_404()
        if channel:
            confbridge_kick(conf.number, channel)
            msg = gettext('Channel %(channel)s is kicked.', channel=channel)
            flash(msg)
            conf.log(msg)
        else:
            confbridge_kick_all(conf.number)
            msg = gettext(
                'All participants have been kicked from the conference.')
            conf.log(msg)
            flash(msg)
        sse_notify(conf.id, 'update_participants')
        time.sleep(1)
        return redirect(url_for('.details_view', id=conf.id))

    @expose('/mute/<conf_id>')
    @expose('/mute/<conf_id>/channel/<path:channel>')
    def mute(self, conf_id, channel=None):
        conf = Conference.query.get_or_404(conf_id)
        if channel:
            confbridge_mute(conf.number, channel)
            msg = gettext('Participant %(channel)s muted.', channel=channel)
            flash(msg)
            conf.log(msg)
        else:
            # Mute all
            for p in confbridge_list_participants(conf.number):
                confbridge_mute(conf.number, p['channel'])
            msg = gettext('Conference muted.')
            flash(msg)
            conf.log(msg)
        sse_notify(conf.id, 'update_participants')
        time.sleep(1)
        return redirect(url_for('.details_view', id=conf_id))

    @expose('/unmute/<conf_id>')
    @expose('/unmute/<conf_id>/channel/<path:channel>')
    def unmute(self, conf_id, channel=None):
        conf = Conference.query.get_or_404(conf_id)
        if channel:
            confbridge_unmute(conf.number, channel)
            msg = gettext('Participant %(channel)s unmuted.', channel=channel)
            flash(msg)
            conf.log(msg)
        else:
            # Mute all
            for p in confbridge_list_participants(conf.number):
                confbridge_unmute(conf.number, p['channel'])
            msg = gettext('Conference unmuted.')
            flash(msg)
            conf.log(msg)
        sse_notify(conf.id, 'update_participants')
        time.sleep(1)
        return redirect(url_for('.details_view', id=conf_id))

    @expose('/<int:conf_id>/record_start')
    def record_start(self, conf_id):
        conf = Conference.query.get_or_404(conf_id)
        confbridge_record_start(conf.number)
        msg = gettext('The conference recording has been started.')
        flash(msg)
        conf.log(msg)
        return redirect(url_for('.details_view', id=conf_id))

    @expose('/<int:conf_id>/record_stop')
    def record_stop(self, conf_id):
        conf = Conference.query.get_or_404(conf_id)
        confbridge_record_stop(conf.number)
        msg = gettext('The conference recording has been stopped.')
        flash(msg)
        conf.log(msg)
        return redirect(url_for('.details_view', id=conf_id))

    @expose('/<int:conf_id>/lock')
    def lock(self, conf_id):
        conf = Conference.query.get_or_404(conf_id)
        confbridge_lock(conf.number)
        msg = gettext('The conference has been locked.')
        flash(msg)
        conf.log(msg)
        sse_notify(conf.id, 'update_participants')
        time.sleep(1)
        return redirect(url_for('.details_view', id=conf_id))

    @expose('/<int:conf_id>/unlock')
    def unlock(self, conf_id):
        conf = Conference.query.get_or_404(conf_id)
        confbridge_unlock(conf.number)
        msg = gettext('The conference has been unlocked.')
        flash(msg)
        conf.log(msg)
        sse_notify(conf.id, 'update_participants')
        time.sleep(1)
        return redirect(url_for('.details_view', id=conf_id))

    @expose('/<int:conf_id>/clear_log')
    def clear_log(self, conf_id):
        logs = ConferenceLog.query.filter_by(conference_id=conf_id)
        for log in logs:
            db.session.delete(log)
        db.session.commit()
        return redirect(url_for('.details_view', id=conf_id))
Beispiel #29
0
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)
Beispiel #30
0
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')