WIP - add and remove shares

This commit is contained in:
Francisco Gaona
2025-12-30 21:42:42 +01:00
parent e73126bcb7
commit c50098a55c
2 changed files with 44 additions and 16 deletions

View File

@@ -9,7 +9,7 @@ export interface RecordShareAccessLevel {
export class RecordShare extends BaseModel {
static tableName = 'record_shares';
// Disable automatic snake_case conversion for this table
// Don't use snake_case mapping since DB columns are already camelCase
static get columnNameMappers() {
return {
parse(obj: any) {
@@ -21,6 +21,15 @@ export class RecordShare extends BaseModel {
};
}
// Override BaseModel hooks to prevent automatic timestamp handling
$beforeInsert(queryContext: any) {
// Don't set timestamps - let database defaults handle it
}
$beforeUpdate(opt: any, queryContext: any) {
// Don't set timestamps - let database defaults handle it
}
id!: string;
objectDefinitionId!: string;
recordId!: string;
@@ -30,6 +39,7 @@ export class RecordShare extends BaseModel {
expiresAt?: Date;
revokedAt?: Date;
createdAt!: Date;
updatedAt!: Date;
static get jsonSchema() {
return {
@@ -49,8 +59,22 @@ export class RecordShare extends BaseModel {
canDelete: { type: 'boolean' },
},
},
expiresAt: { type: ['string', 'null'], format: 'date-time' },
revokedAt: { type: ['string', 'null'], format: 'date-time' },
expiresAt: {
anyOf: [
{ type: 'string', format: 'date-time' },
{ type: 'null' },
{ type: 'object' } // Allow Date objects
]
},
revokedAt: {
anyOf: [
{ type: 'string', format: 'date-time' },
{ type: 'null' },
{ type: 'object' } // Allow Date objects
]
},
createdAt: { type: ['string', 'object'], format: 'date-time' },
updatedAt: { type: ['string', 'object'], format: 'date-time' },
},
};
}

View File

@@ -147,14 +147,16 @@ export class RecordSharingController {
if (existingShare) {
// Update existing share
await RecordShare.query(knex)
.patchAndFetchById(existingShare.id, {
accessLevel: {
await knex('record_shares')
.where({ id: existingShare.id })
.update({
accessLevel: JSON.stringify({
canRead: data.canRead,
canEdit: data.canEdit,
canDelete: data.canDelete,
},
expiresAt: data.expiresAt ? new Date(data.expiresAt) : null,
}),
expiresAt: data.expiresAt ? data.expiresAt : null,
updatedAt: knex.fn.now(),
});
return RecordShare.query(knex)
@@ -163,21 +165,21 @@ export class RecordSharingController {
}
// Create new share
const share = await RecordShare.query(knex).insert({
const [shareId] = await knex('record_shares').insert({
objectDefinitionId: objectDef.id,
recordId,
granteeUserId: data.granteeUserId,
grantedByUserId: currentUser.userId,
accessLevel: {
accessLevel: JSON.stringify({
canRead: data.canRead,
canEdit: data.canEdit,
canDelete: data.canDelete,
},
expiresAt: data.expiresAt ? new Date(data.expiresAt) : null,
}),
expiresAt: data.expiresAt ? data.expiresAt : null,
});
return RecordShare.query(knex)
.findById(share.id)
.findById(shareId)
.withGraphFetched('[granteeUser]');
}
@@ -233,9 +235,11 @@ export class RecordSharingController {
}
// Revoke the share (soft delete)
await RecordShare.query(knex)
.patchAndFetchById(shareId, {
revokedAt: new Date(),
await knex('record_shares')
.where({ id: shareId })
.update({
revokedAt: knex.fn.now(),
updatedAt: knex.fn.now(),
});
return { success: true };