2024-01-23 01:21:41 -05:00
import Database from 'better-sqlite3'
import { generateUUID } from '$lib/utils'
2024-02-01 18:10:15 -05:00
import { isValidURL } from '$lib/utils'
2024-01-23 01:21:41 -05:00
const db = new Database ( './src/lib/server/users.db' , { verbose : console.info } )
db . pragma ( 'foreign_keys = ON' )
const initUsersTable = 'CREATE TABLE IF NOT EXISTS Users(id VARCHAR(36) PRIMARY KEY, username VARCHAR(30) UNIQUE NOT NULL, password VARCHAR(72) NOT NULL)'
2024-02-11 01:03:49 -05:00
const initConnectionsTable = 'CREATE TABLE IF NOT EXISTS Connections(id VARCHAR(36) PRIMARY KEY, userId VARCHAR(36) NOT NULL, service TEXT NOT NULL, tokens TEXT NOT NULL, FOREIGN KEY(userId) REFERENCES Users(id))'
2024-02-01 18:10:15 -05:00
db . exec ( initUsersTable ) , db . exec ( initConnectionsTable )
2024-01-23 01:21:41 -05:00
2024-01-25 03:05:13 -05:00
type UserQueryParams = {
includePassword? : boolean
}
2024-02-01 18:10:15 -05:00
interface ConnectionsTableSchema {
2024-01-24 14:16:24 -05:00
id : string
userId : string
2024-02-01 18:10:15 -05:00
service : string
2024-02-11 01:03:49 -05:00
tokens : string
2024-01-24 14:16:24 -05:00
}
2024-01-23 01:21:41 -05:00
export class Users {
2024-01-25 03:05:13 -05:00
static getUser = ( id : string , params : UserQueryParams | null = null ) : User | undefined = > {
const user = db . prepare ( 'SELECT * FROM Users WHERE id = ?' ) . get ( id ) as User | undefined
if ( user && ! params ? . includePassword ) delete user . password
return user
}
static getUsername = ( username : string , params : UserQueryParams | null = null ) : User | undefined = > {
const user = db . prepare ( 'SELECT * FROM Users WHERE lower(username) = ?' ) . get ( username . toLowerCase ( ) ) as User | undefined
if ( user && ! params ? . includePassword ) delete user . password
return user
}
static allUsers = ( includePassword : boolean = false ) : User [ ] = > {
const users = db . prepare ( 'SELECT * FROM Users' ) . all ( ) as User [ ]
if ( ! includePassword ) users . forEach ( ( user ) = > delete user . password )
return users
2024-01-24 14:16:24 -05:00
}
2024-01-23 01:21:41 -05:00
static addUser = ( username : string , hashedPassword : string ) : User = > {
const userId = generateUUID ( )
db . prepare ( 'INSERT INTO Users(id, username, password) VALUES(?, ?, ?)' ) . run ( userId , username , hashedPassword )
2024-01-25 03:05:13 -05:00
return this . getUser ( userId ) !
}
static deleteUser = ( id : string ) : void = > {
const commandInfo = db . prepare ( 'DELETE FROM Users WHERE id = ?' ) . run ( id )
if ( commandInfo . changes === 0 ) throw new Error ( ` User with id ${ id } does not exist ` )
2024-01-23 01:21:41 -05:00
}
2024-01-24 14:16:24 -05:00
}
2024-01-23 01:21:41 -05:00
2024-01-23 12:05:33 -05:00
export class Connections {
2024-02-01 18:10:15 -05:00
static getConnection = ( id : string ) : Connection = > {
2024-02-11 01:03:49 -05:00
const { userId , service , tokens } = db . prepare ( 'SELECT * FROM Connections WHERE id = ?' ) . get ( id ) as ConnectionsTableSchema
2024-02-12 18:04:30 -05:00
const connection : Connection = { id , userId , service : JSON.parse ( service ) , tokens : JSON.parse ( tokens ) }
2024-01-24 14:16:24 -05:00
return connection
}
2024-02-01 18:10:15 -05:00
static getUserConnections = ( userId : string ) : Connection [ ] = > {
const connectionRows = db . prepare ( 'SELECT * FROM Connections WHERE userId = ?' ) . all ( userId ) as ConnectionsTableSchema [ ]
const connections : Connection [ ] = [ ]
2024-01-25 03:05:13 -05:00
connectionRows . forEach ( ( row ) = > {
2024-02-11 01:03:49 -05:00
const { id , service , tokens } = row
2024-02-12 18:04:30 -05:00
connections . push ( { id , userId , service : JSON.parse ( service ) , tokens : JSON.parse ( tokens ) } )
2024-01-25 03:05:13 -05:00
} )
return connections
}
2024-02-11 01:03:49 -05:00
static addConnection = ( userId : string , service : Service , tokens : Tokens ) : Connection = > {
2024-01-24 14:16:24 -05:00
const connectionId = generateUUID ( )
2024-02-01 18:10:15 -05:00
if ( ! isValidURL ( service . urlOrigin ) ) throw new Error ( 'Service does not have valid url' )
2024-02-11 01:03:49 -05:00
db . prepare ( 'INSERT INTO Connections(id, userId, service, tokens) VALUES(?, ?, ?, ?)' ) . run ( connectionId , userId , JSON . stringify ( service ) , JSON . stringify ( tokens ) )
2024-01-24 14:16:24 -05:00
return this . getConnection ( connectionId )
}
2024-01-25 03:05:13 -05:00
static deleteConnection = ( id : string ) : void = > {
const commandInfo = db . prepare ( 'DELETE FROM Connections WHERE id = ?' ) . run ( id )
if ( commandInfo . changes === 0 ) throw new Error ( ` Connection with id: ${ id } does not exist ` )
}
2024-01-23 12:05:33 -05:00
}