Migrate codebase from CommonJS to ES Modules
- Convert all require()/module.exports to import/export across 260+ files - Add "type": "module" to package.json to enable ESM by default - Add migrations/package.json with "type": "commonjs" to keep db-migrate compatible - Convert eslint.config.js to ESM with sourceType: "module" - Replace __dirname/__filename with import.meta.dirname/import.meta.filename - Replace require.main === module with process.argv[1] === import.meta.filename - Remove 'use strict' directives (implicit in ESM) - Convert dynamic require() in switch statements to static import lookup maps (dns.js, domains.js, backupformats.js, backupsites.js, network.js) - Extract self-referencing exports.CONSTANT patterns into standalone const declarations (apps.js, services.js, locks.js, users.js, mail.js, etc.) - Lazify SERVICES object in services.js to avoid circular dependency TDZ issues - Add clearMailQueue() to mailer.js for ESM-safe queue clearing in tests - Add _setMockApp() to ldapserver.js for ESM-safe test mocking - Add _setMockResolve() wrapper to dig.js for ESM-safe DNS mocking in tests - Convert backupupload.js to use dynamic imports so --check exits before loading the module graph (which requires BOX_ENV) - Update check-install to use ESM import for infra_version.js - Convert scripts/ (hotfix, release, remote_hotfix.js, find-unused-translations) - All 1315 tests passing Migration stats (AI-assisted using Cursor with Claude): - Wall clock time: ~3-4 hours - Assistant completions: ~80-100 - Estimated token usage: ~1-2M tokens Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+55
-65
@@ -1,12 +1,48 @@
|
||||
'use strict';
|
||||
import * as appPasswords from './apppasswords.js';
|
||||
import assert from 'node:assert';
|
||||
import BoxError from './boxerror.js';
|
||||
import crypto from 'node:crypto';
|
||||
import constants from './constants.js';
|
||||
import * as dashboard from './dashboard.js';
|
||||
import * as database from './database.js';
|
||||
import debugModule from 'debug';
|
||||
import eventlog from './eventlog.js';
|
||||
import * as externalLdap from './externalldap.js';
|
||||
import hat from './hat.js';
|
||||
import * as mail from './mail.js';
|
||||
import * as mailer from './mailer.js';
|
||||
import mysql from 'mysql2';
|
||||
import * as notifications from './notifications.js';
|
||||
import oidcClients from './oidcclients.js';
|
||||
import * as passkeys from './passkeys.js';
|
||||
import qrcode from 'qrcode';
|
||||
import safe from 'safetydance';
|
||||
import * as settings from './settings.js';
|
||||
import speakeasy from 'speakeasy';
|
||||
import * as tokens from './tokens.js';
|
||||
import * as translations from './translations.js';
|
||||
import { UAParser as uaParser } from 'ua-parser-js';
|
||||
import * as userDirectory from './user-directory.js';
|
||||
import superagent from '@cloudron/superagent';
|
||||
import util from 'node:util';
|
||||
import * as validator from './validator.js';
|
||||
import * as _ from './underscore.js';
|
||||
|
||||
exports = module.exports = {
|
||||
const debug = debugModule('box:user');
|
||||
|
||||
const AP_MAIL = 'mail';
|
||||
const AP_WEBADMIN = 'webadmin';
|
||||
const ROLE_ADMIN = 'admin';
|
||||
const ROLE_USER = 'user';
|
||||
const ROLE_USER_MANAGER = 'usermanager';
|
||||
const ROLE_MAIL_MANAGER = 'mailmanager';
|
||||
const ROLE_OWNER = 'owner';
|
||||
|
||||
export {
|
||||
removePrivateFields,
|
||||
|
||||
add,
|
||||
createOwner,
|
||||
isActivated,
|
||||
|
||||
list,
|
||||
listPaged,
|
||||
get,
|
||||
@@ -17,87 +53,41 @@ exports = module.exports = {
|
||||
getOwner,
|
||||
getAdmins,
|
||||
getSuperadmins,
|
||||
|
||||
verifyWithId,
|
||||
verifyWithUsername,
|
||||
verifyWithEmail,
|
||||
|
||||
setPassword,
|
||||
setGhost,
|
||||
updateProfile,
|
||||
update,
|
||||
|
||||
del,
|
||||
|
||||
setTwoFactorAuthenticationSecret,
|
||||
enableTwoFactorAuthentication,
|
||||
disableTwoFactorAuthentication,
|
||||
|
||||
sendPasswordResetByIdentifier,
|
||||
|
||||
getPasswordResetLink,
|
||||
sendPasswordResetEmail,
|
||||
|
||||
getInviteLink,
|
||||
sendInviteEmail,
|
||||
|
||||
notifyLoginLocation,
|
||||
|
||||
setupAccount,
|
||||
|
||||
setAvatar,
|
||||
getAvatar,
|
||||
|
||||
getBackgroundImage,
|
||||
setBackgroundImage,
|
||||
|
||||
setNotificationConfig,
|
||||
|
||||
resetSources,
|
||||
|
||||
parseDisplayName,
|
||||
|
||||
AP_MAIL: 'mail',
|
||||
AP_WEBADMIN: 'webadmin',
|
||||
|
||||
ROLE_ADMIN: 'admin',
|
||||
ROLE_USER: 'user',
|
||||
ROLE_USER_MANAGER: 'usermanager',
|
||||
ROLE_MAIL_MANAGER: 'mailmanager',
|
||||
ROLE_OWNER: 'owner',
|
||||
AP_MAIL,
|
||||
AP_WEBADMIN,
|
||||
ROLE_ADMIN,
|
||||
ROLE_USER,
|
||||
ROLE_USER_MANAGER,
|
||||
ROLE_MAIL_MANAGER,
|
||||
ROLE_OWNER,
|
||||
compareRoles,
|
||||
};
|
||||
|
||||
const appPasswords = require('./apppasswords.js'),
|
||||
assert = require('node:assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
crypto = require('node:crypto'),
|
||||
constants = require('./constants.js'),
|
||||
dashboard = require('./dashboard.js'),
|
||||
database = require('./database.js'),
|
||||
debug = require('debug')('box:user'),
|
||||
eventlog = require('./eventlog.js'),
|
||||
externalLdap = require('./externalldap.js'),
|
||||
hat = require('./hat.js'),
|
||||
mail = require('./mail.js'),
|
||||
mailer = require('./mailer.js'),
|
||||
mysql = require('mysql2'),
|
||||
notifications = require('./notifications'),
|
||||
oidcClients = require('./oidcclients.js'),
|
||||
passkeys = require('./passkeys.js'),
|
||||
qrcode = require('qrcode'),
|
||||
safe = require('safetydance'),
|
||||
settings = require('./settings.js'),
|
||||
speakeasy = require('speakeasy'),
|
||||
tokens = require('./tokens.js'),
|
||||
translations = require('./translations.js'),
|
||||
uaParser = require('ua-parser-js'),
|
||||
userDirectory = require('./user-directory.js'),
|
||||
superagent = require('@cloudron/superagent'),
|
||||
util = require('node:util'),
|
||||
validator = require('./validator.js'),
|
||||
_ = require('./underscore.js');
|
||||
|
||||
// the avatar and backgroundImage fields are special and not added here to reduce response sizes
|
||||
const USERS_FIELDS = [ 'id', 'username', 'email', 'fallbackEmail', 'password', 'salt', 'creationTime', 'inviteToken', 'resetToken', 'displayName', 'language',
|
||||
'twoFactorAuthenticationEnabled', 'twoFactorAuthenticationSecret', 'active', 'source', 'role', 'resetTokenCreationTime', 'loginLocationsJson', 'notificationConfigJson',
|
||||
@@ -202,7 +192,7 @@ function removePrivateFields(user) {
|
||||
function validateRole(role) {
|
||||
assert.strictEqual(typeof role, 'string');
|
||||
|
||||
const ORDERED_ROLES = [ exports.ROLE_USER, exports.ROLE_USER_MANAGER, exports.ROLE_MAIL_MANAGER, exports.ROLE_ADMIN, exports.ROLE_OWNER ];
|
||||
const ORDERED_ROLES = [ ROLE_USER, ROLE_USER_MANAGER, ROLE_MAIL_MANAGER, ROLE_ADMIN, ROLE_OWNER ];
|
||||
|
||||
if (ORDERED_ROLES.includes(role)) return null;
|
||||
|
||||
@@ -213,7 +203,7 @@ function compareRoles(role1, role2) {
|
||||
assert.strictEqual(typeof role1, 'string');
|
||||
assert.strictEqual(typeof role2, 'string');
|
||||
|
||||
const ORDERED_ROLES = [ exports.ROLE_USER, exports.ROLE_USER_MANAGER, exports.ROLE_MAIL_MANAGER, exports.ROLE_ADMIN, exports.ROLE_OWNER ];
|
||||
const ORDERED_ROLES = [ ROLE_USER, ROLE_USER_MANAGER, ROLE_MAIL_MANAGER, ROLE_ADMIN, ROLE_OWNER ];
|
||||
|
||||
const roleInt1 = ORDERED_ROLES.indexOf(role1);
|
||||
const roleInt2 = ORDERED_ROLES.indexOf(role2);
|
||||
@@ -235,7 +225,7 @@ async function add(email, data, auditSource) {
|
||||
let { username, password } = data;
|
||||
let fallbackEmail = data.fallbackEmail || '';
|
||||
const source = data.source || ''; // empty is local user
|
||||
const role = data.role || exports.ROLE_USER;
|
||||
const role = data.role || ROLE_USER;
|
||||
const notificationConfig = 'notificationConfig' in data ? data.notificationConfig : null;
|
||||
|
||||
let error;
|
||||
@@ -547,20 +537,20 @@ async function listByRole(role) {
|
||||
}
|
||||
|
||||
async function getOwner() {
|
||||
const owners = await listByRole(exports.ROLE_OWNER);
|
||||
const owners = await listByRole(ROLE_OWNER);
|
||||
if (owners.length === 0) return null;
|
||||
return owners[0];
|
||||
}
|
||||
|
||||
async function getAdmins() {
|
||||
const owners = await listByRole(exports.ROLE_OWNER);
|
||||
const admins = await listByRole(exports.ROLE_ADMIN);
|
||||
const owners = await listByRole(ROLE_OWNER);
|
||||
const admins = await listByRole(ROLE_ADMIN);
|
||||
|
||||
return owners.concat(admins);
|
||||
}
|
||||
|
||||
async function getSuperadmins() {
|
||||
return await listByRole(exports.ROLE_OWNER);
|
||||
return await listByRole(ROLE_OWNER);
|
||||
}
|
||||
|
||||
async function setGhost(user, password, expiresAt) {
|
||||
@@ -875,7 +865,7 @@ async function createOwner(email, username, password, displayName, auditSource)
|
||||
if (activated) throw new BoxError(BoxError.ALREADY_EXISTS, 'Cloudron already activated');
|
||||
|
||||
const notificationConfig = [notifications.TYPE_BACKUP_FAILED, notifications.TYPE_CERTIFICATE_RENEWAL_FAILED, notifications.TYPE_MANUAL_APP_UPDATE_NEEDED, notifications.TYPE_APP_DOWN, notifications.TYPE_CLOUDRON_UPDATE_FAILED ];
|
||||
return await add(email, { username, password, fallbackEmail: '', displayName, role: exports.ROLE_OWNER, notificationConfig }, auditSource);
|
||||
return await add(email, { username, password, fallbackEmail: '', displayName, role: ROLE_OWNER, notificationConfig }, auditSource);
|
||||
}
|
||||
|
||||
async function getInviteLink(user, auditSource) {
|
||||
|
||||
Reference in New Issue
Block a user