PSA/server/migrations/20250915165000_update_ticket_created_email_template.cjs
Hermes 284313f908
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
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

168 lines
7.5 KiB
JavaScript

/**
* Refresh the ticket-created system email template with richer branding details.
*/
exports.up = async function(knex) {
const template = await knex('system_email_templates')
.where({ name: 'ticket-created' })
.first();
if (!template) {
return;
}
const updatedSubject = 'New Ticket • {{ticket.title}} ({{ticket.priority}})';
const updatedHtmlContent = `
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:#f5f3ff;padding:32px 0;font-family:'Segoe UI',Arial,sans-serif;">
<tr>
<td align="center">
<table role="presentation" width="600" cellpadding="0" cellspacing="0" style="width:100%;max-width:600px;background:#ffffff;border-radius:16px;overflow:hidden;border:1px solid #e4ddff;box-shadow:0 12px 32px rgba(138,77,234,0.12);">
<tr>
<td style="padding:32px;background:linear-gradient(135deg,#8A4DEA,#40CFF9);color:#ffffff;">
<div style="text-transform:uppercase;letter-spacing:0.08em;font-size:12px;font-weight:600;opacity:0.85;">New Ticket Created</div>
<div style="font-size:22px;font-weight:600;margin-top:8px;">{{ticket.title}}</div>
<div style="margin-top:12px;font-size:14px;opacity:0.85;">{{ticket.metaLine}}</div>
</td>
</tr>
<tr>
<td style="padding:28px 32px 20px 32px;">
<p style="margin:0 0 16px 0;font-size:15px;color:#1f2933;line-height:1.5;">A new ticket has been logged for <strong>{{ticket.companyName}}</strong>. Review the summary below and follow the link to take action.</p>
<div style="margin-bottom:24px;">
<div style="display:inline-block;padding:6px 12px;border-radius:999px;background:rgba(138,77,234,0.12);color:#5b38b0;font-size:12px;font-weight:600;letter-spacing:0.02em;">Ticket #{{ticket.id}}</div>
</div>
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="border-collapse:collapse;font-size:14px;color:#1f2933;">
<tr>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;width:160px;font-weight:600;color:#475467;">Priority</td>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;">
<span style="display:inline-block;padding:6px 12px;border-radius:999px;background-color:{{ticket.priorityColor}};color:#ffffff;font-weight:600;">{{ticket.priority}}</span>
</td>
</tr>
<tr>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;font-weight:600;color:#475467;">Status</td>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;">{{ticket.status}}</td>
</tr>
<tr>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;font-weight:600;color:#475467;">Created</td>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;">{{ticket.createdAt}} · {{ticket.createdBy}}</td>
</tr>
<tr>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;font-weight:600;color:#475467;">Assigned To</td>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;">
<div style="font-weight:600;">{{ticket.assignedToName}}</div>
<div style="color:#667085;font-size:13px;">{{ticket.assignedToEmail}}</div>
</td>
</tr>
<tr>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;font-weight:600;color:#475467;">Requester</td>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;">
<div style="font-weight:600;">{{ticket.requesterName}}</div>
<div style="color:#667085;font-size:13px;">{{ticket.requesterContact}}</div>
</td>
</tr>
<tr>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;font-weight:600;color:#475467;">Channel</td>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;">{{ticket.channel}}</td>
</tr>
<tr>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;font-weight:600;color:#475467;">Category</td>
<td style="padding:12px 0;border-bottom:1px solid #eef2ff;">{{ticket.categoryDetails}}</td>
</tr>
<tr>
<td style="padding:12px 0;font-weight:600;color:#475467;">Location</td>
<td style="padding:12px 0;">{{ticket.locationSummary}}</td>
</tr>
</table>
<div style="margin:28px 0 16px 0;padding:18px 20px;border-radius:12px;background:#f8f5ff;border:1px solid #e6deff;">
<div style="font-weight:600;color:#5b38b0;margin-bottom:8px;">Description</div>
<div style="color:#475467;line-height:1.5;">{{ticket.description}}</div>
</div>
<a href="{{ticket.url}}" style="display:inline-block;background:#8A4DEA;color:#ffffff;text-decoration:none;padding:12px 24px;border-radius:10px;font-weight:600;">View Ticket</a>
</td>
</tr>
<tr>
<td style="padding:18px 32px;background:#f8f5ff;color:#5b38b0;font-size:12px;text-align:center;">Powered by Alga PSA • Keeping teams aligned</td>
</tr>
</table>
</td>
</tr>
</table>
`;
const updatedTextContent = `
New Ticket Created for {{ticket.companyName}}
{{ticket.metaLine}}
Created: {{ticket.createdAt}} · {{ticket.createdBy}}
Priority: {{ticket.priority}}
Status: {{ticket.status}}
Assigned To: {{ticket.assignedDetails}}
Requester: {{ticket.requesterDetails}}
Channel: {{ticket.channel}}
Category: {{ticket.categoryDetails}}
Location: {{ticket.locationSummary}}
Description:
{{ticket.description}}
View ticket: {{ticket.url}}
`;
await knex('system_email_templates')
.where({ id: template.id })
.update({
subject: updatedSubject,
html_content: updatedHtmlContent,
text_content: updatedTextContent,
updated_at: knex.fn.now()
});
};
exports.down = async function(knex) {
const template = await knex('system_email_templates')
.where({ name: 'ticket-created' })
.first();
if (!template) {
return;
}
const originalSubject = 'New Ticket: {{ticket.title}}';
const originalHtmlContent = `
<h2>New Ticket Created</h2>
<p>A new ticket has been created in your PSA system:</p>
<div class="details">
<p><strong>Ticket ID:</strong> {{ticket.id}}</p>
<p><strong>Title:</strong> {{ticket.title}}</p>
<p><strong>Description:</strong> {{ticket.description}}</p>
<p><strong>Priority:</strong> {{ticket.priority}}</p>
<p><strong>Status:</strong> {{ticket.status}}</p>
</div>
<a href="{{ticket.url}}" class="button">View Ticket</a>
`;
const originalTextContent = `
New Ticket Created
A new ticket has been created in your PSA system:
Ticket ID: {{ticket.id}}
Title: {{ticket.title}}
Description: {{ticket.description}}
Priority: {{ticket.priority}}
Status: {{ticket.status}}
View ticket at: {{ticket.url}}
`;
await knex('system_email_templates')
.where({ id: template.id })
.update({
subject: originalSubject,
html_content: originalHtmlContent,
text_content: originalTextContent,
updated_at: knex.fn.now()
});
};