initial commit
This commit is contained in:
102
app/api/upload/confirm/route.ts
Normal file
102
app/api/upload/confirm/route.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { authMiddleware } from '@/lib/auth-middleware'
|
||||
import { moveToPermStorage, generateUniqueFilename, deleteFile } from '@/lib/file-vault'
|
||||
import { z } from 'zod'
|
||||
|
||||
// Confirm upload request validation
|
||||
const confirmSchema = z.object({
|
||||
tempPath: z.string().min(1, 'Temporary path is required'),
|
||||
permanentFolder: z.string().optional().default('uploads'),
|
||||
filename: z.string().optional(),
|
||||
})
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
// Check authentication
|
||||
const user = await authMiddleware(request)
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const body = await request.json()
|
||||
const { tempPath, permanentFolder, filename } = confirmSchema.parse(body)
|
||||
|
||||
// Validate temp path format
|
||||
if (!tempPath.startsWith('temp/')) {
|
||||
return NextResponse.json({ error: 'Invalid temporary path' }, { status: 400 })
|
||||
}
|
||||
|
||||
// Generate permanent path
|
||||
const originalFilename = tempPath.split('/').pop() || 'file'
|
||||
const finalFilename = filename ? generateUniqueFilename(filename) : originalFilename
|
||||
const permanentPath = `${permanentFolder}/${finalFilename}`
|
||||
|
||||
// Move file from temp to permanent storage
|
||||
await moveToPermStorage(tempPath, permanentPath)
|
||||
|
||||
// TODO: Save file metadata to database
|
||||
// This would include:
|
||||
// - permanentPath
|
||||
// - originalFilename
|
||||
// - uploadedBy (user.id)
|
||||
// - uploadedAt
|
||||
// - fileSize
|
||||
// - mimeType
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
permanentPath,
|
||||
filename: finalFilename,
|
||||
folder: permanentFolder,
|
||||
confirmedBy: user.id,
|
||||
confirmedAt: new Date().toISOString(),
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Upload confirmation error:', error)
|
||||
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid request parameters', details: error.issues },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
// Delete temporary file (cleanup)
|
||||
export async function DELETE(request: NextRequest) {
|
||||
try {
|
||||
// Check authentication
|
||||
const user = await authMiddleware(request)
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url)
|
||||
const tempPath = searchParams.get('path')
|
||||
|
||||
if (!tempPath) {
|
||||
return NextResponse.json({ error: 'Temporary path is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
// Validate temp path format
|
||||
if (!tempPath.startsWith('temp/')) {
|
||||
return NextResponse.json({ error: 'Invalid temporary path' }, { status: 400 })
|
||||
}
|
||||
|
||||
// Delete temporary file
|
||||
await deleteFile(tempPath)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Temporary file deleted successfully',
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Temporary file deletion error:', error)
|
||||
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
129
app/api/upload/route.ts
Normal file
129
app/api/upload/route.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { authMiddleware } from '@/lib/auth-middleware'
|
||||
import { uploadFile, validateFileType, validateFileSize } from '@/lib/file-vault'
|
||||
import { z } from 'zod'
|
||||
|
||||
// Allowed file types and sizes
|
||||
const ALLOWED_IMAGE_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'image/gif']
|
||||
|
||||
const ALLOWED_DOCUMENT_TYPES = [
|
||||
'application/pdf',
|
||||
'application/msword',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'text/plain',
|
||||
]
|
||||
|
||||
const MAX_FILE_SIZE = 10 * 1024 * 1024 // 10MB
|
||||
|
||||
// Upload request validation
|
||||
const uploadSchema = z.object({
|
||||
type: z.enum(['image', 'document']).optional().default('image'),
|
||||
})
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
// Check authentication
|
||||
const user = await authMiddleware(request)
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
// Parse form data
|
||||
const formData = await request.formData()
|
||||
const file = formData.get('file') as File
|
||||
const typeParam = formData.get('type') as string
|
||||
|
||||
if (!file) {
|
||||
return NextResponse.json({ error: 'No file provided' }, { status: 400 })
|
||||
}
|
||||
|
||||
// Validate request parameters
|
||||
const { type } = uploadSchema.parse({ type: typeParam })
|
||||
|
||||
// Determine allowed file types based on upload type
|
||||
const allowedTypes = type === 'image' ? ALLOWED_IMAGE_TYPES : ALLOWED_DOCUMENT_TYPES
|
||||
|
||||
// Validate file type
|
||||
if (!validateFileType(file.type, allowedTypes)) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: `Invalid file type. Allowed types: ${allowedTypes.join(', ')}`,
|
||||
},
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// Validate file size
|
||||
if (!validateFileSize(file.size, MAX_FILE_SIZE)) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: `File size too large. Max size: ${MAX_FILE_SIZE / (1024 * 1024)}MB`,
|
||||
},
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// Convert file to buffer
|
||||
const bytes = await file.arrayBuffer()
|
||||
const buffer = Buffer.from(bytes)
|
||||
|
||||
// Upload file to external API
|
||||
const uploadResult = await uploadFile(buffer, file.name, file.type, user.id)
|
||||
|
||||
// Return upload information
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
tempPath: uploadResult.url, // Use URL as tempPath for compatibility
|
||||
filename: uploadResult.filename,
|
||||
size: file.size,
|
||||
type: file.type,
|
||||
uploadedBy: user.id,
|
||||
uploadedAt: new Date().toISOString(),
|
||||
url: uploadResult.url, // Also include the direct URL
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Upload error:', error)
|
||||
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid request parameters', details: error.issues },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
// Get file information
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
// Check authentication
|
||||
const user = await authMiddleware(request)
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url)
|
||||
const filePath = searchParams.get('path')
|
||||
|
||||
if (!filePath) {
|
||||
return NextResponse.json({ error: 'File path is required' }, { status: 400 })
|
||||
}
|
||||
|
||||
// TODO: Add file metadata retrieval from database
|
||||
// For now, return basic info
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
path: filePath,
|
||||
// Additional metadata would be retrieved from database
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('File retrieval error:', error)
|
||||
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user