Skip to content

Commit

Permalink
fix(PollEditor): rework form validation
Browse files Browse the repository at this point in the history
Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
Antreesy committed Jan 28, 2025

Verified

This commit was signed with the committer’s verified signature.
phillebaba Philip Laine
1 parent c125c74 commit 9296aaf
Showing 3 changed files with 52 additions and 26 deletions.
22 changes: 15 additions & 7 deletions src/components/PollViewer/PollEditor.vue
Original file line number Diff line number Diff line change
@@ -135,7 +135,7 @@ import { POLL } from '../../constants.js'
import { hasTalkFeature } from '../../services/CapabilitiesManager.ts'
import { EventBus } from '../../services/EventBus.ts'
import { usePollsStore } from '../../stores/polls.ts'
import type { createPollParams } from '../../types/index.ts'
import type { createPollParams, requiredPollParams } from '../../types/index.ts'
import { convertToJSONDataURI } from '../../utils/fileDownload.ts'
import { validatePollForm } from '../../utils/validatePollForm.ts'

@@ -238,8 +238,18 @@ function fillPollEditorFromDraft(id: number | null, fromDrafts: boolean) {
isOpenedFromDraft.value = true
}

if (id && pollsStore.drafts[props.token][id]) {
fillPollForm(pollsStore.drafts[props.token][id])
if (id === null) {
return
}

const draft = pollsStore.drafts[props.token][id]
if (draft) {
fillPollForm({
question: draft.question,
options: [...draft.options],
resultMode: draft.resultMode,
maxVotes: draft.maxVotes,
})
}
}

@@ -278,10 +288,8 @@ function importPoll(event: Event) {
* Insert data into form fields
* @param payload data to fill with
*/
function fillPollForm(payload: createPollParams) {
for (const key of Object.keys(pollForm)) {
pollForm[key] = payload[key]
}
function fillPollForm(payload: requiredPollParams) {
Object.assign(pollForm, payload)
}

/**
2 changes: 2 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -232,6 +232,8 @@ export type votePollResponse = ApiResponse<operations['poll-vote-poll']['respons
export type closePollResponse = ApiResponse<operations['poll-close-poll']['responses'][200]['content']['application/json']>
export type deletePollDraftResponse = ApiResponse<operations['poll-close-poll']['responses'][202]['content']['application/json']>

export type requiredPollParams = Omit<createPollParams, 'draft'>

// Mentions
export type ChatMention = components['schemas']['ChatMentionSuggestion']
export type getMentionsParams = operations['chat-mentions']['parameters']['query']
54 changes: 35 additions & 19 deletions src/utils/validatePollForm.ts
Original file line number Diff line number Diff line change
@@ -3,42 +3,58 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import type { createPollParams } from '../types/index.ts'

type requiredPollParams = Omit<createPollParams, 'draft'>
const pollFormExample = {
question: '',
options: ['', ''],
resultMode: 0,
maxVotes: 0,
import type { requiredPollParams } from '../types/index.ts'

const REQUIRED_KEYS = ['question', 'options', 'resultMode', 'maxVotes'] as const

/**
* Type guard for options array
* @param payload payload to check
*/
function isStringArray(payload: unknown): payload is string[] {
return Array.isArray(payload) && payload.every(opt => typeof opt === 'string')
}
const REQUIRED_KEYS: Array<keyof requiredPollParams> = Object.keys(pollFormExample) as Array<keyof requiredPollParams>

/**
* Parses a given JSON object and validates with required poll form object.
* Throws an error if parsed object doesn't match
* @param jsonObject The object to validate
*/
function validatePollForm(jsonObject: requiredPollParams): requiredPollParams {
if (typeof jsonObject !== 'object') {
function validatePollForm(jsonObject: unknown): requiredPollParams {
if (typeof jsonObject !== 'object' || !jsonObject) {
throw new Error('Invalid parsed object')
}

const typedObject = jsonObject as Record<keyof requiredPollParams, unknown>

for (const key of REQUIRED_KEYS) {
if (jsonObject[key] === undefined) {
if (typedObject[key] === undefined) {
throw new Error('Missing required key')
}
}

if (typeof pollFormExample[key] !== typeof jsonObject[key]) {
throw new Error('Invalid parsed value')
}
if (typeof typedObject.question !== 'string') {
throw new Error('Invalid parsed value: question')
}

if (key === 'options' && jsonObject[key]?.some((opt: unknown) => typeof opt !== 'string')) {
throw new Error('Invalid parsed option values')
}
if (typeof typedObject.resultMode !== 'number' || !(typedObject.resultMode === 0 || typedObject.resultMode === 1)) {
throw new Error('Invalid parsed value: resultMode')
}

if (typeof typedObject.maxVotes !== 'number') {
throw new Error('Invalid parsed value: maxVotes')
}

return jsonObject
if (!isStringArray(typedObject.options)) {
throw new Error('Invalid parsed value: options')
}

return {
question: typedObject.question,
options: [...typedObject.options],
resultMode: typedObject.resultMode,
maxVotes: typedObject.maxVotes,
}
}

export {

0 comments on commit 9296aaf

Please sign in to comment.