/** * 看板工单归属判定:范围切到「团队全部」后同事的工单也会上板,这类卡片 * 只读——能看详情、spec/plan、PR 改动,不能改列、开会话、合并或删除。 * * 口径与 webhook/eventOwnership 一致:有 assignee 时指派即真相;无 assignee * 的存量工单退回创建者。身份未知(token 解析失败)时一律按「我的」放行, * 宁可不锁也不能把自己的板锁死。 */ export interface IssueOwnershipFacts { /** Gitea 工单创建者 login;YouTrack 工单没有该字段。 */ poster?: string /** Gitea assignee login 列表;空/缺省表示未指派。 */ assignees?: string[] } /** 该工单是否归当前登录者所有(可写)。 */ export function isIssueMine(facts: IssueOwnershipFacts, me: string | undefined): boolean { if (me === undefined) return true const assignees = facts.assignees ?? [] if (assignees.length > 0) return assignees.includes(me) // 无 assignee:创建者说了算;poster 缺省(非 Gitea 来源)不参与判定。 return facts.poster === undefined || facts.poster === me } /** 卡片头像取谁:assignee 优先(责任人),否则创建者。都没有则 undefined。 */ export function issueOwnerLogin(facts: IssueOwnershipFacts): string | undefined { return (facts.assignees ?? [])[0] ?? facts.poster }