Skip to content

feat: 函数库添加权限 #1189

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

Merged
merged 3 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion apps/application/serializers/application_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,8 @@ def list_function_lib(self, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
application = QuerySet(Application).filter(id=self.data.get("application_id")).first()
return FunctionLibSerializer.Query(data={'user_id': application.user_id}).list(with_valid=True)
return FunctionLibSerializer.Query(data={'user_id': application.user_id, 'is_active': True}).list(
with_valid=True)

def get_function_lib(self, function_lib_id, with_valid=True):
if with_valid:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.15 on 2024-09-14 11:23

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('function_lib', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='functionlib',
name='is_active',
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name='functionlib',
name='permission_type',
field=models.CharField(choices=[('PUBLIC', '公开'), ('PRIVATE', '私有')], default='PRIVATE', max_length=20, verbose_name='权限类型'),
),
]
8 changes: 8 additions & 0 deletions apps/function_lib/models/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
from users.models import User


class PermissionType(models.TextChoices):
PUBLIC = "PUBLIC", '公开'
PRIVATE = "PRIVATE", "私有"


class FunctionLib(AppModelMixin):
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid1, editable=False, verbose_name="主键id")
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户id")
Expand All @@ -24,6 +29,9 @@ class FunctionLib(AppModelMixin):
input_field_list = ArrayField(verbose_name="输入字段列表",
base_field=models.JSONField(verbose_name="输入字段", default=dict)
, default=list)
is_active = models.BooleanField(default=True)
permission_type = models.CharField(max_length=20, verbose_name='权限类型', choices=PermissionType.choices,
default=PermissionType.PRIVATE)

class Meta:
db_table = "function_lib"
24 changes: 19 additions & 5 deletions apps/function_lib/serializers/function_lib_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import uuid

from django.core import validators
from django.db.models import QuerySet
from django.db.models import QuerySet, Q
from rest_framework import serializers

from common.db.search import page_search
Expand All @@ -27,7 +27,7 @@
class FunctionLibModelSerializer(serializers.ModelSerializer):
class Meta:
model = FunctionLib
fields = ['id', 'name', 'desc', 'code', 'input_field_list',
fields = ['id', 'name', 'desc', 'code', 'input_field_list', 'permission_type', 'is_active',
'create_time', 'update_time']


Expand Down Expand Up @@ -68,6 +68,8 @@ class EditFunctionLib(serializers.Serializer):

input_field_list = FunctionLibInputField(required=False, many=True)

is_active = serializers.BooleanField(required=False, error_messages=ErrMessage.char('是否可用'))


class CreateFunctionLib(serializers.Serializer):
name = serializers.CharField(required=True, error_messages=ErrMessage.char("函数名称"))
Expand All @@ -79,6 +81,12 @@ class CreateFunctionLib(serializers.Serializer):

input_field_list = FunctionLibInputField(required=True, many=True)

permission_type = serializers.CharField(required=True, error_messages=ErrMessage.char("权限"), validators=[
validators.RegexValidator(regex=re.compile("^PUBLIC|PRIVATE$"),
message="权限只支持PUBLIC|PRIVATE", code=500)
])
is_active = serializers.BooleanField(required=False, error_messages=ErrMessage.char('是否可用'))


class FunctionLibSerializer(serializers.Serializer):
class Query(serializers.Serializer):
Expand All @@ -87,15 +95,19 @@ class Query(serializers.Serializer):

desc = serializers.CharField(required=False, allow_null=True, allow_blank=True,
error_messages=ErrMessage.char("函数描述"))
is_active = serializers.BooleanField(required=False, error_messages=ErrMessage.char("是否可用"))

user_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("用户id"))

def get_query_set(self):
query_set = QuerySet(FunctionLib).filter(user_id=self.data.get('user_id'))
query_set = QuerySet(FunctionLib).filter(
(Q(user_id=self.data.get('user_id')) | Q(permission_type='PUBLIC')))
if self.data.get('name') is not None:
query_set = query_set.filter(name__contains=self.data.get('name'))
if self.data.get('desc') is not None:
query_set = query_set.filter(desc__contains=self.data.get('desc'))
if self.data.get('is_active') is not None:
query_set = query_set.filter(is_active=self.data.get('is_active'))
query_set = query_set.order_by("-create_time")
return query_set

Expand All @@ -120,7 +132,9 @@ def insert(self, instance, with_valid=True):
function_lib = FunctionLib(id=uuid.uuid1(), name=instance.get('name'), desc=instance.get('desc'),
code=instance.get('code'),
user_id=self.data.get('user_id'),
input_field_list=instance.get('input_field_list'))
input_field_list=instance.get('input_field_list'),
permission_type=instance.get('permission_type'),
is_active=instance.get('is_active', True))
function_lib.save()
return FunctionLibModelSerializer(function_lib).data

