Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add CRUD apis for role, permission, user #1801

Merged
merged 31 commits into from
Apr 12, 2022
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
08ef2b0
Add CRUD apis for role, permission, user
mayurnewase Feb 9, 2022
20d7d3d
black and flake
mayurnewase Feb 9, 2022
4e7bbca
Add schema for user, encrypt password with pre_add
mayurnewase Feb 10, 2022
594e363
Add edit model schema
mayurnewase Feb 10, 2022
a54e006
Add edit model schema
mayurnewase Feb 10, 2022
3e643dc
Merge branch 'master' into feat-user-management-api
dpgaspar Feb 14, 2022
cd638ba
complete apis
mayurnewase Feb 17, 2022
6e00ce6
Merge branch 'feat-user-management-api' of github.com:mayurnewase/Fla…
mayurnewase Feb 17, 2022
6ee7304
Flake and Black
mayurnewase Feb 17, 2022
19dc157
Add tests
mayurnewase Feb 17, 2022
8d404e4
lint
mayurnewase Feb 17, 2022
93d1058
Merge branch 'master' of github.com:dpgaspar/Flask-AppBuilder into fe…
mayurnewase Feb 17, 2022
dde6307
Add view and permission view apis
mayurnewase Feb 18, 2022
172c69f
Fixed session error
mayurnewase Feb 19, 2022
afa191f
Fixed session error
mayurnewase Feb 19, 2022
b95a14d
Fix test
mayurnewase Feb 20, 2022
495dee7
avoid session leak
mayurnewase Feb 20, 2022
973a620
fix api test
mayurnewase Feb 20, 2022
d3403a2
suggestions
mayurnewase Feb 23, 2022
ab517f0
black flake
mayurnewase Feb 23, 2022
0d05fb4
Seperate tests
mayurnewase Feb 26, 2022
563ec06
Merge branch 'master' into feat-user-management-api
mayurnewase Feb 26, 2022
b6d5129
add nested api for role permissions
mayurnewase Mar 7, 2022
9b41c6a
Merge branch 'feat-user-management-api' of github.com:mayurnewase/Fla…
mayurnewase Mar 7, 2022
cf485df
add test for default password validator
mayurnewase Mar 7, 2022
5c1f5e3
Fix mysql test
mayurnewase Mar 8, 2022
00f6dd3
add test for invalid role
mayurnewase Mar 8, 2022
3ad57d7
add 1 test for invlid payload for role permission, suggestions
mayurnewase Mar 12, 2022
790bc94
Remove mutating apis on permissionApi, suggestions
mayurnewase Mar 15, 2022
172ed09
Merge branch 'master' into feat-user-management-api
dpgaspar Mar 21, 2022
4e483a6
Merge branch 'master' into feat-user-management-api
dpgaspar Apr 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions flask_appbuilder/security/sqla/apis/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from flask_appbuilder.security.sqla.apis.permission import PermissionApi # noqa: F401
from flask_appbuilder.security.sqla.apis.permission_view_menu import ( # noqa: F401
PermissionViewMenuApi,
)
from flask_appbuilder.security.sqla.apis.role import RoleApi # noqa: F401
from flask_appbuilder.security.sqla.apis.user import UserApi # noqa: F401
from flask_appbuilder.security.sqla.apis.view_menu import ViewMenuApi # noqa: F401
1 change: 1 addition & 0 deletions flask_appbuilder/security/sqla/apis/permission/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .api import PermissionApi # noqa: F401
18 changes: 18 additions & 0 deletions flask_appbuilder/security/sqla/apis/permission/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from flask_appbuilder import ModelRestApi
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_appbuilder.security.sqla.models import Permission


class PermissionApi(ModelRestApi):
resource_name = "permissions"
openapi_spec_tag = "Security Permissions"

class_permission_name = "Permission"
datamodel = SQLAInterface(Permission)
allow_browser_login = True

list_columns = ["id", "name"]
show_columns = list_columns
add_columns = ["name"]
edit_columns = add_columns
search_columns = list_columns
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .api import PermissionViewMenuApi # noqa: F401
17 changes: 17 additions & 0 deletions flask_appbuilder/security/sqla/apis/permission_view_menu/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from flask_appbuilder import ModelRestApi
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_appbuilder.security.sqla.models import PermissionView


class PermissionViewMenuApi(ModelRestApi):
resource_name = "permissionsviewmenus"
openapi_spec_tag = "Security Permissions View Menus"
class_permission_name = "PermissionViewMenu"
datamodel = SQLAInterface(PermissionView)
allow_browser_login = True

