import ServerDocumentMixin from"../backend/server-document.mjs";import BaseUser from"../../../common/documents/user.mjs";import sessions from"../../sessions.mjs";import{createPassword}from"../../core/auth.mjs";import{USER_ROLES}from"../../../common/constants.mjs";import{isPlainObject}from"../../../common/utils/_module.mjs";export default class User extends(ServerDocumentMixin(BaseUser)){static _migrationRegistry=[...super._migrationRegistry,{fn:migratePlainTextPassword,version:12},{fn:migrateTemplateCreatePermission,version:"14.352"}];get sessions(){return sessions.getUserSessions(this.id)}get sockets(){const e=[];for(const s of config.sockets.values())s.userId===this.id&&e.push(s);return e}get isActive(){return!!this.id&&(game.active&&game.activity&&this.id in game.activity.users)}async _preCreate(e,s,t){if(!1===await super._preCreate(e,s,t))return!1;const{hash:r,salt:a}=createPassword(this.password);this.updateSource({password:r,passwordSalt:a})}static async _preCreateOperation(e,s,t){const r=new Set((await this.find({})).map(e=>e.name));for(const s of e){const e=s.name;if(r.has(e))throw new Error(`User names must be unique, but the name "${e}" is already taken.`);r.add(e)}return super._preCreateOperation(e,s,t)}_onCreate(e,s,t){super._onCreate(e,s,t),game.users.push(this),delete e.password,delete e.passwordSalt}static async _preUpdateOperation(e,s,t){const r=s._updateData,a=e.filter(e=>"name"in r[e.id]);if(a.length){const e=new Set(a.map(e=>e.id)),s=new Set((await this.find({})).filter(s=>!e.has(s.id)).map(e=>e.name));for(const e of a){const t=r[e.id].name;if(s.has(t))throw new Error(`User names must be unique, but the name "${t}" is already taken.`);s.add(t)}}return super._preUpdateOperation(e,s,t)}async _preUpdate(e,s,t){if(!1===await super._preUpdate(e,s,t))return!1;if("role"in e&&(this.role>t.role||e.role>t.role))throw new Error("You are not authorized to perform this role change.");const r=CONST.USER_ROLES.GAMEMASTER;if("role"in e&&e.role<r&&this.role===r&&!game.users.find(e=>e.role===r&&e.id!==this.id))throw new Error("You may not demote the only Gamemaster user within the World.");if("password"in e&&!s.dryRun){const{hash:s,salt:t}=createPassword(e.password);e.password=s,e.passwordSalt=t,sessions.deactivateUserSession(this.id)}}_onUpdate(e,s,t){super._onUpdate(e,s,t),db.User.get(this.id).then(e=>game.users.findSplice(e=>e.id===this.id,e)),delete e.password,delete e.passwordSalt}async _preDelete(e,s){const t=CONST.USER_ROLES.GAMEMASTER;if(this.role===t&&!game.users.find(e=>e.role===t&&e.id!==this.id))throw new Error("You may not delete the only Gamemaster user within the World.");await super._preDelete(e,s)}async _onDelete(e,s){super._onDelete(e,s),game.users.findSplice(e=>e.id===this.id);const t=await db.Setting.find({user:this.id});if(t.length){const e=db.Setting.sublevel.db.batch();t.forEach(s=>s.batchDelete(e)),await e.write(),logger.info(`Deleted ${t.length} Settings scoped to User [${this.id}]: [${t.map(e=>e.key).join(", ")}]`)}}static async dump(e={}){const s=await super.dump(e);return s.forEach(e=>{delete e.password,delete e.passwordSalt}),s.sort(User.#e),s}static fromSource(e,{safe:s=!1,...t}={}){const r=super.fromSource(e,t);return s&&r.updateSource({password:"",passwordSalt:""}),r}static async find(e={},s={}){const t=await super.find(e,s);return t.sort(User.#e),t}static async getUsers(){const e=await User.find({}),s=game.activity.users;for(const t of e){if(!t.id)continue;const e=s[t.id]||{};t.viewedScene=e.sceneId||null,t.viewedLevel=e.levelId||null}return game.users=e}static#e(e,s){const t=e.role>=USER_ROLES.ASSISTANT?e.role:1,r=s.role>=USER_ROLES.ASSISTANT?s.role:1;return t!==r?r-t:e.name.compare(s.name)}}function migratePlainTextPassword(e){if("passwordSalt"in e)return!1;const{hash:s,salt:t}=createPassword(e.password||"");return e.password=s,e.passwordSalt=t,!0}function migrateTemplateCreatePermission(e){const s=e.permissions;return!!isPlainObject(s)&&("TEMPLATE_CREATE"in s&&(s.REGION_CREATE??=s.TEMPLATE_CREATE,delete s.TEMPLATE_CREATE,!0))}