- Create new @link-stack/logger package wrapping Pino for structured logging - Replace all console.log/error/warn statements across the monorepo - Configure environment-aware logging (pretty-print in dev, JSON in prod) - Add automatic redaction of sensitive fields (passwords, tokens, etc.) - Remove dead commented-out logger file from bridge-worker - Follow Pino's standard argument order (context object first, message second) - Support log levels via LOG_LEVEL environment variable - Export TypeScript types for better IDE support This provides consistent, structured logging across all applications and packages, making debugging easier and production logs more parseable.
205 lines
4.8 KiB
TypeScript
205 lines
4.8 KiB
TypeScript
"use server";
|
|
|
|
import { getTicketQuery } from "app/_graphql/getTicketQuery";
|
|
import { getTicketArticlesQuery } from "app/_graphql/getTicketArticlesQuery";
|
|
import { createTicketMutation } from "app/_graphql/createTicketMutation";
|
|
import { updateTicketMutation } from "app/_graphql/updateTicketMutation";
|
|
import { updateTagsMutation } from "app/_graphql/updateTagsMutation";
|
|
import { executeGraphQL, executeREST } from "app/_lib/zammad";
|
|
import { createLogger } from "@link-stack/logger";
|
|
|
|
const logger = createLogger('link-tickets');
|
|
|
|
export const createTicketAction = async (
|
|
currentState: any,
|
|
formData: FormData,
|
|
) => {
|
|
try {
|
|
const ticket = {
|
|
groupId: formData.get("groupId"),
|
|
customerId: formData.get("customerId"),
|
|
title: formData.get("title"),
|
|
article: {
|
|
internal: true,
|
|
body: formData.get("details"),
|
|
},
|
|
};
|
|
|
|
await executeGraphQL({
|
|
query: createTicketMutation,
|
|
variables: {
|
|
input: ticket,
|
|
},
|
|
});
|
|
|
|
return {
|
|
...currentState,
|
|
values: ticket,
|
|
success: true,
|
|
};
|
|
} catch (e: any) {
|
|
logger.error({ error: e }, "Error occurred");
|
|
return {
|
|
success: false,
|
|
values: {},
|
|
message: e?.message ?? "Unknown error",
|
|
};
|
|
}
|
|
};
|
|
|
|
export const createTicketArticleAction = async (
|
|
ticketID: string,
|
|
article: Record<string, any>,
|
|
) => {
|
|
try {
|
|
const result = await executeGraphQL({
|
|
query: updateTicketMutation,
|
|
variables: {
|
|
ticketId: `gid://zammad/Ticket/${ticketID}`,
|
|
input: { article },
|
|
},
|
|
});
|
|
|
|
return {
|
|
result,
|
|
success: true,
|
|
};
|
|
} catch (e: any) {
|
|
logger.error({ error: e }, "Error occurred");
|
|
return {
|
|
success: false,
|
|
message: e?.message ?? "Unknown error",
|
|
};
|
|
}
|
|
};
|
|
|
|
export const updateTicketAction = async (
|
|
ticketID: string,
|
|
ticketInfo: Record<string, any>,
|
|
) => {
|
|
try {
|
|
const input = {};
|
|
if (ticketInfo.state) {
|
|
input["stateId"] = ticketInfo.state;
|
|
}
|
|
if (ticketInfo.pendingTime) {
|
|
input["pendingTime"] = ticketInfo.pendingTime;
|
|
}
|
|
if (ticketInfo.priority) {
|
|
input["priorityId"] = ticketInfo.priority;
|
|
}
|
|
if (ticketInfo.group) {
|
|
input["groupId"] = ticketInfo.group;
|
|
}
|
|
if (ticketInfo.owner) {
|
|
input["ownerId"] = ticketInfo.owner;
|
|
}
|
|
|
|
const result = await executeGraphQL({
|
|
query: updateTicketMutation,
|
|
variables: {
|
|
ticketId: `gid://zammad/Ticket/${ticketID}`,
|
|
input,
|
|
},
|
|
});
|
|
|
|
if (ticketInfo.tags?.length > 0) {
|
|
const tagsResult = await executeGraphQL({
|
|
query: updateTagsMutation,
|
|
variables: {
|
|
objectId: `gid://zammad/Ticket/${ticketID}`,
|
|
tags: ticketInfo.tags,
|
|
},
|
|
});
|
|
}
|
|
|
|
return {
|
|
result,
|
|
success: true,
|
|
};
|
|
} catch (e: any) {
|
|
logger.error({ error: e }, "Error occurred");
|
|
return {
|
|
success: false,
|
|
message: e?.message ?? "Unknown error",
|
|
};
|
|
}
|
|
};
|
|
|
|
export const getTicketAction = async (id: string) => {
|
|
try {
|
|
const ticketData = await executeGraphQL({
|
|
query: getTicketQuery,
|
|
variables: { ticketId: `gid://zammad/Ticket/${id}` },
|
|
});
|
|
|
|
return ticketData?.ticket;
|
|
} catch (e) {
|
|
logger.error({ error: e }, "Error occurred");
|
|
return {};
|
|
}
|
|
};
|
|
|
|
export const getTicketArticlesAction = async (id: string) => {
|
|
try {
|
|
const ticketData = await executeGraphQL({
|
|
query: getTicketArticlesQuery,
|
|
variables: { ticketId: `gid://zammad/Ticket/${id}` },
|
|
});
|
|
|
|
return ticketData?.ticketArticles;
|
|
} catch (e) {
|
|
logger.error({ error: e }, "Error occurred");
|
|
return {};
|
|
}
|
|
};
|
|
|
|
export const getTicketStatesAction = async () => {
|
|
try {
|
|
const states = await executeREST({
|
|
path: "/api/v1/ticket_states",
|
|
});
|
|
const formattedStates =
|
|
states?.map((state: any) => ({
|
|
value: `gid://zammad/Ticket::State/${state.id}`,
|
|
label: state.name,
|
|
disabled: ["new", "merged", "removed"].includes(state.name),
|
|
})) ?? [];
|
|
return formattedStates;
|
|
} catch (e) {
|
|
logger.error({ error: e }, "Error occurred");
|
|
return [];
|
|
}
|
|
};
|
|
|
|
export const getTagsAction = async () => {
|
|
try {
|
|
const { tags } = await executeREST({
|
|
path: "/api/v1/tags",
|
|
});
|
|
|
|
return tags;
|
|
} catch (e) {
|
|
logger.error({ error: e }, "Error occurred");
|
|
return [];
|
|
}
|
|
};
|
|
|
|
export const getTicketPrioritiesAction = async () => {
|
|
try {
|
|
const priorities = await executeREST({
|
|
path: "/api/v1/ticket_priorities",
|
|
});
|
|
|
|
const formattedPriorities =
|
|
priorities?.map((priority: any) => ({
|
|
value: `gid://zammad/Ticket::Priority/${priority.id}`,
|
|
label: priority.name,
|
|
})) ?? [];
|
|
|
|
return formattedPriorities;
|
|
} catch (e) {
|
|
logger.error({ error: e }, "Error occurred");
|
|
return [];
|
|
}
|
|
};
|