Integration: REST и DAV проходят общий набор операций над тестовой папкой
(создать/upload/list/stat/download/rename/move/copy/delete), папка убирается.
go build ./... && go vet ./... && go test ./... зелёные; go test -tags=integration ./... зелёные на живом OO.
Публичные сигнатуры files*.go не изменены.
Epic: #34
## F1 — каноническая модель + `FileStore`/`Searcher`; адаптеры REST и WebDAV
### Цель
Ввести единую внутреннюю абстракцию доступа к файлам и перевести на неё уже
существующие бэкенды (REST и WebDAV), не ломая публичный API.
### Артефакты (плоский пакет, без подпакетов)
- `file_core.go`:
- `type Kind int` (`File`/`Folder`).
- `type Entry struct { ID, ParentID, Title string; Kind Kind; Size int64; MIME string; Created, Modified time.Time; Version int; Provider string }`.
- `type FileStore interface { Name() string; List(ctx, parentID) ([]Entry, error); Stat(ctx,id) (Entry,error); CreateFolder(ctx,parentID,title) (Entry,error); Upload(ctx,parentID,title string, r io.Reader) (Entry,error); Download(ctx,id string, w io.Writer) (int64,error); Move(ctx, ids []string, parentID) error; Copy(...) error; Rename(ctx,id,title) error; Delete(ctx, ids []string) error }`.
- `type SearchQuery struct { Text string; InContent bool; FolderID string; Extensions []string; Limit int }`.
- `type SearchHit struct { Entry; Score float64; Highlight string; Path []string }`.
- `type Searcher interface { Search(ctx, SearchQuery) ([]SearchHit, error); Name() string }`.
- `file_rest.go` — `restStore` поверх существующих методов `files.go`
(`ListFolder`, `GetFile`, `CreateFolder`, `UploadToFolder`, `UpdateFile`,
`DownloadFile`, `MoveFiles`, `RenameFile`, `DeleteFiles`).
- `file_dav.go` — `davStore` поверх `files_webdav.go` (`ListDavFolder`,
`CreateDavFolder`, `UploadDavFile`, `DownloadDavFile`, `MoveDavItems`,
`CopyDavItems`, `RenameDavFile`/`RenameDavFolder`, `DeleteDavItems`).
- Доступ из `*Client`: `c.FileStore(backend)` или `c.Files()` (фасад решается в F4).
### Правила
- Никаких подпакетов; никаких синтетических моков OnlyOffice — только
интеграционные тесты (`//go:build integration`) против живого инстанса.
- Существующие публичные методы сохранить (обратная совместимость).
- Запись — через `DoRetry`.
### Тесты/критерии
- [ ] Unit: конверсия `FileEntry`/`DavFile` → `Entry` (чистые функции), `Kind`.
- [ ] Integration: REST и DAV проходят общий набор операций над тестовой папкой
(создать/upload/list/stat/download/rename/move/copy/delete), папка убирается.
- [ ] `go build ./... && go vet ./... && go test ./...` зелёные;
`go test -tags=integration ./...` зелёные на живом OO.
- [ ] Публичные сигнатуры `files*.go` не изменены.
file_rest.go — restStore поверх files.go: ListFolder, GetFile, CreateFolder, UploadToFolder, DownloadFile, MoveFiles, RenameFile, DeleteFiles; Copy — через CopyDavItems (в files.go копирования нет). Upload (io.Reader) спулится в temp-файл, т.к. UploadToFolder path-based.
file_dav.go — davStore поверх files_webdav.go: ListDavFolder, CreateDavFolder, UploadDavFile, DownloadDavFile, MoveDavItems, CopyDavItems, RenameDavFile/RenameDavFolder, DeleteDavItems.
Иды для fileops классифицируются Stat (папки/файлы).
Все API-вызовы адаптеров — через DoRetry (retryStoreOp, DefaultRetryPolicy).
Фикс MoveFiles (нужен restStore.Move): fileops/move отдаёт envelope
с массивом операций, а старый код через putJSONObject разворачивал его и
затем fileopsError искал уже срезанный response → всегда response missing "response", хотя перенос проходил. Теперь как MoveDavItems: putJSON + fileopsError, сигнатура не изменена.
Тесты (имена + PASS)
Unit — go build ./... && go vet ./... && go test ./... зелёные:
TestFileEntryToEntry — PASS
TestFileEntryToEntryNil — PASS
TestFileEntryToEntrySizeFormats — PASS
TestDavFileToEntry — PASS
TestDavFolderToEntry — PASS
TestEntriesFromFolderMap — PASS
TestEntriesFromFolderMapNil — PASS
TestKindString — PASS
TestClientFileStoreSelection — PASS
Integration (//go:build integration, живой OO https://office.pro-dukt.de) — go test -tags=integration -run TestIntegrationFileStores -v .:
TestIntegrationFileStores/rest — PASS
TestIntegrationFileStores/dav — PASS
Общий набор на тестовой папке проекта: create folder / upload / list / stat /
download / move / copy / rename / delete, папки убираются. Учтена
асинхронность fileops (move/copy/delete видны с задержкой) — тест опрашивает
результат. Прогон повторялся, стабильно зелёный.
Замечания / блокеры
Полный go test -tags=integration ./... на main уже красный в cmd/office/fetch (loader.TaskFields undefined, task_integration_test.go:60) — не связано с этой задачей, не трогал.
При массовом прогоне подряд портал отдаёт 429 на auth
(invalid character '<' / 429 Too Many Requests), из-за чего часть
старых integration-тестов падает; поодиночке/с паузами проходят. Лечится
паузами/DoRetry, вне рамок F1.
Секреты не печатались, gitleaks (git + working tree) — clean.
## F1 — отчёт: каноническая модель + `FileStore`/`Searcher`; адаптеры REST и DAV
PR: https://git.produktor.io/eSlider/go-onlyoffice/pulls/40
Ветка `feat/file-store#35` · коммит `94951fc` (base `main`).
Не мержу и не закрываю.
### Что сделано
- `file_core.go`:
- `type Kind int` (`File`/`Folder`) + `String()`.
- `type Entry struct { ID, ParentID, Title string; Kind Kind; Size int64; MIME string; Created, Modified time.Time; Version int; Provider string }`.
- `type FileStore interface { Name; List; Stat; CreateFolder; Upload; Download; Move; Copy; Rename; Delete }`.
- `type SearchQuery`, `type SearchHit`, `type Searcher`.
- Доступ: `c.FileStore(backend)` (по умолчанию REST, `dav`/`webdav` — DAV) и `c.Files()`. Полноценный фасад — F4 #38, сигнатуры существующих методов не тронуты.
- Чистые конверсии: `FileEntryToEntry`, `DavFileToEntry`, `DavFolderToEntry`.
- `file_rest.go` — `restStore` поверх `files.go`: `ListFolder`, `GetFile`,
`CreateFolder`, `UploadToFolder`, `DownloadFile`, `MoveFiles`, `RenameFile`,
`DeleteFiles`; `Copy` — через `CopyDavItems` (в `files.go` копирования нет).
`Upload` (io.Reader) спулится в temp-файл, т.к. `UploadToFolder` path-based.
- `file_dav.go` — `davStore` поверх `files_webdav.go`: `ListDavFolder`,
`CreateDavFolder`, `UploadDavFile`, `DownloadDavFile`, `MoveDavItems`,
`CopyDavItems`, `RenameDavFile`/`RenameDavFolder`, `DeleteDavItems`.
Иды для fileops классифицируются `Stat` (папки/файлы).
- Все API-вызовы адаптеров — через `DoRetry` (`retryStoreOp`,
`DefaultRetryPolicy`).
- **Фикс `MoveFiles`** (нужен `restStore.Move`): `fileops/move` отдаёт envelope
с массивом операций, а старый код через `putJSONObject` разворачивал его и
затем `fileopsError` искал уже срезанный `response` → всегда
`response missing "response"`, хотя перенос проходил. Теперь как
`MoveDavItems`: `putJSON` + `fileopsError`, сигнатура не изменена.
### Тесты (имена + PASS)
Unit — `go build ./... && go vet ./... && go test ./...` зелёные:
- `TestFileEntryToEntry` — PASS
- `TestFileEntryToEntryNil` — PASS
- `TestFileEntryToEntrySizeFormats` — PASS
- `TestDavFileToEntry` — PASS
- `TestDavFolderToEntry` — PASS
- `TestEntriesFromFolderMap` — PASS
- `TestEntriesFromFolderMapNil` — PASS
- `TestKindString` — PASS
- `TestClientFileStoreSelection` — PASS
Integration (`//go:build integration`, живой OO
`https://office.pro-dukt.de`) — `go test -tags=integration -run
TestIntegrationFileStores -v .`:
- `TestIntegrationFileStores/rest` — PASS
- `TestIntegrationFileStores/dav` — PASS
Общий набор на тестовой папке проекта: create folder / upload / list / stat /
download / move / copy / rename / delete, папки убираются. Учтена
асинхронность `fileops` (move/copy/delete видны с задержкой) — тест опрашивает
результат. Прогон повторялся, стабильно зелёный.
### Замечания / блокеры
- Полный `go test -tags=integration ./...` на main уже красный в
`cmd/office/fetch` (`loader.TaskFields undefined`,
`task_integration_test.go:60`) — не связано с этой задачей, не трогал.
- При массовом прогоне подряд портал отдаёт `429` на auth
(`invalid character '<'` / `429 Too Many Requests`), из-за чего часть
старых integration-тестов падает; поодиночке/с паузами проходят. Лечится
паузами/`DoRetry`, вне рамок F1.
- Секреты не печатались, gitleaks (git + working tree) — clean.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Epic: #34
F1 — каноническая модель +
FileStore/Searcher; адаптеры REST и WebDAVЦель
Ввести единую внутреннюю абстракцию доступа к файлам и перевести на неё уже
существующие бэкенды (REST и WebDAV), не ломая публичный API.
Артефакты (плоский пакет, без подпакетов)
file_core.go:type Kind int(File/Folder).type Entry struct { ID, ParentID, Title string; Kind Kind; Size int64; MIME string; Created, Modified time.Time; Version int; Provider string }.type FileStore interface { Name() string; List(ctx, parentID) ([]Entry, error); Stat(ctx,id) (Entry,error); CreateFolder(ctx,parentID,title) (Entry,error); Upload(ctx,parentID,title string, r io.Reader) (Entry,error); Download(ctx,id string, w io.Writer) (int64,error); Move(ctx, ids []string, parentID) error; Copy(...) error; Rename(ctx,id,title) error; Delete(ctx, ids []string) error }.type SearchQuery struct { Text string; InContent bool; FolderID string; Extensions []string; Limit int }.type SearchHit struct { Entry; Score float64; Highlight string; Path []string }.type Searcher interface { Search(ctx, SearchQuery) ([]SearchHit, error); Name() string }.file_rest.go—restStoreповерх существующих методовfiles.go(
ListFolder,GetFile,CreateFolder,UploadToFolder,UpdateFile,DownloadFile,MoveFiles,RenameFile,DeleteFiles).file_dav.go—davStoreповерхfiles_webdav.go(ListDavFolder,CreateDavFolder,UploadDavFile,DownloadDavFile,MoveDavItems,CopyDavItems,RenameDavFile/RenameDavFolder,DeleteDavItems).*Client:c.FileStore(backend)илиc.Files()(фасад решается в F4).Правила
интеграционные тесты (
//go:build integration) против живого инстанса.DoRetry.Тесты/критерии
FileEntry/DavFile→Entry(чистые функции),Kind.(создать/upload/list/stat/download/rename/move/copy/delete), папка убирается.
go build ./... && go vet ./... && go test ./...зелёные;go test -tags=integration ./...зелёные на живом OO.files*.goне изменены.F1 — отчёт: каноническая модель +
FileStore/Searcher; адаптеры REST и DAVPR: #40
Ветка
feat/file-store#35· коммит94951fc(basemain).Не мержу и не закрываю.
Что сделано
file_core.go:type Kind int(File/Folder) +String().type Entry struct { ID, ParentID, Title string; Kind Kind; Size int64; MIME string; Created, Modified time.Time; Version int; Provider string }.type FileStore interface { Name; List; Stat; CreateFolder; Upload; Download; Move; Copy; Rename; Delete }.type SearchQuery,type SearchHit,type Searcher.c.FileStore(backend)(по умолчанию REST,dav/webdav— DAV) иc.Files(). Полноценный фасад — F4 #38, сигнатуры существующих методов не тронуты.FileEntryToEntry,DavFileToEntry,DavFolderToEntry.file_rest.go—restStoreповерхfiles.go:ListFolder,GetFile,CreateFolder,UploadToFolder,DownloadFile,MoveFiles,RenameFile,DeleteFiles;Copy— черезCopyDavItems(вfiles.goкопирования нет).Upload(io.Reader) спулится в temp-файл, т.к.UploadToFolderpath-based.file_dav.go—davStoreповерхfiles_webdav.go:ListDavFolder,CreateDavFolder,UploadDavFile,DownloadDavFile,MoveDavItems,CopyDavItems,RenameDavFile/RenameDavFolder,DeleteDavItems.Иды для fileops классифицируются
Stat(папки/файлы).DoRetry(retryStoreOp,DefaultRetryPolicy).MoveFiles(нуженrestStore.Move):fileops/moveотдаёт envelopeс массивом операций, а старый код через
putJSONObjectразворачивал его изатем
fileopsErrorискал уже срезанныйresponse→ всегдаresponse missing "response", хотя перенос проходил. Теперь какMoveDavItems:putJSON+fileopsError, сигнатура не изменена.Тесты (имена + PASS)
Unit —
go build ./... && go vet ./... && go test ./...зелёные:TestFileEntryToEntry— PASSTestFileEntryToEntryNil— PASSTestFileEntryToEntrySizeFormats— PASSTestDavFileToEntry— PASSTestDavFolderToEntry— PASSTestEntriesFromFolderMap— PASSTestEntriesFromFolderMapNil— PASSTestKindString— PASSTestClientFileStoreSelection— PASSIntegration (
//go:build integration, живой OOhttps://office.pro-dukt.de) —go test -tags=integration -run TestIntegrationFileStores -v .:TestIntegrationFileStores/rest— PASSTestIntegrationFileStores/dav— PASSОбщий набор на тестовой папке проекта: create folder / upload / list / stat /
download / move / copy / rename / delete, папки убираются. Учтена
асинхронность
fileops(move/copy/delete видны с задержкой) — тест опрашиваетрезультат. Прогон повторялся, стабильно зелёный.
Замечания / блокеры
go test -tags=integration ./...на main уже красный вcmd/office/fetch(loader.TaskFields undefined,task_integration_test.go:60) — не связано с этой задачей, не трогал.429на auth(
invalid character '<'/429 Too Many Requests), из-за чего частьстарых integration-тестов падает; поодиночке/с паузами проходят. Лечится
паузами/
DoRetry, вне рамок F1.