167 lines
5.0 KiB
TypeScript
167 lines
5.0 KiB
TypeScript
"use server";
|
||
|
||
import { cookies } from "next/headers";
|
||
import { redirect } from "next/navigation";
|
||
import { AppwriteException, ID, Permission, Role, Query } from "node-appwrite";
|
||
|
||
import { createAdminClient, createSessionClient } from "./server";
|
||
import { DATABASE_ID, TABLES } from "./schema";
|
||
import { ACTIVE_TENANT_COOKIE, type WorkspaceState } from "./tenant-types";
|
||
|
||
function appwriteError(e: unknown): string {
|
||
if (e instanceof AppwriteException) {
|
||
if (e.type === "team_already_exists") return "Bu isimde bir çalışma alanı zaten var.";
|
||
if (e.type === "general_unauthorized_scope") return "Yetki hatası. Tekrar giriş yapın.";
|
||
return e.message || "Beklenmeyen bir hata oluştu.";
|
||
}
|
||
return "Bağlantı hatası. Tekrar deneyin.";
|
||
}
|
||
|
||
async function setActiveTenantCookie(tenantId: string) {
|
||
(await cookies()).set(ACTIVE_TENANT_COOKIE, tenantId, {
|
||
path: "/",
|
||
httpOnly: true,
|
||
sameSite: "strict",
|
||
secure: process.env.NODE_ENV === "production",
|
||
maxAge: 60 * 60 * 24 * 365,
|
||
});
|
||
}
|
||
|
||
export async function createWorkspaceAction(
|
||
_prev: WorkspaceState,
|
||
formData: FormData,
|
||
): Promise<WorkspaceState> {
|
||
const companyName = String(formData.get("companyName") ?? "").trim();
|
||
const companyPhone = String(formData.get("companyPhone") ?? "").trim() || undefined;
|
||
|
||
if (!companyName) {
|
||
return { ok: false, error: "Ofis adı zorunlu." };
|
||
}
|
||
|
||
let teamId: string | null = null;
|
||
const admin = createAdminClient();
|
||
|
||
try {
|
||
const session = await createSessionClient();
|
||
const user = await session.account.get();
|
||
|
||
const team = await session.teams.create(ID.unique(), companyName, ["owner"]);
|
||
teamId = team.$id;
|
||
|
||
await admin.tablesDB.createRow(
|
||
DATABASE_ID,
|
||
TABLES.tenantSettings,
|
||
ID.unique(),
|
||
{
|
||
tenantId: teamId,
|
||
officeName: companyName,
|
||
phone: companyPhone,
|
||
createdBy: user.$id,
|
||
},
|
||
[
|
||
Permission.read(Role.team(teamId)),
|
||
Permission.update(Role.team(teamId, "owner")),
|
||
Permission.update(Role.team(teamId, "admin")),
|
||
Permission.delete(Role.team(teamId, "owner")),
|
||
],
|
||
);
|
||
|
||
await session.account.updatePrefs({
|
||
...(user.prefs ?? {}),
|
||
activeTenant: teamId,
|
||
});
|
||
|
||
await setActiveTenantCookie(teamId);
|
||
} catch (e) {
|
||
if (teamId) {
|
||
try {
|
||
await admin.teams.delete(teamId);
|
||
} catch {
|
||
// best-effort cleanup; original error is what we surface
|
||
}
|
||
}
|
||
return { ok: false, error: appwriteError(e) };
|
||
}
|
||
|
||
redirect("/dashboard");
|
||
}
|
||
|
||
export async function importWorkspaceAction(
|
||
_prev: WorkspaceState,
|
||
formData: FormData,
|
||
): Promise<WorkspaceState> {
|
||
const teamId = String(formData.get("teamId") ?? "").trim();
|
||
if (!teamId) return { ok: false, error: "Geçersiz istek." };
|
||
|
||
try {
|
||
const { account, teams, tablesDB } = await createSessionClient();
|
||
const user = await account.get();
|
||
|
||
const allTeams = await teams.list();
|
||
const team = allTeams.teams.find((t) => t.$id === teamId);
|
||
if (!team) return { ok: false, error: "Çalışma alanı bulunamadı." };
|
||
|
||
const existing = await tablesDB.listRows({
|
||
databaseId: DATABASE_ID,
|
||
tableId: TABLES.tenantSettings,
|
||
queries: [Query.equal("tenantId", teamId), Query.limit(1)],
|
||
});
|
||
if (existing.total > 0) return { ok: false, error: "Bu çalışma alanı zaten mevcut." };
|
||
|
||
const admin = createAdminClient();
|
||
await admin.tablesDB.createRow(
|
||
DATABASE_ID,
|
||
TABLES.tenantSettings,
|
||
ID.unique(),
|
||
{
|
||
tenantId: teamId,
|
||
officeName: team.name,
|
||
createdBy: user.$id,
|
||
defaultCurrency: "TRY",
|
||
},
|
||
[
|
||
Permission.read(Role.team(teamId)),
|
||
Permission.update(Role.team(teamId, "owner")),
|
||
Permission.update(Role.team(teamId, "admin")),
|
||
Permission.delete(Role.team(teamId, "owner")),
|
||
],
|
||
);
|
||
|
||
await account.updatePrefs({ ...(user.prefs ?? {}), activeTenant: teamId });
|
||
await setActiveTenantCookie(teamId);
|
||
} catch (e) {
|
||
return { ok: false, error: appwriteError(e) };
|
||
}
|
||
|
||
redirect("/dashboard");
|
||
}
|
||
|
||
export async function setActiveTenantAction(tenantId: string) {
|
||
try {
|
||
const { account, teams, tablesDB } = await createSessionClient();
|
||
const user = await account.get();
|
||
|
||
const allTeams = await teams.list();
|
||
const isMember = allTeams.teams.some((t) => t.$id === tenantId);
|
||
if (!isMember) {
|
||
return { ok: false, error: "Bu çalışma alanına erişiminiz yok." };
|
||
}
|
||
|
||
// Verify this team belongs to this app (not a team from another KovakSoft product)
|
||
const settingsCheck = await tablesDB.listRows({
|
||
databaseId: DATABASE_ID,
|
||
tableId: TABLES.tenantSettings,
|
||
queries: [Query.equal("tenantId", tenantId), Query.limit(1)],
|
||
});
|
||
if (settingsCheck.total === 0) {
|
||
return { ok: false, error: "Bu çalışma alanına erişiminiz yok." };
|
||
}
|
||
|
||
await account.updatePrefs({ ...(user.prefs ?? {}), activeTenant: tenantId });
|
||
await setActiveTenantCookie(tenantId);
|
||
return { ok: true };
|
||
} catch (e) {
|
||
return { ok: false, error: appwriteError(e) };
|
||
}
|
||
}
|