Ground-Zerro / Phobos Public
Code Issues Pull requests Actions Releases View on GitHub ↗
3.6 KB typescript
import { sql } from 'drizzle-orm';
import { general } from './schema';
import type { GeneralUpdateType } from './types';
import type { DBType } from '#db/sqlite';

function createPreparedStatement(db: DBType) {
  return {
    getSetupStep: db.query.general
      .findFirst({
        columns: {
          setupStep: true,
        },
      })
      .prepare(),
    getAllowInsecureHttpLogin: db.query.general
      .findFirst({
        columns: {
          allowInsecureHttpLogin: true,
        },
      })
      .prepare(),
    getSessionConfig: db.query.general
      .findFirst({
        columns: {
          sessionPassword: true,
          sessionTimeout: true,
          allowInsecureHttpLogin: true,
        },
      })
      .prepare(),
    getMetricsConfig: db.query.general
      .findFirst({
        columns: {
          metricsPrometheus: true,
          metricsJson: true,
          metricsPassword: true,
        },
      })
      .prepare(),
    getConfig: db.query.general
      .findFirst({
        columns: {
          sessionTimeout: true,
          metricsPrometheus: true,
          metricsJson: true,
          metricsPassword: true,
        },
      })
      .prepare(),
    updateSetupStep: db
      .update(general)
      .set({
        setupStep: sql.placeholder('setupStep') as never as number,
      })
      .prepare(),
  };
}

export class GeneralService {
  #db: DBType;
  #statements: ReturnType<typeof createPreparedStatement>;

  constructor(db: DBType) {
    this.#db = db;
    this.#statements = createPreparedStatement(db);
  }

  /**
   * @throws
   */
  async getSetupStep() {
    const result = await this.#statements.getSetupStep.execute();

    if (!result) {
      throw new Error('General Config not found');
    }

    return { step: result.setupStep, done: result.setupStep === 0 };
  }

  setSetupStep(step: number) {
    return this.#statements.updateSetupStep.execute({ setupStep: step });
  }

  /**
   * @throws
   */
  async getSessionConfig() {
    const result = await this.#statements.getSessionConfig.execute();

    if (!result) {
      throw new Error('General Config not found');
    }

    return {
      sessionPassword: result.sessionPassword,
      sessionTimeout: result.sessionTimeout,
      allowInsecureHttpLogin: result.allowInsecureHttpLogin,
    };
  }

  /** For /api/information etc. — avoids loading session secrets. */
  async getAllowInsecureHttpLogin() {
    const row = await this.#statements.getAllowInsecureHttpLogin.execute();
    return row?.allowInsecureHttpLogin ?? false;
  }

  setAllowInsecureHttpLogin(allowed: boolean) {
    return this.#db
      .update(general)
      .set({ allowInsecureHttpLogin: allowed })
      .execute();
  }

  /**
   * @throws
   */
  async getMetricsConfig() {
    const result = await this.#statements.getMetricsConfig.execute();

    if (!result) {
      throw new Error('General Config not found');
    }

    return {
      prometheus: result.metricsPrometheus,
      json: result.metricsJson,
      password: result.metricsPassword,
    };
  }

  async update(data: GeneralUpdateType) {
    if (data.metricsPassword) {
      data.metricsPassword = await hashPassword(data.metricsPassword);
    }

    return this.#db.update(general).set(data).execute();
  }

  async getConfig() {
    const result = await this.#statements.getConfig.execute();

    if (!result) {
      throw new Error('General Config not found');
    }

    return {
      sessionTimeout: result.sessionTimeout,
      metricsPrometheus: result.metricsPrometheus,
      metricsJson: result.metricsJson,
      metricsPasswordSet: result.metricsPassword != null,
    };
  }
}