This commit is contained in:
Robert Schäfer 2019-08-02 01:45:36 +02:00
parent 0a9991b979
commit e1bb6ed74e
28 changed files with 122 additions and 121 deletions

View File

@ -35,8 +35,8 @@ export default class ActivityPub {
handleFollowActivity(activity) { handleFollowActivity(activity) {
debug(`inside FOLLOW ${activity.actor}`) debug(`inside FOLLOW ${activity.actor}`)
let toActorName = extractNameFromId(activity.object) const toActorName = extractNameFromId(activity.object)
let fromDomain = extractDomainFromUrl(activity.actor) const fromDomain = extractDomainFromUrl(activity.actor)
const dataSource = this.dataSource const dataSource = this.dataSource
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -53,7 +53,7 @@ export default class ActivityPub {
toActorObject = JSON.parse(toActorObject) toActorObject = JSON.parse(toActorObject)
await this.dataSource.addSharedInboxEndpoint(toActorObject.endpoints.sharedInbox) await this.dataSource.addSharedInboxEndpoint(toActorObject.endpoints.sharedInbox)
let followersCollectionPage = await this.dataSource.getFollowersCollectionPage( const followersCollectionPage = await this.dataSource.getFollowersCollectionPage(
activity.object, activity.object,
) )
@ -222,6 +222,7 @@ export default class ActivityPub {
}) })
} }
} }
async trySend(activity, fromName, host, url, tries = 5) { async trySend(activity, fromName, host, url, tries = 5) {
try { try {
return await signAndSend(activity, fromName, host, url) return await signAndSend(activity, fromName, host, url)

View File

@ -2,6 +2,7 @@ export default class Collections {
constructor(dataSource) { constructor(dataSource) {
this.dataSource = dataSource this.dataSource = dataSource
} }
getFollowersCollection(actorId) { getFollowersCollection(actorId) {
return this.dataSource.getFollowersCollection(actorId) return this.dataSource.getFollowersCollection(actorId)
} }

View File

@ -303,6 +303,7 @@ export default class NitroDataSource {
}), }),
) )
} }
async saveFollowingCollectionPage(followingCollection, onlyNewestItem = true) { async saveFollowingCollectionPage(followingCollection, onlyNewestItem = true) {
debug('inside saveFollowers') debug('inside saveFollowers')
let orderedItems = followingCollection.orderedItems let orderedItems = followingCollection.orderedItems
@ -470,6 +471,7 @@ export default class NitroDataSource {
throwErrorIfApolloErrorOccurred(result) throwErrorIfApolloErrorOccurred(result)
return result.data.SharedInboxEnpoint return result.data.SharedInboxEnpoint
} }
async addSharedInboxEndpoint(uri) { async addSharedInboxEndpoint(uri) {
try { try {
const result = await this.client.mutate({ const result = await this.client.mutate({

View File

@ -97,7 +97,7 @@ export function verifySignature(url, headers) {
// private: signing // private: signing
function constructSigningString(url, headers) { function constructSigningString(url, headers) {
const urlObj = new URL(url) const urlObj = new URL(url)
let signingString = `(request-target): post ${urlObj.pathname}${ const signingString = `(request-target): post ${urlObj.pathname}${
urlObj.search !== '' ? urlObj.search : '' urlObj.search !== '' ? urlObj.search : ''
}` }`
return Object.keys(headers).reduce((result, key) => { return Object.keys(headers).reduce((result, key) => {

View File

@ -40,10 +40,11 @@ export function signAndSend(activity, fromName, targetDomain, url) {
// fix for development: replace with http // fix for development: replace with http
url = url.indexOf('localhost') > -1 ? url.replace('https', 'http') : url url = url.indexOf('localhost') > -1 ? url.replace('https', 'http') : url
debug(`passhprase = ${CONFIG.PRIVATE_KEY_PASSPHRASE}`) debug(`passhprase = ${CONFIG.PRIVATE_KEY_PASSPHRASE}`)
return new Promise(async (resolve, reject) => { return new Promise((resolve, reject) => {
debug('inside signAndSend') debug('inside signAndSend')
// get the private key // get the private key
const result = await activityPub.dataSource.client.query({ activityPub.dataSource.client
.query({
query: gql` query: gql`
query { query {
User(slug: "${fromName}") { User(slug: "${fromName}") {
@ -52,7 +53,7 @@ export function signAndSend(activity, fromName, targetDomain, url) {
} }
`, `,
}) })
.then(result => {
if (result.error) { if (result.error) {
reject(result.error) reject(result.error)
} else { } else {
@ -106,4 +107,5 @@ export function signAndSend(activity, fromName, targetDomain, url) {
) )
} }
}) })
})
} }

View File

@ -97,8 +97,6 @@ const invitationLimitReached = rule({
return record.get('limitReached') return record.get('limitReached')
}) })
return limitReached return limitReached
} catch (e) {
throw e
} finally { } finally {
session.close() session.close()
} }

View File

@ -1,6 +1,6 @@
import slugify from 'slug' import slugify from 'slug'
export default async function uniqueSlug(string, isUnique) { export default async function uniqueSlug(string, isUnique) {
let slug = slugify(string || 'anonymous', { const slug = slugify(string || 'anonymous', {
lower: true, lower: true,
}) })
if (await isUnique(slug)) return slug if (await isUnique(slug)) return slug

View File

@ -8,8 +8,8 @@ import linkifyHtml from 'linkifyjs/html'
const embedToAnchor = content => { const embedToAnchor = content => {
const $ = cheerio.load(content) const $ = cheerio.load(content)
$('div[data-url-embed]').each((i, el) => { $('div[data-url-embed]').each((i, el) => {
let url = el.attribs['data-url-embed'] const url = el.attribs['data-url-embed']
let aTag = $(`<a href="${url}" target="_blank" data-url-embed="">${url}</a>`) const aTag = $(`<a href="${url}" target="_blank" data-url-embed="">${url}</a>`)
$(el).replaceWith(aTag) $(el).replaceWith(aTag)
}) })
return $('body').html() return $('body').html()
@ -87,7 +87,7 @@ function clean(dirty) {
b: 'strong', b: 'strong',
s: 'strike', s: 'strike',
img: function(tagName, attribs) { img: function(tagName, attribs) {
let src = attribs.src const src = attribs.src
if (!src) { if (!src) {
// remove broken images // remove broken images

View File

@ -18,7 +18,7 @@ export default {
false, false,
) )
let transactionRes = await session.run( const transactionRes = await session.run(
` `
MATCH (post:Post {id: $postId}), (comment:Comment {id: $commentId}), (author:User {id: $userId}) MATCH (post:Post {id: $postId}), (comment:Comment {id: $commentId}), (author:User {id: $userId})
MERGE (post)<-[:COMMENTS]-(comment)<-[:WROTE]-(author) MERGE (post)<-[:COMMENTS]-(comment)<-[:WROTE]-(author)

View File

@ -5,7 +5,6 @@ import { host, login, gql } from '../../jest/helpers'
const factory = Factory() const factory = Factory()
let client let client
let createCommentVariables let createCommentVariables
let createPostVariables
let createCommentVariablesSansPostId let createCommentVariablesSansPostId
let createCommentVariablesWithNonExistentPost let createCommentVariablesWithNonExistentPost
let userParams let userParams
@ -26,7 +25,7 @@ const createCommentMutation = gql`
} }
} }
` `
createPostVariables = { const createPostVariables = {
id: 'p1', id: 'p1',
title: 'post to comment on', title: 'post to comment on',
content: 'please comment on me', content: 'please comment on me',
@ -325,7 +324,7 @@ describe('ManageComments', () => {
} }
` `
let deleteCommentVariables = { const deleteCommentVariables = {
id: 'c456', id: 'c456',
} }

View File

@ -4,7 +4,7 @@ export default {
const { id, type } = params const { id, type } = params
const session = context.driver.session() const session = context.driver.session()
let transactionRes = await session.run( const transactionRes = await session.run(
`MATCH (node {id: $id}), (user:User {id: $userId}) `MATCH (node {id: $id}), (user:User {id: $userId})
WHERE $type IN labels(node) AND NOT $id = $userId WHERE $type IN labels(node) AND NOT $id = $userId
MERGE (user)-[relation:FOLLOWS]->(node) MERGE (user)-[relation:FOLLOWS]->(node)
@ -29,7 +29,7 @@ export default {
const { id, type } = params const { id, type } = params
const session = context.driver.session() const session = context.driver.session()
let transactionRes = await session.run( const transactionRes = await session.run(
`MATCH (user:User {id: $userId})-[relation:FOLLOWS]->(node {id: $id}) `MATCH (user:User {id: $userId})-[relation:FOLLOWS]->(node {id: $id})
WHERE $type IN labels(node) WHERE $type IN labels(node)
DELETE relation DELETE relation

View File

@ -41,8 +41,7 @@ describe('follow', () => {
describe('follow user', () => { describe('follow user', () => {
describe('unauthenticated follow', () => { describe('unauthenticated follow', () => {
it('throws authorization error', async () => { it('throws authorization error', async () => {
let client const client = new GraphQLClient(host)
client = new GraphQLClient(host)
await expect(client.request(mutationFollowUser('u2'))).rejects.toThrow('Not Authorised') await expect(client.request(mutationFollowUser('u2'))).rejects.toThrow('Not Authorised')
}) })
}) })
@ -93,8 +92,7 @@ describe('follow', () => {
// follow // follow
await clientUser1.request(mutationFollowUser('u2')) await clientUser1.request(mutationFollowUser('u2'))
// unfollow // unfollow
let client const client = new GraphQLClient(host)
client = new GraphQLClient(host)
await expect(client.request(mutationUnfollowUser('u2'))).rejects.toThrow('Not Authorised') await expect(client.request(mutationUnfollowUser('u2'))).rejects.toThrow('Not Authorised')
}) })
}) })

View File

@ -4,7 +4,7 @@ import { host, login } from '../../jest/helpers'
const factory = Factory() const factory = Factory()
let client let client
let userParams = { const userParams = {
id: 'you', id: 'you',
email: 'test@example.org', email: 'test@example.org',
password: '1234', password: '1234',
@ -34,7 +34,7 @@ describe('Notification', () => {
}) })
describe('currentUser { notifications }', () => { describe('currentUser { notifications }', () => {
let variables = {} const variables = {}
describe('authenticated', () => { describe('authenticated', () => {
let headers let headers
@ -79,7 +79,7 @@ describe('currentUser { notifications }', () => {
} }
} }
}` }`
let variables = { read: false } const variables = { read: false }
it('returns only unread notifications of current user', async () => { it('returns only unread notifications of current user', async () => {
const expected = { const expected = {
currentUser: { currentUser: {

View File

@ -41,7 +41,7 @@ export default {
SET u.encryptedPassword = $encryptedNewPassword SET u.encryptedPassword = $encryptedNewPassword
RETURN pr RETURN pr
` `
let transactionRes = await session.run(cypher, { const transactionRes = await session.run(cypher, {
stillValid, stillValid,
email, email,
code, code,

View File

@ -10,7 +10,7 @@ const driver = getDriver()
const getAllPasswordResets = async () => { const getAllPasswordResets = async () => {
const session = driver.session() const session = driver.session()
let transactionRes = await session.run('MATCH (r:PasswordReset) RETURN r') const transactionRes = await session.run('MATCH (r:PasswordReset) RETURN r')
const resets = transactionRes.records.map(record => record.get('r')) const resets = transactionRes.records.map(record => record.get('r'))
session.close() session.close()
return resets return resets
@ -84,9 +84,9 @@ describe('passwordReset', () => {
} }
const mutation = `mutation($code: String!, $email: String!, $newPassword: String!) { resetPassword(code: $code, email: $email, newPassword: $newPassword) }` const mutation = `mutation($code: String!, $email: String!, $newPassword: String!) { resetPassword(code: $code, email: $email, newPassword: $newPassword) }`
let email = 'user@example.org' const email = 'user@example.org'
let code = 'abcdef' const code = 'abcdef'
let newPassword = 'supersecret' const newPassword = 'supersecret'
let variables let variables
describe('invalid email', () => { describe('invalid email', () => {

View File

@ -337,7 +337,7 @@ describe('DeletePost', () => {
} }
` `
let variables = { const variables = {
id: 'p1', id: 'p1',
} }

View File

@ -300,7 +300,7 @@ describe('SignupVerification', () => {
} }
` `
describe('given valid password and email', () => { describe('given valid password and email', () => {
let variables = { const variables = {
nonce: '123456', nonce: '123456',
name: 'John Doe', name: 'John Doe',
password: '123', password: '123',

View File

@ -60,7 +60,7 @@ export default {
if (!dbResponse) return null if (!dbResponse) return null
const { report, submitter, resource, type } = dbResponse const { report, submitter, resource, type } = dbResponse
let response = { const response = {
...report.properties, ...report.properties,
post: null, post: null,
comment: null, comment: null,

View File

@ -4,7 +4,7 @@ import { UserInputError } from 'apollo-server'
const instance = neode() const instance = neode()
const getUserAndBadge = async ({ badgeKey, userId }) => { const getUserAndBadge = async ({ badgeKey, userId }) => {
let user = await instance.first('User', 'id', userId) const user = await instance.first('User', 'id', userId)
const badge = await instance.first('Badge', 'id', badgeKey) const badge = await instance.first('Badge', 'id', badgeKey)
if (!user) throw new UserInputError("Couldn't find a user with that id") if (!user) throw new UserInputError("Couldn't find a user with that id")
if (!badge) throw new UserInputError("Couldn't find a badge with that id") if (!badge) throw new UserInputError("Couldn't find a badge with that id")
@ -36,8 +36,6 @@ export default {
userId, userId,
}, },
) )
} catch (err) {
throw err
} finally { } finally {
session.close() session.close()
} }

View File

@ -4,7 +4,7 @@ export default {
const { id, type } = params const { id, type } = params
const session = context.driver.session() const session = context.driver.session()
let transactionRes = await session.run( const transactionRes = await session.run(
`MATCH (node {id: $id})<-[:WROTE]-(userWritten:User), (user:User {id: $userId}) `MATCH (node {id: $id})<-[:WROTE]-(userWritten:User), (user:User {id: $userId})
WHERE $type IN labels(node) AND NOT userWritten.id = $userId WHERE $type IN labels(node) AND NOT userWritten.id = $userId
MERGE (user)-[relation:SHOUTED]->(node) MERGE (user)-[relation:SHOUTED]->(node)
@ -29,7 +29,7 @@ export default {
const { id, type } = params const { id, type } = params
const session = context.driver.session() const session = context.driver.session()
let transactionRes = await session.run( const transactionRes = await session.run(
`MATCH (user:User {id: $userId})-[relation:SHOUTED]->(node {id: $id}) `MATCH (user:User {id: $userId})-[relation:SHOUTED]->(node {id: $id})
WHERE $type IN labels(node) WHERE $type IN labels(node)
DELETE relation DELETE relation

View File

@ -60,8 +60,7 @@ describe('shout', () => {
describe('shout foreign post', () => { describe('shout foreign post', () => {
describe('unauthenticated shout', () => { describe('unauthenticated shout', () => {
it('throws authorization error', async () => { it('throws authorization error', async () => {
let client const client = new GraphQLClient(host)
client = new GraphQLClient(host)
await expect(client.request(mutationShoutPost('p1'))).rejects.toThrow('Not Authorised') await expect(client.request(mutationShoutPost('p1'))).rejects.toThrow('Not Authorised')
}) })
}) })
@ -109,8 +108,7 @@ describe('shout', () => {
// shout // shout
await clientUser1.request(mutationShoutPost('p2')) await clientUser1.request(mutationShoutPost('p2'))
// unshout // unshout
let client const client = new GraphQLClient(host)
client = new GraphQLClient(host)
await expect(client.request(mutationUnshoutPost('p2'))).rejects.toThrow('Not Authorised') await expect(client.request(mutationUnshoutPost('p2'))).rejects.toThrow('Not Authorised')
}) })
}) })

View File

@ -1,9 +1,9 @@
export const query = (cypher, session) => { export const query = (cypher, session) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let data = [] const data = []
session.run(cypher).subscribe({ session.run(cypher).subscribe({
onNext: function(record) { onNext: function(record) {
let item = {} const item = {}
record.keys.forEach(key => { record.keys.forEach(key => {
item[key] = record.get(key) item[key] = record.get(key)
}) })
@ -34,7 +34,7 @@ const queryOne = (cypher, session) => {
export default { export default {
Query: { Query: {
statistics: async (parent, args, { driver, user }) => { statistics: async (parent, args, { driver, user }) => {
return new Promise(async resolve => { return new Promise(resolve => {
const session = driver.session() const session = driver.session()
const queries = { const queries = {
countUsers: countUsers:
@ -54,18 +54,24 @@ export default {
countFollows: 'MATCH (:User)-[r:FOLLOWS]->(:User) RETURN COUNT(r) AS countFollows', countFollows: 'MATCH (:User)-[r:FOLLOWS]->(:User) RETURN COUNT(r) AS countFollows',
countShouts: 'MATCH (:User)-[r:SHOUTED]->(:Post) RETURN COUNT(r) AS countShouts', countShouts: 'MATCH (:User)-[r:SHOUTED]->(:Post) RETURN COUNT(r) AS countShouts',
} }
let data = { const data = {
countUsers: (await queryOne(queries.countUsers, session)).countUsers.low, countUsers: queryOne(queries.countUsers, session).then(res => res.countUsers.low),
countPosts: (await queryOne(queries.countPosts, session)).countPosts.low, countPosts: queryOne(queries.countPosts, session).then(res => res.countPosts.low),
countComments: (await queryOne(queries.countComments, session)).countComments.low, countComments: queryOne(queries.countComments, session).then(
countNotifications: (await queryOne(queries.countNotifications, session)) res => res.countComments.low,
.countNotifications.low, ),
countOrganizations: (await queryOne(queries.countOrganizations, session)) countNotifications: queryOne(queries.countNotifications, session).then(
.countOrganizations.low, res => res.countNotifications.low,
countProjects: (await queryOne(queries.countProjects, session)).countProjects.low, ),
countInvites: (await queryOne(queries.countInvites, session)).countInvites.low, countOrganizations: queryOne(queries.countOrganizations, session).then(
countFollows: (await queryOne(queries.countFollows, session)).countFollows.low, res => res.countOrganizations.low,
countShouts: (await queryOne(queries.countShouts, session)).countShouts.low, ),
countProjects: queryOne(queries.countProjects, session).then(
res => res.countProjects.low,
),
countInvites: queryOne(queries.countInvites, session).then(res => res.countInvites.low),
countFollows: queryOne(queries.countFollows, session).then(res => res.countFollows.low),
countShouts: queryOne(queries.countShouts, session).then(res => res.countShouts.low),
} }
resolve(data) resolve(data)
}) })

View File

@ -49,7 +49,7 @@ export default {
} }
}, },
changePassword: async (_, { oldPassword, newPassword }, { driver, user }) => { changePassword: async (_, { oldPassword, newPassword }, { driver, user }) => {
let currentUser = await instance.find('User', user.id) const currentUser = await instance.find('User', user.id)
const encryptedPassword = currentUser.get('encryptedPassword') const encryptedPassword = currentUser.get('encryptedPassword')
if (!(await bcrypt.compareSync(oldPassword, encryptedPassword))) { if (!(await bcrypt.compareSync(oldPassword, encryptedPassword))) {

View File

@ -296,7 +296,7 @@ describe('change password', () => {
describe('correct password', () => { describe('correct password', () => {
it('changes the password if given correct credentials "', async () => { it('changes the password if given correct credentials "', async () => {
let response = await client.request( const response = await client.request(
mutation({ mutation({
oldPassword: '1234', oldPassword: '1234',
newPassword: '12345', newPassword: '12345',

View File

@ -23,7 +23,7 @@ export default {
UpdateUser: async (object, args, context, resolveInfo) => { UpdateUser: async (object, args, context, resolveInfo) => {
args = await fileUpload(args, { file: 'avatarUpload', url: 'avatar' }) args = await fileUpload(args, { file: 'avatarUpload', url: 'avatar' })
try { try {
let user = await instance.find('User', args.id) const user = await instance.find('User', args.id)
if (!user) return null if (!user) return null
await user.update(args) await user.update(args)
return user.toJson() return user.toJson()
@ -60,7 +60,7 @@ export default {
const { id } = parent const { id } = parent
const statement = `MATCH(u:User {id: {id}})-[:PRIMARY_EMAIL]->(e:EmailAddress) RETURN e` const statement = `MATCH(u:User {id: {id}})-[:PRIMARY_EMAIL]->(e:EmailAddress) RETURN e`
const result = await instance.cypher(statement, { id }) const result = await instance.cypher(statement, { id })
let [{ email }] = result.records.map(r => r.get('e').properties) const [{ email }] = result.records.map(r => r.get('e').properties)
return email return email
}, },
...Resolver('User', { ...Resolver('User', {

View File

@ -21,7 +21,7 @@ const findGqlFiles = dir => {
return results return results
} }
let typeDefs = [] const typeDefs = []
findGqlFiles(__dirname).forEach(file => { findGqlFiles(__dirname).forEach(file => {
typeDefs.push(fs.readFileSync(file).toString('utf-8')) typeDefs.push(fs.readFileSync(file).toString('utf-8'))

View File

@ -40,15 +40,13 @@ export const cleanDatabase = async (options = {}) => {
const cypher = 'MATCH (n) DETACH DELETE n' const cypher = 'MATCH (n) DETACH DELETE n'
try { try {
return await session.run(cypher) return await session.run(cypher)
} catch (error) {
throw error
} finally { } finally {
session.close() session.close()
} }
} }
export default function Factory(options = {}) { export default function Factory(options = {}) {
let { const {
seedServerHost = 'http://127.0.0.1:4001', seedServerHost = 'http://127.0.0.1:4001',
neo4jDriver = getDriver(), neo4jDriver = getDriver(),
neodeInstance = neode(), neodeInstance = neode(),

View File

@ -37,17 +37,17 @@ const difficulties = ['easy', 'medium', 'hard']
export default { export default {
randomItem: (items, filter) => { randomItem: (items, filter) => {
let ids = filter const ids = filter
? Object.keys(items).filter(id => { ? Object.keys(items).filter(id => {
return filter(items[id]) return filter(items[id])
}) })
: _.keys(items) : _.keys(items)
let randomIds = _.shuffle(ids) const randomIds = _.shuffle(ids)
return items[randomIds.pop()] return items[randomIds.pop()]
}, },
randomItems: (items, key = 'id', min = 1, max = 1) => { randomItems: (items, key = 'id', min = 1, max = 1) => {
let randomIds = _.shuffle(_.keys(items)) const randomIds = _.shuffle(_.keys(items))
let res = [] const res = []
const count = _.random(min, max) const count = _.random(min, max)
@ -86,8 +86,8 @@ export default {
if (allowEmpty === false && count === 0) { if (allowEmpty === false && count === 0) {
count = 1 count = 1
} }
let categorieIds = _.shuffle(_.keys(seederstore.categories)) const categorieIds = _.shuffle(_.keys(seederstore.categories))
let ids = [] const ids = []
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
ids.push(categorieIds.pop()) ids.push(categorieIds.pop())
} }
@ -95,7 +95,7 @@ export default {
}, },
randomAddresses: () => { randomAddresses: () => {
const count = Math.round(Math.random() * 3) const count = Math.round(Math.random() * 3)
let addresses = [] const addresses = []
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
addresses.push({ addresses.push({
city: faker.address.city(), city: faker.address.city(),
@ -116,7 +116,7 @@ export default {
* @param key the field key that is represented in the values (slug, name, etc.) * @param key the field key that is represented in the values (slug, name, etc.)
*/ */
mapIdsByKey: (items, values, key) => { mapIdsByKey: (items, values, key) => {
let res = [] const res = []
values.forEach(value => { values.forEach(value => {
res.push(_.find(items, [key, value]).id.toString()) res.push(_.find(items, [key, value]).id.toString())
}) })