fix: harden machine session fallback and clean lint

This commit is contained in:
Esdras Renan 2025-10-19 03:16:50 -03:00
parent 2607ca5ce3
commit 846e575637
6 changed files with 60 additions and 32 deletions

View file

@ -106,6 +106,53 @@ function normalizeTeams(teams?: string[] | null): string[] {
return teams.map((team) => renameQueueString(team) ?? team);
}
type RequesterFallbackContext = {
ticketId?: Id<"tickets">;
fallbackName?: string | null;
fallbackEmail?: string | null;
};
function buildRequesterSummary(
requester: Doc<"users"> | null,
requesterId: Id<"users">,
context?: RequesterFallbackContext,
) {
if (requester) {
return {
id: requester._id,
name: requester.name,
email: requester.email,
avatarUrl: requester.avatarUrl,
teams: normalizeTeams(requester.teams),
};
}
const idString = String(requesterId);
const fallbackName =
typeof context?.fallbackName === "string" && context.fallbackName.trim().length > 0
? context.fallbackName.trim()
: "Solicitante não encontrado";
const fallbackEmailCandidate =
typeof context?.fallbackEmail === "string" && context.fallbackEmail.includes("@")
? context.fallbackEmail
: null;
const fallbackEmail = fallbackEmailCandidate ?? `requester-${idString}@example.invalid`;
if (process.env.NODE_ENV !== "test") {
const ticketInfo = context?.ticketId ? ` (ticket ${String(context.ticketId)})` : "";
console.warn(
`[tickets] requester ${idString} ausente ao hidratar resposta${ticketInfo}; usando placeholders.`,
);
}
return {
id: requesterId,
name: fallbackName,
email: fallbackEmail,
teams: [],
};
}
type CustomFieldInput = {
fieldId: Id<"ticketFields">;
value: unknown;
@ -348,13 +395,7 @@ export const list = query({
channel: t.channel,
queue: queueName,
company: company ? { id: company._id, name: company.name, isAvulso: company.isAvulso ?? false } : null,
requester: requester && {
id: requester._id,
name: requester.name,
email: requester.email,
avatarUrl: requester.avatarUrl,
teams: normalizeTeams(requester.teams),
},
requester: buildRequesterSummary(requester, t.requesterId, { ticketId: t._id }),
assignee: assignee
? {
id: assignee._id,
@ -526,13 +567,7 @@ export const getById = query({
channel: t.channel,
queue: queueName,
company: company ? { id: company._id, name: company.name, isAvulso: company.isAvulso ?? false } : null,
requester: requester && {
id: requester._id,
name: requester.name,
email: requester.email,
avatarUrl: requester.avatarUrl,
teams: normalizeTeams(requester.teams),
},
requester: buildRequesterSummary(requester, t.requesterId, { ticketId: t._id }),
assignee: assignee
? {
id: assignee._id,
@ -1434,13 +1469,7 @@ export const playNext = mutation({
priority: chosen.priority,
channel: chosen.channel,
queue: queueName,
requester: requester && {
id: requester._id,
name: requester.name,
email: requester.email,
avatarUrl: requester.avatarUrl,
teams: normalizeTeams(requester.teams),
},
requester: buildRequesterSummary(requester, chosen.requesterId, { ticketId: chosen._id }),
assignee: assignee
? {
id: assignee._id,

View file

@ -2,9 +2,6 @@ import { mutation, query } from "./_generated/server";
import { ConvexError, v } from "convex/values";
import { requireAdmin } from "./rbac";
// All roles that have staff-level access in some areas. Do NOT include COLLABORATOR here
// to avoid leaking collaborators into staff pickers such as "responsável".
const STAFF_ROLES = new Set(["ADMIN", "MANAGER", "AGENT"]);
const INTERNAL_STAFF_ROLES = new Set(["ADMIN", "AGENT"]);
export const ensureUser = mutation({