Files
Todo/lib/migration-actions.ts

164 lines
4.6 KiB
TypeScript

'use server'
import { prisma } from './db'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/pages/api/auth/[...nextauth]'
/**
* Migration utilities for transitioning existing anonymous lists to user-owned lists
* Requirements: 10.2, 10.3, 10.4, 10.5
*/
export type MigrationResult =
| { success: true; migratedCount: number }
| { success: false; error: string }
export type ClaimableList = {
id: string
title: string
color: string
itemCount: number
createdAt: Date
updatedAt: Date
}
/**
* Get lists that can be claimed by a new user
* This checks for lists in localStorage that exist in the database
* Requirement: 10.2 - Provide migration path for existing anonymous lists
*/
export async function getClaimableLists(listIds: string[]): Promise<ClaimableList[]> {
try {
if (!listIds || listIds.length === 0) {
return []
}
// Find lists that exist in the database
// Note: In a real migration scenario, we'd need a way to identify orphaned lists
// For now, we'll check if the provided list IDs exist
const lists = await prisma.list.findMany({
where: {
id: {
in: listIds,
},
},
include: {
_count: {
select: {
items: true,
},
},
},
})
return lists.map(list => ({
id: list.id,
title: list.title,
color: list.color,
itemCount: list._count.items,
createdAt: list.createdAt,
updatedAt: list.updatedAt,
}))
} catch (error) {
console.error('Error fetching claimable lists:', error)
return []
}
}
/**
* Claim existing lists and associate them with the current user
* Requirements: 10.2, 10.3, 10.4, 10.5
*/
export async function claimLists(listIds: string[]): Promise<MigrationResult> {
try {
// Get current user session
const session = await getServerSession(authOptions)
if (!session?.user?.id) {
return { success: false, error: 'Unauthorized: Please log in to claim lists' }
}
const userId = session.user.id
if (!listIds || listIds.length === 0) {
return { success: true, migratedCount: 0 }
}
// Update all specified lists to be owned by the current user
// Requirement 10.3 - Preserve all list data including items, metadata, and timestamps
// Requirement 10.4 - Ensure all lists have an associated owner
// Use transaction to update each list individually to ensure proper type checking
let migratedCount = 0
for (const listId of listIds) {
try {
await prisma.list.update({
where: { id: listId },
data: { ownerId: userId },
})
migratedCount++
} catch (err) {
console.error(`Failed to claim list ${listId}:`, err)
// Continue with other lists
}
}
// Requirement 10.5 - Display migrated lists in user's account
// Lists will now appear in getLists() since they have the user's ownerId
return { success: true, migratedCount }
} catch (error) {
console.error('Error claiming lists:', error)
return { success: false, error: 'Failed to claim lists. Please try again.' }
}
}
/**
* Check if a user has any lists (to determine if they're a new user)
*/
export async function hasExistingLists(): Promise<boolean> {
try {
const session = await getServerSession(authOptions)
if (!session?.user?.id) {
return false
}
const count = await prisma.list.count({
where: {
ownerId: session.user.id,
},
})
return count > 0
} catch (error) {
console.error('Error checking existing lists:', error)
return false
}
}
/**
* Migrate all orphaned lists to a system user
* This is a one-time migration script for deployment
* Requirement: 10.1, 10.4 - Migration path and ensure all lists have owner
*/
export async function migrateOrphanedListsToSystemUser(): Promise<MigrationResult> {
try {
// First, check if system user exists
const systemUser = await prisma.user.findUnique({
where: { email: 'system@ultimatelists.app' },
})
if (!systemUser) {
return { success: false, error: 'System user does not exist. Run migration script first.' }
}
// This would migrate lists if ownerId was nullable
// Since our current schema requires ownerId, this is a placeholder
// In a real migration, you'd run this before making ownerId required
return { success: true, migratedCount: 0 }
} catch (error) {
console.error('Error migrating orphaned lists:', error)
return { success: false, error: 'Migration failed. Please contact support.' }
}
}