Connection management now id based rather than type based

This commit is contained in:
Eclypsed
2024-01-07 14:23:22 -05:00
parent 0da467d1e0
commit 4a43b06c72
10 changed files with 166 additions and 164 deletions

View File

@@ -5,10 +5,7 @@ const db = new Database('./src/lib/server/db/users.db', { verbose: console.info
db.pragma('foreign_keys = ON')
const initUsersTable = 'CREATE TABLE IF NOT EXISTS Users(id INTEGER PRIMARY KEY AUTOINCREMENT, username VARCHAR(64) UNIQUE NOT NULL, password VARCHAR(72) NOT NULL)'
const initUserConnectionsTable =
'CREATE TABLE IF NOT EXISTS UserConnections(id INTEGER PRIMARY KEY AUTOINCREMENT, userId INTEGER NOT NULL, serviceName VARCHAR(64) NOT NULL, accessToken TEXT, refreshToken TEXT, expiry DATETIME, FOREIGN KEY(userId) REFERENCES Users(id))'
const initJellyfinAuthTable = 'CREATE TABLE IF NOT EXISTS JellyfinConnections(id INTEGER PRIMARY KEY AUTOINCREMENT, user TEXT, accesstoken TEXT, serverid TEXT)'
const initYouTubeMusicConnectionsTable = ''
const initSpotifyConnectionsTable = ''
'CREATE TABLE IF NOT EXISTS UserConnections(id INTEGER PRIMARY KEY AUTOINCREMENT, userId INTEGER NOT NULL, serviceType VARCHAR(64) NOT NULL, accessToken TEXT, refreshToken TEXT, expiry INTEGER, connectionInfo TEXT, FOREIGN KEY(userId) REFERENCES Users(id))'
db.exec(initUsersTable)
db.exec(initUserConnectionsTable)
@@ -30,41 +27,29 @@ export class Users {
export class UserConnections {
static validServices = Object.keys(Services)
static getConnections = (userId, serviceNames = null) => {
if (!serviceNames) {
const connections = db.prepare('SELECT * FROM UserConnections WHERE userId = ?').all(userId)
if (connections.length === 0) return null
return connections
}
if (!Array.isArray(serviceNames)) {
if (typeof serviceNames !== 'string') throw new Error('Service names must be a string or array of strings')
serviceNames = [serviceNames]
}
serviceNames = serviceNames.filter((service) => this.validServices.includes(service))
const placeholders = serviceNames.map(() => '?').join(', ') // This is SQL-injection safe, the placeholders are just ?, ?, ?....
const connections = db.prepare(`SELECT * FROM UserConnections WHERE userId = ? AND serviceName IN (${placeholders})`).all(userId, ...serviceNames)
static getConnections = (userId) => {
const connections = db.prepare(`SELECT * FROM UserConnections WHERE userId = ?`).all(userId)
if (connections.length === 0) return null
return connections
}
// May want to give accessToken a default of null in the future if one of the services does not use access tokens
static setConnection = (userId, serviceName, accessToken, refreshToken = null, expiry = null) => {
if (!this.validServices.includes(serviceName)) throw new Error(`Service name ${serviceName} is invalid`)
static addConnection = (userId, serviceType, accessToken, options = {}) => {
const { refreshToken = null, expiry = null, connectionInfo = null } = options
const existingConnection = this.getConnections(userId, serviceName)
if (existingConnection) {
db.prepare('UPDATE UserConnections SET accessToken = ?, refreshToken = ?, expiry = ? WHERE userId = ? AND serviceName = ?').run(accessToken, refreshToken, expiry, userId, serviceName)
} else {
db.prepare('INSERT INTO UserConnections(userId, serviceName, accessToken, refreshToken, expiry) VALUES(?, ?, ?, ?, ?)').run(userId, serviceName, accessToken, refreshToken, expiry)
}
// return this.getConnections(userId, serviceName) <--- Uncomment this if want to return new connection data after update
if (!this.validServices.includes(serviceType)) throw new Error(`Service name ${serviceType} is invalid`)
if (connectionInfo) JSON.parse(connectionInfo) // Aditional validation, if connectionInfo is not stringified valid json it will throw an error
const commandInfo = db
.prepare('INSERT INTO UserConnections(userId, serviceType, accessToken, refreshToken, expiry, connectionInfo) VALUES(?, ?, ?, ?, ?, ?)')
.run(userId, serviceType, accessToken, refreshToken, expiry, connectionInfo)
return commandInfo.lastInsertRowid
}
static deleteConnection = (userId, serviceName) => {
const info = db.prepare('DELETE FROM UserConnections WHERE userId = ? AND serviceName = ?').run(userId, serviceName)
if (!info.changes === 0) throw new Error(`User does not have connection: ${serviceName}`)
static deleteConnection = (userId, serviceId) => {
const commandInfo = db.prepare('DELETE FROM UserConnections WHERE userId = ? AND id = ?').run(userId, serviceId)
if (!commandInfo.changes === 0) throw new Error(`User does not have connection with id: ${serviceId}`)
return serviceId
}
}