2022-09-07 23:14:52 +00:00
const std = @import ( " std " ) ;
const builtin = @import ( " builtin " ) ;
const util = @import ( " util " ) ;
const models = @import ( " ../db/models.zig " ) ;
2022-09-08 01:55:55 +00:00
const DbError = @import ( " ../db.zig " ) . ExecError ;
2022-09-07 23:14:52 +00:00
const getRandom = @import ( " ../api.zig " ) . getRandom ;
const Uuid = util . Uuid ;
const CreateError = error {
InvalidOrigin ,
UnsupportedScheme ,
CommunityExists ,
2022-09-08 01:55:55 +00:00
} | | DbError ;
2022-09-07 23:14:52 +00:00
pub const Scheme = enum {
https ,
http ,
pub fn jsonStringify ( s : Scheme , _ : std . json . StringifyOptions , writer : anytype ) ! void {
return std . fmt . format ( writer , " \" {s} \" " , . { @tagName ( s ) } ) ;
}
} ;
pub const Community = struct {
id : Uuid ,
2022-09-08 06:56:29 +00:00
owner_id : ? Uuid ,
2022-09-07 23:14:52 +00:00
host : [ ] const u8 ,
name : [ ] const u8 ,
scheme : Scheme ,
} ;
pub fn create ( db : anytype , origin : [ ] const u8 , name : ? [ ] const u8 ) CreateError ! Community {
const scheme_len = firstIndexOf ( origin , ':' ) orelse return error . InvalidOrigin ;
const scheme_str = origin [ 0 . . scheme_len ] ;
const scheme = std . meta . stringToEnum ( Scheme , scheme_str ) orelse return error . UnsupportedScheme ;
// host must be in the format "{scheme}://{host}"
if ( origin . len < = scheme_len + ( " :// " ) . len or
origin [ scheme_len ] ! = ':' or
origin [ scheme_len + 1 ] ! = '/' or
origin [ scheme_len + 2 ] ! = '/' ) return error . InvalidOrigin ;
const host = origin [ scheme_len + 3 . . ] ;
// community cannot use non-default ports (except for testing)
// NOTE: Do not add, say localhost and localhost:80 or bugs may happen.
// Avoid using non-default ports unless a test can't be conducted without it.
if ( firstIndexOf ( host , ':' ) ! = null and builtin . mode ! = . Debug ) return error . InvalidOrigin ;
// community cannot be hosted on a path
if ( firstIndexOf ( host , '/' ) ! = null ) return error . InvalidOrigin ;
// Require TLS on production builds
if ( scheme ! = . https and builtin . mode ! = . Debug ) return error . UnsupportedScheme ;
const id = Uuid . randV4 ( getRandom ( ) ) ;
const community = Community {
. id = id ,
2022-09-08 06:56:29 +00:00
. owner_id = null ,
2022-09-07 23:14:52 +00:00
. host = host ,
. name = name orelse host ,
. scheme = scheme ,
} ;
2022-09-08 02:01:24 +00:00
if ( ( try db . execRow ( & . { Uuid } , " SELECT id FROM community WHERE host = ? " , . { host } , null ) ) ! = null ) {
2022-09-07 23:14:52 +00:00
return error . CommunityExists ;
}
2022-09-08 02:01:24 +00:00
try db . insert ( " community " , community ) ;
2022-09-07 23:14:52 +00:00
return community ;
}
2022-09-08 05:10:58 +00:00
fn firstIndexOf ( str : [ ] const u8 , ch : u8 ) ? usize {
2022-09-07 23:14:52 +00:00
for ( str ) | c , i | {
if ( c = = ch ) return i ;
}
return null ;
}
2022-09-08 05:10:58 +00:00
pub fn getByHost ( db : anytype , host : [ ] const u8 , alloc : std . mem . Allocator ) ! Community {
2022-09-08 06:56:29 +00:00
const result = ( try db . execRow ( & . { Uuid , ? Uuid , [ ] const u8 , [ ] const u8 , Scheme } , " SELECT id, owner_id, host, name, scheme FROM community WHERE host = ? " , . { host } , alloc ) ) orelse return error . NotFound ;
2022-09-08 05:10:58 +00:00
return Community {
. id = result [ 0 ] ,
2022-09-08 06:56:29 +00:00
. owner_id = result [ 1 ] ,
. host = result [ 2 ] ,
. name = result [ 3 ] ,
. scheme = result [ 4 ] ,
2022-09-08 05:10:58 +00:00
} ;
}
2022-09-08 06:56:29 +00:00
pub fn transferOwnership ( db : anytype , community_id : Uuid , new_owner : Uuid ) ! void {
_ = try db . execRow ( & . { i64 } , " UPDATE community SET owner_id = ? WHERE id = ? " , . { new_owner , community_id } , null ) ;
}