Update
This commit is contained in:
@@ -29,144 +29,114 @@ const RESPONSE_FORMAT = {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
report: {
|
||||
companyPerformance: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
companyPerformance: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
summary: { type: "string" },
|
||||
metrics: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
value: { anyOf: [{ type: "string" }, { type: "number" }] },
|
||||
trend: { enum: ["up", "down", "flat"] }
|
||||
},
|
||||
required: ["name", "value", "trend"]
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ["summary", "metrics"]
|
||||
},
|
||||
keyPersonnelChanges: {
|
||||
summary: { type: "string" },
|
||||
metrics: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
person: { type: "string" },
|
||||
change: { type: "string" }, // e.g. "Promoted to VP Eng"
|
||||
impact: { type: "string" },
|
||||
effectiveDate: { type: "string" }
|
||||
name: { type: "string" },
|
||||
value: { anyOf: [{ type: "string" }, { type: "number" }] },
|
||||
trend: { enum: ["up", "down", "flat"] }
|
||||
},
|
||||
required: ["person", "change", "impact", "effectiveDate"]
|
||||
}
|
||||
},
|
||||
immediateHiringNeeds: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
role: { type: "string" },
|
||||
urgency: { enum: ["low", "medium", "high"] },
|
||||
reason: { type: "string" }
|
||||
},
|
||||
required: ["role", "urgency", "reason"]
|
||||
}
|
||||
},
|
||||
forwardOperatingPlan: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
nextQuarterObjectives: { type: "array", items: { type: "string" } },
|
||||
initiatives: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
owner: { type: "string" },
|
||||
kpis: { type: "array", items: { type: "string" } }
|
||||
},
|
||||
required: ["name", "owner", "kpis"]
|
||||
}
|
||||
},
|
||||
risks: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
risk: { type: "string" },
|
||||
mitigation: { type: "string" }
|
||||
},
|
||||
required: ["risk", "mitigation"]
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ["nextQuarterObjectives", "initiatives", "risks"]
|
||||
},
|
||||
organizationalInsights: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
culture: { type: "string" },
|
||||
teamDynamics: { type: "string" },
|
||||
blockers: { type: "array", items: { type: "string" } }
|
||||
},
|
||||
required: ["culture", "teamDynamics", "blockers"]
|
||||
},
|
||||
strengths: { type: "array", items: { type: "string" } },
|
||||
gradingOverview: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
department: { type: "string" },
|
||||
grade: { enum: ["A", "B", "C", "D", "F"] },
|
||||
notes: { type: "string" }
|
||||
},
|
||||
required: ["department", "grade", "notes"]
|
||||
required: ["name", "value", "trend"]
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ["companyPerformance", "keyPersonnelChanges", "immediateHiringNeeds", "forwardOperatingPlan", "organizationalInsights", "strengths", "gradingOverview"]
|
||||
required: ["summary", "metrics"]
|
||||
},
|
||||
wiki: {
|
||||
keyPersonnelChanges: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
person: { type: "string" },
|
||||
change: { type: "string" }, // e.g. "Promoted to VP Eng"
|
||||
impact: { type: "string" },
|
||||
effectiveDate: { type: "string" }
|
||||
},
|
||||
required: ["person", "change", "impact", "effectiveDate"]
|
||||
}
|
||||
},
|
||||
immediateHiringNeeds: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
role: { type: "string" },
|
||||
urgency: { enum: ["low", "medium", "high"] },
|
||||
reason: { type: "string" }
|
||||
},
|
||||
required: ["role", "urgency", "reason"]
|
||||
}
|
||||
},
|
||||
forwardOperatingPlan: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
companyName: { type: "string" },
|
||||
industry: { type: "string" },
|
||||
description: { type: "string" },
|
||||
mission: { type: "string" },
|
||||
values: { type: "array", items: { type: "string" } },
|
||||
culture: { type: "string" },
|
||||
orgInfo: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
hq: { type: "string" },
|
||||
foundedYear: { type: "number" },
|
||||
headcount: { type: "number" },
|
||||
products: { type: "array", items: { type: "string" } }
|
||||
},
|
||||
required: ["hq", "foundedYear", "headcount", "products"]
|
||||
nextQuarterObjectives: { type: "array", items: { type: "string" } },
|
||||
initiatives: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
owner: { type: "string" },
|
||||
kpis: { type: "array", items: { type: "string" } }
|
||||
},
|
||||
required: ["name", "owner", "kpis"]
|
||||
}
|
||||
},
|
||||
risks: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
risk: { type: "string" },
|
||||
mitigation: { type: "string" }
|
||||
},
|
||||
required: ["risk", "mitigation"]
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ["companyName", "industry", "description", "mission", "values", "culture", "orgInfo"]
|
||||
required: ["nextQuarterObjectives", "initiatives", "risks"]
|
||||
},
|
||||
organizationalInsights: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
culture: { type: "string" },
|
||||
teamDynamics: { type: "string" },
|
||||
blockers: { type: "array", items: { type: "string" } }
|
||||
},
|
||||
required: ["culture", "teamDynamics", "blockers"]
|
||||
},
|
||||
strengths: { type: "array", items: { type: "string" } },
|
||||
gradingOverview: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
department: { type: "string" },
|
||||
grade: { enum: ["A", "B", "C", "D", "F"] },
|
||||
notes: { type: "string" }
|
||||
},
|
||||
required: ["department", "grade", "notes"]
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ["report", "wiki"]
|
||||
required: ["companyPerformance", "keyPersonnelChanges", "immediateHiringNeeds", "forwardOperatingPlan", "organizationalInsights", "strengths", "gradingOverview"]
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -782,6 +752,7 @@ exports.generateCompanyWiki = onRequest({ cors: true }, async (req, res) => {
|
||||
|
||||
if (openai) {
|
||||
// Use OpenAI to generate the company report and wiki
|
||||
db.collection("orgs").doc(orgId)
|
||||
const system = "You are a cut-and-dry expert business analyst. Return ONLY JSON that conforms to the provided schema.";
|
||||
const user = [
|
||||
"Generate a COMPANY REPORT and COMPANY WIKI that fully leverage the input data.",
|
||||
@@ -811,14 +782,20 @@ exports.generateCompanyWiki = onRequest({ cors: true }, async (req, res) => {
|
||||
|
||||
const report = {
|
||||
generatedAt: Date.now(),
|
||||
...parsed.report
|
||||
...parsed
|
||||
};
|
||||
|
||||
const wiki = {
|
||||
companyName: org?.name ?? parsed.wiki.companyName,
|
||||
generatedAt: Date.now(),
|
||||
...parsed.wiki,
|
||||
|
||||
};
|
||||
|
||||
const companyReport = db.collection("orgs").doc(orgId).collection("companyReport");
|
||||
await companyReport.set(report);
|
||||
const companyWiki = db.collection("orgs").doc(orgId).collection("companyWiki");
|
||||
await companyWiki.set(wiki);
|
||||
|
||||
console.log(report);
|
||||
console.log(wiki);
|
||||
|
||||
@@ -1691,4 +1668,539 @@ exports.saveCompanyReport = onRequest({ cors: true }, async (req, res) => {
|
||||
console.error("Save company report error:", error);
|
||||
res.status(500).json({ error: "Failed to save company report" });
|
||||
}
|
||||
});
|
||||
|
||||
// Helper function to verify user authorization
|
||||
const verifyUserAuthorization = async (userId, orgId) => {
|
||||
if (!userId || !orgId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if user exists in the organization's employees collection
|
||||
const employeeDoc = await db.collection("orgs").doc(orgId).collection("employees").doc(userId).get();
|
||||
return employeeDoc.exists;
|
||||
} catch (error) {
|
||||
console.error("Authorization check error:", error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Get Organization Data Function
|
||||
exports.getOrgData = onRequest({ cors: true }, async (req, res) => {
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.status(204).send('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { orgId, userId } = req.query;
|
||||
|
||||
if (!orgId || !userId) {
|
||||
return res.status(400).json({ error: "Organization ID and user ID are required" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify user authorization
|
||||
const isAuthorized = await verifyUserAuthorization(userId, orgId);
|
||||
if (!isAuthorized) {
|
||||
return res.status(403).json({ error: "Unauthorized access to organization" });
|
||||
}
|
||||
|
||||
// Get organization data
|
||||
const orgDoc = await db.collection("orgs").doc(orgId).get();
|
||||
if (!orgDoc.exists) {
|
||||
return res.status(404).json({ error: "Organization not found" });
|
||||
}
|
||||
|
||||
const orgData = { id: orgId, ...orgDoc.data() };
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
org: orgData
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Get org data error:", error);
|
||||
res.status(500).json({ error: "Failed to get organization data" });
|
||||
}
|
||||
});
|
||||
|
||||
// Update Organization Data Function
|
||||
exports.updateOrgData = onRequest({ cors: true }, async (req, res) => {
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.status(204).send('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method !== "PUT") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { orgId, userId, data } = req.body;
|
||||
|
||||
if (!orgId || !userId || !data) {
|
||||
return res.status(400).json({ error: "Organization ID, user ID, and data are required" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify user authorization
|
||||
const isAuthorized = await verifyUserAuthorization(userId, orgId);
|
||||
if (!isAuthorized) {
|
||||
return res.status(403).json({ error: "Unauthorized access to organization" });
|
||||
}
|
||||
|
||||
// Update organization data
|
||||
const orgRef = db.collection("orgs").doc(orgId);
|
||||
await orgRef.update({
|
||||
...data,
|
||||
updatedAt: Date.now()
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: "Organization data updated successfully"
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Update org data error:", error);
|
||||
res.status(500).json({ error: "Failed to update organization data" });
|
||||
}
|
||||
});
|
||||
|
||||
// Get Employees Function
|
||||
exports.getEmployees = onRequest({ cors: true }, async (req, res) => {
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.status(204).send('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { orgId, userId } = req.query;
|
||||
|
||||
if (!orgId || !userId) {
|
||||
return res.status(400).json({ error: "Organization ID and user ID are required" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify user authorization
|
||||
const isAuthorized = await verifyUserAuthorization(userId, orgId);
|
||||
if (!isAuthorized) {
|
||||
return res.status(403).json({ error: "Unauthorized access to organization" });
|
||||
}
|
||||
|
||||
// Get all employees
|
||||
const employeesSnapshot = await db.collection("orgs").doc(orgId).collection("employees").get();
|
||||
const employees = [];
|
||||
|
||||
employeesSnapshot.forEach(doc => {
|
||||
employees.push({ id: doc.id, ...doc.data() });
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
employees
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Get employees error:", error);
|
||||
res.status(500).json({ error: "Failed to get employees" });
|
||||
}
|
||||
});
|
||||
|
||||
// Get Submissions Function
|
||||
exports.getSubmissions = onRequest({ cors: true }, async (req, res) => {
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.status(204).send('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { orgId, userId } = req.query;
|
||||
|
||||
if (!orgId || !userId) {
|
||||
return res.status(400).json({ error: "Organization ID and user ID are required" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify user authorization
|
||||
const isAuthorized = await verifyUserAuthorization(userId, orgId);
|
||||
if (!isAuthorized) {
|
||||
return res.status(403).json({ error: "Unauthorized access to organization" });
|
||||
}
|
||||
|
||||
// Get all submissions
|
||||
const submissionsSnapshot = await db.collection("orgs").doc(orgId).collection("submissions").get();
|
||||
const submissions = {};
|
||||
|
||||
submissionsSnapshot.forEach(doc => {
|
||||
submissions[doc.id] = { id: doc.id, ...doc.data() };
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
submissions
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Get submissions error:", error);
|
||||
res.status(500).json({ error: "Failed to get submissions" });
|
||||
}
|
||||
});
|
||||
|
||||
// Get Reports Function
|
||||
exports.getReports = onRequest({ cors: true }, async (req, res) => {
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.status(204).send('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { orgId, userId } = req.query;
|
||||
|
||||
if (!orgId || !userId) {
|
||||
return res.status(400).json({ error: "Organization ID and user ID are required" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify user authorization
|
||||
const isAuthorized = await verifyUserAuthorization(userId, orgId);
|
||||
if (!isAuthorized) {
|
||||
return res.status(403).json({ error: "Unauthorized access to organization" });
|
||||
}
|
||||
|
||||
// Get all reports
|
||||
const reportsSnapshot = await db.collection("orgs").doc(orgId).collection("reports").get();
|
||||
const reports = {};
|
||||
|
||||
reportsSnapshot.forEach(doc => {
|
||||
reports[doc.id] = { id: doc.id, ...doc.data() };
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
reports
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Get reports error:", error);
|
||||
res.status(500).json({ error: "Failed to get reports" });
|
||||
}
|
||||
});
|
||||
|
||||
// Create/Update Employee Function
|
||||
exports.upsertEmployee = onRequest({ cors: true }, async (req, res) => {
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.status(204).send('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { orgId, userId, employeeData } = req.body;
|
||||
|
||||
if (!orgId || !userId || !employeeData) {
|
||||
return res.status(400).json({ error: "Organization ID, user ID, and employee data are required" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify user authorization
|
||||
const isAuthorized = await verifyUserAuthorization(userId, orgId);
|
||||
if (!isAuthorized) {
|
||||
return res.status(403).json({ error: "Unauthorized access to organization" });
|
||||
}
|
||||
|
||||
// Generate employee ID if not provided
|
||||
if (!employeeData.id) {
|
||||
employeeData.id = `emp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
}
|
||||
|
||||
// Add timestamps
|
||||
const currentTime = Date.now();
|
||||
if (!employeeData.createdAt) {
|
||||
employeeData.createdAt = currentTime;
|
||||
}
|
||||
employeeData.updatedAt = currentTime;
|
||||
|
||||
// Save employee
|
||||
const employeeRef = db.collection("orgs").doc(orgId).collection("employees").doc(employeeData.id);
|
||||
await employeeRef.set(employeeData);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
employee: employeeData,
|
||||
message: "Employee saved successfully"
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Upsert employee error:", error);
|
||||
res.status(500).json({ error: "Failed to save employee" });
|
||||
}
|
||||
});
|
||||
|
||||
// Save Report Function
|
||||
exports.saveReport = onRequest({ cors: true }, async (req, res) => {
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.status(204).send('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { orgId, userId, employeeId, reportData } = req.body;
|
||||
|
||||
if (!orgId || !userId || !employeeId || !reportData) {
|
||||
return res.status(400).json({ error: "Organization ID, user ID, employee ID, and report data are required" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify user authorization
|
||||
const isAuthorized = await verifyUserAuthorization(userId, orgId);
|
||||
if (!isAuthorized) {
|
||||
return res.status(403).json({ error: "Unauthorized access to organization" });
|
||||
}
|
||||
|
||||
// Add metadata
|
||||
const currentTime = Date.now();
|
||||
if (!reportData.id) {
|
||||
reportData.id = `report_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
}
|
||||
if (!reportData.createdAt) {
|
||||
reportData.createdAt = currentTime;
|
||||
}
|
||||
reportData.updatedAt = currentTime;
|
||||
reportData.employeeId = employeeId;
|
||||
|
||||
// Save report
|
||||
const reportRef = db.collection("orgs").doc(orgId).collection("reports").doc(employeeId);
|
||||
await reportRef.set(reportData);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
report: reportData,
|
||||
message: "Report saved successfully"
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Save report error:", error);
|
||||
res.status(500).json({ error: "Failed to save report" });
|
||||
}
|
||||
});
|
||||
|
||||
// Get Company Reports Function
|
||||
exports.getCompanyReports = onRequest({ cors: true }, async (req, res) => {
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.status(204).send('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { orgId, userId } = req.query;
|
||||
|
||||
if (!orgId || !userId) {
|
||||
return res.status(400).json({ error: "Organization ID and user ID are required" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify user authorization
|
||||
const isAuthorized = await verifyUserAuthorization(userId, orgId);
|
||||
if (!isAuthorized) {
|
||||
return res.status(403).json({ error: "Unauthorized access to organization" });
|
||||
}
|
||||
|
||||
// Get all company reports
|
||||
const reportsSnapshot = await db.collection("orgs").doc(orgId).collection("fullCompanyReports").get();
|
||||
const reports = [];
|
||||
|
||||
reportsSnapshot.forEach(doc => {
|
||||
reports.push({ id: doc.id, ...doc.data() });
|
||||
});
|
||||
|
||||
// Sort by creation date (newest first)
|
||||
reports.sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
reports
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Get company reports error:", error);
|
||||
res.status(500).json({ error: "Failed to get company reports" });
|
||||
}
|
||||
});
|
||||
|
||||
// Upload Image Function
|
||||
exports.uploadImage = onRequest({ cors: true }, async (req, res) => {
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.status(204).send('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { orgId, userId, imageData } = req.body;
|
||||
|
||||
if (!orgId || !userId || !imageData) {
|
||||
return res.status(400).json({ error: "Organization ID, user ID, and image data are required" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify user authorization
|
||||
const isAuthorized = await verifyUserAuthorization(userId, orgId);
|
||||
if (!isAuthorized) {
|
||||
return res.status(403).json({ error: "Unauthorized access to organization" });
|
||||
}
|
||||
|
||||
// Validate image data
|
||||
const { collectionName, documentId, dataUrl, filename, originalSize, compressedSize, width, height } = imageData;
|
||||
|
||||
if (!collectionName || !documentId || !dataUrl || !filename) {
|
||||
return res.status(400).json({ error: "Missing required image data fields" });
|
||||
}
|
||||
|
||||
// Create image document
|
||||
const imageDoc = {
|
||||
id: `${Date.now()}_${filename}`,
|
||||
dataUrl,
|
||||
filename,
|
||||
originalSize: originalSize || 0,
|
||||
compressedSize: compressedSize || 0,
|
||||
uploadedAt: Date.now(),
|
||||
width: width || 0,
|
||||
height: height || 0,
|
||||
orgId,
|
||||
uploadedBy: userId
|
||||
};
|
||||
|
||||
// Store image in organization's images collection
|
||||
const imageRef = db.collection("orgs").doc(orgId).collection("images").doc(`${collectionName}_${documentId}`);
|
||||
await imageRef.set({
|
||||
...imageDoc,
|
||||
collectionName,
|
||||
documentId
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
imageId: imageDoc.id,
|
||||
message: "Image uploaded successfully"
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Upload image error:", error);
|
||||
res.status(500).json({ error: "Failed to upload image" });
|
||||
}
|
||||
});
|
||||
|
||||
// Get Image Function
|
||||
exports.getImage = onRequest({ cors: true }, async (req, res) => {
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.status(204).send('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { orgId, userId, collectionName, documentId } = req.query;
|
||||
|
||||
if (!orgId || !userId || !collectionName || !documentId) {
|
||||
return res.status(400).json({ error: "Organization ID, user ID, collection name, and document ID are required" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify user authorization
|
||||
const isAuthorized = await verifyUserAuthorization(userId, orgId);
|
||||
if (!isAuthorized) {
|
||||
return res.status(403).json({ error: "Unauthorized access to organization" });
|
||||
}
|
||||
|
||||
// Get image document
|
||||
const imageRef = db.collection("orgs").doc(orgId).collection("images").doc(`${collectionName}_${documentId}`);
|
||||
const imageDoc = await imageRef.get();
|
||||
|
||||
if (!imageDoc.exists) {
|
||||
return res.status(404).json({ error: "Image not found" });
|
||||
}
|
||||
|
||||
const imageData = imageDoc.data();
|
||||
|
||||
// Return image data (excluding org-specific metadata)
|
||||
const responseData = {
|
||||
id: imageData.id,
|
||||
dataUrl: imageData.dataUrl,
|
||||
filename: imageData.filename,
|
||||
originalSize: imageData.originalSize,
|
||||
compressedSize: imageData.compressedSize,
|
||||
uploadedAt: imageData.uploadedAt,
|
||||
width: imageData.width,
|
||||
height: imageData.height
|
||||
};
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
image: responseData
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Get image error:", error);
|
||||
res.status(500).json({ error: "Failed to get image" });
|
||||
}
|
||||
});
|
||||
|
||||
// Delete Image Function
|
||||
exports.deleteImage = onRequest({ cors: true }, async (req, res) => {
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.status(204).send('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method !== "DELETE") {
|
||||
return res.status(405).json({ error: "Method not allowed" });
|
||||
}
|
||||
|
||||
const { orgId, userId, collectionName, documentId } = req.body;
|
||||
|
||||
if (!orgId || !userId || !collectionName || !documentId) {
|
||||
return res.status(400).json({ error: "Organization ID, user ID, collection name, and document ID are required" });
|
||||
}
|
||||
|
||||
try {
|
||||
// Verify user authorization
|
||||
const isAuthorized = await verifyUserAuthorization(userId, orgId);
|
||||
if (!isAuthorized) {
|
||||
return res.status(403).json({ error: "Unauthorized access to organization" });
|
||||
}
|
||||
|
||||
// Delete image document
|
||||
const imageRef = db.collection("orgs").doc(orgId).collection("images").doc(`${collectionName}_${documentId}`);
|
||||
const imageDoc = await imageRef.get();
|
||||
|
||||
if (!imageDoc.exists) {
|
||||
return res.status(404).json({ error: "Image not found" });
|
||||
}
|
||||
|
||||
await imageRef.delete();
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: "Image deleted successfully"
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Delete image error:", error);
|
||||
res.status(500).json({ error: "Failed to delete image" });
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user