Update
This commit is contained in:
1 parent
0c14a3acbd
commit
2105a0c5f7
11 files changed
+442
-86
No files matched your search
+5
-2
@@ -22,6 +22,7 @@ export type AuthUser = {
|
||||
zammad_session_note_default_enabled: boolean;
|
||||
zammad_time_unit_rounding_enabled: boolean;
|
||||
zammad_time_unit_rounding_minutes: number;
|
||||
zammad_article_type_id: number;
|
||||
};
|
||||
|
||||
declare global {
|
||||
@@ -87,7 +88,8 @@ function publicUser(user: AuthUser) {
|
||||
session_billing_prompt_enabled: Boolean(user.session_billing_prompt_enabled),
|
||||
zammad_session_note_default_enabled: Boolean(user.zammad_session_note_default_enabled),
|
||||
zammad_time_unit_rounding_enabled: Boolean(user.zammad_time_unit_rounding_enabled),
|
||||
zammad_time_unit_rounding_minutes: Number(user.zammad_time_unit_rounding_minutes ?? 15)
|
||||
zammad_time_unit_rounding_minutes: Number(user.zammad_time_unit_rounding_minutes ?? 15),
|
||||
zammad_article_type_id: Number(user.zammad_article_type_id ?? 6)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -149,7 +151,8 @@ export async function requireAuth(req: Request, res: Response, next: NextFunctio
|
||||
u.session_billing_prompt_enabled,
|
||||
u.zammad_session_note_default_enabled,
|
||||
u.zammad_time_unit_rounding_enabled,
|
||||
u.zammad_time_unit_rounding_minutes
|
||||
u.zammad_time_unit_rounding_minutes,
|
||||
u.zammad_article_type_id
|
||||
FROM auth_sessions s
|
||||
JOIN users u ON u.id = s.user_id
|
||||
WHERE s.token_hash = $1
|
||||
|
||||
+158
-15
@@ -240,6 +240,20 @@ function parseZammadTimeUnitRoundingMinutes(value: unknown, fallback = 15) {
|
||||
return minutes;
|
||||
}
|
||||
|
||||
function parseZammadArticleTypeId(value: unknown, fallback = 6) {
|
||||
if (value === undefined || value === null || value === "") {
|
||||
return fallback ?? 6;
|
||||
}
|
||||
|
||||
const typeId = Number(value);
|
||||
|
||||
if (![1, 2, 3, 4, 5, 6].includes(typeId)) {
|
||||
throw badRequest("zammadArticleTypeId must be 1, 2, 3, 4, 5 or 6");
|
||||
}
|
||||
|
||||
return typeId;
|
||||
}
|
||||
|
||||
function optionalTicketSessionMonth(value: unknown) {
|
||||
if (value === undefined || value === null || value === "" || value === "all") {
|
||||
return null;
|
||||
@@ -635,12 +649,14 @@ type ZammadSessionArticlePayload = {
|
||||
body: string;
|
||||
content_type: "text/plain";
|
||||
time_unit: number;
|
||||
accounted_time_type_id: number;
|
||||
};
|
||||
|
||||
function zammadSessionArticlePayload(input: {
|
||||
zammadTicketId: string | number;
|
||||
activity: string;
|
||||
timeUnit: number;
|
||||
articleTypeId: number;
|
||||
}): ZammadSessionArticlePayload {
|
||||
const ticketId = Number(input.zammadTicketId);
|
||||
|
||||
@@ -655,7 +671,8 @@ function zammadSessionArticlePayload(input: {
|
||||
subject: "TicketTracker Session",
|
||||
body: input.activity,
|
||||
content_type: "text/plain",
|
||||
time_unit: input.timeUnit
|
||||
time_unit: input.timeUnit,
|
||||
accounted_time_type_id: input.articleTypeId
|
||||
};
|
||||
}
|
||||
|
||||
@@ -672,6 +689,7 @@ async function enqueueZammadSessionArticle(client: pg.PoolClient, input: {
|
||||
zammadTicketId: string | number | null;
|
||||
activity: string;
|
||||
timeUnit: number;
|
||||
articleTypeId: number;
|
||||
error: string;
|
||||
}) {
|
||||
await client.query(
|
||||
@@ -684,14 +702,16 @@ async function enqueueZammadSessionArticle(client: pg.PoolClient, input: {
|
||||
zammad_ticket_id,
|
||||
activity,
|
||||
time_unit,
|
||||
zammad_article_type_id,
|
||||
last_error
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
ON CONFLICT (session_id) WHERE status = 'pending'
|
||||
DO UPDATE SET
|
||||
zammad_ticket_id = COALESCE(EXCLUDED.zammad_ticket_id, zammad_session_article_queue.zammad_ticket_id),
|
||||
activity = EXCLUDED.activity,
|
||||
time_unit = EXCLUDED.time_unit,
|
||||
zammad_article_type_id = EXCLUDED.zammad_article_type_id,
|
||||
last_error = EXCLUDED.last_error,
|
||||
updated_at = now();
|
||||
`,
|
||||
@@ -703,11 +723,55 @@ async function enqueueZammadSessionArticle(client: pg.PoolClient, input: {
|
||||
input.zammadTicketId,
|
||||
input.activity,
|
||||
input.timeUnit,
|
||||
input.articleTypeId,
|
||||
input.error.slice(0, 1000)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
async function recordZammadSessionArticleSent(client: pg.PoolClient, input: {
|
||||
userId: string;
|
||||
sessionId: string | number;
|
||||
ticketId: string | number;
|
||||
ticketNumber: string;
|
||||
zammadTicketId: string | number;
|
||||
activity: string;
|
||||
timeUnit: number;
|
||||
articleTypeId: number;
|
||||
articleId: number | null;
|
||||
}) {
|
||||
await client.query(
|
||||
`
|
||||
INSERT INTO zammad_session_article_queue (
|
||||
user_id,
|
||||
session_id,
|
||||
ticket_id,
|
||||
ticket_number,
|
||||
zammad_ticket_id,
|
||||
activity,
|
||||
time_unit,
|
||||
zammad_article_type_id,
|
||||
status,
|
||||
sent_at,
|
||||
zammad_article_id,
|
||||
last_error
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 'sent', now(), $9, NULL);
|
||||
`,
|
||||
[
|
||||
input.userId,
|
||||
input.sessionId,
|
||||
input.ticketId,
|
||||
input.ticketNumber,
|
||||
input.zammadTicketId,
|
||||
input.activity,
|
||||
input.timeUnit,
|
||||
input.articleTypeId,
|
||||
input.articleId
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function zammadArticleId(payload: unknown) {
|
||||
return isPlainObject(payload) ? numberOrNull(payload.id) : null;
|
||||
}
|
||||
@@ -721,6 +785,7 @@ type ZammadSessionArticleQueueRow = {
|
||||
zammad_ticket_id: string | null;
|
||||
activity: string;
|
||||
time_unit: string | number;
|
||||
zammad_article_type_id: number | null;
|
||||
};
|
||||
|
||||
async function retryZammadSessionArticleQueueRow(row: ZammadSessionArticleQueueRow) {
|
||||
@@ -750,7 +815,8 @@ async function retryZammadSessionArticleQueueRow(row: ZammadSessionArticleQueueR
|
||||
const payload = zammadSessionArticlePayload({
|
||||
zammadTicketId,
|
||||
activity: row.activity,
|
||||
timeUnit: Number(row.time_unit)
|
||||
timeUnit: Number(row.time_unit),
|
||||
articleTypeId: Number(row.zammad_article_type_id ?? 6)
|
||||
});
|
||||
const zammadResponse = await postZammadSessionArticleForUser(row.user_id, payload);
|
||||
const articleId = zammadArticleId(zammadResponse);
|
||||
@@ -1013,6 +1079,7 @@ type SessionCreationInput = {
|
||||
requestedProjectTeamspaceEntryId: number | null;
|
||||
billingStatus: "billable" | "billed" | "non_billable" | null;
|
||||
createZammadArticle: boolean;
|
||||
zammadArticleTypeId: number;
|
||||
startedAt: Date;
|
||||
endedAt: Date;
|
||||
durationSeconds: number;
|
||||
@@ -1034,6 +1101,7 @@ async function createSessionForUser(input: SessionCreationInput) {
|
||||
requestedProjectTeamspaceEntryId,
|
||||
billingStatus,
|
||||
createZammadArticle,
|
||||
zammadArticleTypeId,
|
||||
startedAt,
|
||||
endedAt,
|
||||
durationSeconds,
|
||||
@@ -1251,6 +1319,18 @@ async function createSessionForUser(input: SessionCreationInput) {
|
||||
);
|
||||
const session = sessionResult.rows[0];
|
||||
|
||||
const zammadArticle: {
|
||||
requested: boolean;
|
||||
status: "not_requested" | "sent" | "queued";
|
||||
error: string | null;
|
||||
articleId: number | null;
|
||||
} = {
|
||||
requested: createZammadArticle,
|
||||
status: createZammadArticle ? "queued" : "not_requested",
|
||||
error: null,
|
||||
articleId: null
|
||||
};
|
||||
|
||||
if (createZammadArticle) {
|
||||
const timeUnit = await zammadTimeUnitForUser(userId, durationSeconds);
|
||||
let zammadArticleTicketId = ticket.zammad_ticket_id;
|
||||
@@ -1276,9 +1356,23 @@ async function createSessionForUser(input: SessionCreationInput) {
|
||||
const payload = zammadSessionArticlePayload({
|
||||
zammadTicketId: zammadArticleTicketId,
|
||||
activity,
|
||||
timeUnit
|
||||
timeUnit,
|
||||
articleTypeId: zammadArticleTypeId
|
||||
});
|
||||
const zammadResponse = await postZammadSessionArticleForUser(userId, payload);
|
||||
zammadArticle.status = "sent";
|
||||
zammadArticle.articleId = zammadArticleId(zammadResponse);
|
||||
await recordZammadSessionArticleSent(client, {
|
||||
userId,
|
||||
sessionId: session.id,
|
||||
ticketId: ticket.id,
|
||||
ticketNumber,
|
||||
zammadTicketId: zammadArticleTicketId,
|
||||
activity,
|
||||
timeUnit,
|
||||
articleTypeId: zammadArticleTypeId,
|
||||
articleId: zammadArticle.articleId
|
||||
});
|
||||
await postZammadSessionArticleForUser(userId, payload);
|
||||
} catch (error) {
|
||||
zammadArticleError = errorMessage(error);
|
||||
}
|
||||
@@ -1287,6 +1381,8 @@ async function createSessionForUser(input: SessionCreationInput) {
|
||||
}
|
||||
|
||||
if (zammadArticleError) {
|
||||
zammadArticle.status = "queued";
|
||||
zammadArticle.error = zammadArticleError;
|
||||
await enqueueZammadSessionArticle(client, {
|
||||
userId,
|
||||
sessionId: session.id,
|
||||
@@ -1295,6 +1391,7 @@ async function createSessionForUser(input: SessionCreationInput) {
|
||||
zammadTicketId: zammadArticleTicketId,
|
||||
activity,
|
||||
timeUnit,
|
||||
articleTypeId: zammadArticleTypeId,
|
||||
error: zammadArticleError
|
||||
});
|
||||
}
|
||||
@@ -1319,7 +1416,8 @@ async function createSessionForUser(input: SessionCreationInput) {
|
||||
|
||||
return {
|
||||
ticket,
|
||||
session
|
||||
session,
|
||||
zammadArticle
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -1675,6 +1773,7 @@ async function createZammadEmailSessionFromWebhook(payload: unknown, deliveryId:
|
||||
requestedProjectTeamspaceEntryId: null,
|
||||
billingStatus: null,
|
||||
createZammadArticle: false,
|
||||
zammadArticleTypeId: 6,
|
||||
startedAt,
|
||||
endedAt,
|
||||
durationSeconds,
|
||||
@@ -4433,6 +4532,27 @@ async function getPeriodTicket(config: PeriodConfig, period: ParsedPeriod, ticke
|
||||
recurring_billing_id,
|
||||
recurring_billing_slot_id,
|
||||
recurring_occurrence_date,
|
||||
(
|
||||
SELECT status
|
||||
FROM zammad_session_article_queue
|
||||
WHERE session_id = sessions.id
|
||||
ORDER BY updated_at DESC
|
||||
LIMIT 1
|
||||
) AS zammad_article_status,
|
||||
(
|
||||
SELECT zammad_article_id::text
|
||||
FROM zammad_session_article_queue
|
||||
WHERE session_id = sessions.id
|
||||
ORDER BY updated_at DESC
|
||||
LIMIT 1
|
||||
) AS zammad_article_id,
|
||||
(
|
||||
SELECT zammad_article_type_id
|
||||
FROM zammad_session_article_queue
|
||||
WHERE session_id = sessions.id
|
||||
ORDER BY updated_at DESC
|
||||
LIMIT 1
|
||||
) AS zammad_article_type_id,
|
||||
project_teamspace_entry_id::text AS project_teamspace_entry_id,
|
||||
(
|
||||
SELECT teamspace_project
|
||||
@@ -4591,10 +4711,20 @@ async function getTicketDetails(ticketId: number, userId: string, filters: { mon
|
||||
s.recurring_billing_id,
|
||||
s.recurring_billing_slot_id,
|
||||
s.recurring_occurrence_date,
|
||||
za.status AS zammad_article_status,
|
||||
za.zammad_article_id::text AS zammad_article_id,
|
||||
za.zammad_article_type_id,
|
||||
s.project_teamspace_entry_id::text AS project_teamspace_entry_id,
|
||||
pte.teamspace_project AS project_teamspace_project
|
||||
FROM sessions s
|
||||
LEFT JOIN project_teamspace_entries pte ON pte.id = s.project_teamspace_entry_id
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT status, zammad_article_id, zammad_article_type_id
|
||||
FROM zammad_session_article_queue
|
||||
WHERE session_id = s.id
|
||||
ORDER BY updated_at DESC
|
||||
LIMIT 1
|
||||
) za ON true
|
||||
WHERE ${sessionWhere}
|
||||
ORDER BY s.started_at ASC;
|
||||
`,
|
||||
@@ -4841,11 +4971,12 @@ app.post("/api/setup/admin", async (req, res) => {
|
||||
zammad_session_note_default_enabled: boolean;
|
||||
zammad_time_unit_rounding_enabled: boolean;
|
||||
zammad_time_unit_rounding_minutes: number;
|
||||
zammad_article_type_id: number | null;
|
||||
}>(
|
||||
`
|
||||
INSERT INTO users (username, display_name, password_hash, role, active)
|
||||
VALUES ($1, $2, $3, 'admin', true)
|
||||
RETURNING id, username, display_name, role, active, zammad_user_id::text AS zammad_user_id, (zammad_api_token IS NOT NULL) AS has_zammad_api_token, zammad_email_session_webhook_enabled, session_billing_prompt_enabled, zammad_session_note_default_enabled, zammad_time_unit_rounding_enabled, zammad_time_unit_rounding_minutes;
|
||||
RETURNING id, username, display_name, role, active, zammad_user_id::text AS zammad_user_id, (zammad_api_token IS NOT NULL) AS has_zammad_api_token, zammad_email_session_webhook_enabled, session_billing_prompt_enabled, zammad_session_note_default_enabled, zammad_time_unit_rounding_enabled, zammad_time_unit_rounding_minutes, zammad_article_type_id;
|
||||
`,
|
||||
[username, displayName, await hashPassword(password)]
|
||||
);
|
||||
@@ -4906,6 +5037,7 @@ app.post("/api/auth/login", async (req, res) => {
|
||||
zammad_session_note_default_enabled: boolean;
|
||||
zammad_time_unit_rounding_enabled: boolean;
|
||||
zammad_time_unit_rounding_minutes: number;
|
||||
zammad_article_type_id: number | null;
|
||||
}>(
|
||||
`
|
||||
SELECT
|
||||
@@ -4921,7 +5053,8 @@ app.post("/api/auth/login", async (req, res) => {
|
||||
session_billing_prompt_enabled,
|
||||
zammad_session_note_default_enabled,
|
||||
zammad_time_unit_rounding_enabled,
|
||||
zammad_time_unit_rounding_minutes
|
||||
zammad_time_unit_rounding_minutes,
|
||||
zammad_article_type_id
|
||||
FROM users
|
||||
WHERE lower(username) = lower($1);
|
||||
`,
|
||||
@@ -4971,7 +5104,8 @@ app.post("/api/auth/login", async (req, res) => {
|
||||
session_billing_prompt_enabled: user.session_billing_prompt_enabled,
|
||||
zammad_session_note_default_enabled: user.zammad_session_note_default_enabled,
|
||||
zammad_time_unit_rounding_enabled: user.zammad_time_unit_rounding_enabled,
|
||||
zammad_time_unit_rounding_minutes: user.zammad_time_unit_rounding_minutes
|
||||
zammad_time_unit_rounding_minutes: user.zammad_time_unit_rounding_minutes,
|
||||
zammad_article_type_id: user.zammad_article_type_id
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -5189,6 +5323,9 @@ app.patch("/api/auth/me", async (req, res) => {
|
||||
const zammadTimeUnitRoundingMinutes = user.role === "user"
|
||||
? parseZammadTimeUnitRoundingMinutes(req.body.zammadTimeUnitRoundingMinutes, user.zammad_time_unit_rounding_minutes)
|
||||
: 15;
|
||||
const zammadArticleTypeId = user.role === "user"
|
||||
? parseZammadArticleTypeId(req.body.zammadArticleTypeId, user.zammad_article_type_id)
|
||||
: 6;
|
||||
|
||||
if (newPassword && newPassword.length < 6) {
|
||||
throw badRequest("newPassword must be at least 6 characters");
|
||||
@@ -5221,9 +5358,10 @@ app.patch("/api/auth/me", async (req, res) => {
|
||||
zammad_session_note_default_enabled = CASE WHEN $8::boolean THEN $11 ELSE zammad_session_note_default_enabled END,
|
||||
zammad_time_unit_rounding_enabled = CASE WHEN $8::boolean THEN $12 ELSE zammad_time_unit_rounding_enabled END,
|
||||
zammad_time_unit_rounding_minutes = CASE WHEN $8::boolean THEN $13 ELSE zammad_time_unit_rounding_minutes END,
|
||||
zammad_article_type_id = CASE WHEN $8::boolean THEN $14 ELSE zammad_article_type_id END,
|
||||
updated_at = now()
|
||||
WHERE id = $4
|
||||
RETURNING id, username, display_name, role, active, zammad_user_id::text AS zammad_user_id, (zammad_api_token IS NOT NULL) AS has_zammad_api_token, zammad_email_session_webhook_enabled, session_billing_prompt_enabled, zammad_session_note_default_enabled, zammad_time_unit_rounding_enabled, zammad_time_unit_rounding_minutes;
|
||||
RETURNING id, username, display_name, role, active, zammad_user_id::text AS zammad_user_id, (zammad_api_token IS NOT NULL) AS has_zammad_api_token, zammad_email_session_webhook_enabled, session_billing_prompt_enabled, zammad_session_note_default_enabled, zammad_time_unit_rounding_enabled, zammad_time_unit_rounding_minutes, zammad_article_type_id;
|
||||
`,
|
||||
[
|
||||
username,
|
||||
@@ -5238,7 +5376,8 @@ app.patch("/api/auth/me", async (req, res) => {
|
||||
sessionBillingPromptEnabled,
|
||||
zammadSessionNoteDefaultEnabled,
|
||||
zammadTimeUnitRoundingEnabled,
|
||||
zammadTimeUnitRoundingMinutes
|
||||
zammadTimeUnitRoundingMinutes,
|
||||
zammadArticleTypeId
|
||||
]
|
||||
);
|
||||
|
||||
@@ -5266,7 +5405,7 @@ app.patch("/api/auth/me", async (req, res) => {
|
||||
app.get("/api/admin/users", requireAdmin, async (_req, res) => {
|
||||
const result = await query(
|
||||
`
|
||||
SELECT id, username, display_name, role, active, zammad_user_id::text AS zammad_user_id, (zammad_api_token IS NOT NULL) AS has_zammad_api_token, zammad_email_session_webhook_enabled, session_billing_prompt_enabled, zammad_session_note_default_enabled, zammad_time_unit_rounding_enabled, zammad_time_unit_rounding_minutes, created_at, updated_at
|
||||
SELECT id, username, display_name, role, active, zammad_user_id::text AS zammad_user_id, (zammad_api_token IS NOT NULL) AS has_zammad_api_token, zammad_email_session_webhook_enabled, session_billing_prompt_enabled, zammad_session_note_default_enabled, zammad_time_unit_rounding_enabled, zammad_time_unit_rounding_minutes, zammad_article_type_id, created_at, updated_at
|
||||
FROM users
|
||||
ORDER BY username ASC;
|
||||
`
|
||||
@@ -5290,7 +5429,7 @@ app.post("/api/admin/users", requireAdmin, async (req, res) => {
|
||||
`
|
||||
INSERT INTO users (username, display_name, password_hash, role, active)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id, username, display_name, role, active, zammad_user_id::text AS zammad_user_id, (zammad_api_token IS NOT NULL) AS has_zammad_api_token, zammad_email_session_webhook_enabled, session_billing_prompt_enabled, zammad_session_note_default_enabled, zammad_time_unit_rounding_enabled, zammad_time_unit_rounding_minutes, created_at, updated_at;
|
||||
RETURNING id, username, display_name, role, active, zammad_user_id::text AS zammad_user_id, (zammad_api_token IS NOT NULL) AS has_zammad_api_token, zammad_email_session_webhook_enabled, session_billing_prompt_enabled, zammad_session_note_default_enabled, zammad_time_unit_rounding_enabled, zammad_time_unit_rounding_minutes, zammad_article_type_id, created_at, updated_at;
|
||||
`,
|
||||
[username, displayName, await hashPassword(password), "user", active]
|
||||
);
|
||||
@@ -5351,7 +5490,7 @@ app.patch("/api/admin/users/:userId", requireAdmin, async (req, res) => {
|
||||
password_hash = COALESCE($4, password_hash),
|
||||
updated_at = now()
|
||||
WHERE id = $5
|
||||
RETURNING id, username, display_name, role, active, zammad_user_id::text AS zammad_user_id, (zammad_api_token IS NOT NULL) AS has_zammad_api_token, zammad_email_session_webhook_enabled, session_billing_prompt_enabled, zammad_session_note_default_enabled, zammad_time_unit_rounding_enabled, zammad_time_unit_rounding_minutes, created_at, updated_at;
|
||||
RETURNING id, username, display_name, role, active, zammad_user_id::text AS zammad_user_id, (zammad_api_token IS NOT NULL) AS has_zammad_api_token, zammad_email_session_webhook_enabled, session_billing_prompt_enabled, zammad_session_note_default_enabled, zammad_time_unit_rounding_enabled, zammad_time_unit_rounding_minutes, zammad_article_type_id, created_at, updated_at;
|
||||
`,
|
||||
[username, displayName, active, password ? await hashPassword(password) : null, userId]
|
||||
);
|
||||
@@ -6329,6 +6468,7 @@ app.post("/api/sessions", requireUser, async (req, res) => {
|
||||
const requestedProjectTeamspaceEntryId = parseOptionalTeamspaceEntryId(req.body.projectTeamspaceEntryId);
|
||||
const billingStatus = req.body.billingStatus === undefined ? null : parseBillingStatus(req.body.billingStatus);
|
||||
const createZammadArticle = optionalBoolean(req.body.createZammadArticle, false);
|
||||
const zammadArticleTypeId = parseZammadArticleTypeId(req.body.zammadArticleTypeId, user.zammad_article_type_id);
|
||||
const startedAt = parseIsoDate(req.body.startedAt, "startedAt");
|
||||
const endedAt = parseIsoDate(req.body.endedAt, "endedAt");
|
||||
const durationSeconds = parsePositiveInteger(req.body.durationSeconds, "durationSeconds");
|
||||
@@ -6343,6 +6483,7 @@ app.post("/api/sessions", requireUser, async (req, res) => {
|
||||
requestedProjectTeamspaceEntryId,
|
||||
billingStatus,
|
||||
createZammadArticle,
|
||||
zammadArticleTypeId,
|
||||
startedAt,
|
||||
endedAt,
|
||||
durationSeconds
|
||||
@@ -6362,6 +6503,7 @@ async function zammadSessionArticleQueueResponse(userId: string) {
|
||||
q.zammad_ticket_id::text AS zammad_ticket_id,
|
||||
q.activity,
|
||||
q.time_unit::float AS time_unit,
|
||||
q.zammad_article_type_id,
|
||||
q.attempt_count,
|
||||
q.last_error,
|
||||
q.last_attempt_at,
|
||||
@@ -6398,7 +6540,8 @@ app.post("/api/zammad/session-article-queue/retry", requireUser, async (req, res
|
||||
ticket_number,
|
||||
zammad_ticket_id::text AS zammad_ticket_id,
|
||||
activity,
|
||||
time_unit::text AS time_unit
|
||||
time_unit::text AS time_unit,
|
||||
zammad_article_type_id
|
||||
FROM zammad_session_article_queue
|
||||
WHERE user_id = $1
|
||||
AND status = 'pending'
|
||||
|
||||
@@ -91,11 +91,18 @@ export async function migrate() {
|
||||
await query("ALTER TABLE users ADD COLUMN IF NOT EXISTS zammad_session_note_default_enabled BOOLEAN NOT NULL DEFAULT false;");
|
||||
await query("ALTER TABLE users ADD COLUMN IF NOT EXISTS zammad_time_unit_rounding_enabled BOOLEAN NOT NULL DEFAULT false;");
|
||||
await query("ALTER TABLE users ADD COLUMN IF NOT EXISTS zammad_time_unit_rounding_minutes INTEGER NOT NULL DEFAULT 15;");
|
||||
await query("ALTER TABLE users ADD COLUMN IF NOT EXISTS zammad_article_type_id INTEGER DEFAULT 6;");
|
||||
await query("ALTER TABLE users ALTER COLUMN zammad_article_type_id DROP NOT NULL;");
|
||||
await query(`
|
||||
ALTER TABLE users
|
||||
DROP CONSTRAINT IF EXISTS users_zammad_time_unit_rounding_minutes_valid,
|
||||
ADD CONSTRAINT users_zammad_time_unit_rounding_minutes_valid CHECK (zammad_time_unit_rounding_minutes IN (5, 10, 15, 30));
|
||||
`);
|
||||
await query(`
|
||||
ALTER TABLE users
|
||||
DROP CONSTRAINT IF EXISTS users_zammad_article_type_id_valid,
|
||||
ADD CONSTRAINT users_zammad_article_type_id_valid CHECK (zammad_article_type_id IS NULL OR zammad_article_type_id IN (1, 2, 3, 4, 5, 6));
|
||||
`);
|
||||
|
||||
await query(`
|
||||
CREATE TABLE IF NOT EXISTS auth_sessions (
|
||||
@@ -266,6 +273,7 @@ export async function migrate() {
|
||||
zammad_ticket_id BIGINT,
|
||||
activity TEXT NOT NULL,
|
||||
time_unit NUMERIC(10, 2) NOT NULL,
|
||||
zammad_article_type_id INTEGER DEFAULT 6,
|
||||
status TEXT NOT NULL DEFAULT 'pending',
|
||||
attempt_count INTEGER NOT NULL DEFAULT 0,
|
||||
last_error TEXT,
|
||||
@@ -277,6 +285,13 @@ export async function migrate() {
|
||||
CONSTRAINT zammad_session_article_queue_status_valid CHECK (status IN ('pending', 'sent'))
|
||||
);
|
||||
`);
|
||||
await query("ALTER TABLE zammad_session_article_queue ADD COLUMN IF NOT EXISTS zammad_article_type_id INTEGER DEFAULT 6;");
|
||||
await query("ALTER TABLE zammad_session_article_queue ALTER COLUMN zammad_article_type_id DROP NOT NULL;");
|
||||
await query(`
|
||||
ALTER TABLE zammad_session_article_queue
|
||||
DROP CONSTRAINT IF EXISTS zammad_session_article_queue_type_id_valid,
|
||||
ADD CONSTRAINT zammad_session_article_queue_type_id_valid CHECK (zammad_article_type_id IS NULL OR zammad_article_type_id IN (1, 2, 3, 4, 5, 6));
|
||||
`);
|
||||
await query(`
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_zammad_session_article_queue_pending_session
|
||||
ON zammad_session_article_queue(session_id)
|
||||
|
||||
Reference in new issue
Block a user