2025-06-25 20:51:29 -07:00
import { get_session , get_user , PRECHECK_TABLE , require_user } from '../../../../utils/prechecks.ts' ;
2025-06-24 16:17:00 -07:00
import { PASSWORD_ENTRIES , PASSWORD_ENTRY } from '../../../../models/password_entry.ts' ;
2025-06-24 15:40:30 -07:00
import { SESSIONS } from '../../../../models/session.ts' ;
2025-06-24 16:17:00 -07:00
import { USER , USERS } from '../../../../models/user.ts' ;
import { PERMISSIONS_STORE , USER_PERMISSIONS } from '../../../../models/user_permissions.ts' ;
2025-06-24 15:40:30 -07:00
import parse_body from '../../../../utils/bodyparser.ts' ;
2025-06-25 20:51:29 -07:00
import { CANNED_RESPONSES } from '../../../../utils/canned_responses.ts' ;
2025-06-24 15:40:30 -07:00
2025-06-25 20:51:29 -07:00
export const PRECHECKS : PRECHECK_TABLE = { } ;
2025-06-24 15:40:30 -07:00
// GET /api/users/:id - Get single user
2025-06-25 20:51:29 -07:00
PRECHECKS . GET = [ get_session , get_user , require_user , ( _req : Request , meta : Record < string , any > ) : Response | undefined = > {
2025-06-24 15:40:30 -07:00
const user_is_self = ! ! meta . user && ! ! meta . params && meta . user . id === meta . params . id ;
const can_read_self = meta . user_permissions ? . permissions . includes ( 'self.read' ) ;
const can_read_others = meta . user_permissions ? . permissions ? . includes ( 'users.read' ) ;
2025-06-25 20:51:29 -07:00
const has_permission = can_read_others || ( can_read_self && user_is_self ) ;
if ( ! has_permission ) {
return CANNED_RESPONSES . permission_denied ( ) ;
}
} ] ;
2025-06-24 15:40:30 -07:00
export async function GET ( _req : Request , meta : Record < string , any > ) : Promise < Response > {
const user_id : string = meta . params ? . id ? . toLowerCase ( ) . trim ( ) ? ? '' ;
2025-06-24 16:17:00 -07:00
const user : USER | null = user_id . length === 49 ? await USERS . get ( user_id ) : null ; // lurid is 49 chars as we use them, eg: "also-play-flow-want-form-wide-thus-work-burn-same"
2025-06-24 15:40:30 -07:00
if ( ! user ) {
return Response . json ( {
error : {
message : ` Could not locate a user with id: " ${ user_id } " ` ,
cause : 'unknown_user'
}
} , {
status : 404
} ) ;
}
return Response . json ( user , {
status : 200
} ) ;
}
// PUT /api/users/:id - Update user
2025-06-25 20:51:29 -07:00
PRECHECKS . PUT = [ get_session , get_user , require_user , ( _req : Request , meta : Record < string , any > ) : Response | undefined = > {
2025-06-24 15:40:30 -07:00
const user_is_self = ! ! meta . user && ! ! meta . params && meta . user . id === meta . params . id ;
const can_write_self = meta . user_permissions ? . permissions . includes ( 'self.write' ) ;
const can_write_others = meta . user_permissions ? . permissions ? . includes ( 'users.write' ) ;
2025-06-25 20:51:29 -07:00
const has_permission = can_write_others || ( can_write_self && user_is_self ) ;
if ( ! has_permission ) {
return CANNED_RESPONSES . permission_denied ( ) ;
}
} ] ;
2025-06-24 15:40:30 -07:00
export async function PUT ( req : Request , meta : { params : Record < string , any > } ) : Promise < Response > {
const now = new Date ( ) . toISOString ( ) ;
const id : string = meta . params . id ? ? '' ;
2025-06-24 16:17:00 -07:00
const existing = await USERS . get ( id ) ;
2025-06-24 15:40:30 -07:00
if ( ! existing ) {
return Response . json ( {
error : {
message : 'User not found' ,
cause : 'unknown_user'
}
} , {
status : 404
} ) ;
}
try {
const body = await parse_body ( req ) ;
const updated = {
. . . existing ,
username : body.username || existing . username ,
timestamps : {
created : existing.timestamps.created ,
updated : now
}
} ;
2025-06-24 16:17:00 -07:00
await USERS . update ( updated ) ;
2025-06-24 15:40:30 -07:00
return Response . json ( updated , {
status : 200
} ) ;
} catch ( err ) {
return Response . json ( {
error : {
message : ( err as Error ) ? . message ? ? 'Unknown error due to invalid user data.' ,
cause : ( err as Error ) ? . cause ? ? 'invalid_user_data'
}
} , {
status : 400
} ) ;
}
}
// DELETE /api/users/:id - Delete user
2025-06-25 20:51:29 -07:00
PRECHECKS . DELETE = [ get_session , get_user , require_user , ( _req : Request , meta : Record < string , any > ) : Response | undefined = > {
2025-06-24 15:40:30 -07:00
const user_is_self = ! ! meta . user && ! ! meta . params && meta . user . id === meta . params . id ;
const can_write_self = meta . user_permissions ? . permissions . includes ( 'self.write' ) ;
const can_write_others = meta . user_permissions ? . permissions ? . includes ( 'users.write' ) ;
2025-06-25 20:51:29 -07:00
const has_permission = can_write_others || ( can_write_self && user_is_self ) ;
if ( ! has_permission ) {
return CANNED_RESPONSES . permission_denied ( ) ;
}
} ] ;
2025-06-24 15:40:30 -07:00
export async function DELETE ( _req : Request , meta : { params : Record < string , any > } ) : Promise < Response > {
const user_id : string = meta . params . id ? ? '' ;
2025-06-24 16:17:00 -07:00
const user : USER | null = await USERS . get ( user_id ) ;
2025-06-24 15:40:30 -07:00
if ( ! user ) {
return Response . json ( {
error : {
message : 'Error deleting user.' ,
cause : 'unknown_user'
}
} , {
status : 404
} ) ;
}
2025-06-24 16:17:00 -07:00
const password_entry : PASSWORD_ENTRY | null = await PASSWORD_ENTRIES . get ( user_id ) ;
2025-06-24 15:40:30 -07:00
if ( password_entry ) {
2025-06-24 16:17:00 -07:00
await PASSWORD_ENTRIES . delete ( password_entry ) ;
2025-06-24 15:40:30 -07:00
}
2025-06-24 16:17:00 -07:00
const user_permissions : USER_PERMISSIONS | null = await PERMISSIONS_STORE . get ( user_id ) ;
2025-06-24 15:40:30 -07:00
if ( user_permissions ) {
2025-06-24 16:17:00 -07:00
await PERMISSIONS_STORE . delete ( user_permissions ) ;
2025-06-24 15:40:30 -07:00
}
const sessions = await SESSIONS . find ( {
user_id
} ) ;
for ( const session of sessions ) {
await SESSIONS . delete ( session ) ;
}
2025-06-24 16:17:00 -07:00
await USERS . delete ( user ) ;
2025-06-24 15:40:30 -07:00
return Response . json ( {
deleted : true
} , {
status : 200
} ) ;
}