-
Notifications
You must be signed in to change notification settings - Fork 3
重構 Pretalx 相關 API #91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
4f615e5
b4593aa
8a8f83f
84d971a
940069b
7b5ea22
d65c8f5
85f6c1e
1d7e25a
9003f2e
ab3a87a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| import type { PretalxData, PretalxResponse, PretalxTable, TableTypeMap } from '#shared/types/pretalx' | ||
| import { PRETALX_TABLE_SCHEMAS } from '#shared/types/pretalx' | ||
| import { z } from 'zod' | ||
|
|
||
| function parsePretalxResponse<T extends PretalxTable>( | ||
| table: T, | ||
| input: unknown, | ||
| ): PretalxResponse<T> { | ||
| return z.object({ | ||
| count: z.number(), | ||
| next: z.string().nullable(), | ||
| previous: z.string().nullable(), | ||
| results: z.array(PRETALX_TABLE_SCHEMAS[table]), | ||
| }).parse(input) as PretalxResponse<T> | ||
| } | ||
|
|
||
| function getPretalxItemKey<T extends PretalxTable>(item: TableTypeMap[T]): string | number { | ||
| if ('code' in item) { | ||
| return item.code | ||
| } | ||
|
|
||
| return item.id | ||
| } | ||
|
|
||
| export async function fetchPretalxTable<T extends PretalxTable>( | ||
| table: T, | ||
| ): Promise<PretalxData<T>> { | ||
| const { pretalxApiUrl, pretalxApiToken } = useRuntimeConfig() | ||
|
|
||
| if (!pretalxApiUrl || !pretalxApiToken) { | ||
| throw createError({ | ||
| statusCode: 500, | ||
| statusMessage: 'Missing NUXT_PRETALX_API_URL or NUXT_PRETALX_API_TOKEN environment variable', | ||
| }) | ||
| } | ||
|
|
||
| const data: PretalxData<T> = { arr: [], map: {} } | ||
| let url: string | null = table | ||
|
|
||
| while (url) { | ||
| const response: PretalxResponse<T> = parsePretalxResponse( | ||
| table, | ||
| await $fetch( | ||
| url, | ||
| { | ||
| baseURL: pretalxApiUrl, | ||
| headers: { | ||
| Authorization: `Token ${pretalxApiToken}`, | ||
| }, | ||
| }, | ||
| ), | ||
| ) | ||
|
|
||
| data.arr.push(...response.results) | ||
| Object.assign( | ||
| data.map, | ||
| Object.fromEntries(response.results.map((item) => [getPretalxItemKey(item), item])), | ||
| ) | ||
| url = response.next | ||
| } | ||
|
|
||
| return data | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,10 +1,11 @@ | ||||||||||||||||||
| import type { Answer, PretalxResult, Slot, Submission, SubmissionType } from './type' | ||||||||||||||||||
| import type { Answer, PretalxResult, Room, Slot, Submission, SubmissionType } from '#shared/types/pretalx' | ||||||||||||||||||
| import type { SessionSpeaker } from '#shared/types/session' | ||||||||||||||||||
|
|
||||||||||||||||||
| // 對應 pretalx 的問題 ID。 | ||||||||||||||||||
| // key 為系統內使用的欄位名稱,value 為 pretalx 的 question id。 | ||||||||||||||||||
| // 這個對應表會被 `parseAnswer` 使用,將 pretalx 的 answers | ||||||||||||||||||
| // 轉換為以 key 為索引的 Record 物件並回傳。 | ||||||||||||||||||
| const QUESTION_MAP: Record<string, number | null> = { | ||||||||||||||||||
| const QUESTION_MAP = { | ||||||||||||||||||
| language: 269, | ||||||||||||||||||
| languageOther: 300, | ||||||||||||||||||
| enTitle: 257, | ||||||||||||||||||
|
|
@@ -18,11 +19,14 @@ const QUESTION_MAP: Record<string, number | null> = { | |||||||||||||||||
| qa: null, | ||||||||||||||||||
| slide: null, | ||||||||||||||||||
| record: null, | ||||||||||||||||||
| } as const | ||||||||||||||||||
| } as const satisfies Record<string, number | null> | ||||||||||||||||||
|
|
||||||||||||||||||
| export function parseAnswer(answers: Answer['id'][], pretalxData: PretalxResult): any { | ||||||||||||||||||
| type QuestionKey = keyof typeof QUESTION_MAP | ||||||||||||||||||
| type ParsedAnswer = Partial<Record<QuestionKey, string>> | ||||||||||||||||||
|
|
||||||||||||||||||
|
Comment on lines
+24
to
+26
|
||||||||||||||||||
| export function parseAnswer(answers: Answer['id'][], pretalxData: PretalxResult): ParsedAnswer { | ||||||||||||||||||
| const answerMap = pretalxData.answers.map | ||||||||||||||||||
| const results: Record<keyof typeof QUESTION_MAP, unknown> = {} | ||||||||||||||||||
| const results: ParsedAnswer = {} | ||||||||||||||||||
|
|
||||||||||||||||||
| const questionMap = answers.reduce((acc: Record<Answer['id'], Answer>, cur: Answer['id']) => { | ||||||||||||||||||
| const ans = answerMap[cur] | ||||||||||||||||||
|
|
@@ -36,7 +40,7 @@ export function parseAnswer(answers: Answer['id'][], pretalxData: PretalxResult) | |||||||||||||||||
| return acc | ||||||||||||||||||
| }, {}) | ||||||||||||||||||
|
|
||||||||||||||||||
| for (const question in QUESTION_MAP) { | ||||||||||||||||||
| for (const question of Object.keys(QUESTION_MAP) as QuestionKey[]) { | ||||||||||||||||||
| const questionId = QUESTION_MAP[question] | ||||||||||||||||||
|
|
||||||||||||||||||
| if (!questionId) { | ||||||||||||||||||
|
|
@@ -49,28 +53,46 @@ export function parseAnswer(answers: Answer['id'][], pretalxData: PretalxResult) | |||||||||||||||||
| return results | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| export function parseSlot(slotId: Slot['id'], pretalxData: PretalxResult) { | ||||||||||||||||||
| export function parseSlot(slotId: Slot['id'], pretalxData: PretalxResult): (Omit<Slot, 'room'> & { room?: Room }) | null { | ||||||||||||||||||
| const slotMap = pretalxData.slots.map | ||||||||||||||||||
| const roomMap = pretalxData.rooms.map | ||||||||||||||||||
|
|
||||||||||||||||||
| const slot = slotMap[slotId] | ||||||||||||||||||
|
|
||||||||||||||||||
| if (!slot) { | ||||||||||||||||||
| console.warn('slot not found', slotId) | ||||||||||||||||||
| return {} | ||||||||||||||||||
| throw createError({ | ||||||||||||||||||
| statusCode: 500, | ||||||||||||||||||
| statusMessage: `Slot not found: ${slotId}`, | ||||||||||||||||||
| }) | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| const roomId = slot.room | ||||||||||||||||||
|
|
||||||||||||||||||
| if (!roomId) { | ||||||||||||||||||
| throw createError({ | ||||||||||||||||||
| statusCode: 500, | ||||||||||||||||||
| statusMessage: `Slot not found: ${slotId}`, | ||||||||||||||||||
| }) | ||||||||||||||||||
| } | ||||||||||||||||||
|
Comment on lines
69
to
+76
|
||||||||||||||||||
|
|
||||||||||||||||||
| const room = roomMap[roomId] | ||||||||||||||||||
|
|
||||||||||||||||||
|
||||||||||||||||||
| if (!room) { | |
| throw createError({ | |
| statusCode: 500, | |
| statusMessage: `Room not found: ${roomId}`, | |
| }) | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
這跟剛剛那個是一樣的
Uh oh!
There was an error while loading. Please reload this page.