feat: Implement Phase 10 support and recommendations features
- Added models for support messages, SLA policies, tickets, ticket events, and ticket links. - Created routes for help, help admin, newsletter, recommendations, and support for both customer and admin. - Developed services for help, marketing (newsletter), and recommendations. - Introduced support service for ticket management, including creation, replies, transitions, and attachments. - Added validation schemas for support recommendations and ticket management. - Implemented a cron job for support reconciliation and recommendation cleanup. - Created migration for new support and recommendation database tables. - Added unit tests for validation and policy checks related to Phase 10 features.
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
jest.mock("../../app/services/activity.service",()=>({logActivity:jest.fn()}));
|
||||
const schemas=require("../../app/validation/supportRecommendation.schemas"),newsletter=require("../../app/services/marketing/newsletter.service"),help=require("../../app/services/help/help.service"),support=require("../../app/services/support/support.service"),permissions=require("../../app/constants/permissions");
|
||||
const parse=(schema,body)=>schema.safeParse({body,params:{},query:{}});
|
||||
describe("Phase 10 validation and policy",()=>{
|
||||
test("ticket accepts safe customer fields",()=>expect(parse(schemas.ticketCreate,{subject:"Missing parcel",message:"Please check this order",attachmentIds:[],source:"WEB"}).success).toBe(true));
|
||||
test("ticket rejects ownership injection",()=>expect(parse(schemas.ticketCreate,{subject:"Missing parcel",message:"Please check",customerUserId:"other"}).success).toBe(false));
|
||||
test("customer cannot submit priority",()=>expect(parse(schemas.ticketCreate,{subject:"Urgent parcel",message:"Please check",priority:"URGENT"}).success).toBe(false));
|
||||
test("empty support messages are rejected",()=>expect(parse(schemas.message,{message:" "}).success).toBe(false));
|
||||
test("support attachments are bounded",()=>expect(parse(schemas.message,{message:"ok",attachmentIds:[1,2,3,4,5,6]}).success).toBe(false));
|
||||
test("ticket links use a strict resource allowlist",()=>expect(parse(schemas.link,{type:"USER",id:"x"}).success).toBe(false));
|
||||
test("closed tickets have no outbound transitions",()=>expect(support.transitions.CLOSED).toEqual([]));
|
||||
test("resolved tickets may explicitly reopen",()=>expect(support.transitions.RESOLVED).toContain("WAITING_FOR_SUPPORT"));
|
||||
test("newsletter email normalization is deterministic",()=>expect(newsletter.normalize(" PERSON@Example.COM ")).toBe("person@example.com"));
|
||||
test("newsletter authorization tokens are hashable without storage of raw token",()=>{const token="a-secure-random-token";expect(newsletter.hash(token)).toMatch(/^[a-f0-9]{64}$/);expect(newsletter.hash(token)).not.toBe(token);});
|
||||
test("newsletter source is allowlisted",()=>expect(parse(schemas.newsletter,{email:"a@example.com",source:"SCRAPED_LIST"}).success).toBe(false));
|
||||
test("client event schema only accepts product views",()=>expect(parse(schemas.viewEvent,{eventId:"evt-1",productId:"p1",eventType:"PURCHASE"}).success).toBe(false));
|
||||
test("client event rejects unknown mutation fields",()=>expect(parse(schemas.viewEvent,{eventId:"evt-1",productId:"p1",source:"WEB",email:"private@example.com"}).success).toBe(false));
|
||||
test("help content strips HTML tags",()=>expect(help.clean("<script>alert(1)</script>Safe")).toBe("alert(1)Safe"));
|
||||
test("all privileged Phase 10 permissions are explicit",()=>expect([permissions.SUPPORT_TICKETS_READ,permissions.HELP_MANAGE,permissions.NEWSLETTER_SUBSCRIBERS_READ,permissions.RECOMMENDATIONS_MANAGE]).toEqual(["support.tickets.read","help.manage","newsletter.subscribers.read","recommendations.manage"]));
|
||||
});
|
||||
Reference in New Issue
Block a user