diff options
-rw-r--r-- | lib/Controller/PublicSessionController.php | 4 | ||||
-rw-r--r-- | lib/Db/Session.php | 3 | ||||
-rw-r--r-- | lib/Db/SessionMapper.php | 2 | ||||
-rw-r--r-- | lib/Service/ApiService.php | 4 | ||||
-rw-r--r-- | lib/Service/SessionService.php | 11 | ||||
-rw-r--r-- | src/components/Editor.vue | 57 | ||||
-rw-r--r-- | src/services/SyncService.js | 3 |
7 files changed, 64 insertions, 20 deletions
diff --git a/lib/Controller/PublicSessionController.php b/lib/Controller/PublicSessionController.php index ee5b446fc..68eb2c937 100644 --- a/lib/Controller/PublicSessionController.php +++ b/lib/Controller/PublicSessionController.php @@ -74,8 +74,8 @@ class PublicSessionController extends PublicShareController { * @NoAdminRequired * @PublicPage */ - public function create(string $token, string $file = null): DataResponse { - return $this->apiService->create(null, $file, $token); + public function create(string $token, string $file = null, $guestName = null): DataResponse { + return $this->apiService->create(null, $file, $token, $guestName); } /** diff --git a/lib/Db/Session.php b/lib/Db/Session.php index 5801ea0ab..dc3bc9b7d 100644 --- a/lib/Db/Session.php +++ b/lib/Db/Session.php @@ -49,7 +49,8 @@ class Session extends Entity implements \JsonSerializable { 'userId' => $this->userId, 'token' => $this->token, 'color' => $this->color, - 'lastContact' => $this->lastContact + 'lastContact' => $this->lastContact, + 'guestName' => $this->guestName ]; } } diff --git a/lib/Db/SessionMapper.php b/lib/Db/SessionMapper.php index aa8b081a0..36e355d00 100644 --- a/lib/Db/SessionMapper.php +++ b/lib/Db/SessionMapper.php @@ -64,7 +64,7 @@ class SessionMapper extends QBMapper { public function findAllActive($documentId) { /* @var $qb IQueryBuilder */ $qb = $this->db->getQueryBuilder(); - $qb->select('id','color','document_id', 'last_contact','user_id') + $qb->select('id','color','document_id', 'last_contact','user_id','guest_name') ->from($this->getTableName()) ->where($qb->expr()->eq('document_id', $qb->createNamedParameter($documentId))) ->andWhere($qb->expr()->gt('last_contact', $qb->createNamedParameter(time()-SessionService::SESSION_VALID_TIME))) diff --git a/lib/Service/ApiService.php b/lib/Service/ApiService.php index 80b349ef8..af4bb5687 100644 --- a/lib/Service/ApiService.php +++ b/lib/Service/ApiService.php @@ -47,7 +47,7 @@ class ApiService { $this->documentService = $documentService; } - public function create($fileId = null, $filePath = null, $token = null): DataResponse { + public function create($fileId = null, $filePath = null, $token = null, $guestName = null): DataResponse { try { $readOnly = true; /** @var File $file */ @@ -71,7 +71,7 @@ class ApiService { return new DataResponse($e->getMessage(), 500); } - $session = $this->sessionService->initSession($document->getId()); + $session = $this->sessionService->initSession($document->getId(), $guestName); return new DataResponse([ 'document' => $document, 'session' => $session, diff --git a/lib/Service/SessionService.php b/lib/Service/SessionService.php index a23447914..9de0ea0a9 100644 --- a/lib/Service/SessionService.php +++ b/lib/Service/SessionService.php @@ -46,20 +46,21 @@ class SessionService { $this->sessionMapper = $sessionMapper; $this->secureRandom = $secureRandom; $this->timeFactory = $timeFactory; - $this->userId = $userId ?? 'Guest'; + $this->userId = $userId; } - public function initSession($documentId): Session { + public function initSession($documentId, $guestName = null): Session { $session = new Session(); $session->setDocumentId($documentId); - $session->setUserId($this->userId); + $userName = $this->userId ? $this->userId : $guestName; + $session->setUserId($userName); $session->setToken($this->secureRandom->generate(64)); /** @var IAvatarManager $avatarGenerator */ $avatarGenerator = \OC::$server->query(IAvatarManager::class); - $color = $avatarGenerator->getGuestAvatar($this->userId)->avatarBackgroundColor($this->userId); + $color = $avatarGenerator->getGuestAvatar($userName)->avatarBackgroundColor($userName); $color = sprintf("#%02x%02x%02x", $color->r, $color->g, $color->b); $session->setColor($color); - $session->setGuestName(null); + $session->setGuestName($guestName); $session->setLastContact($this->timeFactory->getTime()); return $this->sessionMapper->insert($session); } diff --git a/src/components/Editor.vue b/src/components/Editor.vue index c8da579c4..c81c96c6b 100644 --- a/src/components/Editor.vue +++ b/src/components/Editor.vue @@ -21,20 +21,22 @@ --> <template> - <div v-if="currentSession && active" id="editor-container"> - <div id="editor-session-list"> + <div id="editor-container"> + <div id="editor-session-list" v-if="currentSession && active"> <div v-tooltip="lastSavedStatusTooltip" class="save-status" :class="lastSavedStatusClass"> {{ lastSavedStatus }} </div> - <avatar v-for="session in activeSessions" :key="session.id" :user="session.userId" - :display-name="session.displayName" :style="sessionStyle(session)" /> + <avatar v-for="session in activeSessions" :key="session.id" + :user="session.userId" + :display-name="session.guestName ? session.guestName : session.displayName" + :style="sessionStyle(session)" /> </div> - <div> + <div v-if="currentSession && active"> <p v-if="hasSyncCollission" class="msg icon-error"> {{ t('text', 'The document has been changed outside of the editor. The changes cannot be applied.') }} </p> </div> - <div id="editor-wrapper" :class="{'has-conflicts': hasSyncCollission, 'icon-loading': !initialLoading}"> + <div v-if="currentSession && active" id="editor-wrapper" :class="{'has-conflicts': hasSyncCollission, 'icon-loading': !initialLoading}"> <div id="editor"> <editor-menu-bar :editor="tiptap" v-slot="{ commands, isActive }" v-if="!syncError && !readOnly"> <div class="menubar"> @@ -89,6 +91,14 @@ Use the server version </button> </div> + + <div v-if="isPublic && !guestNameConfirmed" class="guest-name-dialog"> + <p>{{ t('text', 'Please enter a name to identify you as a public editor:') }}</p> + <form @submit.prevent="setGuestName()"> + <input type="text" v-model="guestName" /> + <input type="submit" class="icon-confirm" value="" /> + </form> + </div> </div> </template> @@ -183,13 +193,16 @@ export default { syncError: null, readOnly: true, + guestName: '', + guestNameConfirmed: false, + linkUrl: null, linkMenuIsActive: false, } }, computed: { activeSessions() { - return Object.values(this.filteredSessions).filter((session) => session.lastContact > Date.now() / 1000 - COLLABORATOR_DISCONNECT_TIME) + return Object.values(this.filteredSessions).filter((session) => session.lastContact > Date.now() / 1000 - COLLABORATOR_DISCONNECT_TIME && session.id !== this.currentSession.id && session.userId !== null) }, sessionStyle() { return (session) => { @@ -241,7 +254,12 @@ export default { } }, mounted() { - if (this.active && (this.hasDocumentParameters)) { + const guestName = localStorage.getItem('text-guestName') + if (guestName !== null) { + this.guestName = guestName + } + + if (this.active && (this.hasDocumentParameters) && !this.isPublic) { this.initSession() } setInterval(() => { this.updateLastSavedStatus() }, 2000) @@ -254,6 +272,11 @@ export default { } }, methods: { + setGuestName() { + this.guestNameConfirmed = true + localStorage.setItem('text-guestName', this.guestName) + this.initSession() + }, updateLastSavedStatus() { if (this.document) { this.lastSavedString = window.moment(this.document.lastSavedVersionTime * 1000).fromNow() @@ -266,6 +289,7 @@ export default { } this.syncService = new SyncService({ shareToken: this.shareToken, + guestName: this.guestName, serialize: (document) => { return defaultMarkdownSerializer.serialize(document) } @@ -613,6 +637,23 @@ export default { margin: auto; } + .guest-name-dialog { + padding: 30px; + text-align: center; + + form { + display: flex; + width: 100%; + max-width: 200px; + margin: auto; + margin-top: 30px; + + input[type=text] { + flex-grow: 1; + } + } + } + </style> <style lang="scss"> @import './../../css/style'; diff --git a/src/services/SyncService.js b/src/services/SyncService.js index 7ebfe5d62..ab77b0ca9 100644 --- a/src/services/SyncService.js +++ b/src/services/SyncService.js @@ -108,7 +108,8 @@ class SyncService { params: { fileId: fileId, file: filePath, - token: this.options.shareToken + token: this.options.shareToken, + guestName: this.options.guestName } }).then((response) => { this.document = response.data.document |