Expand Down Expand Up @@ -193,7 +207,7 @@ def edit(self, instance, with_valid=True):
if with_valid:
self.is_valid(raise_exception=True)
EditFunctionLib(data=instance).is_valid(raise_exception=True)
edit_field_list = ['name', 'desc', 'code', 'input_field_list']
edit_field_list = ['name', 'desc', 'code', 'input_field_list', 'permission_type', 'is_active']
edit_dict = {field: instance.get(field) for field in edit_field_list if (
field in instance and instance.get(field) is not None)}
QuerySet(FunctionLib).filter(id=self.data.get('id')).update(**edit_dict)
Expand Down
6 changes: 5 additions & 1 deletion apps/function_lib/swagger_api/function_lib_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ def get_request_body_api():
'name': openapi.Schema(type=openapi.TYPE_STRING, title="函数名称", description="函数名称"),
'desc': openapi.Schema(type=openapi.TYPE_STRING, title="函数描述", description="函数描述"),
'code': openapi.Schema(type=openapi.TYPE_STRING, title="函数内容", description="函数内容"),
'permission_type': openapi.Schema(type=openapi.TYPE_STRING, title="权限", description="权限"),
'is_active': openapi.Schema(type=openapi.TYPE_BOOLEAN, title="是否可用", description="是否可用"),
'input_field_list': openapi.Schema(type=openapi.TYPE_ARRAY,
description="输入变量列表",
items=openapi.Schema(type=openapi.TYPE_OBJECT,
Expand Down Expand Up @@ -135,11 +137,13 @@ class Create(ApiMixin):
def get_request_body_api():
return openapi.Schema(
type=openapi.TYPE_OBJECT,
required=['name', 'code', 'input_field_list'],
required=['name', 'code', 'input_field_list', 'permission_type'],
properties={
'name': openapi.Schema(type=openapi.TYPE_STRING, title="函数名称", description="函数名称"),
'desc': openapi.Schema(type=openapi.TYPE_STRING, title="函数描述", description="函数描述"),
'code': openapi.Schema(type=openapi.TYPE_STRING, title="函数内容", description="函数内容"),
'permission_type': openapi.Schema(type=openapi.TYPE_STRING, title="权限", description="权限"),
'is_active': openapi.Schema(type=openapi.TYPE_BOOLEAN, title="是否可用", description="是否可用"),
'input_field_list': openapi.Schema(type=openapi.TYPE_ARRAY,
description="输入变量列表",
items=openapi.Schema(type=openapi.TYPE_OBJECT,
Expand Down
6 changes: 4 additions & 2 deletions ui/src/api/type/function-lib.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
interface functionLibData {
id?: String
name: String
desc: String
name?: String
desc?: String
code?: String
permission_type?: 'PRIVATE' | 'PUBLIC'
input_field_list?: Array<any>
is_active?: Boolean
}

export type { functionLibData }
2 changes: 1 addition & 1 deletion ui/src/views/application/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ onMounted(() => {
.status-tag {
position: absolute;
right: 16px;
top: 20px;
top: 13px;
}
}
.dropdown-custom-switch {
Expand Down
2 changes: 1 addition & 1 deletion ui/src/views/dataset/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ onMounted(() => {
.delete-button {
position: absolute;
right: 12px;
top: 18px;
top: 13px;
height: auto;
}
.footer-content {
Expand Down
41 changes: 35 additions & 6 deletions ui/src/views/function-lib/component/FunctionFormDrawer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
placeholder="请输入函数名称"
maxlength="64"
show-word-limit
@blur="form.name = form.name.trim()"
@blur="form.name = form.name?.trim()"
/>
</el-form-item>
<el-form-item label="描述">
Expand All @@ -30,9 +30,35 @@
maxlength="128"
show-word-limit
:autosize="{ minRows: 3 }"
@blur="form.desc = form.desc.trim()"
@blur="form.desc = form.desc?.trim()"
/>
</el-form-item>
<el-form-item prop="permission_type">
<template #label>
<span>权限</span>
</template>

<el-radio-group v-model="form.permission_type" class="card__radio">
<el-row :gutter="16">
<template v-for="(value, key) of PermissionType" :key="key">
<el-col :span="12">
<el-card
shadow="never"
class="mb-16"
:class="form.permission_type === key ? 'active' : ''"
>
<el-radio :value="key" size="large">
<p class="mb-4">{{ value }}</p>
<el-text type="info">
{{ PermissionDesc[key] }}
</el-text>
</el-radio>
</el-card>
</el-col>
</template>
</el-row>
</el-radio-group>
</el-form-item>
</el-form>
<div class="flex-between">
<h4 class="title-decoration-1 mb-16">
Expand Down Expand Up @@ -137,7 +163,7 @@ import functionLibApi from '@/api/function-lib'
import type { FormInstance } from 'element-plus'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
import { cloneDeep } from 'lodash'

import { PermissionType, PermissionDesc } from '@/enums/model'
const props = defineProps({
title: String
})
Expand All @@ -158,7 +184,8 @@ const form = ref<functionLibData>({
name: '',
desc: '',
code: '',
input_field_list: []
input_field_list: [],
permission_type: 'PRIVATE'
})

const dialogVisible = ref(false)
Expand All @@ -173,13 +200,15 @@ watch(visible, (bool) => {
name: '',
desc: '',
code: '',
input_field_list: []
input_field_list: [],
permission_type: 'PRIVATE'
}
}
})

const rules = reactive({
name: [{ required: true, message: '请输入函数名称', trigger: 'blur' }]
name: [{ required: true, message: '请输入函数名称', trigger: 'blur' }],
permission_type: [{ required: true, message: '请选择', trigger: 'change' }]
})

function openCodemirrorDialog() {
Expand Down
85 changes: 70 additions & 15 deletions ui/src/views/function-lib/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
clearable
/>
</div>
<div v-loading.fullscreen.lock="paginationConfig.current_page === 1 && loading">
<div
v-loading.fullscreen.lock="
(paginationConfig.current_page === 1 && loading) || changeStateloading
"
>
<InfiniteScroll
:size="functionLibList.length"
:total="paginationConfig.total"
Expand Down Expand Up @@ -45,20 +49,34 @@
<img src="@/assets/icon_function_outlined.svg" style="width: 58%" alt="" />
</AppAvatar>
</template>

<div class="status-button">
<el-tag class="info-tag" v-if="item.permission_type === 'PUBLIC'">公用</el-tag>
<el-tag class="danger-tag" v-else-if="item.permission_type === 'PRIVATE'"
>私有</el-tag
>
</div>
<template #footer>
<div class="footer-content">
<el-tooltip effect="dark" content="复制" placement="top">
<el-button text @click.stop="copyFunctionLib(item)">
<AppIcon iconName="app-copy"></AppIcon>
</el-button>
</el-tooltip>
<el-divider direction="vertical" />
<el-tooltip effect="dark" content="删除" placement="top">
<el-button text @click.stop="deleteFunctionLib(item)">
<el-icon><Delete /></el-icon>
</el-button>
</el-tooltip>
<div class="footer-content flex-between">
<div>
<el-tooltip effect="dark" content="复制" placement="top">
<el-button text @click.stop="copyFunctionLib(item)">
<AppIcon iconName="app-copy"></AppIcon>
</el-button>
</el-tooltip>
<el-divider direction="vertical" />
<el-tooltip effect="dark" content="删除" placement="top">
<el-button text @click.stop="deleteFunctionLib(item)">
<el-icon><Delete /></el-icon>
</el-button>
</el-tooltip>
</div>
<div @click.stop>
<el-switch
v-model="item.is_active"
@change="changeState($event, item)"
size="small"
/>
</div>
</div>
</template>
</CardBox>
Expand Down Expand Up @@ -89,6 +107,7 @@ const paginationConfig = reactive({

const searchValue = ref('')
const title = ref('')
const changeStateloading = ref(false)

function openCreateDialog(data?: any) {
title.value = data ? '编辑函数' : '创建函数'
Expand All @@ -102,6 +121,33 @@ function searchHandle() {
getList()
}

function changeState(bool: Boolean, row: any) {
if (!bool) {
MsgConfirm(
`是否禁用函数:${row.name} ?`,
`禁用后,引用了该函数的应用提问时会报错 ,请谨慎操作。`,
{
confirmButtonText: '禁用',
confirmButtonClass: 'danger'
}
)
.then(() => {
const obj = {
is_active: bool
}
functionLibApi.putFunctionLib(row.id, obj, changeStateloading).then((res) => {})
})
.catch(() => {
row.is_active = true
})
} else {
const obj = {
is_active: bool
}
functionLibApi.putFunctionLib(row.id, obj, changeStateloading).then((res) => {})
}
}

function deleteFunctionLib(row: any) {
MsgConfirm(
`是否删除函数:${row.name} ?`,
Expand Down Expand Up @@ -155,4 +201,13 @@ onMounted(() => {
getList()
})
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.function-lib-list-container {
.status-button {
position: absolute;
right: 12px;
top: 13px;
height: auto;
}
}
</style>
Loading