Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions apps/app/src/actions/change-organization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"use server";

import { authActionClient } from "./safe-action";
import { z } from "zod";
import { db } from "@bubba/db";

export const changeOrganizationAction = authActionClient
.schema(
z.object({
organizationId: z.string(),
})
)
.metadata({
name: "change-organization",
track: {
event: "create-employee",
channel: "server",
},
})
.action(async ({ parsedInput, ctx }) => {
const { organizationId } = parsedInput;
const { user } = ctx;

try {
const organization = await db.organization.findUnique({
where: {
id: organizationId,
},
});

if (!organization) {
return {
success: false,
error: "Organization not found",
};
}

await db.user.update({
where: {
id: user.id,
},
data: {
organizationId: organization.id,
},
});

return {
success: true,
data: organization,
};
} catch (error) {
console.error("Error changing organization:", error);

return {
success: false,
error: "Failed to change organization",
};
}
});
202 changes: 101 additions & 101 deletions apps/app/src/actions/organization/create-api-key-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,113 +7,113 @@ import { db } from "@bubba/db";
import { revalidatePath } from "next/cache";

export const createApiKeyAction = authActionClient
.schema(apiKeySchema)
.metadata({
name: "createApiKey",
track: {
event: "createApiKey",
channel: "server",
},
})
.action(async ({ parsedInput, ctx }) => {
try {
const { name, expiresAt } = parsedInput;
console.log(`Creating API key "${name}" with expiration: ${expiresAt}`);
.schema(apiKeySchema)
.metadata({
name: "createApiKey",
track: {
event: "createApiKey",
channel: "server",
},
})
.action(async ({ parsedInput, ctx }) => {
try {
const { name, expiresAt } = parsedInput;
console.log(`Creating API key "${name}" with expiration: ${expiresAt}`);

// Generate a new API key and salt
const apiKey = generateApiKey();
const salt = generateSalt();
const hashedKey = hashApiKey(apiKey, salt);
console.log(
`Generated new API key for organization: ${ctx.user.organizationId}`,
);
// Generate a new API key and salt
const apiKey = generateApiKey();
const salt = generateSalt();
const hashedKey = hashApiKey(apiKey, salt);
console.log(
`Generated new API key for organization: ${ctx.user.organizationId}`
);

// Parse the expiration date
let expirationDate: Date | null = null;
if (expiresAt && expiresAt !== "never") {
const now = new Date();
switch (expiresAt) {
case "30days":
expirationDate = new Date(now.setDate(now.getDate() + 30));
break;
case "90days":
expirationDate = new Date(now.setDate(now.getDate() + 90));
break;
case "1year":
expirationDate = new Date(now.setFullYear(now.getFullYear() + 1));
break;
}
console.log(`Set expiration date to: ${expirationDate?.toISOString()}`);
} else {
console.log("No expiration date set for API key");
}
// Parse the expiration date
let expirationDate: Date | null = null;
if (expiresAt && expiresAt !== "never") {
const now = new Date();
switch (expiresAt) {
case "30days":
expirationDate = new Date(now.setDate(now.getDate() + 30));
break;
case "90days":
expirationDate = new Date(now.setDate(now.getDate() + 90));
break;
case "1year":
expirationDate = new Date(now.setFullYear(now.getFullYear() + 1));
break;
}
console.log(`Set expiration date to: ${expirationDate?.toISOString()}`);
} else {
console.log("No expiration date set for API key");
}

// Create the API key in the database
const apiKeyRecord = await db.organizationApiKey.create({
data: {
name,
key: hashedKey,
salt, // Store the salt with the hashed key
expiresAt: expirationDate,
organizationId: ctx.user.organizationId!,
},
select: {
id: true,
name: true,
createdAt: true,
expiresAt: true,
},
});
console.log(`Successfully created API key with ID: ${apiKeyRecord.id}`);
// Create the API key in the database
const apiKeyRecord = await db.organizationApiKey.create({
data: {
name,
key: hashedKey,
salt, // Store the salt with the hashed key
expiresAt: expirationDate,
organizationId: ctx.user.organizationId!,
},
select: {
id: true,
name: true,
createdAt: true,
expiresAt: true,
},
});
console.log(`Successfully created API key with ID: ${apiKeyRecord.id}`);

revalidatePath("/settings/api-keys");
revalidatePath(`/${ctx.user.organizationId}/settings/api-keys`);

return {
success: true,
data: {
...apiKeyRecord,
key: apiKey,
createdAt: apiKeyRecord.createdAt.toISOString(),
expiresAt: apiKeyRecord.expiresAt
? apiKeyRecord.expiresAt.toISOString()
: null,
},
};
} catch (error) {
console.error("Error creating API key:", error);
return {
success: true,
data: {
...apiKeyRecord,
key: apiKey,
createdAt: apiKeyRecord.createdAt.toISOString(),
expiresAt: apiKeyRecord.expiresAt
? apiKeyRecord.expiresAt.toISOString()
: null,
},
};
} catch (error) {
console.error("Error creating API key:", error);

// Provide more specific error messages based on error type
if (error instanceof Error) {
console.error(`Error details: ${error.message}`);
// Provide more specific error messages based on error type
if (error instanceof Error) {
console.error(`Error details: ${error.message}`);

if (error.message.includes("Unique constraint")) {
return {
success: false,
error: {
code: "DUPLICATE_NAME",
message: "An API key with this name already exists",
},
};
}
if (error.message.includes("Unique constraint")) {
return {
success: false,
error: {
code: "DUPLICATE_NAME",
message: "An API key with this name already exists",
},
};
}

if (error.message.includes("Foreign key constraint")) {
return {
success: false,
error: {
code: "INVALID_ORGANIZATION",
message:
"The organization does not exist or you don't have access",
},
};
}
}
if (error.message.includes("Foreign key constraint")) {
return {
success: false,
error: {
code: "INVALID_ORGANIZATION",
message:
"The organization does not exist or you don't have access",
},
};
}
}

return {
success: false,
error: {
code: "INTERNAL_ERROR",
message: "An unexpected error occurred while creating the API key",
},
};
}
});
return {
success: false,
error: {
code: "INTERNAL_ERROR",
message: "An unexpected error occurred while creating the API key",
},
};
}
});
111 changes: 47 additions & 64 deletions apps/app/src/actions/organization/create-organization-action.ts
Original file line number Diff line number Diff line change
@@ -1,73 +1,56 @@
// update-organization-action.ts

