Skip to content

Commit 6265413

Browse files
authored
Merge pull request #4309 from nextcloud/fix/public-polls
Avoid failing requests on public polls triggered by watcher
2 parents e5f443e + b2edf4c commit 6265413

8 files changed

Lines changed: 68 additions & 11 deletions

File tree

lib/Db/WatchMapper.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
namespace OCA\Polls\Db;
1010

11-
use OCA\Polls\AppConstants;
1211
use OCA\Polls\UserSession;
1312
use OCP\AppFramework\Db\QBMapper;
1413
use OCP\IDBConnection;
@@ -42,7 +41,7 @@ public function findUpdatesForPollId(int $pollId, int $offset): array {
4241
)
4342
->andWhere($qb->expr()->orX(
4443
$qb->expr()->eq('poll_id', $qb->createNamedParameter($pollId)),
45-
$qb->expr()->eq('table', $qb->createNamedParameter(AppConstants::APP_ID))
44+
$qb->expr()->eq('table', $qb->createNamedParameter(Watch::OBJECT_POLLS))
4645
));
4746

4847
return $this->findEntities($qb);

src/Exceptions/Exceptions.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,18 @@ class NotReady extends Error {
1616
}
1717
}
1818

19+
class NotAllowed extends Error {
20+
constructor(message: string | undefined) {
21+
super(message)
22+
this.name = 'NotAllowed'
23+
}
24+
}
25+
1926
class InvalidJSON extends Error {
2027
constructor(message: string | undefined) {
2128
super(message)
2229
this.name = 'InvalidJSON'
2330
}
2431
}
2532

26-
export { Exception, InvalidJSON, NotReady }
33+
export { Exception, InvalidJSON, NotReady, NotAllowed }

src/composables/usePollWatcher.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import type {
2626
} from './usePollWatcher.types'
2727

2828
import type { Watcher } from '../stores/session.types'
29+
import { NotAllowed } from '../Exceptions/Exceptions'
2930

3031
/**
3132
* poll watcher to keep polls collection and the current poll
@@ -179,14 +180,31 @@ export const usePollWatcher = (interval = 30000) => {
179180
const handleWatcherTasks = (tasks: string[]) => {
180181
Logger.info('[PollWatcher] Tasks to handle:', { tasks })
181182

182-
tasks.forEach((task: string) => {
183+
tasks.forEach(async (task: string) => {
183184
switch (task) {
184185
case 'shares':
185-
sharesStore.load()
186+
try {
187+
await sharesStore.load()
188+
} catch (error) {
189+
if ((error as NotAllowed).name === 'NotAllowed') {
190+
// User is not allowed to load shares.
191+
// instead assume a changed share affecting the user.
192+
// Reload the session context to update the share
193+
sessionStore.load()
194+
return
195+
}
196+
Logger.error('Error loading poll shares', { error })
197+
}
186198
break
187199
case 'polls':
188-
pollStore.load()
189-
pollsStore.load()
200+
try {
201+
await pollsStore.load()
202+
} catch (error) {
203+
if ((error as NotAllowed).name === 'NotAllowed') {
204+
return
205+
}
206+
Logger.error('Error loading polls list', { error })
207+
}
190208
break
191209
case 'votes':
192210
votesStore.load()

src/stores/polls.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import type {
2323
FilterType,
2424
SortType,
2525
} from './polls.types'
26+
import { NotAllowed } from '../Exceptions/Exceptions'
2627

2728
export const sortColumnsMapping: { [key in SortType]: string } = {
2829
created: 'status.created',
@@ -312,7 +313,13 @@ export const usePollsStore = defineStore('polls', {
312313
* @return {Promise<void>}
313314
*/
314315
async load(forced: boolean = true): Promise<void> {
315-
const pollGroupsStore = usePollGroupsStore()
316+
const sessionStore = useSessionStore()
317+
318+
if (!sessionStore.userStatus.isLoggedin) {
319+
this.polls = []
320+
this.meta.status = ''
321+
throw new NotAllowed('Not allowed to load polls; not logged in')
322+
}
316323

317324
if (
318325
this.meta.status === 'loading'
@@ -327,6 +334,8 @@ export const usePollsStore = defineStore('polls', {
327334

328335
this.meta.status = 'loading'
329336

337+
const pollGroupsStore = usePollGroupsStore()
338+
330339
try {
331340
const response = await PollsAPI.getPolls()
332341
this.polls = response.data.polls

src/stores/shares.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import type {
2020
SharePurpose,
2121
PublicPollEmailConditions,
2222
} from './shares.types'
23+
import { usePollStore } from './poll'
24+
import { NotAllowed } from '../Exceptions/Exceptions'
2325

2426
export const useSharesStore = defineStore('shares', {
2527
state: (): SharesStore => ({
@@ -69,6 +71,14 @@ export const useSharesStore = defineStore('shares', {
6971

7072
if (purpose === 'pollGroup') {
7173
const pollGroupsStore = usePollGroupsStore()
74+
if (
75+
pollGroupsStore.currentPollGroup?.owner.id
76+
!== useSessionStore().currentUser.id
77+
) {
78+
this.shares = []
79+
throw new NotAllowed('Not allowed to load shares for this group')
80+
}
81+
7282
Logger.info('Loading group shares')
7383
// For group shares, we need to use the current poll group ID
7484

@@ -77,6 +87,11 @@ export const useSharesStore = defineStore('shares', {
7787
}
7888
pollOrPollGroupId = pollGroupsStore.currentPollGroup.id
7989
} else {
90+
const pollStore = usePollStore()
91+
if (!pollStore.permissions.edit) {
92+
this.shares = []
93+
throw new NotAllowed('Not allowed to load shares for this poll')
94+
}
8095
Logger.info('Loading poll shares')
8196
// For regular poll shares, we use the current poll ID
8297
const sessionStore = useSessionStore()

src/stores/votes.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,11 @@ export const useVotesStore = defineStore('votes', {
115115
(user) => user.id === sessionStore.currentUser?.id,
116116
)
117117

118-
if (currentUserIndex < 0 && !pollStore.status.isExpired) {
118+
if (
119+
currentUserIndex < 0
120+
&& !pollStore.status.isExpired
121+
&& sessionStore.currentUser.type !== 'public'
122+
) {
119123
// add current user to the begining of the list if not already present
120124
// and if the poll is not expired
121125
participants.unshift(sessionStore.currentUser)

src/views/Vote.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import { useSubscriptionStore } from '../stores/subscription'
4040
4141
import type { CollapsibleProps } from '../components/Base/modules/Collapsible.vue'
4242
import { Event } from '../Types'
43+
import { loadContext } from '../composables/context'
4344
4445
const pollStore = usePollStore()
4546
const optionsStore = useOptionsStore()
@@ -156,7 +157,11 @@ async function resetPoll() {
156157
subscriptionStore.$reset()
157158
}
158159
159-
onBeforeRouteUpdate(async () => {
160+
onBeforeRouteUpdate(async (to, from) => {
161+
if (to.name === 'publicVote' && to.params.token !== from.params.token) {
162+
loadContext(to)
163+
// Same poll, no need to reload
164+
}
160165
loadPoll(true)
161166
})
162167

src/workers/pollWatcher.worker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ self.onmessage = async (props: MessageEvent<WatcherProps>) => {
182182
status: 'idle',
183183
mode,
184184
interval,
185-
message: `[Worker] Sleeping for .${Math.floor(interval / 1000)} s`,
185+
message: `[Worker] Sleeping for ${Math.floor(interval / 1000)} s`,
186186
})
187187
await sleep(interval)
188188
}

0 commit comments

Comments
 (0)