mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-26 02:00:52 +01:00
fix(server): harden document star idempotency
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
1763f5a76b
commit
bcea9310b2
4 files changed
+25
-13
No files matched your search
@@ -397,6 +397,12 @@ describeEmbeddedPostgres("companyArtifactsService", () => {
|
||||
expect(second.status).toBe(200);
|
||||
expect(second.body.artifacts.map((artifact: { title: string }) => artifact.title)).toEqual(["User Upload Notes"]);
|
||||
expect(second.body.artifacts.every((artifact: { source: string }) => artifact.source === "document")).toBe(true);
|
||||
|
||||
const incompatibleKind = await request(app).get(
|
||||
`/api/companies/${companyId}/artifacts?starred=true&kind=image`,
|
||||
);
|
||||
expect(incompatibleKind.status).toBe(200);
|
||||
expect(incompatibleKind.body).toEqual({ artifacts: [], nextCursor: null });
|
||||
});
|
||||
|
||||
it("returns an empty starred view for agent callers", async () => {
|
||||
|
||||
@@ -429,12 +429,14 @@ describeEmbeddedPostgres("resource membership routes", () => {
|
||||
const { companyId, documentId } = await seed();
|
||||
const app = createApp(db, boardActor(companyId));
|
||||
|
||||
const first = await request(app)
|
||||
.put(`/api/companies/${companyId}/resource-memberships/me/documents/${documentId}`)
|
||||
.send({ starred: true });
|
||||
const second = await request(app)
|
||||
.put(`/api/companies/${companyId}/resource-memberships/me/documents/${documentId}`)
|
||||
.send({ starred: true });
|
||||
const [first, second] = await Promise.all([
|
||||
request(app)
|
||||
.put(`/api/companies/${companyId}/resource-memberships/me/documents/${documentId}`)
|
||||
.send({ starred: true }),
|
||||
request(app)
|
||||
.put(`/api/companies/${companyId}/resource-memberships/me/documents/${documentId}`)
|
||||
.send({ starred: true }),
|
||||
]);
|
||||
const list = await request(app).get(`/api/companies/${companyId}/resource-memberships/me`);
|
||||
|
||||
expect(first.status).toBe(200);
|
||||
|
||||
@@ -348,7 +348,7 @@ export function companyArtifactsService(db: Db, storage?: StorageService) {
|
||||
const artifactSortDates = new Map<string, string>();
|
||||
const workProductAttachmentIds = new Set<string>();
|
||||
|
||||
if (query.starred || query.kind === "all" || query.kind === "document") {
|
||||
if (query.kind === "all" || query.kind === "document") {
|
||||
const createdAgent = alias(agents, "document_created_agent");
|
||||
const updatedAgent = alias(agents, "document_updated_agent");
|
||||
const documentArtifactId = sql<string>`concat('document:', ${documents.id})`;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { and, eq, sql } from "drizzle-orm";
|
||||
import type { Db } from "@paperclipai/db";
|
||||
import {
|
||||
agentMemberships,
|
||||
@@ -491,19 +491,23 @@ export function resourceMembershipService(db: Db, options: ResourceMembershipSer
|
||||
.onConflictDoUpdate({
|
||||
target: [documentMemberships.companyId, documentMemberships.userId, documentMemberships.documentId],
|
||||
set: {
|
||||
starredAt: now,
|
||||
updatedAt: now,
|
||||
starredAt: sql`${documentMemberships.starredAt}`,
|
||||
updatedAt: sql`${documentMemberships.updatedAt}`,
|
||||
},
|
||||
})
|
||||
.returning();
|
||||
.returning({
|
||||
starredAt: documentMemberships.starredAt,
|
||||
updatedAt: documentMemberships.updatedAt,
|
||||
inserted: sql<boolean>`xmax = 0`,
|
||||
});
|
||||
return {
|
||||
resourceType: "document",
|
||||
resourceId: input.documentId,
|
||||
state: "joined",
|
||||
starredAt: row?.starredAt ?? now,
|
||||
updatedAt: row?.updatedAt ?? now,
|
||||
changed: true,
|
||||
changeKind: "starred",
|
||||
changed: row?.inserted === true,
|
||||
changeKind: row?.inserted === true ? "starred" : null,
|
||||
policySource: decision.source ?? "oss_default",
|
||||
};
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user