fix: Resolve linting and TypeScript errors
Some checks failed
CI / skip-ci-check (pull_request) Successful in 1m19s
CI / lint-and-type-check (pull_request) Failing after 1m41s
CI / test (pull_request) Successful in 1m46s
CI / build (pull_request) Failing after 1m46s
CI / secret-scanning (pull_request) Successful in 1m20s
CI / dependency-scan (pull_request) Successful in 1m25s
CI / sast-scan (pull_request) Successful in 2m22s
CI / workflow-summary (pull_request) Successful in 1m18s

- Replace 'any' types with proper Prisma types
- Use PhotoUncheckedCreateInput for photo creation
- Use Prisma.PhotoWhereInput for where clauses
- Add proper type assertions for photo fields
- Fix Photo import error by using Prisma namespace
This commit is contained in:
ilia 2026-01-02 15:15:23 -05:00
parent 9640627972
commit 90c5a9a4df
4 changed files with 25 additions and 16 deletions

View File

@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from "next/server"
import { auth } from "@/lib/auth" import { auth } from "@/lib/auth"
import { prisma } from "@/lib/prisma" import { prisma } from "@/lib/prisma"
import { sendNewPhotoEmail } from "@/lib/email" import { sendNewPhotoEmail } from "@/lib/email"
import type { Prisma } from "@prisma/client"
// Legacy endpoint for URL-based uploads (kept for backward compatibility) // Legacy endpoint for URL-based uploads (kept for backward compatibility)
export async function POST(req: NextRequest) { export async function POST(req: NextRequest) {
@ -46,7 +47,7 @@ export async function POST(req: NextRequest) {
answerName: answerName.trim(), answerName: answerName.trim(),
points: pointsValue, points: pointsValue,
maxAttempts: maxAttemptsValue, maxAttempts: maxAttemptsValue,
} as any, } as Prisma.PhotoUncheckedCreateInput,
include: { include: {
uploader: { uploader: {
select: { select: {

View File

@ -6,7 +6,7 @@ import { writeFile } from "fs/promises"
import { join } from "path" import { join } from "path"
import { existsSync, mkdirSync } from "fs" import { existsSync, mkdirSync } from "fs"
import { createHash } from "crypto" import { createHash } from "crypto"
import type { Photo } from "@prisma/client" import type { Prisma } from "@prisma/client"
export async function POST(req: NextRequest) { export async function POST(req: NextRequest) {
try { try {
@ -44,9 +44,9 @@ export async function POST(req: NextRequest) {
mkdirSync(uploadsDir, { recursive: true }) mkdirSync(uploadsDir, { recursive: true })
} }
type PhotoWithUploader = Photo & { type PhotoWithUploader = Prisma.PhotoGetPayload<{
uploader: { name: string } include: { uploader: { select: { name: true } } }
} }>
const createdPhotos: PhotoWithUploader[] = [] const createdPhotos: PhotoWithUploader[] = []
@ -106,7 +106,7 @@ export async function POST(req: NextRequest) {
// Check for duplicate file // Check for duplicate file
const existingPhoto = await prisma.photo.findFirst({ const existingPhoto = await prisma.photo.findFirst({
where: { fileHash } as any, where: { fileHash } as Prisma.PhotoWhereInput,
}) })
if (existingPhoto) { if (existingPhoto) {
@ -158,7 +158,7 @@ export async function POST(req: NextRequest) {
penaltyEnabled: penaltyEnabled, penaltyEnabled: penaltyEnabled,
penaltyPoints: penaltyPointsValue, penaltyPoints: penaltyPointsValue,
maxAttempts: maxAttemptsValue, maxAttempts: maxAttemptsValue,
} as any, } as Prisma.PhotoUncheckedCreateInput,
include: { include: {
uploader: { uploader: {
select: { select: {
@ -168,7 +168,7 @@ export async function POST(req: NextRequest) {
}, },
}) })
createdPhotos.push(photo as PhotoWithUploader) createdPhotos.push(photo)
} }
// Send emails to all other users for all photos // Send emails to all other users for all photos

View File

@ -6,6 +6,7 @@ import { writeFile } from "fs/promises"
import { join } from "path" import { join } from "path"
import { existsSync, mkdirSync } from "fs" import { existsSync, mkdirSync } from "fs"
import { createHash } from "crypto" import { createHash } from "crypto"
import type { Prisma } from "@prisma/client"
export async function POST(req: NextRequest) { export async function POST(req: NextRequest) {
try { try {
@ -62,7 +63,7 @@ export async function POST(req: NextRequest) {
// Check for duplicate file // Check for duplicate file
const existingPhoto = await prisma.photo.findFirst({ const existingPhoto = await prisma.photo.findFirst({
where: { fileHash } as any, where: { fileHash } as Prisma.PhotoWhereInput,
}) })
if (existingPhoto) { if (existingPhoto) {
@ -122,7 +123,7 @@ export async function POST(req: NextRequest) {
answerName: answerName.trim(), answerName: answerName.trim(),
points: pointsValue, points: pointsValue,
maxAttempts: maxAttemptsValue, maxAttempts: maxAttemptsValue,
} as any, } as Prisma.PhotoUncheckedCreateInput,
include: { include: {
uploader: { uploader: {
select: { select: {

View File

@ -49,10 +49,17 @@ export default async function PhotoPage({ params }: { params: Promise<{ id: stri
const hasCorrectGuess = userGuess?.correct || false const hasCorrectGuess = userGuess?.correct || false
const isOwner = photo.uploaderId === session.user.id const isOwner = photo.uploaderId === session.user.id
// Type assertion for new fields (penaltyEnabled, penaltyPoints, maxAttempts)
type PhotoWithNewFields = typeof photo & {
penaltyEnabled: boolean
penaltyPoints: number
maxAttempts: number | null
}
const photoWithFields = photo as PhotoWithNewFields
// Calculate remaining attempts // Calculate remaining attempts
const photoWithMaxAttempts = photo as typeof photo & { maxAttempts: number | null | undefined }
const userGuessCount = photo.guesses.length const userGuessCount = photo.guesses.length
const maxAttempts = photoWithMaxAttempts.maxAttempts ?? null const maxAttempts = photoWithFields.maxAttempts ?? null
const remainingAttempts = maxAttempts !== null && maxAttempts > 0 const remainingAttempts = maxAttempts !== null && maxAttempts > 0
? Math.max(0, maxAttempts - userGuessCount) ? Math.max(0, maxAttempts - userGuessCount)
: null : null
@ -77,9 +84,9 @@ export default async function PhotoPage({ params }: { params: Promise<{ id: stri
<span className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-purple-100 text-purple-800"> <span className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-purple-100 text-purple-800">
+{photo.points} {photo.points === 1 ? "point" : "points"} if correct +{photo.points} {photo.points === 1 ? "point" : "points"} if correct
</span> </span>
{(photo as any).penaltyEnabled && (photo as any).penaltyPoints > 0 && ( {photoWithFields.penaltyEnabled && photoWithFields.penaltyPoints > 0 && (
<span className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-red-100 text-red-800"> <span className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-red-100 text-red-800">
-{(photo as any).penaltyPoints} {(photo as any).penaltyPoints === 1 ? "point" : "points"} if wrong -{photoWithFields.penaltyPoints} {photoWithFields.penaltyPoints === 1 ? "point" : "points"} if wrong
</span> </span>
)} )}
{maxAttempts !== null && maxAttempts > 0 && ( {maxAttempts !== null && maxAttempts > 0 && (
@ -117,9 +124,9 @@ export default async function PhotoPage({ params }: { params: Promise<{ id: stri
<p className="text-sm text-red-700 mt-1"> <p className="text-sm text-red-700 mt-1">
Your last guess: <strong>{userGuess.guessText}</strong> Your last guess: <strong>{userGuess.guessText}</strong>
</p> </p>
{(photo as any).penaltyEnabled && (photo as any).penaltyPoints > 0 && ( {photoWithFields.penaltyEnabled && photoWithFields.penaltyPoints > 0 && (
<p className="text-sm text-red-700 mt-1"> <p className="text-sm text-red-700 mt-1">
You lost <strong>{(photo as any).penaltyPoints} {(photo as any).penaltyPoints === 1 ? "point" : "points"}</strong> for this wrong guess. You lost <strong>{photoWithFields.penaltyPoints} {photoWithFields.penaltyPoints === 1 ? "point" : "points"}</strong> for this wrong guess.
</p> </p>
)} )}
</div> </div>