Flask-AppBuilder icon indicating copy to clipboard operation
Flask-AppBuilder copied to clipboard

How to use @has_access in custom widget template html file.

Open QKJIN opened this issue 2 years ago • 5 comments

I customize my own ListWidget with a template file where I add an action button like below.

{% block list_header %}
   {{ super() }}
   <a href="url_for('doaction')" class="btn btn-sm btn-primary">
        <i class="fa fa-rocket"></i>
   </a>
{% endblock %}

Then I add @expose in the view.py like below.

    @expose("/action", methods=['GET'])
    @has_access
    def doaction(self):

My questions is how to control the action button display based on user's permission. Thanks.

QKJIN avatar Jun 01 '22 06:06 QKJIN

This might not be best way, but it has worked for me:

in template I have

{% if 'Coordinator' in user_role_list or 'Admin' in user_role_list %}
        <div class="btn-group" role="button group" aria-label="show and edit">

in views.py

    @expose("/example", methods=['GET'])
    def example_view(self):
        user_role_list = get_user_role_list()
        return self.render_template(
            template[show], 
            user_role_list=user_role_list
        )

and

def get_user_role_list():
    """
    Returns:
        list -- of str of names of Roles of g.user, empty list if not logged in
        :rtype: list
    """
    if not g.user.is_anonymous:
        return [str(r) for r in g.user.roles]
    return []

One problem with this methodology is that the user permission role names are hard-coded in source, but it has been ok for me

soundmaking avatar Jun 01 '22 09:06 soundmaking

@soundmaking Thanks for your help. It is work. For me, there are my codes. (1) models.py

class MyUser(User):
    __tablename__ = "ab_user"
    def is_admin(self):
        if 'Admin' in [r.name for r in self.roles] :
            return True
        else :
            return False

(2)widget template html

{% block list_header %}
   {{ super() }}

    {% set user_is_admin = g.user.is_admin() %}
    {% if user_is_admin %}
   <a href="url_for('doaction')" class="btn btn-sm btn-primary">
        <i class="fa fa-rocket"></i>
   </a>
    {% endif %}
{% endblock %}

One problem is that I can only check user's roles. In fact, I want to check user's specifc permission. I don't know how to list permissions.

QKJIN avatar Jun 01 '22 10:06 QKJIN

Good idea to define the function in your User class - I would do that if/when I were starting again!

you can access list of permissions on each role with role.permissions

so maybe something along the line of this untested code:

class MyUser(User):
    # . . .
    def has_permission(self, permission_name)
        for role in self.roles:
            if permission_name in [p.name for p in role.permissions]:
                return True
        return False

soundmaking avatar Jun 01 '22 19:06 soundmaking

There is an error about if permission_name in [p.name for p in role.permissions]: , because p has no attribution name. I change them to below. But it still can not work. I don't know why.

    def has_permission(self, permission_name):
        for role in self.roles:
            if permission_name in role.permissions :
                return True
        return False

QKJIN avatar Jun 02 '22 07:06 QKJIN

I checked the original code about permission_view. And changed the codes into below. They can work.

    def has_permission(self, permission_name, view_menu_name):
        for role in self.roles:
            for ps in role.permissions:
               if (ps.permission.name == permission_name and ps.view_menu.name == view_menu_name):
                    return True
        return False

QKJIN avatar Jun 02 '22 07:06 QKJIN