All files / src/api/drive upload.ts

100% Statements 27/27
95.83% Branches 23/24
100% Functions 1/1
100% Lines 27/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119          53x                                                                                                 53x 94x 94x   94x 31x     63x 63x 63x 63x   63x                       28x 21x 7x   14x 7x   7x     7x     35x     35x 28x 7x         21x 7x   14x 7x             14x          
import { createRoute, RouteHandler } from '@hono/zod-openapi'
import { ErrorSchema, FileUploadResponseSchema, FileUploadRequestSchema } from '../../schema/drive'
import { processFileUpload } from '../../utils/googleDrive'
 
import type { EnvHono } from '../..'
export const uploadRoute = createRoute({
  method: 'post',
  path: '/upload',
  request: {
    body: {
      content: {
        'multipart/form-data': {
          schema: FileUploadRequestSchema
        }
      }
    }
  },
  responses: {
    200: {
      content: {
        'application/json': {
          schema: FileUploadResponseSchema
        }
      },
      description: 'File uploaded successfully'
    },
    400: {
      content: {
        'application/json': {
          schema: ErrorSchema
        }
      },
      description: 'Bad request'
    },
    403: {
      content: {
        'application/json': {
          schema: ErrorSchema
        }
      },
      description: 'Forbidden - folder access denied'
    },
    500: {
      content: {
        'application/json': {
          schema: ErrorSchema
        }
      },
      description: 'Internal server error'
    }
  },
  tags: ['Drive API']
})
 
export const uploadHandler: RouteHandler<typeof uploadRoute, EnvHono> = async (c) => {
  try {
    const { GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REFRESH_TOKEN, GOOGLE_DRIVE_DEFAULT_FOLDER_ID } = c.env
 
    if (!GOOGLE_CLIENT_ID || !GOOGLE_CLIENT_SECRET || !GOOGLE_REFRESH_TOKEN || !GOOGLE_DRIVE_DEFAULT_FOLDER_ID) {
      return c.json({ error: 'Missing required environment variables' }, 400)
    }
 
    const formData = await c.req.formData()
    const file = formData.get('file') as File
    const folderId = formData.get('folderId') as string
    const overwrite = formData.get('overwrite') === 'true'
 
    const result = await processFileUpload(
      file,
      folderId,
      overwrite,
      {
        clientId: GOOGLE_CLIENT_ID,
        clientSecret: GOOGLE_CLIENT_SECRET,
        refreshToken: GOOGLE_REFRESH_TOKEN
      },
      GOOGLE_DRIVE_DEFAULT_FOLDER_ID
    )
 
    if (!result.success) {
      if (result.error === 'Invalid folder ID') {
        return c.json({ error: result.error, details: result.details }, 400)
      }
      if (result.error === 'Unauthorized folder access') {
        return c.json({ error: result.error, details: result.details }, 403)
      }
      return c.json({ error: result.error || 'Upload failed' }, 400)
    }
 
    return c.json({ success: true }, 200)
 
  } catch (error) {
    console.error('Upload error:', error)
 
    // エラーメッセージからHTTPステータスコードを判断
    if (error instanceof Error) {
      if (error.message.includes('Failed to refresh access token')) {
        return c.json({
          error: 'Failed to refresh access token',
          details: error.message.replace('Failed to refresh access token: ', '')
        }, 500)
      }
      if (error.message.includes('No access token')) {
        return c.json({ error: 'Failed to get access token' }, 500)
      }
      if (error.message.includes('Failed to upload to Google Drive')) {
        return c.json({
          error: 'Failed to upload to Google Drive',
          details: error.message.replace('Failed to upload to Google Drive: ', '')
        }, 500)
      }
    }
 
    return c.json({
      error: 'Failed to upload file',
      details: error instanceof Error ? error.message : 'Unknown error'
    }, 500)
  }
}