зеркало из https://github.com/nextcloud/text.git
fix(sync): If `baseVersionEtag` changed, reset frontend
`baseVersionEtag` changes when a new document session got initialized, e.g. after an old document session without session clients got cleaned up, or because the markdown file got changed via webdav. Detect this in the client and ask the user to reload the page for resetting the session. Signed-off-by: Jonas <jonas@freesources.org>
This commit is contained in:
Родитель
4381329b65
Коммит
670d2f8cad
|
@ -80,8 +80,8 @@ class PublicSessionController extends PublicShareController implements ISessionA
|
|||
|
||||
#[NoAdminRequired]
|
||||
#[PublicPage]
|
||||
public function create(string $token, ?string $file = null, ?string $guestName = null): DataResponse {
|
||||
return $this->apiService->create(null, $file, $token, $guestName);
|
||||
public function create(string $token, ?string $file = null, ?string $baseVersionEtag = null, ?string $guestName = null): DataResponse {
|
||||
return $this->apiService->create(null, $file, $baseVersionEtag, $token, $guestName);
|
||||
}
|
||||
|
||||
#[NoAdminRequired]
|
||||
|
|
|
@ -57,8 +57,8 @@ class SessionController extends ApiController implements ISessionAwareController
|
|||
}
|
||||
|
||||
#[NoAdminRequired]
|
||||
public function create(?int $fileId = null, ?string $file = null): DataResponse {
|
||||
return $this->apiService->create($fileId, $file, null, null);
|
||||
public function create(?int $fileId = null, ?string $file = null, ?string $baseVersionEtag = null): DataResponse {
|
||||
return $this->apiService->create($fileId, $file, $baseVersionEtag, null, null);
|
||||
}
|
||||
|
||||
#[NoAdminRequired]
|
||||
|
|
|
@ -71,7 +71,7 @@ class ApiService {
|
|||
$this->l10n = $l10n;
|
||||
}
|
||||
|
||||
public function create(?int $fileId = null, ?string $filePath = null, ?string $token = null, ?string $guestName = null): DataResponse {
|
||||
public function create(?int $fileId = null, ?string $filePath = null, ?string $baseVersionEtag = null, ?string $token = null, ?string $guestName = null): DataResponse {
|
||||
try {
|
||||
if ($token) {
|
||||
$file = $this->documentService->getFileByShareToken($token, $this->request->getParam('filePath'));
|
||||
|
@ -115,6 +115,9 @@ class ApiService {
|
|||
$this->sessionService->removeInactiveSessionsWithoutSteps($file->getId());
|
||||
$document = $this->documentService->getDocument($file->getId());
|
||||
$freshSession = $document === null;
|
||||
if ($baseVersionEtag && $baseVersionEtag !== $document?->getBaseVersionEtag()) {
|
||||
return new DataResponse($this->l10n->t('Editing session has expired. Please reload the page.'), Http::STATUS_CONFLICT);
|
||||
}
|
||||
|
||||
if ($freshSession) {
|
||||
$this->logger->info('Create new document of ' . $file->getId());
|
||||
|
|
|
@ -374,6 +374,7 @@ export default {
|
|||
guestName,
|
||||
shareToken: this.shareToken,
|
||||
filePath: this.relativePath,
|
||||
baseVersionEtag: this.$syncService?.baseVersionEtag,
|
||||
forceRecreate: this.forceRecreate,
|
||||
serialize: this.isRichEditor
|
||||
? (content) => createMarkdownSerializer(this.$editor.schema).serialize(content ?? this.$editor.state.doc)
|
||||
|
|
|
@ -38,9 +38,10 @@ class SessionApi {
|
|||
this.#options = options
|
||||
}
|
||||
|
||||
open({ fileId }) {
|
||||
open({ fileId, baseVersionEtag }) {
|
||||
return axios.put(this.#url(`session/${fileId}/create`), {
|
||||
fileId,
|
||||
baseVersionEtag,
|
||||
filePath: this.#options.filePath,
|
||||
token: this.#options.shareToken,
|
||||
guestName: this.#options.guestName,
|
||||
|
|
|
@ -68,7 +68,7 @@ class SyncService {
|
|||
|
||||
#sendIntervalId
|
||||
|
||||
constructor({ serialize, getDocumentState, ...options }) {
|
||||
constructor({ baseVersionEtag, serialize, getDocumentState, ...options }) {
|
||||
/** @type {import('mitt').Emitter<import('./SyncService').EventTypes>} _bus */
|
||||
this._bus = mitt()
|
||||
|
||||
|
@ -82,6 +82,7 @@ class SyncService {
|
|||
this.lastStepPush = Date.now()
|
||||
|
||||
this.version = null
|
||||
this.baseVersionEtag = baseVersionEtag
|
||||
this.sending = false
|
||||
this.#sendIntervalId = null
|
||||
|
||||
|
@ -94,7 +95,7 @@ class SyncService {
|
|||
|
||||
const connect = initialSession
|
||||
? Promise.resolve(new Connection({ data: initialSession }, {}))
|
||||
: this._api.open({ fileId })
|
||||
: this._api.open({ fileId, baseVersionEtag: this.baseVersionEtag })
|
||||
.catch(error => this._emitError(error))
|
||||
|
||||
this.connection = await connect
|
||||
|
@ -104,6 +105,7 @@ class SyncService {
|
|||
}
|
||||
this.backend = new PollingBackend(this, this.connection)
|
||||
this.version = this.connection.docStateVersion
|
||||
this.baseVersionEtag = this.connection.document.baseVersionEtag
|
||||
this.emit('opened', {
|
||||
...this.connection.state,
|
||||
version: this.version,
|
||||
|
|
Загрузка…
Ссылка в новой задаче