filemgr — 文件/目录管理模块

模块定位

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

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

  1. 独立 app 演示app/fileMGR.pyload_appbase → load_rbac → load_filemgr → load_bricks,监听 9080mediadb,见 conf/config.json
  2. 宿主模块filemgr/init.pyload_filemgr()FileMgr 类本身注册到 ServerEnvenv.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 段引用了 folderinfoorganization 两张表——本仓库未定义需宿主提供organization 属 appbase/组织模块)。folderinfofiid 指向的"目录信息")在仓库内无建表定义,接入新宿主前需确认其来源。

对外 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_filehashvalue+同属主 → 拒收"file exists";同 hashvalue 不同属主 → 复用已有物理文件路径(物理去重,只加一条 file 记录)。删除时物理文件仅在无任何记录再引用该 hashvalue 时才 unlink。配额判断 quota_used + filesize/1e6 >= quota 即拒绝并删除已上传的临时文件。

与产品/计费链路product_management、accounting的集成关系

  • filemgr 不注册 env.product_interface,不参与 resolve_ppid/定价映射——它只是资源事实层。
  • 链路位置:file.filesize机构维度汇总MBstorage_resource.record_storage_sample(...)storres_sample.used_gb/quota_gb/over_gbsummarize_samples 按订购周期求均值/峰值 → storage_chargingstorres_usageaccounting_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.jsonfilesroot=$[workdir]$/files,上传大小受 client_max_size: 20000 限制;生产需确认磁盘与 FileStorage 配置一致。
  4. i18ni18n/{zh,en,jp,ko}/msg.txt 已含表字段词条commit 1461430
  5. pyproject/setup.cfg:包名 filemgr 0.0.1,依赖 apppublic/sqlor/ahserverpackages = find: 会把 app/json/ 一并扫描,安装时注意。

已知问题(实测代码,未修改——修前必读)

  • FileMgr.__init__(self, fiid) 要求 fiid,但 wwwroot 各 dspy 均以 FileMgr() 无参构造 → 直接运行会 TypeErrorgetallfiles.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 递归调用漏传 sordel_folderself.file_deleted(...) 未 await。
  • get_folder_ownerid/file_uploaded/file_deleted 基类均为空实现passis_folder_ownerid 因此恒 False → add_file 属主校验必失败;基类 get_organization_quota 返回 quota=0commit 5a81ea2 特意 revert 回 0→ 未覆写的子类任何上传都触发配额溢出。本模块设计为被业务子类继承覆写这三个钩子后使用。
Description
No description provided
Readme 249 KiB
Languages
Python 99.2%
Shell 0.8%