diff --git a/apps/web/__tests__/unit/mobile-caps-list.test.ts b/apps/web/__tests__/unit/mobile-caps-list.test.ts index 55823a413c9..42a5a8cb056 100644 --- a/apps/web/__tests__/unit/mobile-caps-list.test.ts +++ b/apps/web/__tests__/unit/mobile-caps-list.test.ts @@ -57,6 +57,7 @@ let empty = false; let denied = false; let failDatabase = false; let failAnalytics = false; +let uploadRows = false; let latency = 0; let activeQueries = 0; let peakQueries = 0; @@ -67,6 +68,14 @@ function owner(index: number) { return !sharedList || index % 4 === 0 ? "viewer" : `owner-${index % 4}`; } +function joinsUpload(index: number, sql: string, params: unknown[]) { + if (!uploadRows || (index !== 5 && index !== 6)) return false; + const filter = sql.indexOf("`videos`.`isScreenshot` = ?"); + if (filter === -1) return true; + const isScreenshot = params[sql.slice(0, filter).split("?").length - 1]; + return isScreenshot === (index === 5); +} + function preferences(id: string) { return { blockedUserIds: @@ -111,13 +120,9 @@ const client = drizzle(async (sql, params) => { index === 7, 2, 1, - null, - null, - null, - null, - null, - null, - null, + ...(joinsUpload(index, sql, params) + ? [`video-${index}`, 1024, 2048, "uploading", 0, null, null] + : [null, null, null, null, null, null, null]), null, null, ]; @@ -257,6 +262,7 @@ beforeEach(() => { denied = false; failDatabase = false; failAnalytics = false; + uploadRows = false; latency = 0; activeQueries = 0; peakQueries = 0; @@ -334,6 +340,31 @@ describe("mobile Caps list", () => { expect((await response.json()).caps).toEqual(expectedCaps()); }); + it("shows video uploads but not leftover screenshot progress rows", async () => { + uploadRows = true; + const response = await list(); + expect(response.status).toBe(200); + expect((await response.json()).caps).toEqual( + expectedCaps().map((cap) => + cap.id === "video-6" + ? { + ...cap, + thumbnailUrl: null, + thumbnailCacheKey: null, + upload: { + uploaded: 1024, + total: 2048, + phase: "uploading", + processingProgress: 0, + processingMessage: null, + processingError: null, + }, + } + : cap, + ), + ); + }); + it("rejects inaccessible spaces before loading caps", async () => { denied = true; expect((await list("&spaceId=team")).status).toBe(403); diff --git a/apps/web/app/api/mobile/[...route]/route.ts b/apps/web/app/api/mobile/[...route]/route.ts index 6cdbe00c1ad..591cc95c2ba 100644 --- a/apps/web/app/api/mobile/[...route]/route.ts +++ b/apps/web/app/api/mobile/[...route]/route.ts @@ -356,6 +356,13 @@ const getUploadTitle = (fileName: string) => { return title.length > 0 ? title : "Mobile Upload"; }; +// Web image imports leave a progress row behind, and the web never treats a +// screenshot as uploading, so the app shouldn't either. +const activeUploadJoin = and( + eq(Db.videos.id, Db.videoUploads.videoId), + eq(Db.videos.isScreenshot, false), +); + const toMobileCapSummary = ( row: CapRow, viewCount: number, @@ -1633,7 +1640,7 @@ const getCapRows = Effect.fn("Mobile.getCapRows")(function* ( .from(Db.videos) .leftJoin(Db.comments, eq(Db.videos.id, Db.comments.videoId)) .leftJoin(Db.users, eq(Db.videos.ownerId, Db.users.id)) - .leftJoin(Db.videoUploads, eq(Db.videos.id, Db.videoUploads.videoId)) + .leftJoin(Db.videoUploads, activeUploadJoin) .where( inArray( Db.videos.id, @@ -1765,7 +1772,7 @@ const getCapStatuses = Effect.fn("Mobile.getCapStatuses")(function* ( processingError: Db.videoUploads.processingError, }) .from(Db.videos) - .leftJoin(Db.videoUploads, eq(Db.videos.id, Db.videoUploads.videoId)) + .leftJoin(Db.videoUploads, activeUploadJoin) .where(and(eq(Db.videos.ownerId, user.id), inArray(Db.videos.id, ids))), ); @@ -2141,7 +2148,7 @@ const getCapById = Effect.fn("Mobile.getCapById")(function* ( .from(Db.videos) .leftJoin(Db.comments, eq(Db.videos.id, Db.comments.videoId)) .leftJoin(Db.users, eq(Db.videos.ownerId, Db.users.id)) - .leftJoin(Db.videoUploads, eq(Db.videos.id, Db.videoUploads.videoId)) + .leftJoin(Db.videoUploads, activeUploadJoin) .where(eq(Db.videos.id, videoId)) .groupBy( Db.videos.id, @@ -2597,7 +2604,7 @@ const trackMobileCapView = Effect.fn("Mobile.trackCapView")(function* ( activeUploadVideoId: Db.videoUploads.videoId, }) .from(Db.videos) - .leftJoin(Db.videoUploads, eq(Db.videoUploads.videoId, Db.videos.id)) + .leftJoin(Db.videoUploads, activeUploadJoin) .where(eq(Db.videos.id, videoId)) .limit(1), );