feat: extend PATCH /organization to accept logo upload and removal

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Arthur Belleville 2026-04-02 21:59:07 +02:00
parent 2ab1d8e044
commit bb1b206aea
No known key found for this signature in database

View file

@ -4,6 +4,7 @@ import { Hono } from "hono";
import { createFactory } from "hono/factory";
import { getOrganizationBillingState } from "../helpers/billing.js";
import { createInvitedUser, getOrganizationPlan, MAX_TABLO_LIMIT } from "../helpers/helpers.js";
import { uploadOrgIcons, deleteOrgIcons } from "../helpers/orgIcons.js";
import type { AuthEnv } from "../types/app.types.js";
const factory = createFactory<AuthEnv>();
@ -439,13 +440,8 @@ const getOrganization = factory.createHandlers(async (c) => {
const updateOrganization = factory.createHandlers(async (c) => {
const user = c.get("user");
const supabase = c.get("supabase");
const s3Client = c.get("s3_client");
const body = await c.req.json();
const rawName = typeof body?.name === "string" ? body.name : "";
const name = rawName.trim();
if (name.length < 2 || name.length > 100) {
return c.json({ error: "Organization name must be between 2 and 100 characters" }, 400);
}
const { data: profile, error: profileError } = await supabase
.from("profiles")
@ -461,13 +457,54 @@ const updateOrganization = factory.createHandlers(async (c) => {
return c.json({ error: "Temporary users cannot update organization settings" }, 403);
}
const { error: updateError } = await supabase
.from("organizations")
.update({ name })
.eq("id", profile.organization_id);
const organizationId = profile.organization_id;
const updateData: Record<string, unknown> = {};
if (updateError) {
return c.json({ error: updateError.message }, 500);
// Handle name update
if (body?.name !== undefined) {
const rawName = typeof body.name === "string" ? body.name : "";
const name = rawName.trim();
if (name.length < 2 || name.length > 100) {
return c.json({ error: "Organization name must be between 2 and 100 characters" }, 400);
}
updateData.name = name;
}
// Handle logo upload
if (body?.logo !== undefined) {
if (body.logo === null) {
// Remove logo
await deleteOrgIcons(s3Client, organizationId);
updateData.logo_url = null;
} else if (body.logo?.content && body.logo?.contentType) {
const { content, contentType } = body.logo;
// Validate content type
const allowedTypes = ["image/png", "image/jpeg", "image/webp"];
if (!allowedTypes.includes(contentType)) {
return c.json({ error: "Logo must be PNG, JPEG, or WebP" }, 400);
}
const imageBuffer = Buffer.from(content, "base64");
try {
const basePath = await uploadOrgIcons(s3Client, organizationId, imageBuffer);
updateData.logo_url = basePath;
} catch (err: unknown) {
const message = err instanceof Error ? err.message : "Failed to process logo";
return c.json({ error: message }, 400);
}
}
}
if (Object.keys(updateData).length > 0) {
const { error: updateError } = await supabase
.from("organizations")
.update(updateData)
.eq("id", organizationId);
if (updateError) {
return c.json({ error: updateError.message }, 500);
}
}
return c.json({ message: "Organization updated successfully" });