Skip to content

Commit

Permalink
hard delete projects
Browse files Browse the repository at this point in the history
  • Loading branch information
ruggi committed Feb 12, 2024
1 parent ee7f005 commit 5a69d30
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 1 deletion.
59 changes: 59 additions & 0 deletions utopia-remix/app/models/project.server.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import moment from 'moment'
import { prisma } from '../db.server'
import { createTestProject, createTestUser, truncateTables } from '../test-util'
import {
hardDeleteAllProjects,
hardDeleteProject,
listDeletedProjects,
listProjects,
renameProject,
Expand Down Expand Up @@ -213,4 +215,61 @@ describe('project model', () => {
})
})
})

describe('hardDeleteProject', () => {
beforeEach(async () => {
await createTestUser(prisma, { id: 'bob' })
await createTestUser(prisma, { id: 'alice' })
await createTestProject(prisma, { id: 'foo', ownerId: 'bob' })
await createTestProject(prisma, {
id: 'deleted-project',
ownerId: 'bob',
deleted: true,
})
})
it('requires the user', async () => {
const fn = async () => hardDeleteProject({ id: 'foo', userId: 'JOHN-DOE' })
await expect(fn).rejects.toThrow('Record to delete does not exist')
})
it('requires the project', async () => {
const fn = async () => hardDeleteProject({ id: 'bar', userId: 'bob' })
await expect(fn).rejects.toThrow('Record to delete does not exist')
})
it('requires the project ownership', async () => {
const fn = async () => hardDeleteProject({ id: 'foo', userId: 'alice' })
await expect(fn).rejects.toThrow('Record to delete does not exist')
})
it('requires the project to be soft-deleted', async () => {
const fn = async () => hardDeleteProject({ id: 'foo', userId: 'bob' })
await expect(fn).rejects.toThrow('Record to delete does not exist')
})
it('hard-deletes the project', async () => {
const existing = await prisma.project.count({ where: { proj_id: 'deleted-project' } })
expect(existing).toEqual(1)
await hardDeleteProject({ id: 'deleted-project', userId: 'bob' })
const got = await prisma.project.count({ where: { proj_id: 'deleted-project' } })
expect(got).toEqual(0)
})
})

describe('hardDeleteAllProjects', () => {
beforeEach(async () => {
await createTestUser(prisma, { id: 'bob' })
await createTestUser(prisma, { id: 'alice' })
await createTestProject(prisma, { id: 'one', ownerId: 'bob' })
await createTestProject(prisma, { id: 'two', ownerId: 'bob', deleted: true })
await createTestProject(prisma, { id: 'three', ownerId: 'bob', deleted: true })
await createTestProject(prisma, { id: 'four', ownerId: 'alice', deleted: true })
await createTestProject(prisma, { id: 'five', ownerId: 'bob' })
await createTestProject(prisma, { id: 'six', ownerId: 'bob', deleted: true })
await createTestProject(prisma, { id: 'seven', ownerId: 'alice' })
})
it('hard-deletes all soft-deleted project owned by the user', async () => {
await hardDeleteAllProjects({ userId: 'bob' })
const bobProjects = await prisma.project.findMany({ where: { owner_id: 'bob' } })
expect(bobProjects.map((p) => p.proj_id)).toEqual(['one', 'five'])
const aliceProjects = await prisma.project.findMany({ where: { owner_id: 'alice' } })
expect(aliceProjects.map((p) => p.proj_id)).toEqual(['four', 'seven'])
})
})
})
91 changes: 91 additions & 0 deletions utopia-remix/app/routes-test/projects.$id.destroy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { prisma } from '../db.server'
import { handleDestroyProject } from '../routes/projects.$id.destroy'
import {
createTestProject,
createTestSession,
createTestUser,
newTestRequest,
truncateTables,
} from '../test-util'
import { ApiError } from '../util/api.server'