"use server";

import { createOrganizationAndConnectUser } from "@/auth/org";
import { db } from "@bubba/db";
import { authActionClient } from "../safe-action";
import { organizationSchema } from "../schema";
import { tasks } from "@trigger.dev/sdk/v3";
import type { createOrganizationTask } from "@/jobs/tasks/organization/create-organization";

export const createOrganizationAction = authActionClient
.schema(organizationSchema)
.metadata({
name: "create-organization",
track: {
event: "create-organization",
channel: "server",
},
})
.action(async ({ parsedInput, ctx }) => {
const { name, website, frameworks } = parsedInput;
const { id: userId, organizationId } = ctx.user;

if (!name || !website) {
console.log("Invalid input detected:", { name, website });
throw new Error("Invalid user input");
}

if (!organizationId) {
await createOrganizationAndConnectUser({
userId,
normalizedEmail: ctx.user.email!,
});
}

const organization = await db.organization.findFirst({
where: {
users: {
some: {
id: userId,
},
},
},
});

if (!organization) {
throw new Error("Organization not found");
}

try {
const handle = await tasks.trigger<typeof createOrganizationTask>(
"create-organization",
{
userId,
fullName: name,
website,
frameworkIds: frameworks,
organizationId: organization.id,
},
);

return {
success: true,
runId: handle.id,
publicAccessToken: handle.publicAccessToken,
};
} catch (error) {
console.error("Error during organization update:", error);

throw new Error("Failed to update organization");
}
});
.schema(organizationSchema)
.metadata({
name: "create-organization",
track: {
event: "create-organization",
channel: "server",
},
})
.action(async ({ parsedInput, ctx }) => {
const { name, website, frameworks } = parsedInput;
const { id: userId } = ctx.user;

if (!name || !website) {
console.log("Invalid input detected:", { name, website });
throw new Error("Invalid user input");
}

const newOrganization = await createOrganizationAndConnectUser({
userId,
normalizedEmail: ctx.user.email!,
orgName: name,
});

try {
const handle = await tasks.trigger<typeof createOrganizationTask>(
"create-organization",
{
userId,
fullName: name,
website,
frameworkIds: frameworks,
organizationId: newOrganization.id,
}
);

return {
success: true,
runId: handle.id,
publicAccessToken: handle.publicAccessToken,
newOrganization,
};
} catch (error) {
console.error("Error during organization update:", error);

throw new Error("Failed to update organization");
}
});
Loading