text: const { promisify } = require("util");
  const Knex = require("knex");
  const connection = require("../knexfile");
  const { Model } = require("objection");
  const bcrypt = require("bcryptjs");
  const jwt = require("jsonwebtoken");
  const jwtConfig = require("../config/jwt");
  
  const knexConnection = Knex(connection);
  
  Model.knex(knexConnection);
  
  class Role extends Model {
    static get tableName() {
      return "role";
    }
  
    static get idColumn() {
      return "id";
    }
  }
  
  class User extends Model {
    static get tableName() {
      return "user";
    }
  
    static get idColumn() {
      return "id";
    }
  
    static get relationMappings() {
      return {
        roles: {
          relation: Model.ManyToManyRelation,
          modelClass: Role,
          join: {
            from: "user.id",
            through: {
              from: "user_role.user_id",
              to: "user_role.role_id"
            },
            to: "role.id"
          }
        }
      };
    }
  
    getRoles() {
      return this.roles.map(el => el.name).concat("user");
    }
  
    getUser() {
      return {
        id: this.id,
        username: this.username,
        roles: this.getRoles(),
        token: this.getJwt()
      };
    }
  
    getHasuraClaims() {
      return {
        "x-hasura-allowed-roles": this.getRoles(),
        "x-hasura-default-role": "user",
        "x-hasura-user-id": `${this.id}`
        // 'x-hasura-org-id': '123',
        // 'x-hasura-custom': 'custom-value'
      };
    }
  
    getJwt() {
      const signOptions = {
        subject: this.id,
        expiresIn: "30d", // 30 days validity
        algorithm: "RS256"
      };
      const claim = {
        name: this.username,
        // iat: Math.floor(Date.now() / 1000),
        "https://hasura.io/jwt/claims": this.getHasuraClaims()
      };
      return jwt.sign(claim, jwtConfig.key, signOptions);
    }
  
    async $beforeInsert() {
      const salt = bcrypt.genSaltSync();
      this.password = await bcrypt.hash(this.password, salt);
    }
  
    async $beforeUpdate() {
      await $beforeInsert();
    }
  
    verifyPassword(password, callback) {
      bcrypt.compare(password, this.password, callback);
    }
  
    static get jsonSchema() {
      return {
        type: "object",
        required: ["username"],
        properties: {
          id: { type: "integer" },
          username: { type: "string", minLength: 1, maxLength: 255 }
        }
      };
    }
  }
  
  module.exports = { User, Role };
  