Share every bot and workspace picture with everyone signed in

A bot's or workspace's picture was only shared when its media row carried
the bot-image or workspace-image paradigm. A picture set before pictures
were copied into their own row points at the chat upload itself, so only
its uploader could load it and everyone else saw the default icon. A
picture is now shared because a bot or workspace points at it, whatever
its paradigm; profile photos still have to be the user's primary one.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-25 04:08:16 +01:00
co-authored by Claude Opus 5.5
parent d542b4e9ad
commit feec69adca
2 changed files with 31 additions and 21 deletions
@@ -18,7 +18,9 @@ beforeAll(() => {
(5, 7, NULL, 0), (5, 7, NULL, 0),
(6, 7, NULL, 0), (6, 7, NULL, 0),
(7, 7, NULL, 0), (7, 7, NULL, 0),
(8, 7, NULL, 0)`); (8, 7, NULL, 0),
(10, 7, NULL, 0),
(11, 7, NULL, 0)`);
// 1: user 7's current photo, 2: user 8's, 3: an old photo of user 8's (no longer primary) // 1: user 7's current photo, 2: user 8's, 3: an old photo of user 8's (no longer primary)
db.run(`INSERT INTO media_paradigms VALUES db.run(`INSERT INTO media_paradigms VALUES
@@ -29,12 +31,14 @@ beforeAll(() => {
(5, 'bot-image'), (5, 'bot-image'),
(6, 'workspace-image'), (6, 'workspace-image'),
(7, 'workspace-image'), (7, 'workspace-image'),
(8, 'bot-file')`); (8, 'bot-file'),
(10, 'bot-attachment')`);
// 4: still bot 2's picture, 5: a bot picture no bot points at any more // 4: still bot 2's picture, 5: a bot picture no bot points at any more
db.run(`INSERT INTO bots VALUES (2, 4), (3, NULL)`); db.run(`INSERT INTO bots VALUES (2, 4), (3, NULL)`);
// 6: still workspace 10's picture, 7: a workspace picture nothing points at // 6: still workspace 10's picture, 7: a workspace picture nothing points at
db.run(`INSERT INTO workspaces VALUES (10, 6), (11, NULL)`); // 10: an older picture set straight from a chat upload, still workspace 12's
db.run(`INSERT INTO workspaces VALUES (10, 6), (11, NULL), (12, 10)`);
}); });
function visible({ archived }: { archived?: number } = {}) { function visible({ archived }: { archived?: number } = {}) {
@@ -52,12 +56,12 @@ function visible({ archived }: { archived?: number } = {}) {
describe("sharedPictureMediaSql", () => { describe("sharedPictureMediaSql", () => {
test("every user's current photo, and every bot's and workspace's picture", () => { test("every user's current photo, and every bot's and workspace's picture", () => {
expect(visible()).toEqual([1, 2, 4, 6]); expect(visible()).toEqual([1, 2, 4, 6, 10]);
}); });
test("archived media is not a picture anyone gets", () => { test("archived media is not a picture anyone gets", () => {
db.run(`UPDATE media SET archived = 1 WHERE id = 2`); db.run(`UPDATE media SET archived = 1 WHERE id = 2`);
expect(visible({ archived: 0 })).toEqual([1, 4, 6]); expect(visible({ archived: 0 })).toEqual([1, 4, 6, 10]);
db.run(`UPDATE media SET archived = 0 WHERE id = 2`); db.run(`UPDATE media SET archived = 0 WHERE id = 2`);
}); });
@@ -72,6 +76,11 @@ describe("sharedPictureMediaSql", () => {
test("anything else stays private, a bot's file among them", () => { test("anything else stays private, a bot's file among them", () => {
expect(visible()).not.toContain(8); expect(visible()).not.toContain(8);
expect(visible()).not.toContain(11);
});
test("a picture a workspace points at is shared whatever its paradigm", () => {
expect(visible()).toContain(10);
}); });
test("removing a picture row closes it at once", () => { test("removing a picture row closes it at once", () => {
@@ -13,28 +13,29 @@ type Params = {
* *
* - a member's current profile photo (their primary `user-profile-image`, * - a member's current profile photo (their primary `user-profile-image`,
* the one `grabUsers` reports as `profile_media_id`), * the one `grabUsers` reports as `profile_media_id`),
* - a bot's picture (`bots.image_media_id`), * - a bot's picture (whatever `bots.image_media_id` points at),
* - a workspace's picture (`workspaces.image_media_id`). * - a workspace's picture (whatever `workspaces.image_media_id` points at).
* *
* Bots and workspaces belong to the install, and people know each other by * Bots and workspaces belong to the install, and people know each other by
* their photo, so a picture is never limited to whoever happens to reach * their photo, so a picture is never limited to whoever happens to reach
* its owner. It does have to be one still in use: the paradigm alone is not * its owner. It does have to be one still in use: a profile photo's
* enough, since a removed picture leaves its paradigm row behind. * paradigm alone is not enough, since a removed photo leaves its paradigm
* row behind. A bot's or workspace's picture is shared because the bot or
* workspace points at it, not by its paradigm: a picture set before
* pictures were copied into their own `bot-image`/`workspace-image` row is
* the chat upload itself, and it is still the face everyone sees.
*/ */
export default function sharedPictureMediaSql({ alias = "m" }: Params = {}): SqlCondition { export default function sharedPictureMediaSql({ alias = "m" }: Params = {}): SqlCondition {
return { return {
sql: `EXISTS ( sql: `(
SELECT 1 FROM media_paradigms mp EXISTS (
WHERE mp.media_id = ${alias}.id SELECT 1 FROM media_paradigms mp
AND ( WHERE mp.media_id = ${alias}.id
(mp.media_paradigm = 'user-profile-image' AND ${alias}.is_primary = 1) AND mp.media_paradigm = 'user-profile-image'
OR (mp.media_paradigm = 'bot-image' AND EXISTS ( AND ${alias}.is_primary = 1
SELECT 1 FROM bots b WHERE b.image_media_id = ${alias}.id )
)) OR EXISTS (SELECT 1 FROM bots b WHERE b.image_media_id = ${alias}.id)
OR (mp.media_paradigm = 'workspace-image' AND EXISTS ( OR EXISTS (SELECT 1 FROM workspaces w WHERE w.image_media_id = ${alias}.id)
SELECT 1 FROM workspaces w WHERE w.image_media_id = ${alias}.id
))
)
)`, )`,
values: [], values: [],
}; };