Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
sripwoud committed Oct 29, 2024
1 parent 0dfb8d0 commit d540d93
Show file tree
Hide file tree
Showing 14 changed files with 367 additions and 46 deletions.
4 changes: 3 additions & 1 deletion .dprint.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"apps/server/src/supabase/supabase.types.ts",
"contracts/lib",
"contracts/out",
"supabase/migrations/*_create_feedbacks_table.sql", // sql formatter does not support $$ syntax used to define psql trigger
// sql formatter does not support $$ syntax used to define psql trigger
"supabase/migrations/*_create_feedbacks_table.sql",
"supabase/migrations/*_create_questions_table.sql",
],
"exec": {
"commands": [
Expand Down
8 changes: 7 additions & 1 deletion apps/client/src/app/[groupId]/[questionId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Loader } from 'client/c/Loader'
import { withAuth } from 'client/components/withAuth'
import { trpc } from 'client/l/trpc'
import { useEffect } from 'react'
import type { QuestionType } from 'server/questions/dto'

const QuestionDetails = ({ params: { questionId: questionIdStr } }: { params: { questionId: string } }) => {
const questionId = Number.parseInt(questionIdStr)
Expand All @@ -27,7 +28,12 @@ const QuestionDetails = ({ params: { questionId: questionIdStr } }: { params: {
<button
type='button'
onClick={() => {
toggle({ active: !question.active, questionId })
toggle({
active: !question.active,
questionId,
// FIXME: fix Dto zod validation to avoid having to cast
type: question.type as QuestionType,
})
}}
>
Set {question.active ? 'Ina' : 'A'}ctive
Expand Down
9 changes: 7 additions & 2 deletions apps/client/src/components/CreateQuestionForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { zodValidator } from '@tanstack/zod-form-adapter'
import { clientConfig } from 'client/l/config'
import { trpc } from 'client/l/trpc'
import type { FC, FormEvent } from 'react'
import { CreateQuestionDto } from 'server/questions/dto/create-question.dto'
import { CreateQuestionDto, QuestionType } from 'server/questions/dto'

interface CreateQuestionFormProps {
onClose: () => void
Expand All @@ -16,7 +16,12 @@ export const CreateQuestionForm: FC<CreateQuestionFormProps> = ({ onClose }) =>
defaultValues: { title: '' },
onSubmit: ({ value: { title } }) => {
if (user?.email === undefined) throw new Error('User not found')
createQuestion({ author: user.email, groupId: clientConfig.bandada.pseGroupId, title })
createQuestion({
author: user.email,
groupId: clientConfig.bandada.pseGroupId,
title,
type: QuestionType.BOOLEAN,
})
},
validatorAdapter: zodValidator(),
validators: { onChange: CreateQuestionDto.pick({ title: true }) },
Expand Down
2 changes: 2 additions & 0 deletions apps/server/src/feedbacks/dto/create-feedback.dto.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { QuestionType } from 'server/questions/dto'
import { z } from 'zod'

export const CreateFeedbackDto = z.object({
feedback: z.boolean(),
questionId: z.number().positive(),
type: z.enum([QuestionType.BOOLEAN, QuestionType.TEXT]),
})

export type CreateFeedbackDto = z.infer<typeof CreateFeedbackDto>
2 changes: 2 additions & 0 deletions apps/server/src/feedbacks/dto/send-feedback.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { SemaphoreProof } from '@semaphore-protocol/core'
import { QuestionType } from 'server/questions/dto'
import { z } from 'zod'

export const SendFeedbackDto = z.object({
Expand All @@ -13,6 +14,7 @@ export const SendFeedbackDto = z.object({
points: z.tuple([z.string(), z.string(), z.string(), z.string(), z.string(), z.string(), z.string(), z.string()]),
scope: z.string(),
}),
type: z.enum([QuestionType.BOOLEAN, QuestionType.TEXT]),
})

export type SendFeedbackDto = Omit<z.infer<typeof SendFeedbackDto>, 'proof'> & { proof: SemaphoreProof }
4 changes: 0 additions & 4 deletions apps/server/src/feedbacks/entities/index.ts

This file was deleted.

10 changes: 6 additions & 4 deletions apps/server/src/feedbacks/feedbacks.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@ import { SupabaseService } from 'server/supabase/supabase.service'

@Injectable()
export class FeedbacksService {
readonly resource = 'feedbacks' as const

constructor(
private readonly nullifiers: NullifiersService,
private readonly roots: RootsService,
private readonly supabase: SupabaseService,
private readonly questions: QuestionsService,
) {}

async create({ feedback, questionId: question_id }: CreateFeedbackDto) {
return this.supabase.from('feedbacks').insert({ feedback, question_id })
async create({ feedback, questionId: question_id, type }: CreateFeedbackDto) {
return this.supabase.from(`${this.resource}_${type}`).insert({ feedback, question_id })
}

// TODO: handle errors, abstract in smaller steps?
async send({ groupId, feedback, proof, questionId }: SendFeedbackDto) {
async send({ groupId, feedback, proof, questionId, type }: SendFeedbackDto) {
if (!await this.questions.isInactive({ questionId }))
throw new Error('Question is inactive, you cannot send feedback anymore')

Expand All @@ -30,6 +32,6 @@ export class FeedbacksService {
if (!await verifyProof(proof)) throw new Error('Invalid proof')

await this.nullifiers.create({ nullifier: proof.nullifier })
return this.create({ feedback, questionId })
return this.create({ feedback, questionId, type })
}
}
1 change: 1 addition & 0 deletions apps/server/src/groups/groups.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export class GroupsService {
async members({ questionId }: GroupMembersDto) {
const { data } = await this.questions.find({ questionId })
if (data === null) throw new Error('This question does not exist')
if (data.group_id === null) throw new Error('This question is not associated with a group')
const group = await this.find({ groupId: data.group_id })
return group.members
}
Expand Down
6 changes: 6 additions & 0 deletions apps/server/src/questions/dto/create-question.dto.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { z } from 'zod'

export enum QuestionType {
BOOLEAN = 'boolean',
TEXT = 'text',
}

export const CreateQuestionDto = z.object({
author: z.string().email(),
groupId: z.string().min(1, { message: 'Group ID cannot be empty' }),
title: z.string().min(10, { message: 'Title must be at least 10 characters long' }).includes('?', {
message: 'Title must include a question mark',
}),
type: z.enum([QuestionType.BOOLEAN, QuestionType.TEXT]),
})

export type CreateQuestionDto = z.infer<typeof CreateQuestionDto>
2 changes: 2 additions & 0 deletions apps/server/src/questions/dto/toggle-question.dto.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { z } from 'zod'
import { QuestionType } from './create-question.dto'

export const ToggleQuestionDto = z.object({
active: z.boolean(),
questionId: z.number().positive(),
type: z.enum([QuestionType.BOOLEAN, QuestionType.TEXT]),
})

export type ToggleQuestionDto = z.infer<typeof ToggleQuestionDto>
15 changes: 10 additions & 5 deletions apps/server/src/questions/questions.service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { Injectable, OnModuleInit } from '@nestjs/common'
import type { CreateQuestionDto, FindAllQuestionsDto, FindQuestionDto, ToggleQuestionDto } from 'server/questions/dto'
import {
type CreateQuestionDto,
type FindAllQuestionsDto,
type FindQuestionDto,
type ToggleQuestionDto,
} from 'server/questions/dto'
import { SupabaseService } from 'server/supabase/supabase.service'

@Injectable()
Expand All @@ -12,8 +17,8 @@ export class QuestionsService implements OnModuleInit {
this.supabase.subscribe(this.resource)
}

async create({ author, groupId: group_id, title }: CreateQuestionDto) {
return this.supabase.from(this.resource).insert({ author, group_id, title })
async create({ author, groupId: group_id, title, type }: CreateQuestionDto) {
return this.supabase.from(`${this.resource}_${type}`).insert({ author, group_id, title })
}

async find({ questionId }: FindQuestionDto) {
Expand All @@ -34,7 +39,7 @@ export class QuestionsService implements OnModuleInit {
return data.active
}

async toggle({ active, questionId }: ToggleQuestionDto) {
return this.supabase.from(this.resource).update({ active }).eq('id', questionId)
async toggle({ active, questionId, type }: ToggleQuestionDto) {
return this.supabase.from(`${this.resource}_${type}`).update({ active }).eq('id', questionId)
}
}
Loading

0 comments on commit d540d93

Please sign in to comment.