From 8bced6e20de9cc614aafe41a488549e68264fa73 Mon Sep 17 00:00:00 2001 From: Chen Asraf Date: Sun, 9 Nov 2025 23:39:03 +0200 Subject: [PATCH] fix: thread view counter --- lib/Controller/ThreadController.php | 26 ++++++++++++++++---------- openapi.json | 18 ++++++++++++++++++ src/App.vue | 5 +++-- src/composables/useCurrentThread.ts | 8 ++++++-- src/views/ThreadView.vue | 6 ++++-- 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/lib/Controller/ThreadController.php b/lib/Controller/ThreadController.php index fedd399..c022525 100644 --- a/lib/Controller/ThreadController.php +++ b/lib/Controller/ThreadController.php @@ -84,6 +84,7 @@ class ThreadController extends OCSController { * Get a single thread * * @param int $id Thread ID + * @param string $incrementView Whether to increment view count (1 or 0) * @return DataResponse, array{}> * * 200: Thread returned @@ -91,14 +92,16 @@ class ThreadController extends OCSController { #[NoAdminRequired] #[RequirePermission('canView', resourceType: 'category', resourceIdFromThreadId: 'id')] #[ApiRoute(verb: 'GET', url: '/api/threads/{id}')] - public function show(int $id): DataResponse { + public function show(int $id, string $incrementView = '1'): DataResponse { try { $thread = $this->threadMapper->find($id); - // Increment view count - $thread->setViewCount($thread->getViewCount() + 1); - /** @var \OCA\Forum\Db\Thread */ - $thread = $this->threadMapper->update($thread); + // Increment view count only if requested + if ($incrementView === '1') { + $thread->setViewCount($thread->getViewCount() + 1); + /** @var \OCA\Forum\Db\Thread */ + $thread = $this->threadMapper->update($thread); + } return new DataResponse(Thread::enrichThread($thread)); } catch (DoesNotExistException $e) { @@ -113,20 +116,23 @@ class ThreadController extends OCSController { * Get a thread by slug * * @param string $slug Thread slug + * @param string $incrementView Whether to increment view count (1 or 0) * @return DataResponse, array{}> * * 200: Thread returned */ #[NoAdminRequired] #[ApiRoute(verb: 'GET', url: '/api/threads/slug/{slug}')] - public function bySlug(string $slug): DataResponse { + public function bySlug(string $slug, string $incrementView = '1'): DataResponse { try { $thread = $this->threadMapper->findBySlug($slug); - // Increment view count - $thread->setViewCount($thread->getViewCount() + 1); - /** @var \OCA\Forum\Db\Thread */ - $thread = $this->threadMapper->update($thread); + // Increment view count only if requested + if ($incrementView === '1') { + $thread->setViewCount($thread->getViewCount() + 1); + /** @var \OCA\Forum\Db\Thread */ + $thread = $this->threadMapper->update($thread); + } return new DataResponse(Thread::enrichThread($thread)); } catch (DoesNotExistException $e) { diff --git a/openapi.json b/openapi.json index 781c24e..753f8eb 100644 --- a/openapi.json +++ b/openapi.json @@ -7011,6 +7011,15 @@ "format": "int64" } }, + { + "name": "incrementView", + "in": "query", + "description": "Whether to increment view count (1 or 0)", + "schema": { + "type": "string", + "default": "1" + } + }, { "name": "OCS-APIRequest", "in": "header", @@ -7357,6 +7366,15 @@ "type": "string" } }, + { + "name": "incrementView", + "in": "query", + "description": "Whether to increment view count (1 or 0)", + "schema": { + "type": "string", + "default": "1" + } + }, { "name": "OCS-APIRequest", "in": "header", diff --git a/src/App.vue b/src/App.vue index 73930e8..286a5da 100644 --- a/src/App.vue +++ b/src/App.vue @@ -355,10 +355,11 @@ export default defineComponent({ } // Fetch thread data to get category using the composable + // Don't increment view count when fetching for sidebar navigation if (this.$route.params.slug) { - await this.fetchThread(this.$route.params.slug as string, true) + await this.fetchThread(this.$route.params.slug as string, true, false) } else if (this.$route.params.id) { - await this.fetchThread(this.$route.params.id as string, false) + await this.fetchThread(this.$route.params.id as string, false, false) } }, }, diff --git a/src/composables/useCurrentThread.ts b/src/composables/useCurrentThread.ts index d106314..6663bdc 100644 --- a/src/composables/useCurrentThread.ts +++ b/src/composables/useCurrentThread.ts @@ -7,13 +7,17 @@ const isLoading = ref(false) const error = ref(null) export function useCurrentThread() { - const fetchThread = async (idOrSlug: string | number, isSlug: boolean = false): Promise => { + const fetchThread = async (idOrSlug: string | number, isSlug: boolean = false, incrementView: boolean = true): Promise => { try { isLoading.value = true error.value = null const endpoint = isSlug ? `/threads/slug/${idOrSlug}` : `/threads/${idOrSlug}` - const resp = await ocs.get(endpoint) + const resp = await ocs.get(endpoint, { + params: { + incrementView: incrementView ? '1' : '0', + }, + }) currentThread.value = resp.data return resp.data diff --git a/src/views/ThreadView.vue b/src/views/ThreadView.vue index 32a0663..316ee57 100644 --- a/src/views/ThreadView.vue +++ b/src/views/ThreadView.vue @@ -174,11 +174,13 @@ export default defineComponent({ this.error = null // Fetch thread details using the composable + // Increment view count on initial load, but not on manual refresh + const incrementView = !this.thread let threadData if (this.threadSlug) { - threadData = await this.fetchThread(this.threadSlug, true) + threadData = await this.fetchThread(this.threadSlug, true, incrementView) } else if (this.threadId) { - threadData = await this.fetchThread(this.threadId, false) + threadData = await this.fetchThread(this.threadId, false, incrementView) } else { throw new Error(t('forum', 'No thread ID or slug provided')) }