268 lines
9.1 KiB
Markdown
268 lines
9.1 KiB
Markdown
# DocSystem(MxsDoc)HTTP 接口文档
|
||
|
||
目标系统:MxsDoc / DocSystem V2.02.71
|
||
地址:`http://172.1.4.31:8100/DocSystem`
|
||
前端入口:`/DocSystem/web/index.html` → `projects.html` → `project.html?vid=<仓库ID>`
|
||
|
||
本文档由前端 JS 逆向 + 逐接口实测得出,用于支撑 `scripts/docsys.py`。
|
||
|
||
---
|
||
|
||
## 通用约定
|
||
|
||
- 凭证配置(`scripts/docsys.py` 读取顺序:命令行参数 > `~/.docsys/config.json` > 环境变量 > 内置默认地址):
|
||
```json
|
||
// ~/.docsys/config.json
|
||
{"baseUrl": "http://172.1.4.31:8100/DocSystem", "user": "x@y.com", "password": "xxx"}
|
||
```
|
||
环境变量:`DOCSYS_BASE_URL` / `DOCSYS_USER` / `DOCSYS_PASSWORD`。
|
||
仓库默认库可用 `DOCSYS_DEFAULT_REPO` 覆盖。**凭证不要提交进代码库。**
|
||
- 全部接口为 `POST`,表单编码 `application/x-www-form-urlencoded; charset=UTF-8`
|
||
(仅 `uploadDoc.do` 为 `multipart/form-data`)。
|
||
- 必须带请求头 `X-Requested-With: XMLHttpRequest`。
|
||
- 会话靠 Cookie 维持:`JSESSIONID`、`dstoken`(= base64(密码))、`dsuser`(= 用户名)。
|
||
`rememberMe=1` 时服务端下发 `dstoken`/`dsuser` 用于自动登录。
|
||
- 响应统一 JSON:`{"status":"ok"|"fail","data":...,"msgInfo":"...","msgData":...}`。
|
||
少数接口(如 `getDocContent.do`)返回纯文本。
|
||
- 节点类型:`type=1` 文件,`type=2` 目录。
|
||
- 时间字段为毫秒时间戳。
|
||
|
||
## 鉴权
|
||
|
||
### POST `User/login.do`
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `userName` | 邮箱或手机号 |
|
||
| `pwd` | 密码经 base64 编码后的字符串(标准 base64,非 URL-safe) |
|
||
| `rememberMe` | `1` 记住登录,`0` 不记住 |
|
||
|
||
成功返回 `data` 为用户对象(`id`/`name`/`realName`/`role`/…)。
|
||
|
||
### POST `User/logout.do`
|
||
无参数。
|
||
|
||
### POST `User/getLoginUser.do`
|
||
无参数,返回当前登录用户。可用于探测会话是否有效。
|
||
|
||
---
|
||
|
||
## 仓库
|
||
|
||
### POST `Repos/getReposList.do`
|
||
无参数。返回 `data` 为仓库数组:
|
||
`{id, name, info, type, verCtrl, path, owner, ...}`
|
||
|
||
实测可见仓库:
|
||
|
||
| id | 名称 | 说明 |
|
||
|---|---|---|
|
||
| 1 | 意见与反馈 | 当前账号可新增/编辑,不可删除/下载 |
|
||
| **2** | **研发管理配置库** | **CLI 默认仓库**(`DEFAULT_REPO_NAME`),基本只读,部分目录可下载 |
|
||
| 5 | 常用工具 | 只读 |
|
||
| 6 | 临时仓库 | 无访问权限 |
|
||
|
||
> **约定**:`scripts/docsys.py` 中若省略仓库参数,默认操作 id=2「研发管理配置库」。
|
||
> 判定规则:第一个位置参数以 `/` 或 `./` 开头则视为路径(仓库取默认),否则视为仓库 id/名称。
|
||
|
||
### POST `Repos/getDocSysConfig.do`
|
||
无参数,返回系统配置(如 `defaultReposStorePath`)。
|
||
|
||
---
|
||
|
||
## 目录列举
|
||
|
||
### POST `Repos/getSubDocList.do`
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `vid` | 仓库 id |
|
||
| `docId` | 目录 docId(**实测服务端不使用**,仅随请求透传) |
|
||
| `path` | 目录路径,仓库根为 `""`,其余以 `/` 结尾 |
|
||
| `name` | 目录名。服务端取 `path + name` 作为目标目录 |
|
||
| `sort` | 排序方式,`0` 名称 |
|
||
| `needLockState` | `1` |
|
||
| `shareId` | 可传空 |
|
||
|
||
**关键结论**:目标目录 = `path + name`。传 `path="a/"`、`name=""` 与 `path=""`、`name="a"`
|
||
等价;但传 `path="a/"` 且 `name="a"` 会变成 `a/a` 从而返回空。
|
||
|
||
返回 `data` 为节点数组,节点字段:
|
||
`docId, pid, path, name, type, level, size, checkSum, createTime, latestEditTime,
|
||
latestEditorName, creatorName, localRootPath, reposPath, ...`
|
||
|
||
其中 `path` 是**节点所在目录**的路径,节点完整路径 = `path + name`。
|
||
|
||
---
|
||
|
||
## 权限
|
||
|
||
### POST `Repos/getUserDocAuth.do`
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `docId` | 目录 docId,仓库根为 `0` |
|
||
| `reposId` | 仓库 id |
|
||
| `path` | 目录自身路径 |
|
||
| `name` | 目录名 |
|
||
|
||
返回 `data`:`{access, addEn, editEn, deleteEn, downloadEn, isAdmin, uploadSize, ...}`
|
||
|
||
实测(账号 `qian.huang@sunyard.com`,仓库 1):
|
||
```
|
||
access=1 addEn=1 editEn=1 deleteEn=0 downloadEn=0 isAdmin=0
|
||
```
|
||
|
||
注意:**rename / move 在服务端按"删除 + 新增"鉴权**,因此即使 `addEn=1`,
|
||
`deleteEn=0` 时重命名和移动同样会被拒绝,报错为「您没有该目录的删除权限」。
|
||
|
||
### 权限是逐目录授予的,不是仓库级
|
||
|
||
同一个仓库里不同目录的权限可以完全不同。实测:
|
||
|
||
| 仓库 / 目录 | access | addEn | editEn | deleteEn | downloadEn |
|
||
|---|---|---|---|---|---|
|
||
| 2 研发管理配置库 `/`(根) | 1 | 0 | 0 | 0 | 0 |
|
||
| 2 `/Sunyard/Docs/开发流程` | 1 | 0 | 0 | 0 | **1** |
|
||
| 2 `/Sunyard/Dev/产品/系统研发/工具` | 1 | **1** | **1** | **1** | **1** |
|
||
| 1 意见与反馈 `/`(根) | 1 | 1 | 1 | 0 | 0 |
|
||
|
||
所以**不能凭仓库名推断权限**,写操作前务必先查 `getUserDocAuth`。
|
||
|
||
---
|
||
|
||
## 写操作
|
||
|
||
### POST `Doc/addDoc.do`(新建文件 / 目录)
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `reposId` | 仓库 id |
|
||
| `type` | `1` 文件,`2` 目录 |
|
||
| `pid` | 父目录 docId,仓库根为 `0` |
|
||
| `path` | **父目录完整路径 + `/`**,仓库根为 `""` |
|
||
| `name` | 新节点名 |
|
||
| `content` | 文本文件内容;建目录传空 |
|
||
|
||
返回 `data` 为新节点,`msgData` 为 `isNewNode`。
|
||
|
||
> ⚠️ **实测:`content` 被服务端忽略。** 即使传了内容,建出来也是 0 字节空文件
|
||
> (响应 `size=0`,随后 `getDocContent` 读不到任何内容)。
|
||
> 要创建带内容的文件必须改用 `Doc/uploadDoc.do`(CLI 的 `touch` 已自动走这条路)。
|
||
|
||
### POST `Doc/renameDoc.do`
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `reposId` | 仓库 id |
|
||
| `docId` | 节点 docId |
|
||
| `pid` | 父目录 docId |
|
||
| `type` | 节点类型 |
|
||
| `level` | 节点层级 |
|
||
| `path` | 节点**自身所在目录**路径 |
|
||
| `name` | 原名 |
|
||
| `dstName` | 新名 |
|
||
|
||
### POST `Doc/deleteDoc.do`
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `reposId` | 仓库 id |
|
||
| `docId` | 节点 docId |
|
||
| `pid` | 父目录 docId |
|
||
| `path` | 节点自身所在目录路径 |
|
||
| `name` | 节点名 |
|
||
|
||
删除目录时为递归删除。
|
||
|
||
### POST `Doc/moveDoc.do`
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `reposId` | 仓库 id |
|
||
| `docId` | 节点 docId |
|
||
| `type` | 节点类型 |
|
||
| `srcLevel` | 源层级 |
|
||
| `dstLevel` | 目标层级(父目录 level + 1;移到仓库根为 `0`) |
|
||
| `srcPid` | 源父目录 docId |
|
||
| `dstPid` | 目标父目录 docId,仓库根为 `0` |
|
||
| `srcPath` | 源目录路径 |
|
||
| `srcName` | 源名 |
|
||
| `dstPath` | **目标父目录完整路径 + `/`**,仓库根为 `""` |
|
||
| `dstName` | 目标名(可与源名不同,即改名 + 移动) |
|
||
|
||
### POST `Doc/copyDoc.do`
|
||
参数同 `moveDoc`。
|
||
|
||
---
|
||
|
||
## 上传 / 下载
|
||
|
||
### POST `Doc/uploadDoc.do`(multipart/form-data)
|
||
| 字段 | 说明 |
|
||
|---|---|
|
||
| `reposId` | 仓库 id |
|
||
| `path` | **目标目录完整路径 + `/`** |
|
||
| `name` | 远端文件名 |
|
||
| `size` | 文件字节数 |
|
||
| `checkSum` | 文件 MD5 |
|
||
| `uploadFile` | 文件内容(文件域) |
|
||
| `commitMsg` | 提交说明,可空 |
|
||
| `dirPath` | 文件夹上传标记,可空 |
|
||
|
||
大文件走分片:`chunkNum` / `cutSize` / `chunkIndex` / `chunkSize` / `chunkHash` /
|
||
`combineDisabled=1`,分片全部传完再调 `Doc/combineChunks.do`。
|
||
|
||
### POST `Doc/downloadDocPrepare.do`
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `reposId`, `docId`, `pid`, `path`, `name` | 目标节点 |
|
||
| `downloadType` | `1` 单文件 |
|
||
| `downloadList` | 可空 |
|
||
|
||
返回 `data`:`{path, name, targetPath, targetName}`,`msgData` 为 `deleteFlag`。
|
||
若 `msgData == 5` 表示目录正在打包,用 `data.id` 轮询
|
||
`Doc/queryDownloadPrepareTask.do`(参数 `taskId`),每 2 秒一次,直到 `msgData == 6`。
|
||
|
||
### GET `Doc/downloadDoc.do?...`
|
||
查询串:`vid, path, name, targetPath, targetName, deleteFlag, encryptEn=1`(值需 URL 编码)。
|
||
|
||
> 实测:直接调 `Doc/getDocFileLink.do` 拿到的链接指向 `tmp/History/rdata/<commitId>/...`
|
||
> 历史目录,该文件通常不存在,会返回 500。**必须走 `downloadDocPrepare` 流程。**
|
||
|
||
---
|
||
|
||
## 读取 / 搜索
|
||
|
||
### POST `Doc/searchDoc.do`
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `searchWord` | 关键词 |
|
||
| `sort` | `0` |
|
||
| `reposId` | 仓库 id |
|
||
| `path` | 限定目录范围,全库传 `""` |
|
||
|
||
返回 `data` 为命中项,`hitType`:`1` 文件名命中,`3` 正文命中;
|
||
`content` 为正文的 base64 编码;`dataEx` 为命中总数。
|
||
|
||
### POST `Doc/getDocContent.do`
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `reposId`, `docId`, `pid`, `path`, `name` | 目标文件 |
|
||
|
||
返回**纯文本**,响应以 `ok` 开头,后面才是文件正文,解析时须去掉前两个字符。
|
||
|
||
### POST `Doc/getDoc.do`
|
||
| 参数 | 说明 |
|
||
|---|---|
|
||
| `reposId`, `docId`, `pid`, `path`, `name` | 目标节点 |
|
||
| `docType` | `0` 不读取正文和备注 |
|
||
|
||
返回节点元信息。
|
||
|
||
---
|
||
|
||
## 已探明但未使用的接口
|
||
|
||
- `Doc/lockDoc.do` / `Doc/unlockDoc.do` — 文件锁定
|
||
- `Doc/executeDoc.do`、`Doc/refreshDoc.do`
|
||
- `Doc/checkChunkUploaded.do`、`Doc/combineChunks.do`、`Doc/getMaxThreadCount.do` — 分片上传
|
||
- `Doc/getDocFileLink.do`、`Doc/getZipDocFileLink.do` — 预览/下载链接(下载场景不可靠,见上)
|
||
- `Bussiness/getDocOfficeLink.do`、`Bussiness/getDocCadLink.do` — 在线预览
|
||
- `Bussiness/addDocShare.do`、`Doc/getDocShare.do` — 分享
|
||
- `Doc/querySystemLog.do` — 操作日志
|
||
- `Repos/getReposInitMenu.do` — 目录树初始化菜单
|