filemgr — 文件/目录管理模块

模块定位

通用文件与目录管理包:提供目录树 + 文件上传/删除的基础能力,核心是 filemgr/filemgr.py 里的 FileMgr 类(配 FileMgrResult 结果对象与 get_file_hash sha256 工具函数)。物理文件走 ahserver 的 FileStorage(上传落在 conf/config.json 的 filesroot,即 $[workdir]$/files),元数据落 MySQL 的 folder/file 两张表。

两种运行形态(仓库中都有实物):

  1. 独立 app 演示:app/fileMGR.py(load_appbase → load_rbac → load_filemgr → load_bricks,监听 9080,库 mediadb,见 conf/config.json);
  2. 宿主模块: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,见下)。

部署注意事项

  1. 库名动态解析:get_dbname() 走 get_serverenv('get_module_dbname')('filemgr');独立演示 app 里写死返回 'sage',pipeline-app 宿主返回 'pipeline'——复用模块时勿改死。
  2. 建表:models/file.json、models/folder.json 交宿主 create_tables/xls2ddl 流程;注意 file 表的 codes 外联 folderinfo/organization 必须先存在。
  3. 文件存储根:conf/config.json 的 filesroot=$[workdir]$/files,上传大小受 client_max_size: 20000 限制;生产需确认磁盘与 FileStorage 配置一致。
  4. i18n:i18n/{zh,en,jp,ko}/msg.txt 已含表字段词条(commit 1461430)。
  5. 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(commit 5a81ea2 特意 revert 回 0)→ 未覆写的子类任何上传都触发配额溢出。本模块设计为被业务子类继承覆写这三个钩子后使用。
Description
No description provided
Readme 249 KiB
Languages
Python 99.2%
Shell 0.8%