7.1 KiB
filemgr — 文件/目录管理模块
模块定位
通用文件与目录管理包:提供目录树 + 文件上传/删除的基础能力,核心是 filemgr/filemgr.py 里的 FileMgr 类(配 FileMgrResult 结果对象与 get_file_hash sha256 工具函数)。物理文件走 ahserver 的 FileStorage(上传落在 conf/config.json 的 filesroot,即 $[workdir]$/files),元数据落 MySQL 的 folder/file 两张表。
两种运行形态(仓库中都有实物):
- 独立 app 演示:
app/fileMGR.py(load_appbase → load_rbac → load_filemgr → load_bricks,监听 9080,库mediadb,见conf/config.json); - 宿主模块:
filemgr/init.py的load_filemgr()把 FileMgr 类本身注册到ServerEnv(env.FileMgr = FileMgr),宿主(sage / pipeline-app)在 dspy 里取用。库名经get_module_dbname('filemgr')解析,禁写死。
在账号/存储计费链路中,filemgr 是容量事实的来源:file.filesize 汇总即机构占用量,storage_resource 的容量采样(record_storage_sample)可由扫这些记录得到 used_gb。filemgr 自身不直接调用 product_management / accounting。
表清单(models/*.json,另有同名 .xlsx 源)
| 表 | 用途 | 关键字段 |
|---|---|---|
folder |
目录(树) | id(pk32), parentid(父目录,自关联), fiid(目录信息id), name(500), ownerid(所属机构 → organization.id) |
file |
文件元数据 | id(pk32), folderid(→folder.id), fiid, name(200), webpath(相对路径400), realpath(绝对路径400), filetype(扩展名≤10), filesize(long,字节), ownerid(属主机构), orgperm(同事权限 char3), otherperm(其他人权限), hashvalue(sha256,65) |
⚠️ models 的 codes 段引用了 folderinfo 和 organization 两张表——本仓库未定义,需宿主提供(organization 属 appbase/组织模块)。folderinfo(fiid 指向的"目录信息")在仓库内无建表定义,接入新宿主前需确认其来源。
对外 API / 页面端点(wwwroot/,挂载在 /filemgr/ 下)
| 端点 | 类型 | 说明 |
|---|---|---|
/filemgr/get_folder_subs.dspy |
dspy | 取某目录的直接子项(子目录+文件),供树控件 get_data_url |
/filemgr/delete_folder_or_file.dspy |
dspy | 删除入口:目录有子项时返回 UiComform 二次确认(跳 conformed_delete),否则直接删 |
/filemgr/conformed_delete.dspy |
dspy | 确认后的目录递归删除 |
/filemgr/upload_file.ui |
Bricks Form | 上传弹窗(folderid/fiid 隐藏域 + upfile 文件域),submit 绑定 upload_file.dspy |
/filemgr/upload_file.dspy |
dspy | 调 FileMgr.add_file(request, params_kw) 落库 |
/filemgr/getallfiles.dspy |
dspy | 递归列出目录下全部文件(id+realpath) |
json/folder.json |
Bricks tree widget | 目录树页面定义(xls2ui 生成,json/build.sh: xls2ui -m ../models -o ../wwwroot filemgr *.json):文件类型图标映射(pdf/docx/xlsx/epub/csv…)、工具栏"上传文件"弹 upload_file.ui |
conf/config.json 另注册了 startswith 路由 /idfile → registerfunction 'idfile'(独立演示形态用;该注册函数不在本仓库实现)。
FileMgr 关键方法(实测签名)
FileMgr(fiid) # 构造需要 fiid(见"已知问题")
await add_file(request, params_kw) # 上传: 登录校验→属主校验→配额校验→sha256去重→落file表
await del_folder(request, id) / _del_folder(sor, id, ownerid) # 递归删目录(属主校验)
await del_file(request, fid) / _del_file(sor, fid, ownerid) # 删文件(物理文件按引用计数unlink)
await has_sub(sor, folderid) # 目录是否有子项(union子目录+文件)
await get_subs(id) # 直接子项列表(自建连接)
await sor_get_subfolder(sor, fid) / sor_get_subfile(sor, fid)
await get_quota_used(sor, orgid) # sum(file.filesize)/1e6,单位 MB
await get_organization_quota(sor, orgid) # 基类桩: 返回 (0, '9999-12-31'),子类必须覆写
get_file_hash(filepath, algo='sha256', chunk_size=8192)
上传语义(add_file):同 hashvalue+同属主 → 拒收"file exists";同 hashvalue 不同属主 → 复用已有物理文件路径(物理去重,只加一条 file 记录)。删除时物理文件仅在无任何记录再引用该 hashvalue 时才 unlink。配额判断 quota_used + filesize/1e6 >= quota 即拒绝并删除已上传的临时文件。
与产品/计费链路(product_management、accounting)的集成关系
- filemgr 不注册
env.product_interface,不参与 resolve_ppid/定价映射——它只是资源事实层。 - 链路位置:
file.filesize(机构维度汇总,MB)→storage_resource.record_storage_sample(...)写storres_sample.used_gb/quota_gb/over_gb→summarize_samples按订购周期求均值/峰值 →storage_charging出storres_usage(accounting_status=pending)→ accounting 记账。 get_organization_quota是配额挂钩点:接入 storage_resource 产品后,应由子类/宿主把机构已购容量(订购权益workspace_gb/storage_gb)返回给 filemgr 做上传前置校验(当前基类返回 0,见下)。
部署注意事项
- 库名动态解析:
get_dbname()走get_serverenv('get_module_dbname')('filemgr');独立演示 app 里写死返回'sage',pipeline-app 宿主返回'pipeline'——复用模块时勿改死。 - 建表:models/file.json、models/folder.json 交宿主 create_tables/xls2ddl 流程;注意
file表的codes外联folderinfo/organization必须先存在。 - 文件存储根:
conf/config.json的filesroot=$[workdir]$/files,上传大小受client_max_size: 20000限制;生产需确认磁盘与 FileStorage 配置一致。 - i18n:i18n/{zh,en,jp,ko}/msg.txt 已含表字段词条(commit 1461430)。
- pyproject/setup.cfg:包名 filemgr 0.0.1,依赖 apppublic/sqlor/ahserver;
packages = find:会把app/、json/一并扫描,安装时注意。
已知问题(实测代码,未修改——修前必读)
FileMgr.__init__(self, fiid)要求 fiid,但 wwwroot 各 dspy 均以FileMgr()无参构造 → 直接运行会 TypeError(getallfiles.dspy 更是filemgr = FileMgr拿了类当实例,且调用了不存在的get_subfiles)。conformed_delete.dspy用小写Filemgr()且_del_folder(sor, params_kw.id)少传ownerid。folder_files()有笔误dbanme = get_dbname()(下一行用dbname→ NameError);_folder_files递归调用漏传sor;del_folder里self.file_deleted(...)未 await。get_folder_ownerid/file_uploaded/file_deleted基类均为空实现(pass),is_folder_ownerid因此恒 False → add_file 属主校验必失败;基类get_organization_quota返回 quota=0(commit5a81ea2特意 revert 回 0)→ 未覆写的子类任何上传都触发配额溢出。本模块设计为被业务子类继承覆写这三个钩子后使用。