Skip to content

Commit

Permalink
First working version!
Browse files Browse the repository at this point in the history
  • Loading branch information
HugoGresse committed Jun 30, 2024
1 parent bc5e963 commit 621b97f
Show file tree
Hide file tree
Showing 17 changed files with 479 additions and 11 deletions.
Binary file modified bun.lockb
Binary file not shown.
10 changes: 10 additions & 0 deletions functions/src/api/dao/firebasePlugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fp from 'fastify-plugin'
import fb, { credential } from 'firebase-admin'
import { FastifyInstance } from 'fastify'
import { defineString } from 'firebase-functions/params'

function firebase(fastify: FastifyInstance, options: any, next: () => void) {
const cert = process.env.FIREBASE_SERVICE_ACCOUNT
Expand All @@ -25,3 +26,12 @@ export const firebasePlugin = fp(firebase, {
fastify: '>=1.1.0',
name: 'fastify-firebase',
})

export const getStorageBucketName = () => {
const storageBucketParam = defineString('BUCKET', {
input: { resource: { resource: { type: 'storage.googleapis.com/Bucket' } } },
description:
'This will automatically populate the selector field with the deploying Cloud Project’s storage buckets',
})
return storageBucketParam.value()
}
2 changes: 2 additions & 0 deletions functions/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { filesRoutes } from './routes/file/files'
import { faqRoutes } from './routes/faq/faq'
import { helloRoute } from './routes/hello/hello'
import { sessionsRoutes } from './routes/sessions/sessions'
import { transcriptionRoutes } from './routes/transcription/transcription'

type Firebase = firebaseApp.App

Expand Down Expand Up @@ -48,6 +49,7 @@ registerSwagger(fastify)
fastify.register(sponsorsRoutes)
fastify.register(sessionsRoutes)
fastify.register(faqRoutes)
fastify.register(transcriptionRoutes)
fastify.register(filesRoutes)
fastify.register(helloRoute)

Expand Down
9 changes: 2 additions & 7 deletions functions/src/api/routes/file/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { Static, Type } from '@sinclair/typebox'
import { extractMultipartFormData } from './parseMultipartFiles'
import { v4 as uuidv4 } from 'uuid'
import firebase from 'firebase-admin'
import { defineString } from 'firebase-functions/params'
import { checkFileTypes } from '../../other/checkFileTypes'
import { getStorageBucketName } from '../../dao/firebasePlugin'

export const NewFile = Type.Any()

Expand Down Expand Up @@ -100,12 +100,7 @@ export const uploadBufferToStorage = async (
eventId: string,
fileName: string
): Promise<[boolean, string]> => {
const storageBucketParam = defineString('BUCKET', {
input: { resource: { resource: { type: 'storage.googleapis.com/Bucket' } } },
description:
'This will automatically populate the selector field with the deploying Cloud Project’s storage buckets',
})
const storageBucket = storageBucketParam.value()
const storageBucket = getStorageBucketName()

const fileType = await checkFileTypes(buffer, fileName)

Expand Down
77 changes: 77 additions & 0 deletions functions/src/api/routes/transcription/transcription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { FastifyInstance } from 'fastify'
import { Static, Type } from '@sinclair/typebox'
import { EventDao } from '../../dao/eventDao'
import { getStorageBucketName } from '../../dao/firebasePlugin'

const GetReply = Type.Union([
Type.Object({
eventName: Type.String(),
gladiaAPIKey: Type.String(),
dataUrl: Type.String(),
}),
Type.String(),
])
type GetReplyType = Static<typeof GetReply>

export const transcriptionRoutes = (fastify: FastifyInstance, options: any, done: () => any) => {
fastify.get<{ Reply: GetReplyType }>(
'/v1/:eventId/transcription',
{
schema: {
tags: ['transcription'],
summary: 'Public route to access the Gladia API Key along with some more data',
response: {
200: GetReply,
400: Type.String(),
401: Type.String(),
},
security: [
{
password: [],
},
],
},
},
async (request, reply) => {
const { eventId } = request.params as { eventId: string }

const password = request.headers['password'] as string

const event = await EventDao.getEvent(fastify.firebase, eventId)

const bucket = getStorageBucketName()

if (!event.gladiaAPIKey || !event.transcriptionPassword) {
reply.status(401).send(
JSON.stringify({
error: 'Missing Gladia API Key or password',
})
)
return
}
if (event.transcriptionPassword !== password) {
reply.status(401).send(
JSON.stringify({
error: 'Passwords does not match',
})
)
return
}
if (!event.files?.public) {
reply.status(401).send(
JSON.stringify({
error: 'Missing public file, did you forgot to "Update website" once?',
})
)
return
}

reply.status(200).send({
eventName: event.name,
gladiaAPIKey: event.gladiaAPIKey,
dataUrl: `https://storage.googleapis.com/${bucket}/${event.files.public}`,
})
}
)
done()
}
2 changes: 2 additions & 0 deletions functions/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ export interface Event {
files: EventFiles | null
statusBadgeImage: string | null
statusBadgeLink: string | null
gladiaAPIKey: string | null
transcriptionPassword: string | null
}

export interface SponsorResponse {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@mui/x-data-grid": "^6.19.6",
"@mui/x-date-pickers": "^6.19.7",
"@reduxjs/toolkit": "^1.9.7",
"@uidotdev/usehooks": "^2.4.1",
"@uiw/react-md-editor": "^4.0.1",
"data-uri-to-buffer": "^6.0.2",
"firebase": "^10.5.2",
Expand Down
20 changes: 20 additions & 0 deletions src/events/page/settings/EventSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,26 @@ export const EventSettings = ({ event }: EventSettingsProps) => {
variant="filled"
disabled={formState.isSubmitting}
/>

<TextFieldElement
margin="normal"
fullWidth
id="gladiaAPIKey"
label="Gladia.io API key"
name="gladiaAPIKey"
variant="filled"
helperText="Used for the transcription pages. Don't forget to set the password below or the Gladia.io API Key could be accessed freely"
disabled={formState.isSubmitting}
/>
<TextFieldElement
margin="normal"
fullWidth
id="transcriptionPassword"
label="Password to access transcription"
name="transcriptionPassword"
variant="filled"
disabled={formState.isSubmitting}
/>
</Grid>
</Grid>
<Grid container spacing={4}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export const mapEventSettingsFormToMutateObject = (event: Event, data: EventForF
end: data.dates.end ? (DateTime.fromISO(data.dates.end).toJSDate() as Date) : null,
}
const openAPIKey = data.openAPIKey || ''
const gladiaAPIKey = data.gladiaAPIKey || ''
const transcriptionPassword = data.transcriptionPassword || ''

return {
...event,
Expand All @@ -51,6 +53,8 @@ export const mapEventSettingsFormToMutateObject = (event: Event, data: EventForF
formats,
categories,
openAPIKey,
gladiaAPIKey,
transcriptionPassword,
}
}

Expand Down
1 change: 1 addition & 0 deletions src/public/hooks/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const BaseAPIUrl = import.meta.env.VITE_FIREBASE_OPEN_PLANNER_API_URL
2 changes: 2 additions & 0 deletions src/public/hooks/useFetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ type FetchMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'
interface FetchOptions {
method: FetchMethod
body?: any
headers?: { [key: string]: string }
}

export const useFetch = <T>(url: string, options: FetchOptions): UseQueryResult<T> => {
Expand All @@ -22,6 +23,7 @@ export const useFetch = <T>(url: string, options: FetchOptions): UseQueryResult<
method: options.method,
headers: {
'Content-Type': 'application/json',
...(options.headers || {}),
},
body: JSON.stringify(options.body),
})
Expand Down
4 changes: 2 additions & 2 deletions src/public/hooks/usePublicEventFaq.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { UseQueryResult } from '../../services/hooks/firestoreQueryHook'
import { useFetch } from './useFetch'
import { PublicFaqReply } from '../publicTypes'
import { BaseAPIUrl } from './constants'

const baseAPIUrl = import.meta.env.VITE_FIREBASE_OPEN_PLANNER_API_URL
export const usePublicEventFaq = (eventId?: string, privateId?: string): UseQueryResult<PublicFaqReply> => {
const url = new URL(baseAPIUrl as string)
const url = new URL(BaseAPIUrl as string)
url.pathname += `v1/${eventId}/faq/`

if (privateId) {
Expand Down
115 changes: 115 additions & 0 deletions src/public/hooks/useTranscription.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { PublicJSON, TranscriptionReply } from '../publicTypes'
import { BaseAPIUrl } from './constants'
import { useEffect, useState } from 'react'
import { DateTime } from 'luxon'

export const useTranscription = (
eventId: string,
password: string
): [string | undefined | null, null | PublicJSON, boolean, string | null] => {
const [state, setState] = useState<{
isLoading: boolean
error: string | null
data: TranscriptionReply | null
eventData: null | PublicJSON
}>({
isLoading: false,
error: null,
data: null,
eventData: null,
})

// const dateNow = DateTime.fromISO('2023-07-05T016:00:00.000Z')

useEffect(() => {
const load = async () => {
try {
setState((newState) => {
return {
...newState,
error: null,
isLoading: true,
}
})

if (!password || password.length === 0) {
setState((newState) => {
return {
...newState,
isLoading: false,
error: 'Missing password',
}
})
return
}

const url = new URL(BaseAPIUrl as string)
url.pathname += `v1/${eventId}/transcription`

const apiResult = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
password: password,
},
})

if (!apiResult.ok) {
setState((newState) => {
return {
...newState,
isLoading: false,
error: `HTTP error! status: ${apiResult.status}`,
}
})
return
}

const apiData = await apiResult.json()

setState((newState) => {
return {
...newState,
data: apiData,
}
})
const urlEventData = new URL(`${apiData.dataUrl}?t=${Date.now()}`)

const eventDataResult = await fetch(urlEventData)

if (!eventDataResult.ok) {
setState((newState) => {
return {
...newState,
isLoading: false,
error: `HTTP error! status: ${eventDataResult.status}`,
}
})
return
}

const eventData = await eventDataResult.json()

setState((newState) => {
return {
...newState,
isLoading: false,
eventData: eventData,
}
})
} catch (error) {
setState((newState) => {
return {
...newState,
isLoading: false,
error: `Error! status: ${error}`,
}
})
}
}

load()
}, [password])

return [state.data?.gladiaAPIKey, state.eventData, state.isLoading, state.error]
}
26 changes: 26 additions & 0 deletions src/public/publicTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,29 @@ export type PublicFaqReply = {
faq: PublicFaqType[]
eventName: string
}

export type TranscriptionReply = {
eventName: string
gladiaAPIKey: string
dataUrl: string
}

// This represents the Static Public JSON generated by OpenPlanner
export type PublicJSON = {
event: {
tracks: {
id: string
name: string
}[]
}
sessions: {
id: string
trackId: string
dateStart: string
dateEnd: string
speakersIds: string[]
title: string
abstract: []
showInFeedback: boolean
}[]
}
Loading

0 comments on commit 621b97f

Please sign in to comment.