list_columns = ["id", "permission.name", "view_menu.name"]
show_columns = list_columns
add_columns = ["permission_id", "view_menu_id"]
edit_columns = add_columns
search_columns = list_columns
1 change: 1 addition & 0 deletions flask_appbuilder/security/sqla/apis/role/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .api import RoleApi # noqa: F401
151 changes: 151 additions & 0 deletions flask_appbuilder/security/sqla/apis/role/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
from flask import current_app, request
from flask_appbuilder import ModelRestApi
from flask_appbuilder.api import expose, safe
from flask_appbuilder.const import API_RESULT_RES_KEY
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_appbuilder.security.decorators import permission_name, protect
from flask_appbuilder.security.sqla.apis.role.schema import (
RolePermissionListSchema,
RolePermissionPostSchema,
)
from flask_appbuilder.security.sqla.models import PermissionView, Role
from marshmallow import ValidationError
from sqlalchemy.exc import IntegrityError


class RoleApi(ModelRestApi):
resource_name = "roles"
openapi_spec_tag = "Security Roles"
class_permission_name = "Role"
datamodel = SQLAInterface(Role)
allow_browser_login = True

list_columns = ["id", "name"]
show_columns = list_columns
add_columns = ["name"]
edit_columns = ["name"]
search_columns = list_columns

list_role_permission_schema = RolePermissionListSchema()
add_role_permission_schema = RolePermissionPostSchema()
openapi_spec_component_schemas = (
RolePermissionListSchema,
RolePermissionPostSchema,
)

@expose("/<int:pk>/permissions", methods=["GET"])
@protect()
@safe
@permission_name("list_role_permissions")
def list_role_permissions(self, pk):
"""list role permissions
---
get:
parameters:
- in: path
schema:
type: integer
name: pk
responses:
200:
description: List of permissions
content:
application/json:
schema:
type: object
properties:
result:
$ref: '#/components/schemas/RolePermissionListSchema'
400:
$ref: '#/components/responses/400'
401:
$ref: '#/components/responses/401'
404:
$ref: '#/components/responses/404'
422:
$ref: '#/components/responses/422'
500:
$ref: '#/components/responses/500'
"""
role = self.datamodel.get(pk, select_columns=["permissions"])
if role:
permissions = [
{
"id": p.id,
"permission_name": p.permission.name,
"view_menu_name": p.view_menu.name,
}
for p in role.permissions
]
return self.response(200, **{API_RESULT_RES_KEY: permissions})
return self.response_404()

@expose("/<int:role_id>/permissions", methods=["POST"])
@protect()
@safe
@permission_name("add_role_permissions")
def add_role_permissions(self, role_id):
"""add role permissions
---
post:
parameters:
- in: path
schema:
type: integer
name: role_id
requestBody:
description: Add role permissions schema
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RolePermissionPostSchema'
responses:
200:
description: Permissions added
content:
application/json:
schema:
type: object
properties:
result:
$ref: '#/components/schemas/RolePermissionPostSchema'
400:
$ref: '#/components/responses/400'
401:
$ref: '#/components/responses/401'
404:
$ref: '#/components/responses/404'
422:
$ref: '#/components/responses/422'
500:
$ref: '#/components/responses/500'
"""
try:
item = self.add_role_permission_schema.load(request.json)
role = self.datamodel.get(role_id)
permissions = []
for id in item["permission_view_menu_ids"]:
permission = (
current_app.appbuilder.get_session.query(PermissionView)
.filter_by(id=id)
.one_or_none()
)
if permission:
permissions.append(permission)

role.permissions = permissions
self.datamodel.edit(role, raise_exception=True)
return self.response(
200,
**{
API_RESULT_RES_KEY: self.add_role_permission_schema.dump(
item, many=False
)
},
)

except ValidationError as error:
return self.response_400(message=error.messages)
except IntegrityError as e:
return self.response_422(message=str(e.orig))
13 changes: 13 additions & 0 deletions flask_appbuilder/security/sqla/apis/role/schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from marshmallow import fields, Schema


class RolePermissionPostSchema(Schema):
permission_view_menu_ids = fields.List(
fields.Integer, required=True, description="List of permission view menu id"
)


class RolePermissionListSchema(Schema):
id = fields.Integer()
permission_name = fields.String()
view_menu_name = fields.String()
1 change: 1 addition & 0 deletions flask_appbuilder/security/sqla/apis/user/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .api import UserApi # noqa: F401
Loading