feat: implement cloud backup auto-sync feature with scheduling (#280)
* feat: implement cloud backup auto-sync feature with scheduling - Added a new cron route for auto-syncing Google Drive backups hourly. - Introduced a schedule management system for enabling/disabling auto-sync and setting the sync hour. - Updated the logo upload API to handle logo file management more efficiently. - Created a public storage bucket for company logos with appropriate size and type restrictions. - Enhanced the LogoUpload component to validate file types and sizes during upload. - Added tests for the new auto-sync functionality to ensure correct behavior under various conditions. * Update extensions/general/cloud-backup/lib/sync.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update app/api/settings/logo/route.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * refactor: remove unused parameters from saveExtensionData function --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
greptile-apps[bot]
parent
c0b74d50e4
commit
7a0214c053
@@ -33,13 +33,29 @@ export async function POST(request: Request) {
|
||||
}
|
||||
|
||||
const buffer = Buffer.from(await file.arrayBuffer())
|
||||
const ext = file.name.split('.').pop() || 'png'
|
||||
const storagePath = `logos/${companyId}/logo.${ext}`
|
||||
const mimeToExt: Record<string, string> = {
|
||||
'image/png': 'png',
|
||||
'image/jpeg': 'jpg',
|
||||
'image/svg+xml': 'svg',
|
||||
'image/webp': 'webp',
|
||||
}
|
||||
const ext = mimeToExt[file.type] ?? 'png'
|
||||
const storagePath = `${companyId}/logo-${Date.now()}.${ext}`
|
||||
|
||||
// Upload with service client to bypass storage RLS (auth already verified above)
|
||||
const serviceClient = createServiceClient()
|
||||
|
||||
// Remove any previous logo files for this company so we don't pile up orphans.
|
||||
const { data: existing } = await serviceClient.storage
|
||||
.from('logos')
|
||||
.list(companyId)
|
||||
if (existing && existing.length > 0) {
|
||||
await serviceClient.storage
|
||||
.from('logos')
|
||||
.remove(existing.map((f) => `${companyId}/${f.name}`))
|
||||
}
|
||||
|
||||
const { error: uploadError } = await serviceClient.storage
|
||||
.from('documents')
|
||||
.from('logos')
|
||||
.upload(storagePath, buffer, {
|
||||
contentType: file.type,
|
||||
upsert: true,
|
||||
@@ -49,9 +65,8 @@ export async function POST(request: Request) {
|
||||
return NextResponse.json({ error: `Uppladdning misslyckades: ${uploadError.message}` }, { status: 500 })
|
||||
}
|
||||
|
||||
// Get public URL
|
||||
const { data: urlData } = serviceClient.storage
|
||||
.from('documents')
|
||||
.from('logos')
|
||||
.getPublicUrl(storagePath)
|
||||
|
||||
// Update company settings
|
||||
@@ -86,12 +101,14 @@ export async function DELETE() {
|
||||
.single()
|
||||
|
||||
if (settings?.logo_url) {
|
||||
// Extract storage path from URL
|
||||
const url = new URL(settings.logo_url)
|
||||
const pathMatch = url.pathname.match(/\/object\/public\/documents\/(.+)/)
|
||||
if (pathMatch) {
|
||||
const serviceClient = createServiceClient()
|
||||
await serviceClient.storage.from('documents').remove([pathMatch[1]])
|
||||
const serviceClient = createServiceClient()
|
||||
const { data: existing } = await serviceClient.storage
|
||||
.from('logos')
|
||||
.list(companyId)
|
||||
if (existing && existing.length > 0) {
|
||||
await serviceClient.storage
|
||||
.from('logos')
|
||||
.remove(existing.map((f) => `${companyId}/${f.name}`))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user