diff --git a/backend/src/graphql/types/type/User.gql b/backend/src/graphql/types/type/User.gql index 81dd9cf5b..c2f067f12 100644 --- a/backend/src/graphql/types/type/User.gql +++ b/backend/src/graphql/types/type/User.gql @@ -50,6 +50,7 @@ type User { locationName: String location: Location @cypher(statement: "MATCH (this)-[:IS_IN]->(l:Location) RETURN l") + distanceToMe: Int about: String socialMedia: [SocialMedia]! @relation(name: "OWNED_BY", direction: "IN") diff --git a/backend/src/schema/resolvers/users.spec.ts b/backend/src/schema/resolvers/users.spec.ts index ad37e2024..d666e5fc4 100644 --- a/backend/src/schema/resolvers/users.spec.ts +++ b/backend/src/schema/resolvers/users.spec.ts @@ -660,6 +660,202 @@ const emailNotificationSettingsMutation = gql` } ` +const distanceToMeQuery = gql` + query ($id: ID!) { + User(id: $id) { + distanceToMe + } + } +` +let myPlaceUser, otherPlaceUser, noCordsPlaceUser, noPlaceUser + +describe('distanceToMe', () => { + beforeEach(async () => { + const Hamburg = await Factory.build('location', { + id: 'region.5127278006398860', + name: 'Hamburg', + type: 'region', + lng: 10.0, + lat: 53.55, + nameES: 'Hamburgo', + nameFR: 'Hambourg', + nameIT: 'Amburgo', + nameEN: 'Hamburg', + namePT: 'Hamburgo', + nameDE: 'Hamburg', + nameNL: 'Hamburg', + namePL: 'Hamburg', + nameRU: 'Гамбург', + }) + const Germany = await Factory.build('location', { + id: 'country.10743216036480410', + name: 'Germany', + type: 'country', + namePT: 'Alemanha', + nameDE: 'Deutschland', + nameES: 'Alemania', + nameNL: 'Duitsland', + namePL: 'Niemcy', + nameFR: 'Allemagne', + nameIT: 'Germania', + nameEN: 'Germany', + nameRU: 'Германия', + }) + const Paris = await Factory.build('location', { + id: 'region.9397217726497330', + name: 'Paris', + type: 'region', + lng: 2.35183, + lat: 48.85658, + nameES: 'París', + nameFR: 'Paris', + nameIT: 'Parigi', + nameEN: 'Paris', + namePT: 'Paris', + nameDE: 'Paris', + nameNL: 'Parijs', + namePL: 'Paryż', + nameRU: 'Париж', + }) + + user = await Factory.build('user', { + id: 'user', + role: 'user', + }) + await user.relateTo(Hamburg, 'isIn') + + myPlaceUser = await Factory.build('user', { + id: 'myPlaceUser', + role: 'user', + }) + await myPlaceUser.relateTo(Hamburg, 'isIn') + + otherPlaceUser = await Factory.build('user', { + id: 'otherPlaceUser', + role: 'user', + }) + await otherPlaceUser.relateTo(Paris, 'isIn') + + noCordsPlaceUser = await Factory.build('user', { + id: 'noCordsPlaceUser', + role: 'user', + }) + await noCordsPlaceUser.relateTo(Germany, 'isIn') + + noPlaceUser = await Factory.build('user', { + id: 'noPlaceUser', + role: 'user', + }) + }) + + describe('query the field', () => { + describe('for self user', () => { + it('returns null', async () => { + authenticatedUser = await user.toJson() + const targetUser = await user.toJson() + await expect( + query({ query: distanceToMeQuery, variables: { id: targetUser.id } }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + User: [ + { + distanceToMe: null, + }, + ], + }, + errors: undefined, + }), + ) + }) + }) + + describe('for myPlaceUser', () => { + it('returns 0', async () => { + authenticatedUser = await user.toJson() + const targetUser = await myPlaceUser.toJson() + await expect( + query({ query: distanceToMeQuery, variables: { id: targetUser.id } }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + User: [ + { + distanceToMe: 0, + }, + ], + }, + errors: undefined, + }), + ) + }) + }) + + describe('for otherPlaceUser', () => { + it('returns a number', async () => { + authenticatedUser = await user.toJson() + const targetUser = await otherPlaceUser.toJson() + await expect( + query({ query: distanceToMeQuery, variables: { id: targetUser.id } }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + User: [ + { + distanceToMe: 746, + }, + ], + }, + errors: undefined, + }), + ) + }) + }) + + describe('for noCordsPlaceUser', () => { + it('returns null', async () => { + authenticatedUser = await user.toJson() + const targetUser = await noCordsPlaceUser.toJson() + await expect( + query({ query: distanceToMeQuery, variables: { id: targetUser.id } }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + User: [ + { + distanceToMe: null, + }, + ], + }, + errors: undefined, + }), + ) + }) + }) + + describe('for noPlaceUser', () => { + it('returns null', async () => { + authenticatedUser = await user.toJson() + const targetUser = await noPlaceUser.toJson() + await expect( + query({ query: distanceToMeQuery, variables: { id: targetUser.id } }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + User: [ + { + distanceToMe: null, + }, + ], + }, + errors: undefined, + }), + ) + }) + }) + }) +}) + describe('emailNotificationSettings', () => { beforeEach(async () => { user = await Factory.build('user', { diff --git a/backend/src/schema/resolvers/users.ts b/backend/src/schema/resolvers/users.ts index f549e79a3..7c906d9a9 100644 --- a/backend/src/schema/resolvers/users.ts +++ b/backend/src/schema/resolvers/users.ts @@ -467,6 +467,36 @@ export default { }, }, User: { + distanceToMe: async (parent, _params, context, _resolveInfo) => { + // is it myself? + if (parent.id === context.user.id) { + return null + } + + const session = context.driver.session() + + const query = session.readTransaction(async (transaction) => { + const result = await transaction.run( + ` + MATCH (user:User {id: $parent.id})-[:IS_IN]->(userLoc:Location) + MATCH (me:User {id: $user.id})-[:IS_IN]->(meLoc:Location) + WITH + point({latitude: userLoc.lat, longitude: userLoc.lng}) as userPoint, + point({latitude: meLoc.lat, longitude: meLoc.lng}) as mePoint + RETURN round(point.distance(userPoint, mePoint) / 1000) as distance + `, + { parent, user: context.user }, + ) + + return result.records.map((record) => record.get('distance'))[0] + }) + + try { + return await query + } finally { + session.close() + } + }, emailNotificationSettings: async (parent, _params, _context, _resolveInfo) => { return [ {