describe('handleDestroyProject', () => {
afterEach(async () => {
await truncateTables([
prisma.userDetails,
prisma.persistentSession,
prisma.project,
prisma.projectID,
])
})

beforeEach(async () => {
await createTestUser(prisma, { id: 'foo' })
await createTestUser(prisma, { id: 'bar' })
await createTestSession(prisma, { key: 'the-key', userId: 'foo' })
await createTestProject(prisma, {
id: 'one',
ownerId: 'foo',
title: 'project-one',
})
await createTestProject(prisma, {
id: 'two',
ownerId: 'foo',
title: 'project-two',
deleted: true,
})
await createTestProject(prisma, {
id: 'three',
ownerId: 'bar',
title: 'project-three',
deleted: true,
})
})

it('requires a user', async () => {
const fn = async () =>
handleDestroyProject(newTestRequest({ method: 'POST', authCookie: 'wrong-key' }), {})
await expect(fn).rejects.toThrow(ApiError)
await expect(fn).rejects.toThrow('session not found')
})
it('requires a valid id', async () => {
const fn = async () =>
handleDestroyProject(newTestRequest({ method: 'POST', authCookie: 'the-key' }), {})
await expect(fn).rejects.toThrow(ApiError)
await expect(fn).rejects.toThrow('id is null')
})
it('requires a valid project', async () => {
const fn = async () => {
const req = newTestRequest({ method: 'POST', authCookie: 'the-key' })
return handleDestroyProject(req, { id: 'doesnt-exist' })
}

await expect(fn).rejects.toThrow('Record to delete does not exist')
})
it('requires ownership of the project', async () => {
const fn = async () => {
const req = newTestRequest({ method: 'POST', authCookie: 'the-key' })
return handleDestroyProject(req, { id: 'three' })
}

await expect(fn).rejects.toThrow('Record to delete does not exist')
})
it('requires soft-deletion of the project', async () => {
const fn = async () => {
const req = newTestRequest({ method: 'POST', authCookie: 'the-key' })
return handleDestroyProject(req, { id: 'one' })
}

await expect(fn).rejects.toThrow('Record to delete does not exist')
})
it('hard-deletes the project', async () => {
const fn = async () => {
const req = newTestRequest({ method: 'POST', authCookie: 'the-key' })
return handleDestroyProject(req, { id: 'two' })
}

await fn()
const got = await prisma.project.count({ where: { proj_id: 'two' } })
expect(got).toEqual(0)
})
})
50 changes: 50 additions & 0 deletions utopia-remix/app/routes-test/projects.destroy.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { prisma } from '../db.server'
import { handleDestroyAllProjects } from '../routes/projects.destroy'
import {
createTestProject,
createTestSession,
createTestUser,
newTestRequest,
truncateTables,
} from '../test-util'
import { ApiError } from '../util/api.server'

describe('handleDestroyAllProjects', () => {
afterEach(async () => {
await truncateTables([
prisma.userDetails,
prisma.persistentSession,
prisma.project,
prisma.projectID,
])
})

beforeEach(async () => {
await createTestUser(prisma, { id: 'bob' })
await createTestUser(prisma, { id: 'alice' })
await createTestSession(prisma, { key: 'the-key', userId: 'bob' })
await createTestProject(prisma, { id: 'one', ownerId: 'bob' })
await createTestProject(prisma, { id: 'two', ownerId: 'bob', deleted: true })
await createTestProject(prisma, { id: 'three', ownerId: 'alice', deleted: true })
await createTestProject(prisma, { id: 'four', ownerId: 'bob' })
await createTestProject(prisma, { id: 'five', ownerId: 'bob' })
await createTestProject(prisma, { id: 'six', ownerId: 'bob', deleted: true })
})

it('requires a user', async () => {
const fn = async () =>
handleDestroyAllProjects(newTestRequest({ method: 'POST', authCookie: 'wrong-key' }), {})
await expect(fn).rejects.toThrow(ApiError)
await expect(fn).rejects.toThrow('session not found')
})
it('hard-deletes all soft-deleted projects owned by the user', async () => {
const fn = async () => {
const req = newTestRequest({ method: 'POST', authCookie: 'the-key' })
return handleDestroyAllProjects(req, {})
}

await fn()
const got = await prisma.project.findMany({ where: { owner_id: 'bob' } })
expect(got.map((p) => p.proj_id)).toEqual(['one', 'four', 'five'])
})
})
20 changes: 20 additions & 0 deletions utopia-remix/app/routes/projects.$id.destroy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ActionFunctionArgs } from '@remix-run/node'
import { Params } from '@remix-run/react'
import { ensure, handle, requireUser } from '../util/api.server'
import { Status } from '../util/statusCodes.server'
import { hardDeleteProject } from '../models/project.server'

export async function action(args: ActionFunctionArgs) {
return handle(args, { POST: handleDestroyProject })
}

export async function handleDestroyProject(req: Request, params: Params<string>) {
const user = await requireUser(req)

const { id } = params
ensure(id != null, 'id is null', Status.BAD_REQUEST)

await hardDeleteProject({ id: id, userId: user.user_id })

return {}
}
16 changes: 16 additions & 0 deletions utopia-remix/app/routes/projects.destroy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ActionFunctionArgs } from '@remix-run/node'
import { Params } from '@remix-run/react'
import { hardDeleteAllProjects } from '../models/project.server'
import { handle, requireUser } from '../util/api.server'

export async function action(args: ActionFunctionArgs) {
return handle(args, { POST: handleDestroyAllProjects })
}

export async function handleDestroyAllProjects(req: Request, params: Params<string>) {
const user = await requireUser(req)

await hardDeleteAllProjects({ userId: user.user_id })

return {}
}
3 changes: 2 additions & 1 deletion utopia-remix/app/routes/projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { useLoaderData } from '@remix-run/react'
import moment from 'moment'
import { UserDetails } from 'prisma-client'
import React, { useEffect, useState } from 'react'
import { ProjectWithoutContent, listProjects } from '../models/project.server'
import { listProjects } from '../models/project.server'
import { newProjectButton } from '../styles/newProjectButton.css'
import { projectCategoryButton, userName } from '../styles/sidebarComponents.css'
import { sprinkles } from '../styles/sprinkles.css'
import { requireUser } from '../util/api.server'
import { ProjectWithoutContent } from '../types'

export async function loader(args: LoaderFunctionArgs) {
const user = await requireUser(args.request)
Expand Down

0 comments on commit 5a69d30

Please sign in to comment.