diff --git a/backend/package.json b/backend/package.json index 29152e1b3..ab8e430a3 100644 --- a/backend/package.json +++ b/backend/package.json @@ -80,7 +80,7 @@ "metascraper-youtube": "^5.8.13", "minimatch": "^3.0.4", "mustache": "^3.2.1", - "neo4j-driver": "~1.7.6", + "neo4j-driver": "^4.0.1", "neo4j-graphql-js": "^2.11.3", "neode": "^0.3.6", "node-fetch": "~2.6.0", diff --git a/backend/src/bootstrap/neo4j.js b/backend/src/bootstrap/neo4j.js index 404e8a2c0..6d46a0279 100644 --- a/backend/src/bootstrap/neo4j.js +++ b/backend/src/bootstrap/neo4j.js @@ -1,4 +1,4 @@ -import { v1 as neo4j } from 'neo4j-driver' +import neo4j from 'neo4j-driver' import CONFIG from './../config' import Neode from 'neode' import models from '../models' diff --git a/backend/src/middleware/index.js b/backend/src/middleware/index.js index 16becb7a0..25195b1b5 100644 --- a/backend/src/middleware/index.js +++ b/backend/src/middleware/index.js @@ -7,7 +7,6 @@ import sluggify from './sluggifyMiddleware' import excerpt from './excerptMiddleware' import xss from './xssMiddleware' import permissions from './permissionsMiddleware' -import user from './user/userMiddleware' import includedFields from './includedFieldsMiddleware' import orderBy from './orderByMiddleware' import validation from './validation/validationMiddleware' @@ -29,7 +28,6 @@ export default schema => { notifications, hashtags, softDelete, - user, includedFields, orderBy, } @@ -46,7 +44,6 @@ export default schema => { 'notifications', 'hashtags', 'softDelete', - 'user', 'includedFields', 'orderBy', ] diff --git a/backend/src/middleware/user/userMiddleware.js b/backend/src/middleware/user/userMiddleware.js deleted file mode 100644 index 2ca61e69f..000000000 --- a/backend/src/middleware/user/userMiddleware.js +++ /dev/null @@ -1,16 +0,0 @@ -import createOrUpdateLocations from '../nodes/locations' - -export default { - Mutation: { - SignupVerification: async (resolve, root, args, context, info) => { - const result = await resolve(root, args, context, info) - await createOrUpdateLocations(result.id, args.locationName, context.driver) - return result - }, - UpdateUser: async (resolve, root, args, context, info) => { - const result = await resolve(root, args, context, info) - await createOrUpdateLocations(args.id, args.locationName, context.driver) - return result - }, - }, -} diff --git a/backend/src/schema/resolvers/helpers/databaseLogger.js b/backend/src/schema/resolvers/helpers/databaseLogger.js index 1e97b4d72..fac1a5c4a 100644 --- a/backend/src/schema/resolvers/helpers/databaseLogger.js +++ b/backend/src/schema/resolvers/helpers/databaseLogger.js @@ -3,8 +3,8 @@ const debugCypher = Debug('human-connection:neo4j:cypher') const debugStats = Debug('human-connection:neo4j:stats') export default function log(response) { - const { statement, counters, resultConsumedAfter, resultAvailableAfter } = response.summary - const { text, parameters } = statement + const { counters, resultConsumedAfter, resultAvailableAfter, query } = response.summary + const { text, parameters } = query debugCypher('%s', text) debugCypher('%o', parameters) debugStats('%o', counters) diff --git a/backend/src/schema/resolvers/registration.js b/backend/src/schema/resolvers/registration.js index 1a6bda1c8..e03f294cd 100644 --- a/backend/src/schema/resolvers/registration.js +++ b/backend/src/schema/resolvers/registration.js @@ -5,6 +5,7 @@ import encryptPassword from '../../helpers/encryptPassword' import generateNonce from './helpers/generateNonce' import existingEmailAddress from './helpers/existingEmailAddress' import normalizeEmail from './helpers/normalizeEmail' +import createOrUpdateLocations from './users/location' const neode = getNeode() @@ -22,7 +23,9 @@ export default { throw new UserInputError(e.message) } }, - SignupVerification: async (_parent, args) => { + SignupVerification: async (_parent, args, context) => { + const { driver } = context + const session = driver.session() const { termsAndConditionsAgreedVersion } = args const regEx = new RegExp(/^[0-9]+\.[0-9]+\.[0-9]+$/g) if (!regEx.test(termsAndConditionsAgreedVersion)) { @@ -51,11 +54,14 @@ export default { emailAddress.relateTo(user, 'belongsTo'), emailAddress.update({ verifiedAt: new Date().toISOString() }), ]) + await createOrUpdateLocations(args.id, args.locationName, session) return user.toJson() } catch (e) { if (e.code === 'Neo.ClientError.Schema.ConstraintValidationFailed') throw new UserInputError('User with this slug already exists!') throw new UserInputError(e.message) + } finally { + session.close() } }, }, diff --git a/backend/src/schema/resolvers/users.js b/backend/src/schema/resolvers/users.js index be9a69e80..0b3f13631 100644 --- a/backend/src/schema/resolvers/users.js +++ b/backend/src/schema/resolvers/users.js @@ -4,6 +4,7 @@ import { getNeode } from '../../bootstrap/neo4j' import { UserInputError, ForbiddenError } from 'apollo-server' import Resolver from './helpers/Resolver' import log from './helpers/databaseLogger' +import createOrUpdateLocations from './users/location' const neode = getNeode() @@ -127,6 +128,7 @@ export default { }) try { const [user] = await writeTxResultPromise + await createOrUpdateLocations(params.id, params.locationName, session) return user } catch (error) { throw new UserInputError(error.message) diff --git a/backend/src/middleware/nodes/locations.js b/backend/src/schema/resolvers/users/location.js similarity index 76% rename from backend/src/middleware/nodes/locations.js rename to backend/src/schema/resolvers/users/location.js index 47262d7ba..3f3638bf5 100644 --- a/backend/src/middleware/nodes/locations.js +++ b/backend/src/schema/resolvers/users/location.js @@ -2,8 +2,8 @@ import request from 'request' import { UserInputError } from 'apollo-server' import isEmpty from 'lodash/isEmpty' import Debug from 'debug' -import asyncForEach from '../../helpers/asyncForEach' -import CONFIG from './../../config' +import asyncForEach from '../../../helpers/asyncForEach' +import CONFIG from '../../../config' const debug = Debug('human-connection:location') @@ -57,16 +57,12 @@ const createLocation = async (session, mapboxData) => { } mutation += ' RETURN l.id' - try { - await session.writeTransaction(transaction => { - return transaction.run(mutation, data) - }) - } finally { - session.close() - } + await session.writeTransaction(transaction => { + return transaction.run(mutation, data) + }) } -const createOrUpdateLocations = async (userId, locationName, driver) => { +const createOrUpdateLocations = async (userId, locationName, session) => { if (isEmpty(locationName)) { return } @@ -99,7 +95,6 @@ const createOrUpdateLocations = async (userId, locationName, driver) => { throw new UserInputError('locationName is invalid') } - const session = driver.session() if (data.place_type.length > 1) { data.id = 'region.' + data.id.split('.')[1] } @@ -110,44 +105,36 @@ const createOrUpdateLocations = async (userId, locationName, driver) => { if (data.context) { await asyncForEach(data.context, async ctx => { await createLocation(session, ctx) - try { - await session.writeTransaction(transaction => { - return transaction.run( - ` + await session.writeTransaction(transaction => { + return transaction.run( + ` MATCH (parent:Location {id: $parentId}), (child:Location {id: $childId}) MERGE (child)<-[:IS_IN]-(parent) RETURN child.id, parent.id `, - { - parentId: parent.id, - childId: ctx.id, - }, - ) - }) - parent = ctx - } finally { - session.close() - } + { + parentId: parent.id, + childId: ctx.id, + }, + ) + }) + parent = ctx }) } // delete all current locations from user and add new location - try { - await session.writeTransaction(transaction => { - return transaction.run( - ` + await session.writeTransaction(transaction => { + return transaction.run( + ` MATCH (user:User {id: $userId})-[relationship:IS_IN]->(location:Location) DETACH DELETE relationship WITH user - MATCH (location:Location {id: $locationId}) - MERGE (user)-[:IS_IN]->(location) + MATCH (location:Location {id: $locationId}) + MERGE (user)-[:IS_IN]->(location) RETURN location.id, user.id `, - { userId: userId, locationId: data.id }, - ) - }) - } finally { - session.close() - } + { userId: userId, locationId: data.id }, + ) + }) } export default createOrUpdateLocations diff --git a/backend/src/middleware/user/userMiddleware.spec.js b/backend/src/schema/resolvers/users/location.spec.js similarity index 96% rename from backend/src/middleware/user/userMiddleware.spec.js rename to backend/src/schema/resolvers/users/location.spec.js index 4ca8fd89f..59d093afb 100644 --- a/backend/src/middleware/user/userMiddleware.spec.js +++ b/backend/src/schema/resolvers/users/location.spec.js @@ -1,8 +1,8 @@ -import { gql } from '../../helpers/jest' -import Factory from '../../seed/factories' -import { getNeode, getDriver } from '../../bootstrap/neo4j' +import { gql } from '../../../helpers/jest' +import Factory from '../../../seed/factories' +import { getNeode, getDriver } from '../../../bootstrap/neo4j' import { createTestClient } from 'apollo-server-testing' -import createServer from '../../server' +import createServer from '../../../server' const factory = Factory() const neode = getNeode() diff --git a/backend/yarn.lock b/backend/yarn.lock index 29859d9fb..8c15f1733 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -6238,7 +6238,7 @@ neo-async@^2.6.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== -neo4j-driver@^1.7.6, neo4j-driver@~1.7.6: +neo4j-driver@^1.7.6: version "1.7.6" resolved "https://registry.yarnpkg.com/neo4j-driver/-/neo4j-driver-1.7.6.tgz#eccb135a71eba9048c68717444593a6424cffc49" integrity sha512-6c3ALO3vYDfUqNoCy8OFzq+fQ7q/ab3LCuJrmm8P04M7RmyRCCnUtJ8IzSTGbiZvyhcehGK+azNDAEJhxPV/hA== @@ -7632,11 +7632,6 @@ serve-static@1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.1" set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" diff --git a/package.json b/package.json index ea8df2548..201924ed1 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "expect": "^24.9.0", "faker": "Marak/faker.js#master", "graphql-request": "^1.8.2", - "neo4j-driver": "^1.7.6", + "neo4j-driver": "^4.0.1", "neode": "^0.3.7", "npm-run-all": "^4.1.5", "slug": "^2.1.0" diff --git a/yarn.lock b/yarn.lock index 28a53fea4..9a639b7aa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3989,6 +3989,16 @@ neo4j-driver@^1.7.6: text-encoding-utf-8 "^1.0.2" uri-js "^4.2.2" +neo4j-driver@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/neo4j-driver/-/neo4j-driver-4.0.1.tgz#b25ffde0f16602e94c46d097e16a8bacbd773d5a" + integrity sha512-SqBhXyyyayVs5gV/6BrgdKbcmU5AsYQXkFAiYO74XAE8XPLJ1HVR/Hu4wjonAX7+70DsalkWEiFN1c6UaCVzlQ== + dependencies: + "@babel/runtime" "^7.5.5" + rxjs "^6.5.2" + text-encoding-utf-8 "^1.0.2" + uri-js "^4.2.2" + neode@^0.3.7: version "0.3.7" resolved "https://registry.yarnpkg.com/neode/-/neode-0.3.7.tgz#766105307e138b1212957aceba538e89e3d784cb" @@ -4777,6 +4787,13 @@ rxjs@^5.0.0-beta.11: dependencies: symbol-observable "1.0.1" +rxjs@^6.5.2: + version "6.5.4" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" + integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== + dependencies: + tslib "^1.9.0" + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -5368,6 +5385,11 @@ tough-cookie@~2.4.3: psl "^1.1.24" punycode "^1.4.1" +tslib@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + tty-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811"