diff --git a/setup-mysql.sql b/setup-mysql.sql index c0f7866..5cf2f42 100644 --- a/setup-mysql.sql +++ b/setup-mysql.sql @@ -22,6 +22,7 @@ GRANT UPDATE ON swf_assets TO impress2020; -- User data tables GRANT SELECT ON closet_hangers TO impress2020; +GRANT SELECT ON closet_lists TO impress2020; GRANT SELECT ON item_outfit_relationships TO impress2020; GRANT SELECT ON outfits TO impress2020; GRANT SELECT ON users TO impress2020; diff --git a/src/server/loaders.js b/src/server/loaders.js index d3c5a16..7c1bce4 100644 --- a/src/server/loaders.js +++ b/src/server/loaders.js @@ -507,6 +507,22 @@ const buildUserOwnedClosetHangersLoader = (db) => ); }); +const buildUserClosetListsLoader = (db) => + new DataLoader(async (userIds) => { + const qs = userIds.map((_) => "?").join(","); + const [rows, _] = await db.execute( + `SELECT * FROM closet_lists + WHERE user_id IN (${qs}) + ORDER BY name`, + userIds + ); + const entities = rows.map(normalizeRow); + + return userIds.map((userId) => + entities.filter((e) => e.userId === String(userId)) + ); + }); + const buildZoneLoader = (db) => { const zoneLoader = new DataLoader(async (ids) => { const qs = ids.map((_) => "?").join(","); @@ -589,6 +605,7 @@ function buildLoaders(db) { loaders.speciesTranslationLoader = buildSpeciesTranslationLoader(db); loaders.userLoader = buildUserLoader(db); loaders.userOwnedClosetHangersLoader = buildUserOwnedClosetHangersLoader(db); + loaders.userClosetListsLoader = buildUserClosetListsLoader(db); loaders.zoneLoader = buildZoneLoader(db); loaders.zoneTranslationLoader = buildZoneTranslationLoader(db); diff --git a/src/server/query-tests/User.test.js b/src/server/query-tests/User.test.js index ac3e00d..48c91f7 100644 --- a/src/server/query-tests/User.test.js +++ b/src/server/query-tests/User.test.js @@ -148,6 +148,14 @@ describe("User", () => { "id": "49026", "name": "Abominable Snowman Hat", }, + Object { + "id": "39948", + "name": "Altador Cup Background - Lost Desert", + }, + Object { + "id": "39955", + "name": "Altador Cup Background - Virtupets", + }, Object { "id": "40319", "name": "Blue Jelly Tiara", @@ -176,6 +184,14 @@ describe("User", () => { "44743", ], ], + Array [ + "SELECT * FROM closet_lists + WHERE user_id IN (?) + ORDER BY name", + Array [ + "44743", + ], + ], ] `); }); @@ -201,7 +217,12 @@ describe("User", () => { Object { "user": Object { "id": "44743", - "itemsTheyOwn": Array [], + "itemsTheyOwn": Array [ + Object { + "id": "39955", + "name": "Altador Cup Background - Virtupets", + }, + ], "username": "dti-test", }, } @@ -214,6 +235,25 @@ describe("User", () => { "44743", ], ], + Array [ + "SELECT closet_hangers.*, item_translations.name as item_name FROM closet_hangers + INNER JOIN items ON items.id = closet_hangers.item_id + INNER JOIN item_translations ON + item_translations.item_id = items.id AND locale = \\"en\\" + WHERE user_id IN (?) AND owned = 1 + ORDER BY item_name", + Array [ + "44743", + ], + ], + Array [ + "SELECT * FROM closet_lists + WHERE user_id IN (?) + ORDER BY name", + Array [ + "44743", + ], + ], ] `); }); diff --git a/src/server/types/User.js b/src/server/types/User.js index 556aa6c..5f05803 100644 --- a/src/server/types/User.js +++ b/src/server/types/User.js @@ -22,21 +22,29 @@ const resolvers = { itemsTheyOwn: async ( { id }, _, - { currentUserId, userLoader, userOwnedClosetHangersLoader } - ) => { - const user = await userLoader.load(id); - const hangersAreVisible = - user.ownedClosetHangersVisibility >= 2 || user.id === currentUserId; - if (!hangersAreVisible) { - return []; + { + currentUserId, + userClosetListsLoader, + userLoader, + userOwnedClosetHangersLoader, } + ) => { + const [allClosetHangers, closetLists, user] = await Promise.all([ + userOwnedClosetHangersLoader.load(id), + userClosetListsLoader.load(id), + userLoader.load(id), + ]); - const allClosetHangers = await userOwnedClosetHangersLoader.load(id); - const closetHangersWithNoList = allClosetHangers.filter( - (h) => h.listId == null + const closetListsById = new Map(closetLists.map((l) => [l.id, l])); + + const visibleClosetHangers = allClosetHangers.filter( + (h) => + user.id === currentUserId || + (h.listId == null && user.ownedClosetHangersVisibility >= 1) || + (h.listId != null && closetListsById.get(h.listId).visibility >= 1) ); - const items = closetHangersWithNoList.map((h) => ({ + const items = visibleClosetHangers.map((h) => ({ id: h.itemId, // We get this for the ORDER BY clause anyway - may as well include it // here to avoid an extra lookup!