Files
blackcanyontickets/reactrebuild0825/functions/lib/claims.js
dzinesco aa81eb5adb feat: add advanced analytics and territory management system
- Add comprehensive analytics components with export functionality
- Implement territory management with manager performance tracking
- Add seatmap components for venue layout management
- Create customer management features with modal interface
- Add advanced hooks for dashboard flags and territory data
- Implement seat selection and venue management utilities
- Add type definitions for ticketing and seatmap systems

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-26 09:25:10 -06:00

187 lines
6.7 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getUserClaims = exports.updateUserClaims = void 0;
const app_1 = require("firebase-admin/app");
const auth_1 = require("firebase-admin/auth");
const firestore_1 = require("firebase-admin/firestore");
const https_1 = require("firebase-functions/v2/https");
const v2_1 = require("firebase-functions/v2");
// Initialize Firebase Admin if not already initialized
if ((0, app_1.getApps)().length === 0) {
(0, app_1.initializeApp)();
}
(0, v2_1.setGlobalOptions)({
region: "us-central1",
});
const auth = (0, auth_1.getAuth)();
const db = (0, firestore_1.getFirestore)();
// Helper function to validate authorization
async function validateAuthorization(req) {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
throw new Error('Unauthorized: Missing or invalid authorization header');
}
const idToken = authHeader.split('Bearer ')[1];
const decodedToken = await auth.verifyIdToken(idToken);
const { orgId, role, territoryIds } = decodedToken;
return {
uid: decodedToken.uid,
orgId,
role,
territoryIds: territoryIds || []
};
}
// Helper function to check if user can manage claims for target org
function canManageClaims(user, targetOrgId) {
// Superadmin can manage any org
if (user.role === 'superadmin') {
return true;
}
// OrgAdmin can only manage their own org
if (user.role === 'orgAdmin' && user.orgId === targetOrgId) {
return true;
}
return false;
}
// POST /api/admin/users/:uid/claims
exports.updateUserClaims = (0, https_1.onRequest)({ cors: true }, async (req, res) => {
try {
// Only allow POST requests
if (req.method !== 'POST') {
res.status(405).json({ error: 'Method not allowed' });
return;
}
// Validate authorization
const authUser = await validateAuthorization(req);
// Extract target user ID from path
const targetUid = req.params.uid;
if (!targetUid) {
res.status(400).json({ error: 'Missing user ID in path' });
return;
}
// Parse request body
const { orgId, role, territoryIds } = req.body;
if (!orgId || !role || !Array.isArray(territoryIds)) {
res.status(400).json({
error: 'Missing required fields: orgId, role, territoryIds'
});
return;
}
// Validate role
const validRoles = ['superadmin', 'orgAdmin', 'territoryManager', 'staff'];
if (!validRoles.includes(role)) {
res.status(400).json({
error: `Invalid role. Must be one of: ${ validRoles.join(', ')}`
});
return;
}
// Check authorization
if (!canManageClaims(authUser, orgId)) {
res.status(403).json({
error: 'Insufficient permissions to manage claims for this organization'
});
return;
}
// Validate territories exist in the org
if (territoryIds.length > 0) {
const territoryChecks = await Promise.all(territoryIds.map(async (territoryId) => {
const territoryDoc = await db.collection('territories').doc(territoryId).get();
return territoryDoc.exists && territoryDoc.data()?.orgId === orgId;
}));
if (territoryChecks.some(valid => !valid)) {
res.status(400).json({
error: 'One or more territory IDs are invalid or not in the specified organization'
});
return;
}
}
// Set custom user claims
const customClaims = {
orgId,
role,
territoryIds
};
await auth.setCustomUserClaims(targetUid, customClaims);
// Update user document in Firestore for UI consistency
await db.collection('users').doc(targetUid).set({
orgId,
role,
territoryIds,
updatedAt: new Date().toISOString(),
updatedBy: authUser.uid
}, { merge: true });
res.status(200).json({
success: true,
claims: customClaims,
message: 'User claims updated successfully'
});
}
catch (error) {
console.error('Error updating user claims:', error);
if (error instanceof Error) {
if (error.message.includes('Unauthorized')) {
res.status(401).json({ error: error.message });
}
else if (error.message.includes('not found')) {
res.status(404).json({ error: 'User not found' });
}
else {
res.status(500).json({ error: 'Internal server error' });
}
}
else {
res.status(500).json({ error: 'Internal server error' });
}
}
});
// GET /api/admin/users/:uid/claims
exports.getUserClaims = (0, https_1.onRequest)({ cors: true }, async (req, res) => {
try {
// Only allow GET requests
if (req.method !== 'GET') {
res.status(405).json({ error: 'Method not allowed' });
return;
}
// Validate authorization
const authUser = await validateAuthorization(req);
// Extract target user ID from path
const targetUid = req.params.uid;
if (!targetUid) {
res.status(400).json({ error: 'Missing user ID in path' });
return;
}
// Get user record
const userRecord = await auth.getUser(targetUid);
const claims = userRecord.customClaims || {};
// Check if user can view these claims
if (claims.orgId && !canManageClaims(authUser, claims.orgId)) {
res.status(403).json({
error: 'Insufficient permissions to view claims for this user'
});
return;
}
res.status(200).json({
uid: targetUid,
email: userRecord.email,
claims
});
}
catch (error) {
console.error('Error getting user claims:', error);
if (error instanceof Error) {
if (error.message.includes('Unauthorized')) {
res.status(401).json({ error: error.message });
}
else if (error.message.includes('not found')) {
res.status(404).json({ error: 'User not found' });
}
else {
res.status(500).json({ error: 'Internal server error' });
}
}
else {
res.status(500).json({ error: 'Internal server error' });
}
}
});
// # sourceMappingURL=claims.js.map