Skip to content

Commit

Permalink
feat: adding invites for users
Browse files Browse the repository at this point in the history
  • Loading branch information
aacevski committed Feb 9, 2025
1 parent ca5bf18 commit 6f509ea
Show file tree
Hide file tree
Showing 30 changed files with 551 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ CREATE TABLE `project` (
`icon` text DEFAULT 'Layout',
`name` text NOT NULL,
`description` text,
`created_at` integer DEFAULT '"2025-02-08T22:05:26.528Z"' NOT NULL,
`created_at` integer DEFAULT '"2025-02-09T21:03:20.815Z"' NOT NULL,
FOREIGN KEY (`workspace_id`) REFERENCES `workspace`(`id`) ON UPDATE cascade ON DELETE cascade
);
--> statement-breakpoint
Expand All @@ -20,41 +20,41 @@ CREATE TABLE `task` (
`id` text PRIMARY KEY NOT NULL,
`project_id` text NOT NULL,
`number` integer DEFAULT 1,
`assignee_id` text NOT NULL,
`assignee_email` text NOT NULL,
`title` text NOT NULL,
`description` text,
`status` text DEFAULT 'to-do' NOT NULL,
`priority` text DEFAULT 'low',
`due_date` integer,
`created_at` integer DEFAULT '"2025-02-08T22:05:26.528Z"' NOT NULL,
`created_at` integer DEFAULT '"2025-02-09T21:03:20.815Z"' NOT NULL,
FOREIGN KEY (`project_id`) REFERENCES `project`(`id`) ON UPDATE cascade ON DELETE cascade,
FOREIGN KEY (`assignee_id`) REFERENCES `user`(`id`) ON UPDATE cascade ON DELETE cascade
FOREIGN KEY (`assignee_email`) REFERENCES `user`(`email`) ON UPDATE cascade ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `user` (
`id` text PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`password` text NOT NULL,
`email` text NOT NULL,
`created_at` integer DEFAULT '"2025-02-08T22:05:26.528Z"' NOT NULL
`created_at` integer DEFAULT '"2025-02-09T21:03:20.814Z"' NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `user_email_unique` ON `user` (`email`);--> statement-breakpoint
CREATE TABLE `workspace` (
`id` text PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`description` text,
`owner_id` text NOT NULL,
`created_at` integer DEFAULT '"2025-02-08T22:05:26.528Z"' NOT NULL,
FOREIGN KEY (`owner_id`) REFERENCES `user`(`id`) ON UPDATE cascade ON DELETE cascade
`owner_email` text NOT NULL,
`created_at` integer DEFAULT '"2025-02-09T21:03:20.815Z"' NOT NULL,
FOREIGN KEY (`owner_email`) REFERENCES `user`(`email`) ON UPDATE cascade ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `workspace_member` (
`id` text PRIMARY KEY NOT NULL,
`workspace_id` text NOT NULL,
`user_id` text NOT NULL,
`user_email` text NOT NULL,
`role` text,
`joined_at` integer DEFAULT '"2025-02-08T22:05:26.528Z"' NOT NULL,
`joined_at` integer DEFAULT '"2025-02-09T21:03:20.815Z"' NOT NULL,
FOREIGN KEY (`workspace_id`) REFERENCES `workspace`(`id`) ON UPDATE cascade ON DELETE cascade,
FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON UPDATE cascade ON DELETE cascade
FOREIGN KEY (`user_email`) REFERENCES `user`(`email`) ON UPDATE cascade ON DELETE cascade
);
48 changes: 24 additions & 24 deletions apps/api/drizzle/meta/0000_snapshot.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"version": "6",
"dialect": "sqlite",
"id": "6a9833af-80f3-46e9-a34a-f0cad5ddd6f1",
"id": "49787b32-4e2b-4274-a0e2-d2784a178329",
"prevId": "00000000-0000-0000-0000-000000000000",
"tables": {
"project": {
Expand Down Expand Up @@ -56,7 +56,7 @@
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'\"2025-02-08T22:05:26.528Z\"'"
"default": "'\"2025-02-09T21:03:20.815Z\"'"
}
},
"indexes": {},
Expand Down Expand Up @@ -141,8 +141,8 @@
"autoincrement": false,
"default": 1
},
"assignee_id": {
"name": "assignee_id",
"assignee_email": {
"name": "assignee_email",
"type": "text",
"primaryKey": false,
"notNull": true,
Expand Down Expand Up @@ -191,7 +191,7 @@
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'\"2025-02-08T22:05:26.528Z\"'"
"default": "'\"2025-02-09T21:03:20.815Z\"'"
}
},
"indexes": {},
Expand All @@ -205,12 +205,12 @@
"onDelete": "cascade",
"onUpdate": "cascade"
},
"task_assignee_id_user_id_fk": {
"name": "task_assignee_id_user_id_fk",
"task_assignee_email_user_email_fk": {
"name": "task_assignee_email_user_email_fk",
"tableFrom": "task",
"tableTo": "user",
"columnsFrom": ["assignee_id"],
"columnsTo": ["id"],
"columnsFrom": ["assignee_email"],
"columnsTo": ["email"],
"onDelete": "cascade",
"onUpdate": "cascade"
}
Expand Down Expand Up @@ -256,7 +256,7 @@
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'\"2025-02-08T22:05:26.528Z\"'"
"default": "'\"2025-02-09T21:03:20.814Z\"'"
}
},
"indexes": {
Expand Down Expand Up @@ -295,8 +295,8 @@
"notNull": false,
"autoincrement": false
},
"owner_id": {
"name": "owner_id",
"owner_email": {
"name": "owner_email",
"type": "text",
"primaryKey": false,
"notNull": true,
Expand All @@ -308,17 +308,17 @@
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'\"2025-02-08T22:05:26.528Z\"'"
"default": "'\"2025-02-09T21:03:20.815Z\"'"
}
},
"indexes": {},
"foreignKeys": {
"workspace_owner_id_user_id_fk": {
"name": "workspace_owner_id_user_id_fk",
"workspace_owner_email_user_email_fk": {
"name": "workspace_owner_email_user_email_fk",
"tableFrom": "workspace",
"tableTo": "user",
"columnsFrom": ["owner_id"],
"columnsTo": ["id"],
"columnsFrom": ["owner_email"],
"columnsTo": ["email"],
"onDelete": "cascade",
"onUpdate": "cascade"
}
Expand All @@ -344,8 +344,8 @@
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"user_email": {
"name": "user_email",
"type": "text",
"primaryKey": false,
"notNull": true,
Expand All @@ -364,7 +364,7 @@
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'\"2025-02-08T22:05:26.528Z\"'"
"default": "'\"2025-02-09T21:03:20.815Z\"'"
}
},
"indexes": {},
Expand All @@ -378,12 +378,12 @@
"onDelete": "cascade",
"onUpdate": "cascade"
},
"workspace_member_user_id_user_id_fk": {
"name": "workspace_member_user_id_user_id_fk",
"workspace_member_user_email_user_email_fk": {
"name": "workspace_member_user_email_user_email_fk",
"tableFrom": "workspace_member",
"tableTo": "user",
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"columnsFrom": ["user_email"],
"columnsTo": ["email"],
"onDelete": "cascade",
"onUpdate": "cascade"
}
Expand Down
4 changes: 2 additions & 2 deletions apps/api/drizzle/meta/_journal.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
{
"idx": 0,
"version": "6",
"when": 1739052326535,
"tag": "0000_broad_veda",
"when": 1739135000822,
"tag": "0000_conscious_golden_guardian",
"breakpoints": true
}
]
Expand Down
12 changes: 6 additions & 6 deletions apps/api/src/database/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ export const workspaceTable = sqliteTable("workspace", {
.primaryKey(),
name: text("name").notNull(),
description: text("description"),
ownerId: text("owner_id")
ownerEmail: text("owner_email")
.notNull()
.references(() => userTable.id, {
.references(() => userTable.email, {
onDelete: "cascade",
onUpdate: "cascade",
}),
Expand All @@ -53,9 +53,9 @@ export const workspaceUserTable = sqliteTable("workspace_member", {
onDelete: "cascade",
onUpdate: "cascade",
}),
userId: text("user_id")
userEmail: text("user_email")
.notNull()
.references(() => userTable.id, {
.references(() => userTable.email, {
onDelete: "cascade",
onUpdate: "cascade",
}),
Expand Down Expand Up @@ -95,9 +95,9 @@ export const taskTable = sqliteTable("task", {
onUpdate: "cascade",
}),
number: int().default(1),
assigneeId: text("assignee_id")
userEmail: text("assignee_email")
.notNull()
.references(() => userTable.id, {
.references(() => userTable.email, {
onDelete: "cascade",
onUpdate: "cascade",
}),
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import workspace from "./workspace";
import workspaceUser from "./workspace-user";

const app = new Elysia()
.state("userId", "")
.state("userEmail", "")
.use(cors())
.use(logger())
.use(user)
Expand All @@ -27,7 +27,7 @@ const app = new Elysia()
return { user: null };
}

store.userId = user.id;
store.userEmail = user.email;
},
})
.get("/me", async ({ cookie: { session } }) => {
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/task/controllers/create-task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ async function getNextTaskNumber(projectId: string) {

async function createTask(body: {
projectId: string;
assigneeId: string;
userEmail: string;
title: string;
status: string;
dueDate: Date | null;
Expand All @@ -23,7 +23,7 @@ async function createTask(body: {
const [assignee] = await db
.select({ name: userTable.name })
.from(userTable)
.where(eq(userTable.id, body.assigneeId));
.where(eq(userTable.email, body.userEmail));

if (!assignee) {
throw new Error("Assignee not found");
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/task/controllers/get-tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ async function getTasks(projectId: string) {
priority: taskTable.priority,
dueDate: taskTable.dueDate,
createdAt: taskTable.createdAt,
assigneeId: taskTable.assigneeId,
userEmail: taskTable.userEmail,
assigneeName: userTable.name,
assigneeEmail: userTable.email,
})
.from(taskTable)
.leftJoin(userTable, eq(taskTable.assigneeId, userTable.id))
.leftJoin(userTable, eq(taskTable.userEmail, userTable.id))
.where(eq(taskTable.projectId, projectId));

const columns = DEFAULT_COLUMNS.map((column) => ({
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/task/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const task = new Elysia({ prefix: "/task" })
{
body: t.Object({
projectId: t.String(),
assigneeId: t.String(),
userEmail: t.String(),
title: t.String(),
status: t.String(),
dueDate: t.Date(),
Expand Down
10 changes: 6 additions & 4 deletions apps/api/src/workspace-user/controllers/get-workspace-users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,26 @@ import {
function getWorkspaceUsers({ workspaceId }: { workspaceId: string }) {
return db
.select({
userId: userTable.id,
userEmail: userTable.email,
userName: userTable.name,
joinedAt: userTable.createdAt,
})
.from(workspaceTable)
.where(eq(workspaceTable.id, workspaceId))
.innerJoin(
workspaceUserTable,
eq(workspaceTable.id, workspaceUserTable.workspaceId),
)
.innerJoin(userTable, eq(workspaceUserTable.userId, userTable.id))
.innerJoin(userTable, eq(workspaceUserTable.userEmail, userTable.email))
.unionAll(
db
.select({
userId: userTable.id,
userEmail: userTable.email,
userName: userTable.name,
joinedAt: userTable.createdAt,
})
.from(workspaceTable)
.innerJoin(userTable, eq(workspaceTable.ownerId, userTable.id))
.innerJoin(userTable, eq(workspaceTable.ownerEmail, userTable.email))
.where(eq(workspaceTable.id, workspaceId)),
);
}
Expand Down
19 changes: 19 additions & 0 deletions apps/api/src/workspace-user/controllers/invite-workspace-user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import db from "../../database";
import { workspaceUserTable } from "../../database/schema";

async function inviteWorkspaceUser({
workspaceId,
userEmail,
}: { workspaceId: string; userEmail: string }) {
const [invitedUser] = await db
.insert(workspaceUserTable)
.values({
userEmail,
workspaceId,
})
.returning();

return invitedUser;
}

export default inviteWorkspaceUser;
26 changes: 20 additions & 6 deletions apps/api/src/workspace-user/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
import Elysia from "elysia";
import Elysia, { t } from "elysia";
import getWorkspaceUsers from "./controllers/get-workspace-users";
import inviteWorkspaceUser from "./controllers/invite-workspace-user";

const workspaceUser = new Elysia({ prefix: "/workspace-user" }).get(
"/list/:workspaceId",
async ({ params: { workspaceId } }) => {
const workspaceUser = new Elysia({ prefix: "/workspace-user" })
.get("/list/:workspaceId", async ({ params: { workspaceId } }) => {
const workspaceUsersInWorkspace = await getWorkspaceUsers({ workspaceId });
console.log({ workspaceUsersInWorkspace });

return workspaceUsersInWorkspace;
},
);
})
.post(
"/:workspaceId/invite",
async ({ body }) => {
const invitedWorkspaceUser = await inviteWorkspaceUser(body);

return invitedWorkspaceUser;
},
{
body: t.Object({
userEmail: t.String(),
workspaceId: t.String(),
}),
},
);

export default workspaceUser;
Loading

0 comments on commit 6f509ea

Please sign in to comment.