-
-
Notifications
You must be signed in to change notification settings - Fork 131
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add page to display dynamic configuration (#365)
* Add page to display dynamic configuration * update config data and api * add config route * update config api route * update config api route * fix config schema * update config services
- Loading branch information
Showing
11 changed files
with
261 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#!/usr/bin/env python3 | ||
# -*- coding: utf-8 -*- | ||
from typing import Annotated | ||
|
||
from fastapi import APIRouter, Depends, Path, Query | ||
|
||
from backend.app.admin.schema.config import CreateConfigParam, UpdateConfigParam | ||
from backend.app.admin.service.config_service import config_service | ||
from backend.common.response.response_schema import ResponseModel, response_base | ||
from backend.common.security.jwt import DependsJwtAuth | ||
from backend.common.security.permission import RequestPermission | ||
from backend.common.security.rbac import DependsRBAC | ||
|
||
router = APIRouter() | ||
|
||
|
||
@router.get('', summary='获取系统配置详情', dependencies=[DependsJwtAuth]) | ||
async def get_config() -> ResponseModel: | ||
config = await config_service.get() | ||
return await response_base.success(data=config) | ||
|
||
|
||
@router.post( | ||
'', | ||
summary='创建系统配置', | ||
dependencies=[ | ||
Depends(RequestPermission('sys:config:add')), | ||
DependsRBAC, | ||
], | ||
) | ||
async def create_config(obj: CreateConfigParam) -> ResponseModel: | ||
await config_service.create(obj=obj) | ||
return await response_base.success() | ||
|
||
|
||
@router.put( | ||
'/{pk}', | ||
summary='更新系统配置', | ||
dependencies=[ | ||
Depends(RequestPermission('sys:config:edit')), | ||
DependsRBAC, | ||
], | ||
) | ||
async def update_config(pk: Annotated[int, Path(...)], obj: UpdateConfigParam) -> ResponseModel: | ||
count = await config_service.update(pk=pk, obj=obj) | ||
if count > 0: | ||
return await response_base.success() | ||
return await response_base.fail() | ||
|
||
|
||
@router.delete( | ||
'', | ||
summary='(批量)删除系统配置', | ||
dependencies=[ | ||
Depends(RequestPermission('sys:config:del')), | ||
DependsRBAC, | ||
], | ||
) | ||
async def delete_config(pk: Annotated[list[int], Query(...)]) -> ResponseModel: | ||
count = await config_service.delete(pk=pk) | ||
if count > 0: | ||
return await response_base.success() | ||
return await response_base.fail() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
#!/usr/bin/env python3 | ||
# -*- coding: utf-8 -*- | ||
from typing import Sequence | ||
|
||
from sqlalchemy import delete, select | ||
from sqlalchemy.ext.asyncio import AsyncSession | ||
from sqlalchemy_crud_plus import CRUDPlus | ||
|
||
from backend.app.admin.model import Config | ||
from backend.app.admin.schema.config import CreateConfigParam, UpdateConfigParam | ||
|
||
|
||
class CRUDConfig(CRUDPlus[Config]): | ||
async def get_one(self, db: AsyncSession) -> Config | None: | ||
""" | ||
获取 Config | ||
:param db: | ||
:return: | ||
""" | ||
query = await db.execute(select(self.model).limit(1)) | ||
return query.scalars().first() | ||
|
||
async def get_all(self, db: AsyncSession) -> Sequence[Config]: | ||
""" | ||
获取所有 Config | ||
:param db: | ||
:return: | ||
""" | ||
return await self.select_models(db) | ||
|
||
async def create(self, db: AsyncSession, obj_in: CreateConfigParam) -> None: | ||
""" | ||
创建 Config | ||
:param db: | ||
:param obj_in: | ||
:return: | ||
""" | ||
await self.create_model(db, obj_in) | ||
|
||
async def update(self, db: AsyncSession, pk: int, obj_in: UpdateConfigParam) -> int: | ||
""" | ||
更新 Config | ||
:param db: | ||
:param pk: | ||
:param obj_in: | ||
:return: | ||
""" | ||
return await self.update_model(db, pk, obj_in) | ||
|
||
async def delete(self, db: AsyncSession, pk: list[int]) -> int: | ||
""" | ||
删除 Config | ||
:param db: | ||
:param pk: | ||
:return: | ||
""" | ||
configs = await db.execute(delete(self.model).where(self.model.id.in_(pk))) | ||
return configs.rowcount | ||
|
||
|
||
config_dao: CRUDConfig = CRUDConfig(Config) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#!/usr/bin/env python3 | ||
# -*- coding: utf-8 -*- | ||
from sqlalchemy import String | ||
from sqlalchemy.dialects.mysql import LONGTEXT | ||
from sqlalchemy.orm import Mapped, mapped_column | ||
|
||
from backend.common.model import Base, id_key | ||
|
||
|
||
class Config(Base): | ||
"""系统配置表""" | ||
|
||
__tablename__ = 'sys_config' | ||
|
||
id: Mapped[id_key] = mapped_column(init=False) | ||
login_title: Mapped[str] = mapped_column(String(20), default='登陆 FBA', comment='登陆页面标题') | ||
login_sub_title: Mapped[str] = mapped_column( | ||
String(50), default='fastapi_best_architecture', comment='登陆页面子标题' | ||
) | ||
footer: Mapped[str] = mapped_column(String(50), default='FBA', comment='页脚标题') | ||
logo: Mapped[str] = mapped_column(LONGTEXT, default='Arco', comment='Logo') | ||
system_title: Mapped[str] = mapped_column(String(20), default='Arco', comment='系统标题') | ||
system_comment: Mapped[str] = mapped_column( | ||
LONGTEXT, | ||
default='基于 FastAPI 构建的前后端分离 RBAC 权限控制系统,采用独特的伪三层架构模型设计,' | ||
'内置 fastapi-admin 基本实现,并作为模板库免费开源', | ||
comment='系统描述', | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#!/usr/bin/env python3 | ||
# -*- coding: utf-8 -*- | ||
from datetime import datetime | ||
|
||
from pydantic import ConfigDict, Field | ||
|
||
from backend.common.schema import SchemaBase | ||
|
||
|
||
class ConfigSchemaBase(SchemaBase): | ||
login_title: str = Field(default='登陆 FBA') | ||
login_sub_title: str = Field(default='fastapi_best_architecture') | ||
footer: str = Field(default='FBA') | ||
logo: str = Field(default='Arco') | ||
system_title: str = Field(default='Arco') | ||
system_comment: str = Field( | ||
default='基于 FastAPI 构建的前后端分离 RBAC 权限控制系统,采用独特的伪三层架构模型设计,' | ||
'内置 fastapi-admin 基本实现,并作为模板库免费开源' | ||
) | ||
|
||
|
||
class CreateConfigParam(ConfigSchemaBase): | ||
pass | ||
|
||
|
||
class UpdateConfigParam(ConfigSchemaBase): | ||
pass | ||
|
||
|
||
class GetConfigListDetails(ConfigSchemaBase): | ||
model_config = ConfigDict(from_attributes=True) | ||
|
||
id: int | ||
created_time: datetime | ||
updated_time: datetime | None = None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
#!/usr/bin/env python3 | ||
# -*- coding: utf-8 -*- | ||
from backend.app.admin.conf import admin_settings | ||
from backend.app.admin.crud.crud_config import config_dao | ||
from backend.app.admin.model import Config | ||
from backend.app.admin.schema.config import CreateConfigParam, UpdateConfigParam | ||
from backend.common.exception import errors | ||
from backend.database.db_mysql import async_db_session | ||
from backend.database.db_redis import redis_client | ||
from backend.utils.serializers import select_as_dict | ||
|
||
|
||
class ConfigService: | ||
@staticmethod | ||
async def get() -> Config | dict: | ||
async with async_db_session() as db: | ||
cache_config = await redis_client.hgetall(admin_settings.CONFIG_REDIS_KEY) | ||
if not cache_config: | ||
config = await config_dao.get_one(db) | ||
if not config: | ||
raise errors.NotFoundError(msg='系统配置不存在') | ||
data_map = await select_as_dict(config) | ||
del data_map['created_time'] | ||
del data_map['updated_time'] | ||
await redis_client.hset(admin_settings.CONFIG_REDIS_KEY, mapping=data_map) | ||
return config | ||
else: | ||
return cache_config | ||
|
||
@staticmethod | ||
async def create(*, obj: CreateConfigParam) -> None: | ||
async with async_db_session.begin() as db: | ||
config = await config_dao.get_one(db) | ||
if config: | ||
raise errors.ForbiddenError(msg='系统配置已存在') | ||
await config_dao.create(db, obj) | ||
await redis_client.hset(admin_settings.CONFIG_REDIS_KEY, mapping=obj.model_dump()) | ||
|
||
@staticmethod | ||
async def update(*, pk: int, obj: UpdateConfigParam) -> int: | ||
async with async_db_session.begin() as db: | ||
count = await config_dao.update(db, pk, obj) | ||
await redis_client.hset(admin_settings.CONFIG_REDIS_KEY, mapping=obj.model_dump()) | ||
return count | ||
|
||
@staticmethod | ||
async def delete(*, pk: list[int]) -> int: | ||
async with async_db_session.begin() as db: | ||
configs = await config_dao.get_all(db) | ||
if len(configs) == 1: | ||
raise errors.ForbiddenError(msg='系统配置无法彻底删除') | ||
count = await config_dao.delete(db, pk) | ||
await redis_client.delete(admin_settings.CONFIG_REDIS_KEY) | ||
return count | ||
|
||
|
||
config_service = ConfigService() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters