HVD2NGYM4J2PKQ72SFMXLBGQPKPCGDRB54IK3ISOQZDWKGM3WGQQC OSNBT6AANZB3TF7HAJ35N3Z2EGDU5VQ4LGQORKMA25ACMNV35CQQC UCDTBEK3CF6YT2H6V57HI6FAFW44BIYYAK3Z2QJ5LJE7QWX7OEYAC LYPSC7BOH6T45FCPRHSCXILAJSJ74D5WSQTUIKPWD5ECXOYGUY5AC YX7LU4WRAUDMWS3DEDXZDSF6DXBHLYDWVSMSRK6KIW3MO6GRXSVQC 7ESBJZLIH3TAERLH2HIZAAQHVNVHQWLWCOBLMJRFTIL33YITJNIAC 2WKGHT2TVFMQT7VUL5OCYVNE365QOYNRXA34LOZ4DBFJ2ZVB4XQQC ROQGXQWL2V363K3W7TVVYKIAX4N4IWRERN5BJ7NYJRRVB6OMIJ4QC J2RLNDEXTGAV4BB6ANIIR7XJLJBHSB4NFQWSBWHNAFB6DMLGS5RAC M3JUJ2WWZGCVMBITKRM5FUJMHFYL2QRMXJUVRUE4AC2RF74AOL5AC 4M3EBLTLSS2BRCM42ZP7WVD4YMRRLGV2P2XF47IAV5XHHJD52HTQC KGUU3ZMRY65ZN5G6QC7P7ORPAXXTIMTDBJ37IC6AOKMGQJQ7FVMQC RLH37YB4D7O42IFM2T7GJG4AVVAURWBZ7AOTHAWR7YJZRG3JOPLQC EUEH65HBT4XZXCNWECJXNDEQAWR2NLNSAXFPXLMQ27NOVMQBJT5QC JHFIJJSLVMQNYIDE6CXWUK5UTB7BTUSY7NCI33WKCWIRZHCSMBHQC 4FBIL6IZUDNCXTM6EUHTEOJRHVI4LIIX4BU2IXPXKR362GKIAJMQC O7W4FZVRKDQDAAXEW4T7P262PPRILRCSSACODMUTQZ6VNR36PVCQC /*** Helper function to check if a user has a specific permission for a dataset** @param db - Database connection* @param userId - User ID to check permissions for* @param datasetId - Dataset ID to check permissions for* @param permission - Permission to check (READ, EDIT, DELETE, etc.)* @returns Promise<boolean> - True if user has permission, false otherwise*/async function checkUserPermission(// eslint-disable-next-line @typescript-eslint/no-explicit-anydb: any,userId: string,datasetId: string,permission: string): Promise<boolean> {try {// First check if user is the owner (owners have all permissions)const ownerCheck = await db.select({ owner: dataset.owner }).from(dataset).where(eq(dataset.id, datasetId)).limit(1);if (ownerCheck.length > 0 && ownerCheck[0].owner === userId) {return true;}// Get user's roleconst userRoleResult = await db.select({ role: userRole.role }).from(userRole).where(eq(userRole.userId, userId)).limit(1);const userRoleName = userRoleResult.length > 0 ? userRoleResult[0].role : 'USER';// Check access grantsconst grants = await db.select({ permission: accessGrant.permission }).from(accessGrant).where(sqlExpr`${accessGrant.datasetId} = ${datasetId} AND${accessGrant.permission} = ${permission} AND${accessGrant.active} = true AND((${accessGrant.userId} = ${userId}) OR(${accessGrant.userId} IS NULL AND ${accessGrant.role} = ${userRoleName}))`).limit(1);return grants.length > 0;} catch (error) {console.error('Error checking user permission:', error);return false;}}
* { "id": "123", "name": "Bird Sounds 2024", "description": "Costa Rica recordings", "public": true, ... }
* {* "id": "123",* "name": "Bird Sounds 2024",* "description": "Costa Rica recordings",* "public": true,* "permissions": ["READ", "EDIT", "DELETE"]* }
// Query datasets that are owned by the authenticated user// const results = await db.select().from(dataset).where(eq(dataset.owner, userId));const results = await db.select({id: dataset.id,name: dataset.name,description: dataset.description,public: dataset.public,createdAt: dataset.createdAt,owner: dataset.owner}).from(dataset).where(eq(dataset.active, true)).limit(20); // Add pagination with 20 datasets limit
// First, get the user's roleconst userRoleResult = await db.select({ role: userRole.role }).from(userRole).where(eq(userRole.userId, userId)).limit(1);const userRoleName = userRoleResult.length > 0 ? userRoleResult[0].role : 'USER';// Query to get datasets with permissions// This complex query gets datasets where the user has READ access either through:// 1. Direct user-specific grants// 2. Role-based grants for their role// 3. Being the owner of the datasetconst results = await db.select({id: dataset.id,name: dataset.name,description: dataset.description,public: dataset.public,createdAt: dataset.createdAt,owner: dataset.owner,type: dataset.type,permission: accessGrant.permission,userId: accessGrant.userId}).from(dataset).leftJoin(accessGrant,sqlExpr`${accessGrant.datasetId} = ${dataset.id} AND ${accessGrant.active} = true AND ((${accessGrant.userId} = ${userId}) OR(${accessGrant.userId} IS NULL AND ${accessGrant.role} = ${userRoleName}))`).where(sqlExpr`${dataset.active} = true AND (${dataset.owner} = ${userId} OR${accessGrant.permission} IS NOT NULL)`).orderBy(dataset.name);// Group results by dataset and collect permissionsconst datasetMap = new Map<string, {id: string;name: string;description: string | null;public: boolean;createdAt: string;owner: string;type: string;permissions: string[];}>();results.forEach(row => {if (!datasetMap.has(row.id)) {// If user is owner, they have all permissionsconst isOwner = row.owner === userId;const basePermissions = isOwner ? ['READ', 'UPLOAD', 'DOWNLOAD', 'EDIT', 'DELETE'] : [];datasetMap.set(row.id, {id: row.id,name: row.name,description: row.description,public: row.public ?? false,createdAt: row.createdAt?.toISOString() ?? new Date().toISOString(),owner: row.owner,type: row.type,permissions: basePermissions});}// Add permission from access grants (avoid duplicates)if (row.permission && !datasetMap.get(row.id)!.permissions.includes(row.permission)) {datasetMap.get(row.id)!.permissions.push(row.permission);}});// Filter datasets to only include those with READ permissionconst datasetsWithReadAccess = Array.from(datasetMap.values()).filter(dataset => dataset.permissions.includes('READ')).slice(0, 20); // Limit to 20 datasets
// Connect to the database first to check permissionsconst sql = neon(c.env.DATABASE_URL);const db = drizzle(sql);// Check if user has permission to create datasets (ADMIN or CURATOR roles)const userRoleResult = await db.select({ role: userRole.role }).from(userRole).where(eq(userRole.userId, userId)).limit(1);const userRoleName = userRoleResult.length > 0 ? userRoleResult[0].role : 'USER';if (userRoleName !== 'ADMIN' && userRoleName !== 'CURATOR') {return c.json({error: "You don't have permission to create datasets"}, 403);}
<ButtononClick={handleCreateNew}variant="default"size="sm"className="flex items-center gap-2"><Plus className="h-4 w-4" />Add Dataset</Button>
{canCreateDatasets && (<ButtononClick={handleCreateNew}variant="default"size="sm"className="flex items-center gap-2"><Plus className="h-4 w-4" />Add Dataset</Button>)}
<ButtononClick={(e) => {e.stopPropagation();handleEditDataset(dataset);}}variant="ghost"size="sm"className="p-1 h-8 w-8"title="Edit dataset"><Edit className="h-4 w-4" /></Button><ButtononClick={(e) => {e.stopPropagation();handleDeleteDataset(dataset);}}variant="ghost"size="sm"className="p-1 h-8 w-8 text-red-600 hover:text-red-700 hover:bg-red-50"title="Delete dataset"><Trash2 className="h-4 w-4" /></Button>
{dataset.permissions?.includes('EDIT') && (<ButtononClick={(e) => {e.stopPropagation();handleEditDataset(dataset);}}variant="ghost"size="sm"className="p-1 h-8 w-8"title="Edit dataset"><Edit className="h-4 w-4" /></Button>)}{dataset.permissions?.includes('DELETE') && (<ButtononClick={(e) => {e.stopPropagation();handleDeleteDataset(dataset);}}variant="ghost"size="sm"className="p-1 h-8 w-8 text-red-600 hover:text-red-700 hover:bg-red-50"title="Delete dataset"><Trash2 className="h-4 w-4" /></Button>)}{/* Show placeholder if no actions available */}{!dataset.permissions?.includes('EDIT') && !dataset.permissions?.includes('DELETE') && (<span className="text-gray-400 text-sm">—</span>)}