尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

WeKan 看板背景图(Board Backgrounds):存储机制、界面操作与 REST API 全流程解析

WeKan 看板背景图(Board Backgrounds):存储机制、界面操作与 REST API 全流程解析 WeKan 看板背景图Board Backgrounds存储机制、界面操作与 REST API 全流程解析【免费下载链接】wekanThe Open Source kanban, built with Meteor. GitHub issues/PRs are only for FLOSS Developers, not for support, support is at https://wekan.fi/commercial-support/ . PR source translation to imports/i18n/data/en.i18n.json, other translations at https://app.transifex.com/wekan/wekan项目地址: https://gitcode.com/GitHub_Trending/we/wekanWeKan 允许看板管理员把背景图片直接存储在 WeKan 自身而不是依赖外部 URL并通过「看板菜单 → 看板背景」完成上传、设为当前背景、下载与删除。本篇以docs/Features/Board/Board-Backgrounds/Board-Backgrounds.md为主体逐条还原文档描述的存储目录、界面操作、导入导出行为并结合源码server/boardBackgrounds.js、server/routes/attachmentApi.js、models/boards.js深入讲解其权限模型、存储策略与 DDP/REST 两套 API 的落地实现读完你既能上手配置背景图也能理解其底层调用链与回归测试。一、背景图如何被存储backgrounds目录与默认存储后端文档开篇说明看板背景图会存储在 WeKan 内部具体做法是在attachments与avatars旁边创建一个backgrounds文件存储目录并使用当前默认存储后端default storage backend。默认存储后端由管理员在Admin Panel / Attachments / Default Storage中配置与卡片附件共用同一套后端。从源码结构看背景图本质上是一条**看板级附件board-level attachment**记录。上传时meta字段里带有boardId与source: api-backgroundREST或source: board-background界面上传见 client/components/sidebar/sidebar.js并没有cardId。正因为它是“附件的一种”它天然复用了 WeKan 的整套存储策略filesystem / gridfs / S3与软删除机制。适用前提背景图走的是附件存储体系因此其可用后端受管理员在 Admin Panel 中配置的 Default Storage 限制。当后端为 filesystem 时落到backgrounds目录当为 gridfs/S3 时文件会先落 filesystem再异步moveToStorage迁移到目标后端见 server/routes/attachmentApi.js。二、界面操作上传 / 设为当前 / 下载 / 删除文档列出的界面入口是Board menu → Board backgrounds看板管理员可执行四类操作。对应前端实现位于 client/components/sidebar/sidebar.jade 的两个模板boardBackgroundUpload上传区选择本地图片写入meta: { boardId, source: board-background }。boardBackgroundList管理区classboard-backgrounds-grid以缩略图网格列出该看板所有背景图每项支持点击缩略图 →设为当前背景js-set-board-backgroundtitleset-as-active下载js-download-board-backgroundhref{{link}}?downloadtrue download删除js-delete-board-background先弹出确认框。此外模板里还提供了一个input.js-board-background-image-url允许管理员直接粘贴一个图片 URL 作为背景board-background-image-url。设为当前背景setBackgroundImage“设为当前”这一动作会更新看板文档上的backgroundImageId与backgroundImageURL两个字段。核心实现在 models/boards.js// Set a board-level background attachment as the active board background. async setBackgroundImage(backgroundId) { const currentUser await ReactiveCache.getCurrentUser(); if (currentUser.isBoardAdmin() || currentUser.isAdmin()) { const backgroundImageURL generateUniversalAttachmentUrl(backgroundId); return await Boards.updateAsync(this._id, { $set: { backgroundImageId: backgroundId, backgroundImageURL }, }); } return false; }要点权限仅isBoardAdmin()看板管理员或isAdmin()站点管理员可写其余成员返回false。backgroundImageURL由generateUniversalAttachmentUrl(backgroundId)生成是一条通用的附件访问 URL前端据此渲染背景。对称地unsetBackgroundImage()会把两个字段都置空字符串setBackgroundImageURL()则允许直接设置 URL。删除背景软删除与“当前背景”的联动清除删除走的是看板级方法removeBoardBackgroundserver/boardBackgrounds.js它被设计成 method 而非allow规则因为需要做异步的看板管理员校验async removeBoardBackground(attachmentId) { // ... 权限校验board.hasAdmin(this.userId) || user.isAdmin // If this background is the boards active one, clear it. if (board.backgroundImageId attachmentId) { await Boards.updateAsync(boardId, { $set: { backgroundImageId: , backgroundImageURL: }, }); } // A soft delete (History.md §12.3), like every attachment: the file stays // and the boards history can restore it. await softDeleteAttachment({ userId: this.userId, attachment }); return true; }这里有两个关键设计当前背景联动清除被删除的图如果恰好是看板的当前背景board.backgroundImageId attachmentId会同时清空backgroundImageId与backgroundImageURL避免指向一条已删除的附件。软删除soft delete与所有附件一致文件保留、可通过看板历史恢复而非物理删除。三、看板页与“全部看板”列表中的背景渲染文档指出当前背景图还会作为看板卡片tile的背景显示在 All Boards 列表页并配一层深色遮罩dark overlay保证标题可读。渲染决策辅助函数computeBoardBackground前端如何决定“当前这块看板背景该画成什么”由纯函数 models/lib/boardBackground.js 给出// Returns the background descriptor for board: // { type: image, url } - board has a background image (apply inline url) // { type: color } - board has a color but no image // { type: none } - board has neither: clear any stale inline bg function computeBoardBackground(board) { if (!board) return { type: none }; const url board.backgroundImageURL; if (typeof url string url.length 0) { return { type: image, url }; } if (board[background-color] || board.color) { return { type: color }; } return { type: none }; }这个函数背后是一个真实的线上缺陷修复Issue #4978。文件头注释解释得很清楚从收藏栏在看板 A 与 B 之间直接切换时boardBody模板实例会被复用currentBoard由 A 变 B 而非变 null一次性的Utils.setBackgroundImage()不会重跑导致 A 的background:url(...)内联样式“粘”在.board-wrapper上。修复思路是(1) 在响应式 autorun 中调用setBackgroundImage()使当前看板变化时重算(2) 由本纯函数返回包含none在内的结果主动清除过期的内联背景——旧代码只会 SET 背景、从不 RESET所以 image→color 或 image→plain 的切换会残留旧图。回归测试boardBackground.test.cjstests/boardBackground.test.cjs 是纯 Node 单测不依赖 Meteor可直接node tests/boardBackground.test.cjs运行正是为守住 #4978 的回归test(board with a background image URL - type image url, () { const bg computeBoardBackground({ backgroundImageURL: https://x/y.png }); assert.deepStrictEqual(bg, { type: image, url: https://x/y.png }); }); // NEGATIVE: board with neither image nor color - none (clears stale bg) test(NEGATIVE: board with neither image nor color - none, () { assert.deepStrictEqual(computeBoardBackground({ title: Plain }), { type: none }); });它同时覆盖了“图片优先级高于颜色”“空字符串 URL 不被误判为图片”“image→plain 切换绝不保留旧 url”“null/undefined board 不抛异常”等边界是理解该功能健壮性的最佳入口。四、导入与导出背景图的随迁文档在 Import and export 一节说明了两点均可在源码中得到印证看板导出会包含该看板的背景图并支持重新导入。Trello 看板的背景图会在导入时下载并存入本地这样即便原始 Trello URL 日后失效背景仍可用。第 2 点的实现落在 models/trelloCreator.js导入时先读取prefs.backgroundImageScaled缩放后优先或prefs.backgroundImage作为backgroundImageURL兜底随后在拿到本地文件引用后把backgroundImageId与backgroundImageURLgenerateUniversalAttachmentUrl(fileRef._id)写入看板文档。这正是“先保留 Trello 公共 URL 兜底、再替换为本地存储附件 URL”的两段式处理。结论背景图作为看板的一部分参与导入/导出且 Trello 迁移时做了“下载落地”以摆脱对外部 URL 的长期依赖。五、REST API上传与下载背景图这是文档中参数最密集的一节。背景图可经 REST API 上传与下载是卡片附件上传/下载 API 的看板级对应物。5.1 端点总览MethodPath用途POST/api/attachment/upload-background上传图片并设为看板背景。JSON body{ boardId, fileData (base64), fileName, fileType? }GET/api/attachment/download-background/:boardId下载看板当前背景图返回base64Data 元数据配套 CLIapi.pypython3 api.py uploadbackground BOARDID /path/to/background.png python3 api.py downloadbackground BOARDID /path/to/saved-background.png5.2 权限模型与文档一致源码可验证文档强调上传需要看板管理员下载需要看板成员。上传server/routes/attachmentApi.js校验board.hasAdmin(userId) || 站点管理员否则返回403 Board admin required。这与 DDP 侧的api.board.uploadBackgroundserver/attachmentApi.js以及 methodremoveBoardBackground的权限口径完全一致。下载server/routes/attachmentApi.js校验board.hasMember(userId)即任意成员均可下载当前背景。5.3 上传流程的关键细节源码级/api/attachment/upload-background的完整处理链鉴权authenticateApiRequest(req)支持 accounts-express 上下文、可信 SSO 头登录、以及兼容性的X-User-Id/X-Auth-Token。传输限额getApiTransferLimits()读取AttachmentStorageSettings.limitSettings的apiUploadBlocked/apiUploadMaxBytes并存在硬性安全上限HARD_MAX_API_FILE_BYTES 64 * 1024 * 102464MB。超限时413。存储后端始终使用管理员配置的默认后端settings.getDefaultStorage()若为 gridfs/S3 则异步moveToStorage。写入并设为当前背景const file new File([fileBuffer], fileName, { type: fileType || image/png }); const meta { boardId, fileId, source: api-background, storageBackend: targetStorage }; const uploader await Attachments.insertAsync({ file, meta, isBase64: false, transport: http }); await board.setBackgroundImage(uploader._id);响应返回success、attachmentId、fileName、fileSize、storageBackend、backgroundImageURL与提示消息。注意这里fileType缺省值是image/png背景图默认按 PNG 处理而卡片附件缺省是application/octet-stream——这是背景端点与通用附件端点的细微差别。5.4 下载流程的关键细节/api/attachment/download-background/:boardId校验成员资格 → 读取board.backgroundImageId若无则404 Board has no background image set。通过fileStoreStrategyFactory.getFileStrategy(attachment, original)拿到读流按apiDownloadMaxBytes限额流式读取。成功响应 JSON{ success, attachmentId, fileName, fileSize, fileType, base64Data, backgroundImageURL, storageBackend }。5.5 DDP 方法对SDK / DDP 客户端文档还提到存在一对 DDP 方法供 SDK/DDP 客户端使用实现在 server/attachmentApi.jsapi.board.uploadBackground(boardId, fileData, fileName, fileType)与 REST 上传逻辑对齐——校验登录、看板存在、看板管理员权限、默认存储后端、上传限额写入附件后board.setBackgroundImage(uploader._id)。api.board.downloadBackground(boardId)校验成员资格读取当前背景附件并返回 base64 与元数据。两条链REST 与 DDP在权限口径、存储后端选择、限额与“上传即设为当前背景”的行为上保持镜像一致方便不同集成方式HTTP 或 SDK选择。六、与主题的其它能力如何衔接背景图功能并非孤立它与 WeKan 的看板与附件体系多处交汇看板Boards字段backgroundImageId/backgroundImageURL/color/background-color是看板文档上的可写字段写入受看板管理员权限保护models/boards.js。附件与文件存储背景图复用 docs/Features/Cards/Attachments/Attachments.md 所述的存储/软删除/迁移体系。主题与自定义 CSS背景图是看板级“图片”背景区别于 docs/Features/Theme/Custom-CSS-themes.md 的主题/自定义 CSS二者可并存图片经background:url()内联颜色经.board-wrapper的 colorClass。从 Trello 迁移见 docs/Features/ImportExport/Trello/trello/Migrating-from-Trello.md 与 models/trelloCreator.js 的背景落地逻辑。相关文档docs/Features/Board/Boards/Boards.md。七、要点回顾与可验证路径关注点事实证据路径存储位置backgrounds目录随默认存储后端server/routes/attachmentApi.js设为当前背景setBackgroundImage写backgroundImageId/URL仅看板/站点管理员models/boards.js删除methodremoveBoardBackground软删除且联动清空当前背景server/boardBackgrounds.js渲染决策computeBoardBackground返回 image/color/none支持清除旧背景#4978models/lib/boardBackground.js回归测试纯 Node 单测可node tests/boardBackground.test.cjstests/boardBackground.test.cjsTrello 导入下载 Trello 背景并落地为本地附件models/trelloCreator.jsREST 上传POST /api/attachment/upload-background看板管理员默认后端server/routes/attachmentApi.jsREST 下载GET /api/attachment/download-background/:boardId看板成员server/routes/attachmentApi.jsDDP 方法api.board.uploadBackground/api.board.downloadBackgroundserver/attachmentApi.jsCLIapi.py uploadbackground/downloadbackgroundapi.py综上WeKan 的看板背景图是一条“以附件为底、看板管理员可控、导入导出随迁、REST/DDP 双通道”的完整能力链。理解computeBoardBackground的三态返回与setBackgroundImage/removeBoardBackground的权限口径是把握该功能设计与健壮性的关键。【免费下载链接】wekanThe Open Source kanban, built with Meteor. GitHub issues/PRs are only for FLOSS Developers, not for support, support is at https://wekan.fi/commercial-support/ . PR source translation to imports/i18n/data/en.i18n.json, other translations at https://app.transifex.com/wekan/wekan项目地址: https://gitcode.com/GitHub_Trending/we/wekan创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表