Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
214 lines
8.1 KiB
Plaintext
214 lines
8.1 KiB
Plaintext
#!/usr/bin/env nu
|
|
|
|
# Tenant management commands for Alga PSA
|
|
|
|
# Create a new tenant
|
|
export def create-tenant [
|
|
tenant_name: string # Name of the tenant client
|
|
admin_email: string # Email for the admin user
|
|
--first-name: string = "Admin" # Admin user's first name
|
|
--last-name: string = "User" # Admin user's last name
|
|
--client-name: string = "" # Client name (defaults to tenant name)
|
|
--password: string = "" # Admin password (generated if not provided)
|
|
--seed-onboarding = true # Run onboarding seeds after creation
|
|
--skip-onboarding = false # Set onboarding_skipped flag to true in tenant_settings
|
|
] {
|
|
print $"($env.ALGA_COLOR_CYAN)Creating new tenant: ($tenant_name)($env.ALGA_COLOR_RESET)"
|
|
|
|
# Set client name to tenant name if not provided
|
|
let client_name = if $client_name == "" { $tenant_name } else { $client_name }
|
|
|
|
# Get the project root
|
|
let project_root = (find-project-root)
|
|
|
|
# Run the tenant creation
|
|
print $"($env.ALGA_COLOR_YELLOW)→ Creating tenant and admin user...($env.ALGA_COLOR_RESET)"
|
|
|
|
# Use the shared tenant creation module
|
|
let result = (
|
|
cd $"($project_root)/server"; npm run --silent create-tenant -- --tenant $"($tenant_name)" --email $"($admin_email)" --firstName $"($first_name)" --lastName $"($last_name)" --clientName $"($client_name)" --password $"($password)"
|
|
| complete
|
|
)
|
|
|
|
if $result.exit_code != 0 {
|
|
print $"($env.ALGA_COLOR_RED)✗ Failed to create tenant($env.ALGA_COLOR_RESET)"
|
|
print $"Error: ($result.stderr)"
|
|
return
|
|
}
|
|
|
|
# Extract tenant ID and password from output
|
|
let output = $result.stdout
|
|
let tenant_id_line = ($output | lines | where { |line| $line | str contains "Tenant ID:" } | first)
|
|
# Remove brackets from tenant ID
|
|
let tenant_id = ($tenant_id_line | split column ":" | get column2 | first | str trim | str replace "[" "" | str replace "]" "")
|
|
let temp_password = if $password == "" {
|
|
let password_line = ($output | lines | where { |line| $line | str contains "Temporary Password:" } | first)
|
|
($password_line | split column ":" | get column2 | first | str trim)
|
|
} else {
|
|
$password
|
|
}
|
|
|
|
print $"($env.ALGA_COLOR_GREEN)✓ Tenant created successfully!($env.ALGA_COLOR_RESET)"
|
|
print $" Tenant ID: ($tenant_id)"
|
|
print $" Admin Email: ($admin_email)"
|
|
if $password == "" {
|
|
print $" Temporary Password: ($temp_password)"
|
|
}
|
|
|
|
# Create tenant_settings record
|
|
print $"\n($env.ALGA_COLOR_YELLOW)→ Creating tenant settings...($env.ALGA_COLOR_RESET)"
|
|
print $" Debug: Tenant ID = ($tenant_id)"
|
|
|
|
let settings_sql = if $skip_onboarding {
|
|
"INSERT INTO tenant_settings (tenant, onboarding_skipped, onboarding_completed, created_at, updated_at) VALUES (?, true, false, NOW(), NOW()) ON CONFLICT (tenant) DO UPDATE SET onboarding_skipped = true, updated_at = NOW()"
|
|
} else {
|
|
"INSERT INTO tenant_settings (tenant, onboarding_skipped, onboarding_completed, created_at, updated_at) VALUES (?, false, false, NOW(), NOW()) ON CONFLICT (tenant) DO NOTHING"
|
|
}
|
|
|
|
let settings_result = (
|
|
cd $"($project_root)/server"; node scripts/run-sql.cjs migration $settings_sql $tenant_id
|
|
| complete
|
|
)
|
|
|
|
if $settings_result.exit_code == 0 {
|
|
if $skip_onboarding {
|
|
print $"($env.ALGA_COLOR_GREEN)✓ Tenant settings created with onboarding skipped($env.ALGA_COLOR_RESET)"
|
|
} else {
|
|
print $"($env.ALGA_COLOR_GREEN)✓ Tenant settings created($env.ALGA_COLOR_RESET)"
|
|
}
|
|
} else {
|
|
print $"($env.ALGA_COLOR_YELLOW)⚠ Could not create tenant settings($env.ALGA_COLOR_RESET)"
|
|
# Try to debug the error
|
|
print $"Debug: ($settings_result.stderr)"
|
|
}
|
|
|
|
# Run onboarding seeds if requested
|
|
if $seed_onboarding {
|
|
print $"\n($env.ALGA_COLOR_YELLOW)→ Running onboarding seeds...($env.ALGA_COLOR_RESET)"
|
|
seed-tenant-onboarding $tenant_id
|
|
}
|
|
|
|
print $"\n($env.ALGA_COLOR_GREEN)✓ Tenant setup complete!($env.ALGA_COLOR_RESET)"
|
|
print $" Login URL: http://localhost:3000"
|
|
print $" Email: ($admin_email)"
|
|
if $password == "" {
|
|
print $" Password: ($temp_password)"
|
|
}
|
|
}
|
|
|
|
# Seed a tenant with onboarding data
|
|
export def seed-tenant-onboarding [
|
|
tenant_id: string # The tenant ID to seed
|
|
] {
|
|
print $"($env.ALGA_COLOR_CYAN)Seeding onboarding data for tenant: ($tenant_id)($env.ALGA_COLOR_RESET)"
|
|
|
|
# Get the project root
|
|
let project_root = (find-project-root)
|
|
|
|
# Run all seeds from the onboarding directory
|
|
print $"($env.ALGA_COLOR_YELLOW)→ Running all onboarding seeds...($env.ALGA_COLOR_RESET)"
|
|
|
|
# Create a temporary knexfile that points to the onboarding directory
|
|
let temp_knexfile_content = "
|
|
const baseConfig = require('./knexfile.cjs');
|
|
module.exports = {
|
|
...baseConfig,
|
|
migration: {
|
|
...baseConfig.migration,
|
|
seeds: {
|
|
directory: './seeds/dev/onboarding',
|
|
loadExtensions: ['.cjs', '.js']
|
|
}
|
|
}
|
|
};"
|
|
|
|
# Write the temporary knexfile
|
|
let temp_knexfile_path = $"($project_root)/server/knexfile.onboarding.cjs"
|
|
$temp_knexfile_content | save -f $temp_knexfile_path
|
|
|
|
# Run the seeds
|
|
let result = (
|
|
cd $"($project_root)/server"; with-env {TENANT_ID: $tenant_id} { npx knex seed:run --knexfile knexfile.onboarding.cjs --env migration }
|
|
| complete
|
|
)
|
|
|
|
# Clean up the temporary file
|
|
rm -f $temp_knexfile_path
|
|
|
|
if $result.exit_code != 0 {
|
|
print $"($env.ALGA_COLOR_RED)✗ Failed to run onboarding seeds($env.ALGA_COLOR_RESET)"
|
|
print $"Error: ($result.stderr)"
|
|
return
|
|
}
|
|
|
|
print $"($env.ALGA_COLOR_GREEN)✓ All onboarding seeds completed($env.ALGA_COLOR_RESET)"
|
|
|
|
print $"\n($env.ALGA_COLOR_GREEN)✓ Onboarding seeds completed!($env.ALGA_COLOR_RESET)"
|
|
}
|
|
|
|
# List all tenants
|
|
export def list-tenants [] {
|
|
print $"($env.ALGA_COLOR_CYAN)Listing all tenants($env.ALGA_COLOR_RESET)\n"
|
|
|
|
# Get the project root
|
|
let project_root = (find-project-root)
|
|
|
|
# Query the database for tenants
|
|
let sql = "SELECT t.tenant, t.client_name, t.email, t.created_at, ts.onboarding_completed, ts.onboarding_skipped FROM tenants t LEFT JOIN tenant_settings ts ON t.tenant = ts.tenant ORDER BY t.created_at DESC"
|
|
let result = (
|
|
cd $"($project_root)/server"; node scripts/run-sql.cjs migration $sql 2>/dev/null
|
|
| complete
|
|
)
|
|
|
|
if $result.exit_code != 0 {
|
|
print $"($env.ALGA_COLOR_RED)✗ Failed to list tenants($env.ALGA_COLOR_RESET)"
|
|
print $"Error: ($result.stderr)"
|
|
return
|
|
}
|
|
|
|
# Parse and display results
|
|
let tenants = ($result.stdout | from json)
|
|
|
|
if ($tenants | length) == 0 {
|
|
print "No tenants found."
|
|
return
|
|
}
|
|
|
|
# Display as a table
|
|
$tenants | table
|
|
}
|
|
|
|
# Delete a tenant (use with caution!)
|
|
export def delete-tenant [
|
|
tenant_id: string # The tenant ID to delete
|
|
--force = false # Skip confirmation
|
|
] {
|
|
if not $force {
|
|
print $"($env.ALGA_COLOR_YELLOW)⚠️ WARNING: This will permanently delete the tenant and all associated data!($env.ALGA_COLOR_RESET)"
|
|
let confirm = (input $"Are you sure you want to delete tenant ($tenant_id)? (yes/no): ")
|
|
|
|
if $confirm != "yes" {
|
|
print "Deletion cancelled."
|
|
return
|
|
}
|
|
}
|
|
|
|
print $"($env.ALGA_COLOR_RED)Deleting tenant: ($tenant_id)($env.ALGA_COLOR_RESET)"
|
|
|
|
# Get the project root
|
|
let project_root = (find-project-root)
|
|
|
|
# Use the rollback function from the tenant creation module
|
|
let result = (
|
|
cd $"($project_root)/server"; npm run --silent rollback-tenant -- --tenantId $"($tenant_id)"
|
|
| complete
|
|
)
|
|
|
|
if $result.exit_code != 0 {
|
|
print $"($env.ALGA_COLOR_RED)✗ Failed to delete tenant($env.ALGA_COLOR_RESET)"
|
|
print $"Error: ($result.stderr)"
|
|
return
|
|
}
|
|
|
|
print $"($env.ALGA_COLOR_GREEN)✓ Tenant deleted successfully($env.ALGA_COLOR_RESET)"
|
|
} |