mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge branch 'master' of github.com:Human-Connection/Nitro-Backend into 37-full-text-search-top-bar
This commit is contained in:
commit
671a713410
18
docker-compose.cypress.yml
Normal file
18
docker-compose.cypress.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
version: "3.7"
|
||||||
|
|
||||||
|
services:
|
||||||
|
neo4j:
|
||||||
|
environment:
|
||||||
|
- NEO4J_AUTH=none
|
||||||
|
ports:
|
||||||
|
- 7687:7687
|
||||||
|
- 7474:7474
|
||||||
|
backend:
|
||||||
|
ports:
|
||||||
|
- 4001:4001
|
||||||
|
- 4123:4123
|
||||||
|
image: humanconnection/nitro-backend:builder
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
target: builder
|
||||||
|
command: yarn run test:cypress
|
||||||
@ -1,8 +1,18 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -e
|
|
||||||
if [[ -z "${NEO4J_PASSWORD}" ]]; then
|
# If the user has the password `neo4j` this is a strong indicator, that we are
|
||||||
echo 'CALL db.index.fulltext.createNodeIndex("full_text_search",["Post"],["title", "content"]);' | cypher-shell
|
# the initial default user. Before we can create constraints, we have to change
|
||||||
else
|
# the default password. This is a security feature of neo4j.
|
||||||
echo "CALL dbms.security.changePassword('${NEO4J_PASSWORD}');" | cypher-shell --username neo4j --password neo4j
|
if echo ":exit" | cypher-shell --password neo4j 2> /dev/null ; then
|
||||||
echo 'CALL db.index.fulltext.createNodeIndex("full_text_search",["Post"],["title", "content"]);' | cypher-shell --username neo4j --password $NEO4J_PASSWORD
|
echo "CALL dbms.security.changePassword('${NEO4J_PASSWORD}');" | cypher-shell --password neo4j
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo '
|
||||||
|
CALL db.index.fulltext.createNodeIndex("full_text_search",["Post"],["title", "content"]);
|
||||||
|
CREATE CONSTRAINT ON (p:Post) ASSERT p.slug IS UNIQUE;
|
||||||
|
CREATE CONSTRAINT ON (c:Category) ASSERT c.slug IS UNIQUE;
|
||||||
|
CREATE CONSTRAINT ON (u:User) ASSERT u.slug IS UNIQUE;
|
||||||
|
CREATE CONSTRAINT ON (o:Organization) ASSERT o.slug IS UNIQUE;
|
||||||
|
' | cypher-shell
|
||||||
12
package.json
12
package.json
@ -13,6 +13,7 @@
|
|||||||
"dev:debug": "nodemon --exec babel-node --inspect=0.0.0.0:9229 src/index.js",
|
"dev:debug": "nodemon --exec babel-node --inspect=0.0.0.0:9229 src/index.js",
|
||||||
"lint": "eslint src --config .eslintrc.js",
|
"lint": "eslint src --config .eslintrc.js",
|
||||||
"test": "nyc --reporter=text-lcov yarn run test:jest",
|
"test": "nyc --reporter=text-lcov yarn run test:jest",
|
||||||
|
"test:cypress": "run-p --race test:before:*",
|
||||||
"test:before:server": "cross-env GRAPHQL_URI=http://localhost:4123 GRAPHQL_PORT=4123 babel-node src/ 2> /dev/null",
|
"test:before:server": "cross-env GRAPHQL_URI=http://localhost:4123 GRAPHQL_PORT=4123 babel-node src/ 2> /dev/null",
|
||||||
"test:before:seeder": "cross-env GRAPHQL_URI=http://localhost:4001 GRAPHQL_PORT=4001 PERMISSIONS=disabled babel-node src/ 2> /dev/null",
|
"test:before:seeder": "cross-env GRAPHQL_URI=http://localhost:4001 GRAPHQL_PORT=4001 PERMISSIONS=disabled babel-node src/ 2> /dev/null",
|
||||||
"test:jest:cmd": "wait-on tcp:4001 tcp:4123 && jest --forceExit --detectOpenHandles --runInBand",
|
"test:jest:cmd": "wait-on tcp:4001 tcp:4123 && jest --forceExit --detectOpenHandles --runInBand",
|
||||||
@ -21,9 +22,8 @@
|
|||||||
"test:jest:debug": "run-p --race test:before:* 'test:jest:cmd:debug {@}' --",
|
"test:jest:debug": "run-p --race test:before:* 'test:jest:cmd:debug {@}' --",
|
||||||
"test:coverage": "nyc report --reporter=text-lcov > coverage.lcov",
|
"test:coverage": "nyc report --reporter=text-lcov > coverage.lcov",
|
||||||
"db:script:seed": "wait-on tcp:4001 && babel-node src/seed/seed-db.js",
|
"db:script:seed": "wait-on tcp:4001 && babel-node src/seed/seed-db.js",
|
||||||
"db:script:reset": "wait-on tcp:4001 && babel-node src/seed/reset-db.js",
|
"db:reset": "babel-node src/seed/reset-db.js",
|
||||||
"db:seed": "$npm_package_config_no_auth run-p --race dev db:script:seed",
|
"db:seed": "$npm_package_config_no_auth run-p --race dev db:script:seed"
|
||||||
"db:reset": "$npm_package_config_no_auth run-p --race dev db:script:reset"
|
|
||||||
},
|
},
|
||||||
"author": "Human Connection gGmbH",
|
"author": "Human Connection gGmbH",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -34,8 +34,8 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"apollo-cache-inmemory": "~1.4.3",
|
"apollo-cache-inmemory": "~1.5.0",
|
||||||
"apollo-client": "~2.4.13",
|
"apollo-client": "~2.5.1",
|
||||||
"apollo-link-http": "~1.5.11",
|
"apollo-link-http": "~1.5.11",
|
||||||
"apollo-server": "~2.4.2",
|
"apollo-server": "~2.4.2",
|
||||||
"bcryptjs": "~2.4.3",
|
"bcryptjs": "~2.4.3",
|
||||||
@ -77,7 +77,7 @@
|
|||||||
"babel-eslint": "~10.0.1",
|
"babel-eslint": "~10.0.1",
|
||||||
"babel-jest": "~24.1.0",
|
"babel-jest": "~24.1.0",
|
||||||
"chai": "~4.2.0",
|
"chai": "~4.2.0",
|
||||||
"eslint": "~5.13.0",
|
"eslint": "~5.14.1",
|
||||||
"eslint-config-standard": "~12.0.0",
|
"eslint-config-standard": "~12.0.0",
|
||||||
"eslint-plugin-import": "~2.16.0",
|
"eslint-plugin-import": "~2.16.0",
|
||||||
"eslint-plugin-jest": "~22.3.0",
|
"eslint-plugin-jest": "~22.3.0",
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
import { v1 as neo4j } from "neo4j-driver";
|
import { v1 as neo4j } from 'neo4j-driver'
|
||||||
import dotenv from "dotenv";
|
import dotenv from 'dotenv'
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config()
|
||||||
|
|
||||||
let driver;
|
let driver
|
||||||
|
|
||||||
export function getDriver(options = {}) {
|
export function getDriver (options = {}) {
|
||||||
const {
|
const {
|
||||||
uri = process.env.NEO4J_URI || "bolt://localhost:7687",
|
uri = process.env.NEO4J_URI || 'bolt://localhost:7687',
|
||||||
username = process.env.NEO4J_USERNAME || "neo4j",
|
username = process.env.NEO4J_USERNAME || 'neo4j',
|
||||||
password = process.env.NEO4J_PASSWORD || "neo4j"
|
password = process.env.NEO4J_PASSWORD || 'neo4j'
|
||||||
} = options;
|
} = options
|
||||||
if (!driver) {
|
if (!driver) {
|
||||||
driver = neo4j.driver(uri, neo4j.auth.basic(username, password));
|
driver = neo4j.driver(uri, neo4j.auth.basic(username, password))
|
||||||
}
|
}
|
||||||
return driver;
|
return driver
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
// import { neo4jgraphql } from "neo4j-graphql-js"
|
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import bcrypt from 'bcryptjs'
|
import bcrypt from 'bcryptjs'
|
||||||
@ -6,35 +5,36 @@ import generateJwt from './jwt/generateToken'
|
|||||||
import uuid from 'uuid/v4'
|
import uuid from 'uuid/v4'
|
||||||
import { fixUrl } from './middleware/fixImageUrlsMiddleware'
|
import { fixUrl } from './middleware/fixImageUrlsMiddleware'
|
||||||
import { AuthenticationError } from 'apollo-server'
|
import { AuthenticationError } from 'apollo-server'
|
||||||
|
import { neo4jgraphql } from 'neo4j-graphql-js'
|
||||||
|
|
||||||
export const typeDefs =
|
export const typeDefs = fs
|
||||||
fs.readFileSync(process.env.GRAPHQL_SCHEMA || path.join(__dirname, 'schema.graphql'))
|
.readFileSync(
|
||||||
.toString('utf-8')
|
process.env.GRAPHQL_SCHEMA || path.join(__dirname, 'schema.graphql')
|
||||||
|
)
|
||||||
|
.toString('utf-8')
|
||||||
|
|
||||||
export const query = (cypher, session) => {
|
export const query = (cypher, session) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let data = []
|
let data = []
|
||||||
session
|
session.run(cypher).subscribe({
|
||||||
.run(cypher)
|
onNext: function (record) {
|
||||||
.subscribe({
|
let item = {}
|
||||||
onNext: function (record) {
|
record.keys.forEach(key => {
|
||||||
let item = {}
|
item[key] = record.get(key)
|
||||||
record.keys.forEach(key => {
|
})
|
||||||
item[key] = record.get(key)
|
data.push(item)
|
||||||
})
|
},
|
||||||
data.push(item)
|
onCompleted: function () {
|
||||||
},
|
session.close()
|
||||||
onCompleted: function () {
|
resolve(data)
|
||||||
session.close()
|
},
|
||||||
resolve(data)
|
onError: function (error) {
|
||||||
},
|
reject(error)
|
||||||
onError: function (error) {
|
}
|
||||||
reject(error)
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export const queryOne = (cypher, session) => {
|
const queryOne = (cypher, session) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
query(cypher, session)
|
query(cypher, session)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -52,29 +52,51 @@ export const resolvers = {
|
|||||||
return Boolean(user && user.id)
|
return Boolean(user && user.id)
|
||||||
},
|
},
|
||||||
statistics: async (parent, args, { driver, user }) => {
|
statistics: async (parent, args, { driver, user }) => {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async resolve => {
|
||||||
const session = driver.session()
|
const session = driver.session()
|
||||||
const queries = {
|
const queries = {
|
||||||
countUsers: 'MATCH (r:User) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countUsers',
|
countUsers:
|
||||||
countPosts: 'MATCH (r:Post) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countPosts',
|
'MATCH (r:User) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countUsers',
|
||||||
countComments: 'MATCH (r:Comment) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countComments',
|
countPosts:
|
||||||
countNotifications: 'MATCH (r:Notification) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countNotifications',
|
'MATCH (r:Post) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countPosts',
|
||||||
countOrganizations: 'MATCH (r:Organization) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countOrganizations',
|
countComments:
|
||||||
countProjects: 'MATCH (r:Project) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countProjects',
|
'MATCH (r:Comment) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countComments',
|
||||||
countInvites: 'MATCH (r:Invite) WHERE r.wasUsed <> true OR NOT exists(r.wasUsed) RETURN COUNT(r) AS countInvites',
|
countNotifications:
|
||||||
countFollows: 'MATCH (:User)-[r:FOLLOWS]->(:User) RETURN COUNT(r) AS countFollows',
|
'MATCH (r:Notification) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countNotifications',
|
||||||
countShouts: 'MATCH (:User)-[r:SHOUTED]->(:Post) RETURN COUNT(r) AS countShouts'
|
countOrganizations:
|
||||||
|
'MATCH (r:Organization) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countOrganizations',
|
||||||
|
countProjects:
|
||||||
|
'MATCH (r:Project) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countProjects',
|
||||||
|
countInvites:
|
||||||
|
'MATCH (r:Invite) WHERE r.wasUsed <> true OR NOT exists(r.wasUsed) RETURN COUNT(r) AS countInvites',
|
||||||
|
countFollows:
|
||||||
|
'MATCH (:User)-[r:FOLLOWS]->(:User) RETURN COUNT(r) AS countFollows',
|
||||||
|
countShouts:
|
||||||
|
'MATCH (:User)-[r:SHOUTED]->(:Post) RETURN COUNT(r) AS countShouts'
|
||||||
}
|
}
|
||||||
let data = {
|
let data = {
|
||||||
countUsers: (await queryOne(queries.countUsers, session)).countUsers.low,
|
countUsers: (await queryOne(queries.countUsers, session)).countUsers
|
||||||
countPosts: (await queryOne(queries.countPosts, session)).countPosts.low,
|
.low,
|
||||||
countComments: (await queryOne(queries.countComments, session)).countComments.low,
|
countPosts: (await queryOne(queries.countPosts, session)).countPosts
|
||||||
countNotifications: (await queryOne(queries.countNotifications, session)).countNotifications.low,
|
.low,
|
||||||
countOrganizations: (await queryOne(queries.countOrganizations, session)).countOrganizations.low,
|
countComments: (await queryOne(queries.countComments, session))
|
||||||
countProjects: (await queryOne(queries.countProjects, session)).countProjects.low,
|
.countComments.low,
|
||||||
countInvites: (await queryOne(queries.countInvites, session)).countInvites.low,
|
countNotifications: (await queryOne(
|
||||||
countFollows: (await queryOne(queries.countFollows, session)).countFollows.low,
|
queries.countNotifications,
|
||||||
countShouts: (await queryOne(queries.countShouts, session)).countShouts.low
|
session
|
||||||
|
)).countNotifications.low,
|
||||||
|
countOrganizations: (await queryOne(
|
||||||
|
queries.countOrganizations,
|
||||||
|
session
|
||||||
|
)).countOrganizations.low,
|
||||||
|
countProjects: (await queryOne(queries.countProjects, session))
|
||||||
|
.countProjects.low,
|
||||||
|
countInvites: (await queryOne(queries.countInvites, session))
|
||||||
|
.countInvites.low,
|
||||||
|
countFollows: (await queryOne(queries.countFollows, session))
|
||||||
|
.countFollows.low,
|
||||||
|
countShouts: (await queryOne(queries.countShouts, session))
|
||||||
|
.countShouts.low
|
||||||
}
|
}
|
||||||
resolve(data)
|
resolve(data)
|
||||||
})
|
})
|
||||||
@ -97,38 +119,53 @@ export const resolvers = {
|
|||||||
// throw new Error('Already logged in.')
|
// throw new Error('Already logged in.')
|
||||||
// }
|
// }
|
||||||
const session = driver.session()
|
const session = driver.session()
|
||||||
return session.run(
|
return session
|
||||||
'MATCH (user:User {email: $userEmail}) ' +
|
.run(
|
||||||
'RETURN user {.id, .slug, .name, .avatar, .locationName, .about, .email, .password, .role} as user LIMIT 1', {
|
'MATCH (user:User {email: $userEmail}) ' +
|
||||||
userEmail: email
|
'RETURN user {.id, .slug, .name, .avatar, .locationName, .about, .email, .password, .role} as user LIMIT 1',
|
||||||
})
|
{
|
||||||
.then(async (result) => {
|
userEmail: email
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(async result => {
|
||||||
session.close()
|
session.close()
|
||||||
const [currentUser] = await result.records.map(function (record) {
|
const [currentUser] = await result.records.map(function (record) {
|
||||||
return record.get('user')
|
return record.get('user')
|
||||||
})
|
})
|
||||||
|
|
||||||
if (currentUser && await bcrypt.compareSync(password, currentUser.password)) {
|
if (
|
||||||
|
currentUser &&
|
||||||
|
(await bcrypt.compareSync(password, currentUser.password))
|
||||||
|
) {
|
||||||
delete currentUser.password
|
delete currentUser.password
|
||||||
currentUser.avatar = fixUrl(currentUser.avatar)
|
currentUser.avatar = fixUrl(currentUser.avatar)
|
||||||
return Object.assign(currentUser, {
|
return Object.assign(currentUser, {
|
||||||
token: generateJwt(currentUser)
|
token: generateJwt(currentUser)
|
||||||
})
|
})
|
||||||
} else throw new AuthenticationError('Incorrect email address or password.')
|
} else {
|
||||||
|
throw new AuthenticationError(
|
||||||
|
'Incorrect email address or password.'
|
||||||
|
)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
report: async (parent, { resource, description }, { driver, req, user }, resolveInfo) => {
|
report: async (
|
||||||
|
parent,
|
||||||
|
{ resource, description },
|
||||||
|
{ driver, req, user },
|
||||||
|
resolveInfo
|
||||||
|
) => {
|
||||||
const contextId = uuid()
|
const contextId = uuid()
|
||||||
const session = driver.session()
|
const session = driver.session()
|
||||||
const data = {
|
const data = {
|
||||||
id: contextId,
|
id: contextId,
|
||||||
type: resource.type,
|
type: resource.type,
|
||||||
createdAt: (new Date()).toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
description: resource.description
|
description: resource.description
|
||||||
}
|
}
|
||||||
await session.run(
|
await session.run(
|
||||||
'CREATE (r:Report $report) ' +
|
'CREATE (r:Report $report) ' + 'RETURN r.id, r.type, r.description',
|
||||||
'RETURN r.id, r.type, r.description', {
|
{
|
||||||
report: data
|
report: data
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -149,9 +186,10 @@ export const resolvers = {
|
|||||||
|
|
||||||
await session.run(
|
await session.run(
|
||||||
`MATCH (author:User {id: $userId}), (context:${contentType} {id: $resourceId}), (report:Report {id: $contextId}) ` +
|
`MATCH (author:User {id: $userId}), (context:${contentType} {id: $resourceId}), (report:Report {id: $contextId}) ` +
|
||||||
'MERGE (report)<-[:REPORTED]-(author) ' +
|
'MERGE (report)<-[:REPORTED]-(author) ' +
|
||||||
'MERGE (context)<-[:REPORTED]-(report) ' +
|
'MERGE (context)<-[:REPORTED]-(report) ' +
|
||||||
'RETURN context', {
|
'RETURN context',
|
||||||
|
{
|
||||||
resourceId: resource.id,
|
resourceId: resource.id,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
contextId: contextId
|
contextId: contextId
|
||||||
@ -161,6 +199,29 @@ export const resolvers = {
|
|||||||
|
|
||||||
// TODO: output Report compatible object
|
// TODO: output Report compatible object
|
||||||
return data
|
return data
|
||||||
|
},
|
||||||
|
CreatePost: async (object, params, ctx, resolveInfo) => {
|
||||||
|
const result = await neo4jgraphql(
|
||||||
|
object,
|
||||||
|
params,
|
||||||
|
ctx,
|
||||||
|
resolveInfo,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
const session = ctx.driver.session()
|
||||||
|
await session.run(
|
||||||
|
'MATCH (author:User {id: $userId}), (post:Post {id: $postId}) ' +
|
||||||
|
'MERGE (post)<-[:WROTE]-(author) ' +
|
||||||
|
'RETURN author',
|
||||||
|
{
|
||||||
|
userId: ctx.user.id,
|
||||||
|
postId: result.id
|
||||||
|
}
|
||||||
|
)
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,34 @@
|
|||||||
import { GraphQLClient, request } from 'graphql-request'
|
|
||||||
import Factory from './seed/factories'
|
import Factory from './seed/factories'
|
||||||
|
import { GraphQLClient, request } from 'graphql-request'
|
||||||
import jwt from 'jsonwebtoken'
|
import jwt from 'jsonwebtoken'
|
||||||
import { host, login } from './jest/helpers'
|
import { host, login } from './jest/helpers'
|
||||||
|
|
||||||
const factory = Factory()
|
const factory = Factory()
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await factory.create('User', {
|
||||||
|
email: 'test@example.org',
|
||||||
|
password: '1234'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await factory.cleanDatabase()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('isLoggedIn', () => {
|
||||||
|
describe('unauthenticated', () => {
|
||||||
|
it('returns false', async () => {
|
||||||
|
const query = '{ isLoggedIn }'
|
||||||
|
await expect(request(host, query)).resolves.toEqual({
|
||||||
|
isLoggedIn: false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('login', () => {
|
describe('login', () => {
|
||||||
const mutation = (params) => {
|
const mutation = params => {
|
||||||
const { email, password } = params
|
const { email, password } = params
|
||||||
return `
|
return `
|
||||||
mutation {
|
mutation {
|
||||||
@ -16,48 +38,104 @@ describe('login', () => {
|
|||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('given an existing user', () => {
|
describe('ask for a `token`', () => {
|
||||||
beforeEach(async () => {
|
describe('with valid email/password combination', () => {
|
||||||
await factory.create('user', {
|
it('responds with a JWT token', async () => {
|
||||||
email: 'test@example.org',
|
const data = await request(
|
||||||
password: '1234'
|
host,
|
||||||
})
|
mutation({
|
||||||
})
|
email: 'test@example.org',
|
||||||
|
password: '1234'
|
||||||
afterEach(async () => {
|
|
||||||
await factory.cleanDatabase()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('asking for a `token`', () => {
|
|
||||||
describe('with valid email/password combination', () => {
|
|
||||||
it('responds with a JWT token', async () => {
|
|
||||||
const data = await request(host, mutation({ email: 'test@example.org', password: '1234' }))
|
|
||||||
const { token } = data.login
|
|
||||||
jwt.verify(token, process.env.JWT_SECRET, (err, data) => {
|
|
||||||
expect(data.email).toEqual('test@example.org')
|
|
||||||
expect(err).toBeNull()
|
|
||||||
})
|
})
|
||||||
|
)
|
||||||
|
const { token } = data.login
|
||||||
|
jwt.verify(token, process.env.JWT_SECRET, (err, data) => {
|
||||||
|
expect(data.email).toEqual('test@example.org')
|
||||||
|
expect(err).toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with a valid email but incorrect password', () => {
|
||||||
|
it('responds with "Incorrect email address or password."', async () => {
|
||||||
|
await expect(
|
||||||
|
request(
|
||||||
|
host,
|
||||||
|
mutation({
|
||||||
|
email: 'test@example.org',
|
||||||
|
password: 'wrong'
|
||||||
|
})
|
||||||
|
)
|
||||||
|
).rejects.toThrow('Incorrect email address or password.')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with a non-existing email', () => {
|
||||||
|
it('responds with "Incorrect email address or password."', async () => {
|
||||||
|
await expect(
|
||||||
|
request(
|
||||||
|
host,
|
||||||
|
mutation({
|
||||||
|
email: 'non-existent@example.org',
|
||||||
|
password: 'wrong'
|
||||||
|
})
|
||||||
|
)
|
||||||
|
).rejects.toThrow('Incorrect email address or password.')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('CreatePost', () => {
|
||||||
|
describe('unauthenticated', () => {
|
||||||
|
let client
|
||||||
|
it('throws authorization error', async () => {
|
||||||
|
client = new GraphQLClient(host)
|
||||||
|
await expect(
|
||||||
|
client.request(`mutation {
|
||||||
|
CreatePost(
|
||||||
|
title: "I am a post",
|
||||||
|
content: "Some content"
|
||||||
|
) { slug }
|
||||||
|
}`)
|
||||||
|
).rejects.toThrow('Not Authorised')
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('authenticated', () => {
|
||||||
|
let headers
|
||||||
|
let response
|
||||||
|
beforeEach(async () => {
|
||||||
|
headers = await login({ email: 'test@example.org', password: '1234' })
|
||||||
|
client = new GraphQLClient(host, { headers })
|
||||||
|
response = await client.request(
|
||||||
|
`mutation {
|
||||||
|
CreatePost(
|
||||||
|
title: "A title",
|
||||||
|
content: "Some content"
|
||||||
|
) { title, content }
|
||||||
|
}`,
|
||||||
|
{ headers }
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('creates a post', () => {
|
||||||
|
expect(response).toEqual({
|
||||||
|
CreatePost: { title: 'A title', content: 'Some content' }
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('with a valid email but incorrect password', () => {
|
it('assigns the authenticated user as author', async () => {
|
||||||
it('responds with "Incorrect email address or password."', async () => {
|
const { User } = await client.request(
|
||||||
try {
|
`{
|
||||||
await request(host, mutation({ email: 'test@example.org', password: 'wrong' }))
|
User(email:"test@example.org") {
|
||||||
} catch (error) {
|
contributions {
|
||||||
expect(error.response.errors[0].message).toEqual('Incorrect email address or password.')
|
title
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
}`,
|
||||||
})
|
{ headers }
|
||||||
|
)
|
||||||
describe('with a non-existing email', () => {
|
expect(User).toEqual([{ contributions: [{ title: 'A title' }] }])
|
||||||
it('responds with "Incorrect email address or password."', async () => {
|
|
||||||
try {
|
|
||||||
await request(host, mutation({ email: 'non-existent@example.org', password: 'wrong' }))
|
|
||||||
} catch (error) {
|
|
||||||
expect(error.response.errors[0].message).toEqual('Incorrect email address or password.')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -65,11 +143,11 @@ describe('login', () => {
|
|||||||
|
|
||||||
describe('report', () => {
|
describe('report', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await factory.create('user', {
|
await factory.create('User', {
|
||||||
email: 'test@example.org',
|
email: 'test@example.org',
|
||||||
password: '1234'
|
password: '1234'
|
||||||
})
|
})
|
||||||
await factory.create('user', {
|
await factory.create('User', {
|
||||||
id: 'u2',
|
id: 'u2',
|
||||||
name: 'abusive-user',
|
name: 'abusive-user',
|
||||||
role: 'user',
|
role: 'user',
|
||||||
@ -104,7 +182,8 @@ describe('report', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
headers = await login({ email: 'test@example.org', password: '1234' })
|
headers = await login({ email: 'test@example.org', password: '1234' })
|
||||||
client = new GraphQLClient(host, { headers })
|
client = new GraphQLClient(host, { headers })
|
||||||
response = await client.request(`mutation {
|
response = await client.request(
|
||||||
|
`mutation {
|
||||||
report(
|
report(
|
||||||
description: "I don't like this user",
|
description: "I don't like this user",
|
||||||
resource: {
|
resource: {
|
||||||
@ -113,7 +192,7 @@ describe('report', () => {
|
|||||||
}
|
}
|
||||||
) { id, createdAt }
|
) { id, createdAt }
|
||||||
}`,
|
}`,
|
||||||
{ headers }
|
{ headers }
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
it('creates a report', () => {
|
it('creates a report', () => {
|
||||||
|
|||||||
@ -7,15 +7,30 @@ export default {
|
|||||||
const result = await resolve(root, args, context, info)
|
const result = await resolve(root, args, context, info)
|
||||||
return result
|
return result
|
||||||
},
|
},
|
||||||
|
UpdatePost: async (resolve, root, args, context, info) => {
|
||||||
|
args.contentExcerpt = trunc(args.content, 120).html
|
||||||
|
const result = await resolve(root, args, context, info)
|
||||||
|
return result
|
||||||
|
},
|
||||||
CreateComment: async (resolve, root, args, context, info) => {
|
CreateComment: async (resolve, root, args, context, info) => {
|
||||||
args.contentExcerpt = trunc(args.content, 180).html
|
args.contentExcerpt = trunc(args.content, 180).html
|
||||||
const result = await resolve(root, args, context, info)
|
const result = await resolve(root, args, context, info)
|
||||||
return result
|
return result
|
||||||
},
|
},
|
||||||
|
UpdateComment: async (resolve, root, args, context, info) => {
|
||||||
|
args.contentExcerpt = trunc(args.content, 180).html
|
||||||
|
const result = await resolve(root, args, context, info)
|
||||||
|
return result
|
||||||
|
},
|
||||||
CreateOrganization: async (resolve, root, args, context, info) => {
|
CreateOrganization: async (resolve, root, args, context, info) => {
|
||||||
args.descriptionExcerpt = trunc(args.description, 120).html
|
args.descriptionExcerpt = trunc(args.description, 120).html
|
||||||
const result = await resolve(root, args, context, info)
|
const result = await resolve(root, args, context, info)
|
||||||
return result
|
return result
|
||||||
|
},
|
||||||
|
UpdateOrganization: async (resolve, root, args, context, info) => {
|
||||||
|
args.descriptionExcerpt = trunc(args.description, 120).html
|
||||||
|
const result = await resolve(root, args, context, info)
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
src/middleware/idMiddleware.js
Normal file
28
src/middleware/idMiddleware.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import cloneDeep from 'lodash/cloneDeep'
|
||||||
|
|
||||||
|
const includeId = async (resolve, root, args, context, resolveInfo) => {
|
||||||
|
// Keeping the graphql resolveInfo untouched ensures that we don't add the
|
||||||
|
// following attributes to the result set returned to the graphQL client.
|
||||||
|
// We only want to pass these attributes to our resolver for internal
|
||||||
|
// purposes e.g. authorization.
|
||||||
|
const copy = cloneDeep(resolveInfo)
|
||||||
|
|
||||||
|
copy.fieldNodes[0].selectionSet.selections.unshift({
|
||||||
|
kind: 'Field',
|
||||||
|
name: { kind: 'Name', value: 'id' }
|
||||||
|
})
|
||||||
|
return resolve(root, args, context, copy)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Query: {
|
||||||
|
User: (resolve, root, args, context, info) => {
|
||||||
|
return includeId(resolve, root, args, context, info)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Mutation: {
|
||||||
|
CreatePost: (resolve, root, args, context, info) => {
|
||||||
|
return includeId(resolve, root, args, context, info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,6 +7,7 @@ import dateTimeMiddleware from './dateTimeMiddleware'
|
|||||||
import xssMiddleware from './xssMiddleware'
|
import xssMiddleware from './xssMiddleware'
|
||||||
import permissionsMiddleware from './permissionsMiddleware'
|
import permissionsMiddleware from './permissionsMiddleware'
|
||||||
import userMiddleware from './userMiddleware'
|
import userMiddleware from './userMiddleware'
|
||||||
|
import idMiddleware from './idMiddleware'
|
||||||
|
|
||||||
export default schema => {
|
export default schema => {
|
||||||
let middleware = [
|
let middleware = [
|
||||||
@ -17,7 +18,8 @@ export default schema => {
|
|||||||
xssMiddleware,
|
xssMiddleware,
|
||||||
fixImageUrlsMiddleware,
|
fixImageUrlsMiddleware,
|
||||||
softDeleteMiddleware,
|
softDeleteMiddleware,
|
||||||
userMiddleware
|
userMiddleware,
|
||||||
|
idMiddleware
|
||||||
]
|
]
|
||||||
|
|
||||||
// add permisions middleware at the first position (unless we're seeding)
|
// add permisions middleware at the first position (unless we're seeding)
|
||||||
|
|||||||
@ -16,7 +16,7 @@ const isModerator = rule()(async (parent, args, ctx, info) => {
|
|||||||
})
|
})
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const isOwner = rule({ cache: 'no_cache' })(async (parent, args, ctx, info) => {
|
const isMyOwn = rule({ cache: 'no_cache' })(async (parent, args, ctx, info) => {
|
||||||
return ctx.user.id === parent.id
|
return ctx.user.id === parent.id
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -28,13 +28,16 @@ const permissions = shield({
|
|||||||
// customers: and(isAuthenticated, isAdmin)
|
// customers: and(isAuthenticated, isAdmin)
|
||||||
},
|
},
|
||||||
Mutation: {
|
Mutation: {
|
||||||
|
CreatePost: isAuthenticated,
|
||||||
|
// TODO UpdatePost: isOwner,
|
||||||
|
// TODO DeletePost: isOwner,
|
||||||
report: isAuthenticated
|
report: isAuthenticated
|
||||||
// addFruitToBasket: isAuthenticated
|
// addFruitToBasket: isAuthenticated
|
||||||
// CreateUser: allow,
|
// CreateUser: allow,
|
||||||
},
|
},
|
||||||
User: {
|
User: {
|
||||||
email: isOwner,
|
email: isMyOwn,
|
||||||
password: isOwner
|
password: isMyOwn
|
||||||
}
|
}
|
||||||
// Post: isAuthenticated
|
// Post: isAuthenticated
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,16 +1,18 @@
|
|||||||
import { create, cleanDatabase } from '../seed/factories'
|
import Factory from '../seed/factories'
|
||||||
import { host, login } from '../jest/helpers'
|
import { host, login } from '../jest/helpers'
|
||||||
import { GraphQLClient } from 'graphql-request'
|
import { GraphQLClient } from 'graphql-request'
|
||||||
|
|
||||||
|
const factory = Factory()
|
||||||
|
|
||||||
describe('authorization', () => {
|
describe('authorization', () => {
|
||||||
describe('given two existing users', () => {
|
describe('given two existing users', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await create('user', {
|
await factory.create('User', {
|
||||||
email: 'owner@example.org',
|
email: 'owner@example.org',
|
||||||
name: 'Owner',
|
name: 'Owner',
|
||||||
password: 'iamtheowner'
|
password: 'iamtheowner'
|
||||||
})
|
})
|
||||||
await create('user', {
|
await factory.create('User', {
|
||||||
email: 'someone@example.org',
|
email: 'someone@example.org',
|
||||||
name: 'Someone else',
|
name: 'Someone else',
|
||||||
password: 'else'
|
password: 'else'
|
||||||
@ -18,51 +20,63 @@ describe('authorization', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await cleanDatabase()
|
await factory.cleanDatabase()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('access email address', () => {
|
describe('access email address', () => {
|
||||||
let headers = {}
|
let headers = {}
|
||||||
const action = async (headers) => {
|
let loginCredentials = null
|
||||||
|
const action = async () => {
|
||||||
|
if (loginCredentials) {
|
||||||
|
headers = await login(loginCredentials)
|
||||||
|
}
|
||||||
const graphQLClient = new GraphQLClient(host, { headers })
|
const graphQLClient = new GraphQLClient(host, { headers })
|
||||||
return graphQLClient.request(`{
|
return graphQLClient.request('{User(name: "Owner") { email } }')
|
||||||
User(name: "Owner") {
|
|
||||||
email
|
|
||||||
}
|
|
||||||
}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('not logged in', async () => {
|
describe('not logged in', async () => {
|
||||||
|
it('rejects', async () => {
|
||||||
|
await expect(action()).rejects.toThrow('Not Authorised!')
|
||||||
|
})
|
||||||
|
|
||||||
it('does not expose the owner\'s email address', async () => {
|
it('does not expose the owner\'s email address', async () => {
|
||||||
try {
|
try {
|
||||||
await action(headers)
|
await action()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
expect(error.response.errors[0].message).toEqual('Not Authorised!')
|
|
||||||
expect(error.response.data).toEqual({ User: [ { email: null } ] })
|
expect(error.response.data).toEqual({ User: [ { email: null } ] })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('as owner', () => {
|
describe('as owner', () => {
|
||||||
it('exposes the owner\'s email address', async () => {
|
beforeEach(() => {
|
||||||
headers = await login({
|
loginCredentials = {
|
||||||
email: 'owner@example.org',
|
email: 'owner@example.org',
|
||||||
password: 'iamtheowner'
|
password: 'iamtheowner'
|
||||||
})
|
}
|
||||||
expect(await action(headers)).toEqual({ User: [ { email: 'owner@example.org' } ] })
|
})
|
||||||
|
|
||||||
|
it('exposes the owner\'s email address', async () => {
|
||||||
|
await expect(action()).resolves.toEqual({ User: [ { email: 'owner@example.org' } ] })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('as someone else', () => {
|
describe('authenticated as another user', () => {
|
||||||
it('does not expose the owner\'s email address', async () => {
|
beforeEach(async () => {
|
||||||
headers = await login({
|
loginCredentials = {
|
||||||
email: 'someone@example.org',
|
email: 'someone@example.org',
|
||||||
password: 'else'
|
password: 'else'
|
||||||
})
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('rejects', async () => {
|
||||||
|
await expect(action()).rejects.toThrow('Not Authorised!')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not expose the owner\'s email address', async () => {
|
||||||
try {
|
try {
|
||||||
await action(headers)
|
await action()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
expect(error.response.errors[0].message).toEqual('Not Authorised!')
|
|
||||||
expect(error.response.data).toEqual({ User: [ { email: null } ] })
|
expect(error.response.data).toEqual({ User: [ { email: null } ] })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,40 +1,44 @@
|
|||||||
import slug from 'slug'
|
import uniqueSlug from './slugify/uniqueSlug'
|
||||||
|
|
||||||
|
const isUniqueFor = (context, type) => {
|
||||||
|
return async slug => {
|
||||||
|
const session = context.driver.session()
|
||||||
|
const response = await session.run(
|
||||||
|
`MATCH(p:${type} {slug: $slug }) return p.slug`,
|
||||||
|
{
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
)
|
||||||
|
session.close()
|
||||||
|
return response.records.length === 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Mutation: {
|
Mutation: {
|
||||||
CreatePost: async (resolve, root, args, context, info) => {
|
CreatePost: async (resolve, root, args, context, info) => {
|
||||||
args.slug = slug(args.title, {
|
args.slug =
|
||||||
lower: true
|
args.slug ||
|
||||||
})
|
(await uniqueSlug(args.title, isUniqueFor(context, 'Post')))
|
||||||
const result = await resolve(root, args, context, info)
|
return resolve(root, args, context, info)
|
||||||
return result
|
|
||||||
},
|
},
|
||||||
CreateUser: async (resolve, root, args, context, info) => {
|
CreateUser: async (resolve, root, args, context, info) => {
|
||||||
if (!args.slug) {
|
args.slug =
|
||||||
args.slug = slug(args.name, {
|
args.slug ||
|
||||||
lower: true
|
(await uniqueSlug(args.name, isUniqueFor(context, 'User')))
|
||||||
})
|
return resolve(root, args, context, info)
|
||||||
}
|
|
||||||
const result = await resolve(root, args, context, info)
|
|
||||||
return result
|
|
||||||
},
|
},
|
||||||
CreateOrganization: async (resolve, root, args, context, info) => {
|
CreateOrganization: async (resolve, root, args, context, info) => {
|
||||||
if (!args.slug) {
|
args.slug =
|
||||||
args.slug = slug(args.name, {
|
args.slug ||
|
||||||
lower: true
|
(await uniqueSlug(args.name, isUniqueFor(context, 'Organization')))
|
||||||
})
|
return resolve(root, args, context, info)
|
||||||
}
|
|
||||||
const result = await resolve(root, args, context, info)
|
|
||||||
return result
|
|
||||||
},
|
},
|
||||||
CreateCategory: async (resolve, root, args, context, info) => {
|
CreateCategory: async (resolve, root, args, context, info) => {
|
||||||
if (!args.slug) {
|
args.slug =
|
||||||
args.slug = slug(args.name, {
|
args.slug ||
|
||||||
lower: true
|
(await uniqueSlug(args.name, isUniqueFor(context, 'Category')))
|
||||||
})
|
return resolve(root, args, context, info)
|
||||||
}
|
|
||||||
const result = await resolve(root, args, context, info)
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/middleware/slugify/uniqueSlug.js
Normal file
15
src/middleware/slugify/uniqueSlug.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import slugify from 'slug'
|
||||||
|
export default async function uniqueSlug (string, isUnique) {
|
||||||
|
let slug = slugify(string, {
|
||||||
|
lower: true
|
||||||
|
})
|
||||||
|
if (await isUnique(slug)) return slug
|
||||||
|
|
||||||
|
let count = 0
|
||||||
|
let uniqueSlug
|
||||||
|
do {
|
||||||
|
count += 1
|
||||||
|
uniqueSlug = `${slug}-${count}`
|
||||||
|
} while (!await isUnique(uniqueSlug))
|
||||||
|
return uniqueSlug
|
||||||
|
}
|
||||||
18
src/middleware/slugify/uniqueSlug.spec.js
Normal file
18
src/middleware/slugify/uniqueSlug.spec.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import uniqueSlug from './uniqueSlug'
|
||||||
|
|
||||||
|
describe('uniqueSlug', () => {
|
||||||
|
it('slugifies given string', () => {
|
||||||
|
const string = 'Hello World'
|
||||||
|
const isUnique = jest.fn()
|
||||||
|
.mockResolvedValue(true)
|
||||||
|
expect(uniqueSlug(string, isUnique)).resolves.toEqual('hello-world')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('increments slugified string until unique', () => {
|
||||||
|
const string = 'Hello World'
|
||||||
|
const isUnique = jest.fn()
|
||||||
|
.mockResolvedValueOnce(false)
|
||||||
|
.mockResolvedValueOnce(true)
|
||||||
|
expect(uniqueSlug(string, isUnique)).resolves.toEqual('hello-world-1')
|
||||||
|
})
|
||||||
|
})
|
||||||
115
src/middleware/slugifyMiddleware.spec.js
Normal file
115
src/middleware/slugifyMiddleware.spec.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import Factory from '../seed/factories'
|
||||||
|
import { host, login } from '../jest/helpers'
|
||||||
|
import { GraphQLClient } from 'graphql-request'
|
||||||
|
|
||||||
|
let authenticatedClient
|
||||||
|
let headers
|
||||||
|
const factory = Factory()
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await factory.create('User', { email: 'user@example.org', password: '1234' })
|
||||||
|
await factory.create('User', {
|
||||||
|
email: 'someone@example.org',
|
||||||
|
password: '1234'
|
||||||
|
})
|
||||||
|
headers = await login({ email: 'user@example.org', password: '1234' })
|
||||||
|
authenticatedClient = new GraphQLClient(host, { headers })
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await factory.cleanDatabase()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('slugify', () => {
|
||||||
|
describe('CreatePost', () => {
|
||||||
|
it('generates a slug based on title', async () => {
|
||||||
|
const response = await authenticatedClient.request(`mutation {
|
||||||
|
CreatePost(
|
||||||
|
title: "I am a brand new post",
|
||||||
|
content: "Some content"
|
||||||
|
) { slug }
|
||||||
|
}`)
|
||||||
|
expect(response).toEqual({
|
||||||
|
CreatePost: { slug: 'i-am-a-brand-new-post' }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('if slug exists', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
const asSomeoneElse = await Factory().authenticateAs({
|
||||||
|
email: 'someone@example.org',
|
||||||
|
password: '1234'
|
||||||
|
})
|
||||||
|
await asSomeoneElse.create('Post', {
|
||||||
|
title: 'Pre-existing post',
|
||||||
|
slug: 'pre-existing-post'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('chooses another slug', async () => {
|
||||||
|
const response = await authenticatedClient.request(`mutation {
|
||||||
|
CreatePost(
|
||||||
|
title: "Pre-existing post",
|
||||||
|
content: "Some content"
|
||||||
|
) { slug }
|
||||||
|
}`)
|
||||||
|
expect(response).toEqual({
|
||||||
|
CreatePost: { slug: 'pre-existing-post-1' }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('but if the client specifies a slug', () => {
|
||||||
|
it('rejects CreatePost', async () => {
|
||||||
|
await expect(
|
||||||
|
authenticatedClient.request(`mutation {
|
||||||
|
CreatePost(
|
||||||
|
title: "Pre-existing post",
|
||||||
|
content: "Some content",
|
||||||
|
slug: "pre-existing-post"
|
||||||
|
) { slug }
|
||||||
|
}`)
|
||||||
|
).rejects.toThrow('already exists')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('CreateUser', () => {
|
||||||
|
const action = async (mutation, params) => {
|
||||||
|
return authenticatedClient.request(`mutation {
|
||||||
|
${mutation}(password: "yo", ${params}) { slug }
|
||||||
|
}`)
|
||||||
|
}
|
||||||
|
it('generates a slug based on name', async () => {
|
||||||
|
await expect(
|
||||||
|
action('CreateUser', 'name: "I am a user"')
|
||||||
|
).resolves.toEqual({ CreateUser: { slug: 'i-am-a-user' } })
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('if slug exists', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await action(
|
||||||
|
'CreateUser',
|
||||||
|
'name: "Pre-existing user", slug: "pre-existing-user"'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('chooses another slug', async () => {
|
||||||
|
await expect(
|
||||||
|
action('CreateUser', 'name: "pre-existing-user"')
|
||||||
|
).resolves.toEqual({ CreateUser: { slug: 'pre-existing-user-1' } })
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('but if the client specifies a slug', () => {
|
||||||
|
it('rejects CreateUser', async () => {
|
||||||
|
await expect(
|
||||||
|
action(
|
||||||
|
'CreateUser',
|
||||||
|
'name: "Pre-existing user", slug: "pre-existing-user"'
|
||||||
|
)
|
||||||
|
).rejects.toThrow('already exists')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import createOrUpdateLocations from './nodes/locations'
|
import createOrUpdateLocations from './nodes/locations'
|
||||||
import find from 'lodash/find'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Mutation: {
|
Mutation: {
|
||||||
@ -13,28 +12,5 @@ export default {
|
|||||||
await createOrUpdateLocations(args.id, args.locationName, context.driver)
|
await createOrUpdateLocations(args.id, args.locationName, context.driver)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
},
|
|
||||||
Query: {
|
|
||||||
User: async (resolve, root, args, context, info) => {
|
|
||||||
let isIdPresent
|
|
||||||
let removeIdFromResult
|
|
||||||
try {
|
|
||||||
isIdPresent = find(info.fieldNodes[0].selectionSet.selections, item => item.name.value === 'id')
|
|
||||||
if (!isIdPresent) {
|
|
||||||
// add id to request as the user did not ask but we need it
|
|
||||||
info.fieldNodes[0].selectionSet.selections.unshift({
|
|
||||||
kind: 'Field',
|
|
||||||
name: { kind: 'Name', value: 'id' }
|
|
||||||
})
|
|
||||||
removeIdFromResult = true
|
|
||||||
}
|
|
||||||
} catch (err) {}
|
|
||||||
const result = await resolve(root, args, context, info)
|
|
||||||
if (!isIdPresent && removeIdFromResult) {
|
|
||||||
// remove id if the user did not ask for it
|
|
||||||
info.fieldNodes[0].selectionSet.selections.shift()
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ function clean (dirty) {
|
|||||||
dirty = embedToAnchor(dirty)
|
dirty = embedToAnchor(dirty)
|
||||||
dirty = linkifyHtml(dirty)
|
dirty = linkifyHtml(dirty)
|
||||||
dirty = sanitizeHtml(dirty, {
|
dirty = sanitizeHtml(dirty, {
|
||||||
allowedTags: ['iframe', 'img', 'p', 'br', 'b', 'i', 'em', 'strong', 'a', 'pre', 'ul', 'li', 'ol', 's', 'strike', 'span', 'blockquote'],
|
allowedTags: ['iframe', 'img', 'p', 'h3', 'h4', 'br', 'hr', 'b', 'i', 'em', 'strong', 'a', 'pre', 'ul', 'li', 'ol', 's', 'strike', 'span', 'blockquote'],
|
||||||
allowedAttributes: {
|
allowedAttributes: {
|
||||||
a: ['href', 'class', 'target', 'data-*', 'contenteditable'],
|
a: ['href', 'class', 'target', 'data-*', 'contenteditable'],
|
||||||
span: ['contenteditable', 'class', 'data-*'],
|
span: ['contenteditable', 'class', 'data-*'],
|
||||||
@ -47,16 +47,22 @@ function clean (dirty) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
h1: 'h3',
|
||||||
|
h2: 'h3',
|
||||||
|
h3: 'h3',
|
||||||
|
h4: 'h4',
|
||||||
|
h5: 'strong',
|
||||||
i: 'em',
|
i: 'em',
|
||||||
// a: function (tagName, attribs) {
|
a: function (tagName, attribs) {
|
||||||
// return {
|
return {
|
||||||
// tagName: 'a',
|
tagName: 'a',
|
||||||
// attribs: {
|
attribs: {
|
||||||
// href: attribs.href,
|
href: attribs.href,
|
||||||
// target: '_blank',
|
target: '_blank',
|
||||||
// }
|
rel: 'noopener noreferrer nofollow'
|
||||||
// }
|
}
|
||||||
// },
|
}
|
||||||
|
},
|
||||||
b: 'strong',
|
b: 'strong',
|
||||||
s: 'strike',
|
s: 'strike',
|
||||||
img: function (tagName, attribs) {
|
img: function (tagName, attribs) {
|
||||||
@ -92,18 +98,32 @@ function clean (dirty) {
|
|||||||
// remove empty html tags and duplicated linebreaks and returns
|
// remove empty html tags and duplicated linebreaks and returns
|
||||||
dirty = dirty
|
dirty = dirty
|
||||||
// remove all tags with "space only"
|
// remove all tags with "space only"
|
||||||
.replace(/<[a-z]>[\s]*<\/[a-z]>/igm, '')
|
.replace(/<[a-z-]+>[\s]+<\/[a-z-]+>/gim, '')
|
||||||
// remove all iframes
|
// remove all iframes
|
||||||
.replace(/(<iframe(?!.*?src=(['"]).*?\2)[^>]*)(>)[^>]*\/*>/igm, '')
|
.replace(
|
||||||
// replace all p tags with line breaks (and spaces) only by single linebreaks
|
/(<iframe(?!.*?src=(['"]).*?\2)[^>]*)(>)[^>]*\/*>/gim,
|
||||||
.replace(/<p>[\s]*(<br ?\/?>)+[\s]*<\/p>/igm, '<br>')
|
''
|
||||||
// replace multiple linebreaks with single ones
|
)
|
||||||
// limit linebreaks to max 2 (equivalent to html "br" linebreak)
|
.replace(/[\n]{3,}/gim, '\n\n')
|
||||||
.replace(/(<br ?\/?>){2,}/igm, '<br>')
|
|
||||||
.replace(/[\n]{3,}/igm, '\n\n')
|
|
||||||
.replace(/(\r\n|\n\r|\r|\n)/g, '<br>$1')
|
.replace(/(\r\n|\n\r|\r|\n)/g, '<br>$1')
|
||||||
|
|
||||||
|
// replace all p tags with line breaks (and spaces) only by single linebreaks
|
||||||
|
// limit linebreaks to max 2 (equivalent to html "br" linebreak)
|
||||||
|
.replace(/(<br ?\/?>\s*){2,}/gim, '<br>')
|
||||||
|
// remove additional linebreaks after p tags
|
||||||
|
.replace(
|
||||||
|
/<\/(p|div|th|tr)>\s*(<br ?\/?>\s*)+\s*<(p|div|th|tr)>/gim,
|
||||||
|
'</p><p>'
|
||||||
|
)
|
||||||
// remove additional linebreaks inside p tags
|
// remove additional linebreaks inside p tags
|
||||||
.replace(/<p><br><\/p>/g, '')
|
.replace(
|
||||||
|
/<[a-z-]+>(<[a-z-]+>)*\s*(<br ?\/?>\s*)+\s*(<\/[a-z-]+>)*<\/[a-z-]+>/gim,
|
||||||
|
''
|
||||||
|
)
|
||||||
|
// remove additional linebreaks when first child inside p tags
|
||||||
|
.replace(/<p>(\s*<br ?\/?>\s*)+/gim, '<p>')
|
||||||
|
// remove additional linebreaks when last child inside p tags
|
||||||
|
.replace(/(\s*<br ?\/?>\s*)+<\/p+>/gim, '</p>')
|
||||||
return dirty
|
return dirty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,62 +0,0 @@
|
|||||||
import { request } from 'graphql-request'
|
|
||||||
import { create, cleanDatabase } from './seed/factories'
|
|
||||||
import { host } from './jest/helpers'
|
|
||||||
|
|
||||||
describe('filter for searchQuery', () => {
|
|
||||||
const query = (searchQuery) => {
|
|
||||||
return `
|
|
||||||
{
|
|
||||||
findPosts(filter: "${searchQuery}", limit: 10) {
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('given some posts', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
await create('post', {
|
|
||||||
title: 'Hamlet',
|
|
||||||
content: 'To be, or not to be: that is the question'
|
|
||||||
})
|
|
||||||
await create('post', {
|
|
||||||
title: 'Threepenny Opera',
|
|
||||||
content: 'And the shark, it has teeth, And it wears them in the face.'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await cleanDatabase()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('sanitization', () => {
|
|
||||||
it('escapes cypher statement', async () => {
|
|
||||||
await request(host, query(`'');
|
|
||||||
MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE n,r;
|
|
||||||
CALL db.index.fulltext.queryNodes('full_text_search', ''
|
|
||||||
`))
|
|
||||||
const data = await request(host, query('the'))
|
|
||||||
expect(data).toEqual({ findPosts: [{ title: 'Hamlet' }, { title: 'Threepenny Opera' }] })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('result set', () => {
|
|
||||||
describe('includes posts if search term', () => {
|
|
||||||
it('matches title', async () => {
|
|
||||||
const data = await request(host, query('Hamlet'))
|
|
||||||
expect(data).toEqual({ findPosts: [{ title: 'Hamlet' }] })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('matches mistyped title', async () => {
|
|
||||||
const data = await request(host, query('amlet'))
|
|
||||||
expect(data).toEqual({ findPosts: [{ title: 'Hamlet' }] })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('matches a part of the content', async () => {
|
|
||||||
const data = await request(host, query('shark'))
|
|
||||||
expect(data).toEqual({ findPosts: [{ title: 'Threepenny Opera' }] })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
export default function (data) {
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
b1: CreateBadge(id: "b1", key: "indiegogo_en_racoon", type: crowdfunding, status: permanent, icon: "/img/badges/indiegogo_en_racoon.svg") { id }
|
|
||||||
b2: CreateBadge(id: "b2", key: "indiegogo_en_rabbit", type: crowdfunding, status: permanent, icon: "/img/badges/indiegogo_en_rabbit.svg") { id }
|
|
||||||
b3: CreateBadge(id: "b3", key: "indiegogo_en_wolf", type: crowdfunding, status: permanent, icon: "/img/badges/indiegogo_en_wolf.svg") { id }
|
|
||||||
b4: CreateBadge(id: "b4", key: "indiegogo_en_bear", type: crowdfunding, status: permanent, icon: "/img/badges/indiegogo_en_bear.svg") { id }
|
|
||||||
b5: CreateBadge(id: "b5", key: "indiegogo_en_turtle", type: crowdfunding, status: permanent, icon: "/img/badges/indiegogo_en_turtle.svg") { id }
|
|
||||||
b6: CreateBadge(id: "b6", key: "indiegogo_en_rhino", type: crowdfunding, status: permanent, icon: "/img/badges/indiegogo_en_rhino.svg") { id }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
export default function (data) {
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
cat1: CreateCategory( id: "cat1", name: "Just For Fun", slug: "justforfun", icon: "smile" ) { name }
|
|
||||||
cat2: CreateCategory( id: "cat2", name: "Happyness & Values", slug: "happyness-values", icon: "heart-o" ) { name }
|
|
||||||
cat3: CreateCategory( id: "cat3", name: "Health & Wellbeing", slug: "health-wellbeing", icon: "medkit" ) { name }
|
|
||||||
cat4: CreateCategory( id: "cat4", name: "Environment & Nature", slug: "environment-nature", icon: "tree" ) { name }
|
|
||||||
cat5: CreateCategory( id: "cat5", name: "Animal Protection", slug: "animalprotection", icon: "paw" ) { name }
|
|
||||||
cat6: CreateCategory( id: "cat6", name: "Humanrights Justice", slug: "humanrights-justice", icon: "balance-scale" ) { name }
|
|
||||||
cat7: CreateCategory( id: "cat7", name: "Education & Sciences", slug: "education-sciences", icon: "graduation-cap" ) { name }
|
|
||||||
cat8: CreateCategory( id: "cat8", name: "Cooperation & Development", slug: "cooperation-development", icon: "users" ) { name }
|
|
||||||
cat9: CreateCategory( id: "cat9", name: "Democracy & Politics", slug: "democracy-politics", icon: "university" ) { name }
|
|
||||||
cat10: CreateCategory( id: "cat10", name: "Economy & Finances", slug: "economy-finances", icon: "money" ) { name }
|
|
||||||
cat11: CreateCategory( id: "cat11", name: "Energy & Technology", slug: "energy-technology", icon: "flash" ) { name }
|
|
||||||
cat12: CreateCategory( id: "cat12", name: "IT, Internet & Data Privacy", slug: "it-internet-dataprivacy", icon: "mouse-pointer" ) { name }
|
|
||||||
cat13: CreateCategory( id: "cat13", name: "Art, Curlure & Sport", slug: "art-culture-sport", icon: "paint-brush" ) { name }
|
|
||||||
cat14: CreateCategory( id: "cat14", name: "Freedom of Speech", slug: "freedomofspeech", icon: "bullhorn" ) { name }
|
|
||||||
cat15: CreateCategory( id: "cat15", name: "Consumption & Sustainability", slug: "consumption-sustainability", icon: "shopping-cart" ) { name }
|
|
||||||
cat16: CreateCategory( id: "cat16", name: "Global Peace & Nonviolence", slug: "globalpeace-nonviolence", icon: "angellist" ) { name }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
@ -1,80 +0,0 @@
|
|||||||
import faker from 'faker'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: add a comment automatically to the correct post and relate it to the current user
|
|
||||||
*/
|
|
||||||
export default function (data) {
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
c1: CreateComment(
|
|
||||||
id: "c1",
|
|
||||||
content: "<p>da stimm ich dir zu. Mir ging das auch nie in den kopf, und hatte jesus nie als gott gesehen </p>"
|
|
||||||
) { id }
|
|
||||||
c1_u1: AddCommentAuthor(from: { id: "u3" }, to: { id: "c1" }) { from { id } }
|
|
||||||
c1_p1: AddCommentPost(
|
|
||||||
from: { id: "c1" },
|
|
||||||
to: { id: "p1" }
|
|
||||||
) { from { id } }
|
|
||||||
|
|
||||||
c2: CreateComment(
|
|
||||||
id: "c2",
|
|
||||||
content: "<p>Schön das es dich gibt ❤️❤️❤️❤️❤️❤️❤️❤️❤️</p>"
|
|
||||||
) { id }
|
|
||||||
c2_u1: AddCommentAuthor(from: { id: "u1" }, to: { id: "c2" }) { from { id } }
|
|
||||||
c2_p1: AddCommentPost(
|
|
||||||
from: { id: "c2" },
|
|
||||||
to: { id: "p1" }
|
|
||||||
) { from { id } }
|
|
||||||
|
|
||||||
c3: CreateComment(
|
|
||||||
id: "c3",
|
|
||||||
content: "<p>Hi Dieter,</p><p>danke für Deine Info. Hast Du mal ein Foto von Deinem Cabrio mit dem Logo drauf?</p>"
|
|
||||||
) { id }
|
|
||||||
c3_u2: AddCommentAuthor(from: { id: "u1" }, to: { id: "c3" }) { from { id } }
|
|
||||||
c3_p3: AddCommentPost(
|
|
||||||
from: { id: "c3" },
|
|
||||||
to: { id: "p3" }
|
|
||||||
) { from { id } }
|
|
||||||
|
|
||||||
c4: CreateComment(
|
|
||||||
id: "c4",
|
|
||||||
content: "<p>Das Zusammenführen aller Gruppen, die mit uns am gleichen Strang in die gleiche Richtung ziehen, in eine gemeinsame Adressenstruktur sehe ich auch als Haupt - Aufgabe für unsere neue Netzwerkbildung an.</p>"
|
|
||||||
) { id }
|
|
||||||
c4_u3: AddCommentAuthor(from: { id: "u4" }, to: { id: "c4" }) { from { id } }
|
|
||||||
c4_p2: AddCommentPost(
|
|
||||||
from: { id: "c4" },
|
|
||||||
to: { id: "p2" }
|
|
||||||
) { from { id } }
|
|
||||||
|
|
||||||
c5: CreateComment(
|
|
||||||
id: "c5",
|
|
||||||
content: "${faker.lorem.paragraph()}"
|
|
||||||
) { id }
|
|
||||||
c5_u4: AddCommentAuthor(from: { id: "u4" }, to: { id: "c5" }) { from { id } }
|
|
||||||
c5_p3: AddCommentPost(
|
|
||||||
from: { id: "c5" },
|
|
||||||
to: { id: "p3" }
|
|
||||||
) { from { id } }
|
|
||||||
|
|
||||||
c6: CreateComment(
|
|
||||||
id: "c6",
|
|
||||||
content: "${faker.lorem.paragraph()}"
|
|
||||||
) { id }
|
|
||||||
c6_u3: AddCommentAuthor(from: { id: "u3" }, to: { id: "c6" }) { from { id } }
|
|
||||||
c6_p4: AddCommentPost(
|
|
||||||
from: { id: "c6" },
|
|
||||||
to: { id: "p4" }
|
|
||||||
) { from { id } }
|
|
||||||
|
|
||||||
c7: CreateComment(
|
|
||||||
id: "c7",
|
|
||||||
content: "${faker.lorem.paragraph()}"
|
|
||||||
) { id }
|
|
||||||
c7_u2: AddCommentAuthor(from: { id: "u2" }, to: { id: "c7" }) { from { id } }
|
|
||||||
c7_p2: AddCommentPost(
|
|
||||||
from: { id: "c7" },
|
|
||||||
to: { id: "p2" }
|
|
||||||
) { from { id } }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
import gql from 'graphql-tag'
|
|
||||||
import asyncForEach from '../../helpers/asyncForEach'
|
|
||||||
|
|
||||||
const seed = {
|
|
||||||
Badge: require('./badges.js').default,
|
|
||||||
Category: require('./categories.js').default,
|
|
||||||
Tags: require('./tags.js').default,
|
|
||||||
|
|
||||||
User: require('./users.js').default,
|
|
||||||
UserBadges: require('./users-badges.js').default,
|
|
||||||
UserBlacklist: require('./users-blacklist.js').default,
|
|
||||||
UserFollows: require('./users-follows.js').default,
|
|
||||||
UserFriends: require('./users-friends.js').default,
|
|
||||||
|
|
||||||
Organization: require('./organizations.js').default,
|
|
||||||
Post: require('./posts.js').default,
|
|
||||||
Comment: require('./comments.js').default,
|
|
||||||
UserShouts: require('./users-shouts.js').default
|
|
||||||
|
|
||||||
// Reports: require('./reports.js').default
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = {}
|
|
||||||
|
|
||||||
export default async function (client) {
|
|
||||||
// iterate through seeds
|
|
||||||
await asyncForEach(Object.keys(seed), async key => {
|
|
||||||
const mutations = seed[key]
|
|
||||||
try {
|
|
||||||
const res = await client
|
|
||||||
.mutate({
|
|
||||||
mutation: gql(mutations(data))
|
|
||||||
})
|
|
||||||
data[key] = Object.assign(data[key] || {}, res.data)
|
|
||||||
} catch (err) {
|
|
||||||
/* eslint-disable-next-line no-console */
|
|
||||||
console.error(err)
|
|
||||||
process.exit(1)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
/* eslint-disable-next-line no-console */
|
|
||||||
console.log('Seeded Data...')
|
|
||||||
}
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
export default () => {
|
|
||||||
return `mutation {
|
|
||||||
o1: CreateOrganization(
|
|
||||||
id: "o1",
|
|
||||||
name: "Democracy Deutschland",
|
|
||||||
description: "Description for democracy-deutschland.",
|
|
||||||
disabled: false,
|
|
||||||
deleted: false
|
|
||||||
) { name }
|
|
||||||
o2: CreateOrganization(
|
|
||||||
id: "o2",
|
|
||||||
name: "Human-Connection",
|
|
||||||
description: "Description for human-connection.",
|
|
||||||
disabled: false,
|
|
||||||
deleted: false
|
|
||||||
) { name }
|
|
||||||
o3: CreateOrganization(
|
|
||||||
id: "o3",
|
|
||||||
name: "Pro Veg",
|
|
||||||
description: "Description for pro-veg.",
|
|
||||||
disabled: false,
|
|
||||||
deleted: false
|
|
||||||
) { name }
|
|
||||||
o4: CreateOrganization(
|
|
||||||
id: "o4",
|
|
||||||
name: "Greenpeace",
|
|
||||||
description: "Description for greenpeace.",
|
|
||||||
disabled: false,
|
|
||||||
deleted: false
|
|
||||||
) { name }
|
|
||||||
|
|
||||||
u1_c_o1: AddOrganizationCreatedBy(
|
|
||||||
from: { id: "u1" },
|
|
||||||
to: { id: "o1" }
|
|
||||||
) { from { id } }
|
|
||||||
u1_c_o2: AddOrganizationCreatedBy(
|
|
||||||
from: { id: "u1" },
|
|
||||||
to: { id: "o2" }
|
|
||||||
) { from { id } }
|
|
||||||
|
|
||||||
u2_o_o1: AddOrganizationOwnedBy(
|
|
||||||
from: { id: "u2" },
|
|
||||||
to: { id: "o2" }
|
|
||||||
) { from { id } }
|
|
||||||
u2_c_o3: AddOrganizationOwnedBy(
|
|
||||||
from: { id: "u2" },
|
|
||||||
to: { id: "o3" }
|
|
||||||
) { from { id } }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
@ -1,112 +0,0 @@
|
|||||||
import faker from 'faker'
|
|
||||||
|
|
||||||
export default function (data) {
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
p1: CreatePost(
|
|
||||||
id: "p1",
|
|
||||||
title: "Gedanken eines Polizisten zum Einsatz im Hambacher Forst",
|
|
||||||
content: "<p><strong>Diese Zukunftsstadt ist real und keine Computer-Animation</strong> – sondern sie ist das Lebenswerk des mittlerweile über 100 Jahre alten Futuristen und Architekten Jacque Fresco aus Florida. In 35 Jahren (seit seinem 13. Lebensjahr) hat dieser zusammen mit seiner Frau seinen futuristischen Traum von einer besonderen Zukunftsstadt auf 85.000 Quadratmetern realisiert. In den Gebäuden und Gärten befinden sich u.a. ein Forschungszentrum, Vortragsräume und unzählige seiner Modelle & Architekturentwürfe.</p><br /><p>Sein zentrales Anliegen ist eine resourcenbasierte Wirtschaft und die Abschaffung von Geld und Privatbesitz. Mit Hilfe von Roboterarbeit und dem Bedingungslosen Grundeinkommen (da nach seiner Ansicht in den kommenden Jahren fast alle Jobs automatisiert werden), möchte er eine ökologische Landwirtschaft mit Permakulturen etc. und eine effiziente Energiegewinnung (ausschließlich durch regenerative Energien) schaffen. Wenige kompatible Formen in einer sparsamen Modulbauweise (in die u.a. bereits variable Service- und Reparaturelemente integriert sind) sollen insgesamt eine soziale & ökologische Utopie im Einklang mit der Natur ermöglichen.</p><br /><p>Nachfolgend der Direkt-Link auf den interessanten Artikel von Zoltan Istvan, der den Architekten und seine Frau in Florida besuchen durfte und seinen Artikel Ende 2016 auf „MOTHERBOARD“ veröffentlicht hatte:</p><br /><p>https://motherboard.vice.com/de/article/vv34nb/ich-habe-die-zukunft-besucht-in-der-wir-ohne-geld-steuern-und-besitz-leben</p><br /><p>Da soll noch jemand behaupten, es gäbe keine Utopien mehr bzw. keine Futuristen, die ihre kreativen und zukunftsfähigen Ideen (auch in ganz großem Stil) selbst in die Tat umsetzen. LG @all :)</p><br /><p><strong>Wir sind eine Menschheitsfamilie. • Wir sind eins. • Wir sind HUMAN CONNECTION</strong>❤️</p>",
|
|
||||||
image: "https://picsum.photos/1280/1024?image=352",
|
|
||||||
visibility: public,
|
|
||||||
disabled: false,
|
|
||||||
deleted: false
|
|
||||||
) { title }
|
|
||||||
p1_cat1: AddPostCategories(from: {id: "p1"}, to: {id: "cat1"}) { from { id } }
|
|
||||||
p1_cat2: AddPostCategories(from: {id: "p1"}, to: {id: "cat2"}) { from { id } }
|
|
||||||
ur1: AddUserContributions(from: { id: "u1" }, to: { id: "p1" }) { from { id } }
|
|
||||||
p1_t1: AddPostTags(
|
|
||||||
from: { id: "p1" }
|
|
||||||
to: { id: "t1" }
|
|
||||||
) { from { id } }
|
|
||||||
p1_t2: AddPostTags(
|
|
||||||
from: { id: "p1" }
|
|
||||||
to: { id: "t2" }
|
|
||||||
) { from { id } }
|
|
||||||
p1_t3: AddPostTags(
|
|
||||||
from: { id: "p1" }
|
|
||||||
to: { id: "t3" }
|
|
||||||
) { from { id } }
|
|
||||||
|
|
||||||
p2: CreatePost(
|
|
||||||
id: "p2",
|
|
||||||
title: "Julian Assange",
|
|
||||||
content: "<p><strong>Diese Zukunftsstadt ist real und keine Computer-Animation</strong> – sondern sie ist das Lebenswerk des mittlerweile über 100 Jahre alten Futuristen und Architekten Jacque Fresco aus Florida. In 35 Jahren (seit seinem 13. Lebensjahr) hat dieser zusammen mit seiner Frau seinen futuristischen Traum von einer besonderen Zukunftsstadt auf 85.000 Quadratmetern realisiert. In den Gebäuden und Gärten befinden sich u.a. ein Forschungszentrum, Vortragsräume und unzählige seiner Modelle & Architekturentwürfe.</p><br /><p>Sein zentrales Anliegen ist eine resourcenbasierte Wirtschaft und die Abschaffung von Geld und Privatbesitz. Mit Hilfe von Roboterarbeit und dem Bedingungslosen Grundeinkommen (da nach seiner Ansicht in den kommenden Jahren fast alle Jobs automatisiert werden), möchte er eine ökologische Landwirtschaft mit Permakulturen etc. und eine effiziente Energiegewinnung (ausschließlich durch regenerative Energien) schaffen. Wenige kompatible Formen in einer sparsamen Modulbauweise (in die u.a. bereits variable Service- und Reparaturelemente integriert sind) sollen insgesamt eine soziale & ökologische Utopie im Einklang mit der Natur ermöglichen.</p><br /><p>Nachfolgend der Direkt-Link auf den interessanten Artikel von Zoltan Istvan, der den Architekten und seine Frau in Florida besuchen durfte und seinen Artikel Ende 2016 auf „MOTHERBOARD“ veröffentlicht hatte:</p><br /><p>https://motherboard.vice.com/de/article/vv34nb/ich-habe-die-zukunft-besucht-in-der-wir-ohne-geld-steuern-und-besitz-leben</p><br /><p>Da soll noch jemand behaupten, es gäbe keine Utopien mehr bzw. keine Futuristen, die ihre kreativen und zukunftsfähigen Ideen (auch in ganz großem Stil) selbst in die Tat umsetzen. LG @all :)</p><br /><p><strong>Wir sind eine Menschheitsfamilie. • Wir sind eins. • Wir sind HUMAN CONNECTION</strong>❤️</p>",
|
|
||||||
image: "https://picsum.photos/1280/1024?image=72",
|
|
||||||
visibility: public,
|
|
||||||
disabled: false,
|
|
||||||
deleted: false
|
|
||||||
) { title }
|
|
||||||
p2_cat1: AddPostCategories(from: {id: "p2"}, to: {id: "cat1"}) { from { id } }
|
|
||||||
p2_cat16: AddPostCategories(from: {id: "p2"}, to: {id: "cat16"}) { from { id } }
|
|
||||||
ur2: AddUserContributions(from: { id: "u2" }, to: { id: "p2" }) { from { id } }
|
|
||||||
p2_t4: AddPostTags(
|
|
||||||
from: { id: "p2" }
|
|
||||||
to: { id: "t4" }
|
|
||||||
) { from { id } }
|
|
||||||
|
|
||||||
p3: CreatePost(
|
|
||||||
id: "p3",
|
|
||||||
title: "Hacker, Freaks und Funktionäre...Der CCC",
|
|
||||||
content: "${faker.lorem.sentence()} ${faker.lorem.sentence()} ${faker.lorem.sentence()} ${faker.lorem.sentence()} ${faker.lorem.sentence()}",
|
|
||||||
image: "https://picsum.photos/1280/1024?image=121",
|
|
||||||
visibility: public,
|
|
||||||
disabled: false,
|
|
||||||
deleted: false
|
|
||||||
) { title }
|
|
||||||
p3_cat1: AddPostCategories(from: {id: "p3"}, to: {id: "cat1"}) { from { id } }
|
|
||||||
p3_cat3: AddPostCategories(from: {id: "p3"}, to: {id: "cat3"}) { from { id } }
|
|
||||||
p3_cat14: AddPostCategories(from: {id: "p3"}, to: {id: "cat14"}) { from { id } }
|
|
||||||
ur3: AddUserContributions(from: { id: "u3" }, to: { id: "p3" }) { from { id } }
|
|
||||||
p3_t2: AddPostTags(
|
|
||||||
from: { id: "p3" }
|
|
||||||
to: { id: "t2" }
|
|
||||||
) { from { id } }
|
|
||||||
p3_t4: AddPostTags(
|
|
||||||
from: { id: "p3" }
|
|
||||||
to: { id: "t4" }
|
|
||||||
) { from { id } }
|
|
||||||
|
|
||||||
p4: CreatePost(
|
|
||||||
id: "p4",
|
|
||||||
title: "Lebensmittel (?)",
|
|
||||||
content: "${faker.lorem.sentence()} ${faker.lorem.sentence()} ${faker.lorem.sentence()} ${faker.lorem.sentence()} ${faker.lorem.sentence()}",
|
|
||||||
image: "https://picsum.photos/1280/1024?image=142",
|
|
||||||
visibility: public,
|
|
||||||
disabled: false,
|
|
||||||
deleted: false
|
|
||||||
) { title }
|
|
||||||
p4_cat1: AddPostCategories(from: {id: "p4"}, to: {id: "cat1"}) { from { id } }
|
|
||||||
p4_cat9: AddPostCategories(from: {id: "p4"}, to: {id: "cat9"}) { from { id } }
|
|
||||||
p4_cat4: AddPostCategories(from: {id: "p4"}, to: {id: "cat4"}) { from { id } }
|
|
||||||
ur4: AddUserContributions(from: { id: "u4" }, to: { id: "p4" }) { from { id } }
|
|
||||||
|
|
||||||
p5: CreatePost(
|
|
||||||
id: "p5",
|
|
||||||
title: "${faker.lorem.sentence()}",
|
|
||||||
content: "${faker.lorem.sentence()} ${faker.lorem.sentence()} ${faker.lorem.sentence()} ${faker.lorem.sentence()} ${faker.lorem.sentence()}",
|
|
||||||
image: "https://picsum.photos/1280/1024?image=231",
|
|
||||||
visibility: public,
|
|
||||||
disabled: false,
|
|
||||||
deleted: false
|
|
||||||
) { title }
|
|
||||||
p5_cat8: AddPostCategories(from: {id: "p5"}, to: {id: "cat8"}) { from { id } }
|
|
||||||
p5_cat12: AddPostCategories(from: {id: "p5"}, to: {id: "cat12"}) { from { id } }
|
|
||||||
ur5: AddUserContributions(from: { id: "u2" }, to: { id: "p5" }) { from { id } }
|
|
||||||
|
|
||||||
p6: CreatePost(
|
|
||||||
id: "p6",
|
|
||||||
title: "${faker.lorem.sentence()}",
|
|
||||||
content: "${faker.lorem.sentence()} ${faker.lorem.sentence()} ${faker.lorem.sentence()} ${faker.lorem.sentence()} ${faker.lorem.sentence()}",
|
|
||||||
image: "https://picsum.photos/1280/1024?image=424",
|
|
||||||
visibility: public,
|
|
||||||
disabled: false,
|
|
||||||
deleted: false
|
|
||||||
) { title }
|
|
||||||
p6_cat1: AddPostCategories(from: {id: "p6"}, to: {id: "cat1"}) { from { id } }
|
|
||||||
p6_cat2: AddPostCategories(from: {id: "p6"}, to: {id: "cat2"}) { from { id } }
|
|
||||||
p6_cat5: AddPostCategories(from: {id: "p6"}, to: {id: "cat5"}) { from { id } }
|
|
||||||
ur6: AddUserContributions(from: { id: "u4" }, to: { id: "p6" }) { from { id } }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
export default function (data) {
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
r1: CreateReport(id: "r1", type: contribution, description: "Bad Stuff") {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
r2: CreateReport(id: "r2", type: comment, description: "Please remove this sh**") {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
r3: CreateReport(id: "r3", type: user, description: "The user have misbehaved!") {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
ra1: AddReportReporter(from: { id: "u1" }, to: { id: "r1" }) {
|
|
||||||
from {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ra2: AddReportReporter(from: { id: "u2" }, to: { id: "r2" }) {
|
|
||||||
from {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ra3: AddReportReporter(from: { id: "u3" }, to: { id: "r3" }) {
|
|
||||||
from {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rc1: AddReportContribution(from: { id: "r1" }, to: { id: "p2" }) {
|
|
||||||
from {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rc2: AddReportComment(from: { id: "r2" }, to: { id: "c2" }) {
|
|
||||||
from {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rc3: AddReportUser(from: { id: "r3" }, to: { id: "u4" }) {
|
|
||||||
from {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
export default function (data) {
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
t1: CreateTag(
|
|
||||||
id: "t1",
|
|
||||||
name: "Umwelt"
|
|
||||||
) { name }
|
|
||||||
t2: CreateTag(
|
|
||||||
id: "t2",
|
|
||||||
name: "Naturschutz"
|
|
||||||
) { name }
|
|
||||||
t3: CreateTag(
|
|
||||||
id: "t3",
|
|
||||||
name: "Demokratie"
|
|
||||||
) { name }
|
|
||||||
t4: CreateTag(
|
|
||||||
id: "t4",
|
|
||||||
name: "Freiheit"
|
|
||||||
) { name }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
export default function (data) {
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
b1_u1: AddUserBadges(from: {id: "b1"}, to: {id: "u1"}) { from { id } }
|
|
||||||
b2_u1: AddUserBadges(from: {id: "b2"}, to: {id: "u1"}) { from { id } }
|
|
||||||
b3_u1: AddUserBadges(from: {id: "b3"}, to: {id: "u1"}) { from { id } }
|
|
||||||
b6_u2: AddUserBadges(from: {id: "b6"}, to: {id: "u2"}) { from { id } }
|
|
||||||
b3_u3: AddUserBadges(from: {id: "b3"}, to: {id: "u3"}) { from { id } }
|
|
||||||
b5_u4: AddUserBadges(from: {id: "b5"}, to: {id: "u4"}) { from { id } }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
export default function (data) {
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
u1_blacklist_u4: AddUserBlacklisted(from: { id: "u1" }, to: { id: "u4" }) { from { id } }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
export default function (data) {
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
u1_follow_u2: AddUserFollowing(
|
|
||||||
from: { id: "u1" },
|
|
||||||
to: { id: "u2" }
|
|
||||||
) { from { id } }
|
|
||||||
u2_follow_u1: AddUserFollowing(
|
|
||||||
from: { id: "u2" },
|
|
||||||
to: { id: "u1" }
|
|
||||||
) { from { id } }
|
|
||||||
u2_follow_u3: AddUserFollowing(
|
|
||||||
from: { id: "u2" },
|
|
||||||
to: { id: "u3" }
|
|
||||||
) { from { id } }
|
|
||||||
u2_follow_u4: AddUserFollowing(
|
|
||||||
from: { id: "u2" },
|
|
||||||
to: { id: "u4" }
|
|
||||||
) { from { id } }
|
|
||||||
u4_follow_u2: AddUserFollowing(
|
|
||||||
from: { id: "u4" },
|
|
||||||
to: { id: "u2" }
|
|
||||||
) { from { id } }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
export default function (data) {
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
u1_friends_u2: AddUserFriends(
|
|
||||||
from: { id: "u1" },
|
|
||||||
to: { id: "u2" }
|
|
||||||
) { from { id } }
|
|
||||||
u1_friends_u3: AddUserFriends(
|
|
||||||
from: { id: "u1" },
|
|
||||||
to: { id: "u3" }
|
|
||||||
) { from { id } }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
export default function (data) {
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
u1s2: AddUserShouted(
|
|
||||||
from: { id: "u1" },
|
|
||||||
to: { id: "p2" }
|
|
||||||
) { from { id } }
|
|
||||||
u1s3: AddUserShouted(
|
|
||||||
from: { id: "u1" },
|
|
||||||
to: { id: "p3" }
|
|
||||||
) { from { id } }
|
|
||||||
u2s1: AddUserShouted(
|
|
||||||
from: { id: "u2" },
|
|
||||||
to: { id: "p1" }
|
|
||||||
) { from { id } }
|
|
||||||
u3s1: AddUserShouted(
|
|
||||||
from: { id: "u3" },
|
|
||||||
to: { id: "p1" }
|
|
||||||
) { from { id } }
|
|
||||||
u3s4: AddUserShouted(
|
|
||||||
from: { id: "u3" },
|
|
||||||
to: { id: "p4" }
|
|
||||||
) { from { id } }
|
|
||||||
u4s1: AddUserShouted(
|
|
||||||
from: { id: "u4" },
|
|
||||||
to: { id: "p1" }
|
|
||||||
) { from { id } }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
import faker from 'faker'
|
|
||||||
|
|
||||||
export default function (data) {
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
u1: CreateUser(
|
|
||||||
id: "u1",
|
|
||||||
name: "Peter Lustig",
|
|
||||||
password: "1234",
|
|
||||||
email: "admin@example.org",
|
|
||||||
avatar: "${faker.internet.avatar()}",
|
|
||||||
locationName: "Hamburg, Germany",
|
|
||||||
role: admin,
|
|
||||||
disabled: false,
|
|
||||||
deleted: false) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
email
|
|
||||||
avatar
|
|
||||||
role
|
|
||||||
}
|
|
||||||
u2: CreateUser(
|
|
||||||
id: "u2",
|
|
||||||
name: "Bob der Bausmeister",
|
|
||||||
password: "1234",
|
|
||||||
email: "moderator@example.org",
|
|
||||||
avatar: "${faker.internet.avatar()}",
|
|
||||||
locationName: "USA",
|
|
||||||
role: moderator,
|
|
||||||
disabled: false,
|
|
||||||
deleted: false) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
email
|
|
||||||
avatar
|
|
||||||
role
|
|
||||||
}
|
|
||||||
u3: CreateUser(
|
|
||||||
id: "u3",
|
|
||||||
name: "Jenny Rostock",
|
|
||||||
password: "1234",
|
|
||||||
email: "user@example.org",
|
|
||||||
avatar: "${faker.internet.avatar()}",
|
|
||||||
role: user,
|
|
||||||
disabled: false,
|
|
||||||
deleted: false) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
email
|
|
||||||
avatar
|
|
||||||
role
|
|
||||||
}
|
|
||||||
u4: CreateUser(
|
|
||||||
id: "u4",
|
|
||||||
name: "Angie Banjie",
|
|
||||||
password: "1234",
|
|
||||||
email: "angie@example.org",
|
|
||||||
avatar: "${faker.internet.avatar()}",
|
|
||||||
role: user,
|
|
||||||
disabled: false,
|
|
||||||
deleted: false) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
email
|
|
||||||
avatar
|
|
||||||
role
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
@ -23,15 +23,3 @@ export default function (params) {
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function relate (type, params) {
|
|
||||||
const { from, to } = params
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
${from}_${type}_${to}: AddComment${type}(
|
|
||||||
from: { id: "${from}" },
|
|
||||||
to: { id: "${to}" }
|
|
||||||
) { from { id } }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
import { GraphQLClient, request } from "graphql-request";
|
import { GraphQLClient, request } from 'graphql-request'
|
||||||
import { getDriver } from "../../bootstrap/neo4j";
|
import { getDriver } from '../../bootstrap/neo4j'
|
||||||
|
|
||||||
import createBadge from "./badges.js";
|
import createBadge from './badges.js'
|
||||||
import createUser from "./users.js";
|
import createUser from './users.js'
|
||||||
import createOrganization from "./organizations.js";
|
import createOrganization from './organizations.js'
|
||||||
import createPost from "./posts.js";
|
import createPost from './posts.js'
|
||||||
import createComment from "./comments.js";
|
import createComment from './comments.js'
|
||||||
import createCategory from "./categories.js";
|
import createCategory from './categories.js'
|
||||||
import createTag from "./tags.js";
|
import createTag from './tags.js'
|
||||||
import createReport from "./reports.js";
|
import createReport from './reports.js'
|
||||||
|
|
||||||
export const seedServerHost = "http://127.0.0.1:4001";
|
export const seedServerHost = 'http://127.0.0.1:4001'
|
||||||
|
|
||||||
const authenticatedHeaders = async ({ email, password }, host) => {
|
const authenticatedHeaders = async ({ email, password }, host) => {
|
||||||
const mutation = `
|
const mutation = `
|
||||||
@ -18,12 +18,12 @@ const authenticatedHeaders = async ({ email, password }, host) => {
|
|||||||
login(email:"${email}", password:"${password}"){
|
login(email:"${email}", password:"${password}"){
|
||||||
token
|
token
|
||||||
}
|
}
|
||||||
}`;
|
}`
|
||||||
const response = await request(host, mutation);
|
const response = await request(host, mutation)
|
||||||
return {
|
return {
|
||||||
authorization: `Bearer ${response.login.token}`
|
authorization: `Bearer ${response.login.token}`
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
const factories = {
|
const factories = {
|
||||||
Badge: createBadge,
|
Badge: createBadge,
|
||||||
User: createUser,
|
User: createUser,
|
||||||
@ -33,28 +33,28 @@ const factories = {
|
|||||||
Category: createCategory,
|
Category: createCategory,
|
||||||
Tag: createTag,
|
Tag: createTag,
|
||||||
Report: createReport
|
Report: createReport
|
||||||
};
|
}
|
||||||
|
|
||||||
export const cleanDatabase = async (options = {}) => {
|
export const cleanDatabase = async (options = {}) => {
|
||||||
const { driver = getDriver() } = options;
|
const { driver = getDriver() } = options
|
||||||
const session = driver.session();
|
const session = driver.session()
|
||||||
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) {
|
} catch (error) {
|
||||||
throw error;
|
throw error
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
session.close()
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default function Factory(options = {}) {
|
export default function Factory (options = {}) {
|
||||||
const {
|
const {
|
||||||
neo4jDriver = getDriver(),
|
neo4jDriver = getDriver(),
|
||||||
seedServerHost = "http://127.0.0.1:4001"
|
seedServerHost = 'http://127.0.0.1:4001'
|
||||||
} = options;
|
} = options
|
||||||
|
|
||||||
const graphQLClient = new GraphQLClient(seedServerHost);
|
const graphQLClient = new GraphQLClient(seedServerHost)
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
neo4jDriver,
|
neo4jDriver,
|
||||||
@ -62,22 +62,22 @@ export default function Factory(options = {}) {
|
|||||||
graphQLClient,
|
graphQLClient,
|
||||||
factories,
|
factories,
|
||||||
lastResponse: null,
|
lastResponse: null,
|
||||||
async authenticateAs({ email, password }) {
|
async authenticateAs ({ email, password }) {
|
||||||
const headers = await authenticatedHeaders(
|
const headers = await authenticatedHeaders(
|
||||||
{ email, password },
|
{ email, password },
|
||||||
seedServerHost
|
seedServerHost
|
||||||
);
|
)
|
||||||
this.lastResponse = headers;
|
this.lastResponse = headers
|
||||||
this.graphQLClient = new GraphQLClient(seedServerHost, { headers });
|
this.graphQLClient = new GraphQLClient(seedServerHost, { headers })
|
||||||
return this;
|
return this
|
||||||
},
|
},
|
||||||
async create(node, properties) {
|
async create (node, properties) {
|
||||||
const mutation = this.factories[node](properties);
|
const mutation = this.factories[node](properties)
|
||||||
this.lastResponse = await this.graphQLClient.request(mutation);
|
this.lastResponse = await this.graphQLClient.request(mutation)
|
||||||
return this;
|
return this
|
||||||
},
|
},
|
||||||
async relate(node, relationship, properties) {
|
async relate (node, relationship, properties) {
|
||||||
const { from, to } = properties;
|
const { from, to } = properties
|
||||||
const mutation = `
|
const mutation = `
|
||||||
mutation {
|
mutation {
|
||||||
Add${node}${relationship}(
|
Add${node}${relationship}(
|
||||||
@ -85,18 +85,18 @@ export default function Factory(options = {}) {
|
|||||||
to: { id: "${to}" }
|
to: { id: "${to}" }
|
||||||
) { from { id } }
|
) { from { id } }
|
||||||
}
|
}
|
||||||
`;
|
`
|
||||||
this.lastResponse = await this.graphQLClient.request(mutation);
|
this.lastResponse = await this.graphQLClient.request(mutation)
|
||||||
return this;
|
return this
|
||||||
},
|
},
|
||||||
async cleanDatabase() {
|
async cleanDatabase () {
|
||||||
this.lastResponse = await cleanDatabase({ driver: this.neo4jDriver });
|
this.lastResponse = await cleanDatabase({ driver: this.neo4jDriver })
|
||||||
return this;
|
return this
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
result.authenticateAs.bind(result);
|
result.authenticateAs.bind(result)
|
||||||
result.create.bind(result);
|
result.create.bind(result)
|
||||||
result.relate.bind(result);
|
result.relate.bind(result)
|
||||||
result.cleanDatabase.bind(result);
|
result.cleanDatabase.bind(result)
|
||||||
return result;
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,15 +22,3 @@ export default function create (params) {
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function relate (type, params) {
|
|
||||||
const { from, to } = params
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
${from}_${type}_${to}: AddOrganization${type}(
|
|
||||||
from: { id: "${from}" },
|
|
||||||
to: { id: "${to}" }
|
|
||||||
) { from { id } }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import faker from "faker";
|
import faker from 'faker'
|
||||||
import uuid from "uuid/v4";
|
import uuid from 'uuid/v4'
|
||||||
|
|
||||||
export default function(params) {
|
export default function (params) {
|
||||||
const {
|
const {
|
||||||
id = uuid(),
|
id = uuid(),
|
||||||
title = faker.lorem.sentence(),
|
title = faker.lorem.sentence(),
|
||||||
@ -11,12 +11,12 @@ export default function(params) {
|
|||||||
faker.lorem.sentence(),
|
faker.lorem.sentence(),
|
||||||
faker.lorem.sentence(),
|
faker.lorem.sentence(),
|
||||||
faker.lorem.sentence()
|
faker.lorem.sentence()
|
||||||
].join(". "),
|
].join('. '),
|
||||||
image = faker.image.image(),
|
image = faker.image.image(),
|
||||||
visibility = "public",
|
visibility = 'public',
|
||||||
disabled = false,
|
disabled = false,
|
||||||
deleted = false
|
deleted = false
|
||||||
} = params;
|
} = params
|
||||||
|
|
||||||
return `
|
return `
|
||||||
mutation {
|
mutation {
|
||||||
@ -30,5 +30,5 @@ export default function(params) {
|
|||||||
deleted: ${deleted}
|
deleted: ${deleted}
|
||||||
) { title, content }
|
) { title, content }
|
||||||
}
|
}
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,15 +33,3 @@ export default function create (params) {
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function relate (type, params) {
|
|
||||||
const { from, to } = params
|
|
||||||
return `
|
|
||||||
mutation {
|
|
||||||
${from}_${type}_${to}: AddUser${type}(
|
|
||||||
from: { id: "${from}" },
|
|
||||||
to: { id: "${to}" }
|
|
||||||
) { from { id } }
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,19 +1,199 @@
|
|||||||
import ApolloClient from 'apollo-client'
|
import Factory from './factories'
|
||||||
import dotenv from 'dotenv'
|
|
||||||
import fetch from 'node-fetch'
|
|
||||||
import { HttpLink } from 'apollo-link-http'
|
|
||||||
import { InMemoryCache } from 'apollo-cache-inmemory'
|
|
||||||
import Seed from './data/index'
|
|
||||||
|
|
||||||
dotenv.config()
|
/* eslint-disable no-multi-spaces */
|
||||||
|
(async function () {
|
||||||
|
try {
|
||||||
|
const f = Factory()
|
||||||
|
await Promise.all([
|
||||||
|
f.create('Badge', { id: 'b1', key: 'indiegogo_en_racoon', type: 'crowdfunding', status: 'permanent', icon: '/img/badges/indiegogo_en_racoon.svg' }),
|
||||||
|
f.create('Badge', { id: 'b2', key: 'indiegogo_en_rabbit', type: 'crowdfunding', status: 'permanent', icon: '/img/badges/indiegogo_en_rabbit.svg' }),
|
||||||
|
f.create('Badge', { id: 'b3', key: 'indiegogo_en_wolf', type: 'crowdfunding', status: 'permanent', icon: '/img/badges/indiegogo_en_wolf.svg' }),
|
||||||
|
f.create('Badge', { id: 'b4', key: 'indiegogo_en_bear', type: 'crowdfunding', status: 'permanent', icon: '/img/badges/indiegogo_en_bear.svg' }),
|
||||||
|
f.create('Badge', { id: 'b5', key: 'indiegogo_en_turtle', type: 'crowdfunding', status: 'permanent', icon: '/img/badges/indiegogo_en_turtle.svg' }),
|
||||||
|
f.create('Badge', { id: 'b6', key: 'indiegogo_en_rhino', type: 'crowdfunding', status: 'permanent', icon: '/img/badges/indiegogo_en_rhino.svg' })
|
||||||
|
])
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
await Promise.all([
|
||||||
throw new Error('YOU CAN`T SEED IN PRODUCTION MODE')
|
f.create('User', { id: 'u1', name: 'Peter Lustig', role: 'admin', email: 'admin@example.org' }),
|
||||||
}
|
f.create('User', { id: 'u2', name: 'Bob der Baumeister', role: 'moderator', email: 'moderator@example.org' }),
|
||||||
|
f.create('User', { id: 'u3', name: 'Jenny Rostock', role: 'user', email: 'user@example.org' }),
|
||||||
|
f.create('User', { id: 'u4', name: 'Tick', role: 'user', email: 'tick@example.org' }),
|
||||||
|
f.create('User', { id: 'u5', name: 'Trick', role: 'user', email: 'trick@example.org' }),
|
||||||
|
f.create('User', { id: 'u6', name: 'Track', role: 'user', email: 'track@example.org' }),
|
||||||
|
f.create('User', { id: 'u7', name: 'Dagobert', role: 'user', email: 'dagobert@example.org' })
|
||||||
|
])
|
||||||
|
|
||||||
const client = new ApolloClient({
|
await Promise.all([
|
||||||
link: new HttpLink({ uri: process.env.GRAPHQL_URI, fetch }),
|
f.relate('User', 'Badges', { from: 'b6', to: 'u1' }),
|
||||||
cache: new InMemoryCache()
|
f.relate('User', 'Badges', { from: 'b5', to: 'u2' }),
|
||||||
})
|
f.relate('User', 'Badges', { from: 'b4', to: 'u3' }),
|
||||||
|
f.relate('User', 'Badges', { from: 'b3', to: 'u4' }),
|
||||||
|
f.relate('User', 'Badges', { from: 'b2', to: 'u5' }),
|
||||||
|
f.relate('User', 'Badges', { from: 'b1', to: 'u6' }),
|
||||||
|
f.relate('User', 'Following', { from: 'u1', to: 'u2' }),
|
||||||
|
f.relate('User', 'Following', { from: 'u2', to: 'u3' }),
|
||||||
|
f.relate('User', 'Following', { from: 'u3', to: 'u4' }),
|
||||||
|
f.relate('User', 'Following', { from: 'u4', to: 'u5' }),
|
||||||
|
f.relate('User', 'Following', { from: 'u5', to: 'u6' }),
|
||||||
|
f.relate('User', 'Following', { from: 'u6', to: 'u7' }),
|
||||||
|
f.relate('User', 'Friends', { from: 'u1', to: 'u2' }),
|
||||||
|
f.relate('User', 'Friends', { from: 'u1', to: 'u3' }),
|
||||||
|
f.relate('User', 'Friends', { from: 'u2', to: 'u3' }),
|
||||||
|
f.relate('User', 'Blacklisted', { from: 'u7', to: 'u4' }),
|
||||||
|
f.relate('User', 'Blacklisted', { from: 'u7', to: 'u5' }),
|
||||||
|
f.relate('User', 'Blacklisted', { from: 'u7', to: 'u6' })
|
||||||
|
])
|
||||||
|
|
||||||
Seed(client)
|
await Promise.all([
|
||||||
|
f.create('Category', { id: 'cat1', name: 'Just For Fun', slug: 'justforfun', icon: 'smile' }),
|
||||||
|
f.create('Category', { id: 'cat2', name: 'Happyness & Values', slug: 'happyness-values', icon: 'heart-o' }),
|
||||||
|
f.create('Category', { id: 'cat3', name: 'Health & Wellbeing', slug: 'health-wellbeing', icon: 'medkit' }),
|
||||||
|
f.create('Category', { id: 'cat4', name: 'Environment & Nature', slug: 'environment-nature', icon: 'tree' }),
|
||||||
|
f.create('Category', { id: 'cat5', name: 'Animal Protection', slug: 'animalprotection', icon: 'paw' }),
|
||||||
|
f.create('Category', { id: 'cat6', name: 'Humanrights Justice', slug: 'humanrights-justice', icon: 'balance-scale' }),
|
||||||
|
f.create('Category', { id: 'cat7', name: 'Education & Sciences', slug: 'education-sciences', icon: 'graduation-cap' }),
|
||||||
|
f.create('Category', { id: 'cat8', name: 'Cooperation & Development', slug: 'cooperation-development', icon: 'users' }),
|
||||||
|
f.create('Category', { id: 'cat9', name: 'Democracy & Politics', slug: 'democracy-politics', icon: 'university' }),
|
||||||
|
f.create('Category', { id: 'cat10', name: 'Economy & Finances', slug: 'economy-finances', icon: 'money' }),
|
||||||
|
f.create('Category', { id: 'cat11', name: 'Energy & Technology', slug: 'energy-technology', icon: 'flash' }),
|
||||||
|
f.create('Category', { id: 'cat12', name: 'IT, Internet & Data Privacy', slug: 'it-internet-dataprivacy', icon: 'mouse-pointer' }),
|
||||||
|
f.create('Category', { id: 'cat13', name: 'Art, Curlure & Sport', slug: 'art-culture-sport', icon: 'paint-brush' }),
|
||||||
|
f.create('Category', { id: 'cat14', name: 'Freedom of Speech', slug: 'freedomofspeech', icon: 'bullhorn' }),
|
||||||
|
f.create('Category', { id: 'cat15', name: 'Consumption & Sustainability', slug: 'consumption-sustainability', icon: 'shopping-cart' }),
|
||||||
|
f.create('Category', { id: 'cat16', name: 'Global Peace & Nonviolence', slug: 'globalpeace-nonviolence', icon: 'angellist' })
|
||||||
|
])
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
f.create('Tag', { id: 't1', name: 'Umwelt' }),
|
||||||
|
f.create('Tag', { id: 't2', name: 'Naturschutz' }),
|
||||||
|
f.create('Tag', { id: 't3', name: 'Demokratie' }),
|
||||||
|
f.create('Tag', { id: 't4', name: 'Freiheit' })
|
||||||
|
])
|
||||||
|
|
||||||
|
const [ asAdmin, asModerator, asUser, asTick, asTrick, asTrack ] = await Promise.all([
|
||||||
|
Factory().authenticateAs({ email: 'admin@example.org', password: '1234' }),
|
||||||
|
Factory().authenticateAs({ email: 'moderator@example.org', password: '1234' }),
|
||||||
|
Factory().authenticateAs({ email: 'user@example.org', password: '1234' }),
|
||||||
|
Factory().authenticateAs({ email: 'tick@example.org', password: '1234' }),
|
||||||
|
Factory().authenticateAs({ email: 'trick@example.org', password: '1234' }),
|
||||||
|
Factory().authenticateAs({ email: 'track@example.org', password: '1234' })
|
||||||
|
])
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
asAdmin.create('Post', { id: 'p0' }),
|
||||||
|
asModerator.create('Post', { id: 'p1' }),
|
||||||
|
asUser.create('Post', { id: 'p2' }),
|
||||||
|
asTick.create('Post', { id: 'p3' }),
|
||||||
|
asTrick.create('Post', { id: 'p4' }),
|
||||||
|
asTrack.create('Post', { id: 'p5' }),
|
||||||
|
asAdmin.create('Post', { id: 'p6' }),
|
||||||
|
asModerator.create('Post', { id: 'p7' }),
|
||||||
|
asUser.create('Post', { id: 'p8' }),
|
||||||
|
asTick.create('Post', { id: 'p9' }),
|
||||||
|
asTrick.create('Post', { id: 'p10' }),
|
||||||
|
asTrack.create('Post', { id: 'p11' }),
|
||||||
|
asAdmin.create('Post', { id: 'p12' }),
|
||||||
|
asModerator.create('Post', { id: 'p13' }),
|
||||||
|
asUser.create('Post', { id: 'p14' }),
|
||||||
|
asTick.create('Post', { id: 'p15' })
|
||||||
|
])
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
f.relate('Post', 'Categories', { from: 'p0', to: 'cat16' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p1', to: 'cat1' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p2', to: 'cat2' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p3', to: 'cat3' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p4', to: 'cat4' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p5', to: 'cat5' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p6', to: 'cat6' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p7', to: 'cat7' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p8', to: 'cat8' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p9', to: 'cat9' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p10', to: 'cat10' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p11', to: 'cat11' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p12', to: 'cat12' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p13', to: 'cat13' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p14', to: 'cat14' }),
|
||||||
|
f.relate('Post', 'Categories', { from: 'p15', to: 'cat15' }),
|
||||||
|
|
||||||
|
f.relate('Post', 'Tags', { from: 'p0', to: 't4' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p1', to: 't1' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p2', to: 't2' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p3', to: 't3' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p4', to: 't4' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p5', to: 't1' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p6', to: 't2' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p7', to: 't3' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p8', to: 't4' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p9', to: 't1' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p10', to: 't2' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p11', to: 't3' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p12', to: 't4' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p13', to: 't1' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p14', to: 't2' }),
|
||||||
|
f.relate('Post', 'Tags', { from: 'p15', to: 't3' })
|
||||||
|
])
|
||||||
|
await Promise.all([
|
||||||
|
f.relate('User', 'Shouted', { from: 'u1', to: 'p2' }),
|
||||||
|
f.relate('User', 'Shouted', { from: 'u1', to: 'p3' }),
|
||||||
|
f.relate('User', 'Shouted', { from: 'u2', to: 'p1' }),
|
||||||
|
f.relate('User', 'Shouted', { from: 'u3', to: 'p1' }),
|
||||||
|
f.relate('User', 'Shouted', { from: 'u3', to: 'p4' }),
|
||||||
|
f.relate('User', 'Shouted', { from: 'u4', to: 'p1' })
|
||||||
|
])
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
f.create('Comment', { id: 'c1' }),
|
||||||
|
f.create('Comment', { id: 'c2' }),
|
||||||
|
f.create('Comment', { id: 'c3' }),
|
||||||
|
f.create('Comment', { id: 'c4' }),
|
||||||
|
f.create('Comment', { id: 'c5' }),
|
||||||
|
f.create('Comment', { id: 'c6' }),
|
||||||
|
f.create('Comment', { id: 'c7' })
|
||||||
|
])
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
f.relate('Comment', 'Author', { from: 'u3', to: 'c1' }),
|
||||||
|
f.relate('Comment', 'Post', { from: 'c1', to: 'p1' }),
|
||||||
|
f.relate('Comment', 'Author', { from: 'u1', to: 'c2' }),
|
||||||
|
f.relate('Comment', 'Post', { from: 'c2', to: 'p1' }),
|
||||||
|
f.relate('Comment', 'Author', { from: 'u1', to: 'c3' }),
|
||||||
|
f.relate('Comment', 'Post', { from: 'c3', to: 'p3' }),
|
||||||
|
f.relate('Comment', 'Author', { from: 'u4', to: 'c4' }),
|
||||||
|
f.relate('Comment', 'Post', { from: 'c4', to: 'p2' }),
|
||||||
|
f.relate('Comment', 'Author', { from: 'u4', to: 'c5' }),
|
||||||
|
f.relate('Comment', 'Post', { from: 'c5', to: 'p3' }),
|
||||||
|
f.relate('Comment', 'Author', { from: 'u3', to: 'c6' }),
|
||||||
|
f.relate('Comment', 'Post', { from: 'c6', to: 'p4' }),
|
||||||
|
f.relate('Comment', 'Author', { from: 'u2', to: 'c7' }),
|
||||||
|
f.relate('Comment', 'Post', { from: 'c7', to: 'p2' })
|
||||||
|
])
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
asTick.create('Report', { description: 'I don\'t like this comment', resource: { id: 'c1', type: 'comment' } }),
|
||||||
|
asTrick.create('Report', { description: 'I don\'t like this post', resource: { id: 'p1', type: 'contribution' } }),
|
||||||
|
asTrack.create('Report', { description: 'I don\'t like this user', resource: { id: 'u1', type: 'user' } })
|
||||||
|
])
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
f.create('Organization', { id: 'o1', name: 'Democracy Deutschland', description: 'Description for democracy-deutschland.' }),
|
||||||
|
f.create('Organization', { id: 'o2', name: 'Human-Connection', description: 'Description for human-connection.' }),
|
||||||
|
f.create('Organization', { id: 'o3', name: 'Pro Veg', description: 'Description for pro-veg.' }),
|
||||||
|
f.create('Organization', { id: 'o4', name: 'Greenpeace', description: 'Description for greenpeace.' })
|
||||||
|
])
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
f.relate('Organization', 'CreatedBy', { from: 'u1', to: 'o1' }),
|
||||||
|
f.relate('Organization', 'CreatedBy', { from: 'u1', to: 'o2' }),
|
||||||
|
f.relate('Organization', 'OwnedBy', { from: 'u2', to: 'o2' }),
|
||||||
|
f.relate('Organization', 'OwnedBy', { from: 'u2', to: 'o3' })
|
||||||
|
])
|
||||||
|
/* eslint-disable-next-line no-console */
|
||||||
|
console.log('Seeded Data...')
|
||||||
|
} catch (err) {
|
||||||
|
/* eslint-disable-next-line no-console */
|
||||||
|
console.error(err)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
/* eslint-enable no-multi-spaces */
|
||||||
|
|||||||
235
yarn.lock
235
yarn.lock
@ -871,15 +871,20 @@ acorn@^5.5.3:
|
|||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
|
||||||
integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
|
integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
|
||||||
|
|
||||||
acorn@^6.0.1, acorn@^6.0.2:
|
acorn@^6.0.1:
|
||||||
version "6.0.4"
|
version "6.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.4.tgz#77377e7353b72ec5104550aa2d2097a2fd40b754"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.4.tgz#77377e7353b72ec5104550aa2d2097a2fd40b754"
|
||||||
integrity sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==
|
integrity sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==
|
||||||
|
|
||||||
ajv@^6.5.3, ajv@^6.5.5, ajv@^6.6.1:
|
acorn@^6.0.7:
|
||||||
version "6.6.1"
|
version "6.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.6.1.tgz#6360f5ed0d80f232cc2b294c362d5dc2e538dd61"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.0.tgz#b0a3be31752c97a0f7013c5f4903b71a05db6818"
|
||||||
integrity sha512-ZoJjft5B+EJBjUyu9C9Hc0OZyPZSSlOF+plzouTrg6UlA8f+e/n8NIgBFG/9tppJtpPWfthHakK7juJdNDODww==
|
integrity sha512-MW/FjM+IvU9CgBzjO3UIPCE2pyEwUsoFl+VGdczOPEdxfGFjuKny/gN54mOuX7Qxmb9Rg9MCn2oKiSUeW+pjrw==
|
||||||
|
|
||||||
|
ajv@^6.5.5, ajv@^6.9.1:
|
||||||
|
version "6.9.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.9.2.tgz#4927adb83e7f48e5a32b45729744c71ec39c9c7b"
|
||||||
|
integrity sha512-4UFy0/LgDo7Oa/+wOAlj44tp9K78u38E5/359eSrqEp1Z5PdVfimCcs7SluXMP755RUQu6d2b4AvF0R1C9RZjg==
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-deep-equal "^2.0.1"
|
fast-deep-equal "^2.0.1"
|
||||||
fast-json-stable-stringify "^2.0.0"
|
fast-json-stable-stringify "^2.0.0"
|
||||||
@ -898,6 +903,11 @@ ansi-escapes@^3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30"
|
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30"
|
||||||
integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==
|
integrity sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==
|
||||||
|
|
||||||
|
ansi-escapes@^3.2.0:
|
||||||
|
version "3.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
|
||||||
|
integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
|
||||||
|
|
||||||
ansi-regex@^2.0.0:
|
ansi-regex@^2.0.0:
|
||||||
version "2.1.1"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||||
@ -943,35 +953,37 @@ apollo-cache-control@^0.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
graphql-extensions "^0.0.x"
|
graphql-extensions "^0.0.x"
|
||||||
|
|
||||||
apollo-cache-inmemory@~1.4.3:
|
apollo-cache-inmemory@~1.5.0:
|
||||||
version "1.4.3"
|
version "1.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/apollo-cache-inmemory/-/apollo-cache-inmemory-1.4.3.tgz#aded4fb8b3de9e2fb2573a6c03591b07ef98ed36"
|
resolved "https://registry.yarnpkg.com/apollo-cache-inmemory/-/apollo-cache-inmemory-1.5.0.tgz#90b1a38f744762ab47c415b9d7b2d32fbd803088"
|
||||||
integrity sha512-p9KGtEZ9Mlb+FS0UEaxR8WvKOijYV0c+TXlhC/XZ3/ltYvP1zL3b1ozSOLGR9SawN2895Fc7QDV5nzPpihV0rA==
|
integrity sha512-hyg8R7G3XOfZhl8fQLs0vGEwi2rr8PuEIiumCY4qmwviaGsmwjs/Dm63cyeMm3Sfu05vzFQkwMdBf5u7xBg3cQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
apollo-cache "^1.1.26"
|
apollo-cache "^1.2.0"
|
||||||
apollo-utilities "^1.1.3"
|
apollo-utilities "^1.2.0"
|
||||||
optimism "^0.6.9"
|
optimism "^0.6.9"
|
||||||
|
ts-invariant "^0.2.1"
|
||||||
tslib "^1.9.3"
|
tslib "^1.9.3"
|
||||||
|
|
||||||
apollo-cache@1.1.26, apollo-cache@^1.1.26:
|
apollo-cache@1.2.1, apollo-cache@^1.2.0:
|
||||||
version "1.1.26"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/apollo-cache/-/apollo-cache-1.1.26.tgz#5afe023270effbc2063d90f51d8e56bce274ab37"
|
resolved "https://registry.yarnpkg.com/apollo-cache/-/apollo-cache-1.2.1.tgz#aae71eb4a11f1f7322adc343f84b1a39b0693644"
|
||||||
integrity sha512-JKFHijwkhXpcQ3jOat+ctwiXyjDhQgy0p6GSaj7zG+or+ZSalPqUnPzFRgRwFLVbYxBKJgHCkWX+2VkxWTZzQQ==
|
integrity sha512-nzFmep/oKlbzUuDyz6fS6aYhRmfpcHWqNkkA9Bbxwk18RD6LXC4eZkuE0gXRX0IibVBHNjYVK+Szi0Yied4SpQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
apollo-utilities "^1.1.3"
|
apollo-utilities "^1.2.1"
|
||||||
tslib "^1.9.3"
|
tslib "^1.9.3"
|
||||||
|
|
||||||
apollo-client@~2.4.13:
|
apollo-client@~2.5.1:
|
||||||
version "2.4.13"
|
version "2.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-2.4.13.tgz#09829fcbd68e069de9840d0a10764d7c6a3d0787"
|
resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-2.5.1.tgz#36126ed1d32edd79c3713c6684546a3bea80e6d1"
|
||||||
integrity sha512-7mBdW/CW1qHB8Mj4EFAG3MTtbRc6S8aUUntUdrKfRWV1rZdWa0NovxsgVD/R4HZWZjRQ2UOM4ENsHdM5g1uXOQ==
|
integrity sha512-MNcQKiqLHdGmNJ0rZ0NXaHrToXapJgS/5kPk0FygXt+/FmDCdzqcujI7OPxEC6e9Yw5S/8dIvOXcRNuOMElHkA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/zen-observable" "^0.8.0"
|
"@types/zen-observable" "^0.8.0"
|
||||||
apollo-cache "1.1.26"
|
apollo-cache "1.2.1"
|
||||||
apollo-link "^1.0.0"
|
apollo-link "^1.0.0"
|
||||||
apollo-link-dedup "^1.0.0"
|
apollo-link-dedup "^1.0.0"
|
||||||
apollo-utilities "1.1.3"
|
apollo-utilities "1.2.1"
|
||||||
symbol-observable "^1.0.2"
|
symbol-observable "^1.0.2"
|
||||||
|
ts-invariant "^0.2.1"
|
||||||
tslib "^1.9.3"
|
tslib "^1.9.3"
|
||||||
zen-observable "^0.8.0"
|
zen-observable "^0.8.0"
|
||||||
|
|
||||||
@ -1188,12 +1200,13 @@ apollo-upload-server@^7.0.0:
|
|||||||
http-errors "^1.7.0"
|
http-errors "^1.7.0"
|
||||||
object-path "^0.11.4"
|
object-path "^0.11.4"
|
||||||
|
|
||||||
apollo-utilities@1.1.3, apollo-utilities@^1.0.1, apollo-utilities@^1.1.3:
|
apollo-utilities@1.2.1, apollo-utilities@^1.0.1, apollo-utilities@^1.2.0, apollo-utilities@^1.2.1:
|
||||||
version "1.1.3"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.1.3.tgz#a8883c0392f6b46eac0d366204ebf34be9307c87"
|
resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.2.1.tgz#1c3a1ebf5607d7c8efe7636daaf58e7463b41b3c"
|
||||||
integrity sha512-pF9abhiClX5gfj/WFWZh8DiI33nOLGxRhXH9ZMquaM1V8bhq1WLFPt2QjShWH3kGQVeIGUK+FQefnhe+ZaaAYg==
|
integrity sha512-Zv8Udp9XTSFiN8oyXOjf6PMHepD4yxxReLsl6dPUy5Ths7jti3nmlBzZUOxuTWRwZn0MoclqL7RQ5UEJN8MAxg==
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-json-stable-stringify "^2.0.0"
|
fast-json-stable-stringify "^2.0.0"
|
||||||
|
ts-invariant "^0.2.1"
|
||||||
tslib "^1.9.3"
|
tslib "^1.9.3"
|
||||||
|
|
||||||
append-transform@^1.0.0:
|
append-transform@^1.0.0:
|
||||||
@ -1693,16 +1706,7 @@ chai@~4.2.0:
|
|||||||
pathval "^1.1.0"
|
pathval "^1.1.0"
|
||||||
type-detect "^4.0.5"
|
type-detect "^4.0.5"
|
||||||
|
|
||||||
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1:
|
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2:
|
||||||
version "2.4.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
|
|
||||||
integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==
|
|
||||||
dependencies:
|
|
||||||
ansi-styles "^3.2.1"
|
|
||||||
escape-string-regexp "^1.0.5"
|
|
||||||
supports-color "^5.3.0"
|
|
||||||
|
|
||||||
chalk@^2.4.2:
|
|
||||||
version "2.4.2"
|
version "2.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||||
@ -1767,11 +1771,6 @@ ci-info@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
|
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
|
||||||
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
|
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
|
||||||
|
|
||||||
circular-json@^0.3.1:
|
|
||||||
version "0.3.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
|
|
||||||
integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==
|
|
||||||
|
|
||||||
class-utils@^0.3.5:
|
class-utils@^0.3.5:
|
||||||
version "0.3.6"
|
version "0.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
|
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
|
||||||
@ -2225,10 +2224,10 @@ doctrine@1.5.0:
|
|||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
isarray "^1.0.0"
|
isarray "^1.0.0"
|
||||||
|
|
||||||
doctrine@^2.1.0:
|
doctrine@^3.0.0:
|
||||||
version "2.1.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
|
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
|
||||||
integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
|
integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
|
||||||
dependencies:
|
dependencies:
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
|
|
||||||
@ -2327,6 +2326,11 @@ electron-to-chromium@^1.3.86:
|
|||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.88.tgz#f36ab32634f49ef2b0fdc1e82e2d1cc17feb29e7"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.88.tgz#f36ab32634f49ef2b0fdc1e82e2d1cc17feb29e7"
|
||||||
integrity sha512-UPV4NuQMKeUh1S0OWRvwg0PI8ASHN9kBC8yDTk1ROXLC85W5GnhTRu/MZu3Teqx3JjlQYuckuHYXSUSgtb3J+A==
|
integrity sha512-UPV4NuQMKeUh1S0OWRvwg0PI8ASHN9kBC8yDTk1ROXLC85W5GnhTRu/MZu3Teqx3JjlQYuckuHYXSUSgtb3J+A==
|
||||||
|
|
||||||
|
emoji-regex@^7.0.1:
|
||||||
|
version "7.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
|
||||||
|
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
|
||||||
|
|
||||||
encodeurl@~1.0.2:
|
encodeurl@~1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
|
||||||
@ -2508,35 +2512,35 @@ eslint-visitor-keys@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"
|
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"
|
||||||
integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==
|
integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==
|
||||||
|
|
||||||
eslint@~5.13.0:
|
eslint@~5.14.1:
|
||||||
version "5.13.0"
|
version "5.14.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.13.0.tgz#ce71cc529c450eed9504530939aa97527861ede9"
|
resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.14.1.tgz#490a28906be313685c55ccd43a39e8d22efc04ba"
|
||||||
integrity sha512-nqD5WQMisciZC5EHZowejLKQjWGuFS5c70fxqSKlnDME+oz9zmE8KTlX+lHSg+/5wsC/kf9Q9eMkC8qS3oM2fg==
|
integrity sha512-CyUMbmsjxedx8B0mr79mNOqetvkbij/zrXnFeK2zc3pGRn3/tibjiNAv/3UxFEyfMDjh+ZqTrJrEGBFiGfD5Og==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame" "^7.0.0"
|
"@babel/code-frame" "^7.0.0"
|
||||||
ajv "^6.5.3"
|
ajv "^6.9.1"
|
||||||
chalk "^2.1.0"
|
chalk "^2.1.0"
|
||||||
cross-spawn "^6.0.5"
|
cross-spawn "^6.0.5"
|
||||||
debug "^4.0.1"
|
debug "^4.0.1"
|
||||||
doctrine "^2.1.0"
|
doctrine "^3.0.0"
|
||||||
eslint-scope "^4.0.0"
|
eslint-scope "^4.0.0"
|
||||||
eslint-utils "^1.3.1"
|
eslint-utils "^1.3.1"
|
||||||
eslint-visitor-keys "^1.0.0"
|
eslint-visitor-keys "^1.0.0"
|
||||||
espree "^5.0.0"
|
espree "^5.0.1"
|
||||||
esquery "^1.0.1"
|
esquery "^1.0.1"
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
file-entry-cache "^2.0.0"
|
file-entry-cache "^5.0.1"
|
||||||
functional-red-black-tree "^1.0.1"
|
functional-red-black-tree "^1.0.1"
|
||||||
glob "^7.1.2"
|
glob "^7.1.2"
|
||||||
globals "^11.7.0"
|
globals "^11.7.0"
|
||||||
ignore "^4.0.6"
|
ignore "^4.0.6"
|
||||||
import-fresh "^3.0.0"
|
import-fresh "^3.0.0"
|
||||||
imurmurhash "^0.1.4"
|
imurmurhash "^0.1.4"
|
||||||
inquirer "^6.1.0"
|
inquirer "^6.2.2"
|
||||||
js-yaml "^3.12.0"
|
js-yaml "^3.12.0"
|
||||||
json-stable-stringify-without-jsonify "^1.0.1"
|
json-stable-stringify-without-jsonify "^1.0.1"
|
||||||
levn "^0.3.0"
|
levn "^0.3.0"
|
||||||
lodash "^4.17.5"
|
lodash "^4.17.11"
|
||||||
minimatch "^3.0.4"
|
minimatch "^3.0.4"
|
||||||
mkdirp "^0.5.1"
|
mkdirp "^0.5.1"
|
||||||
natural-compare "^1.4.0"
|
natural-compare "^1.4.0"
|
||||||
@ -2547,15 +2551,15 @@ eslint@~5.13.0:
|
|||||||
semver "^5.5.1"
|
semver "^5.5.1"
|
||||||
strip-ansi "^4.0.0"
|
strip-ansi "^4.0.0"
|
||||||
strip-json-comments "^2.0.1"
|
strip-json-comments "^2.0.1"
|
||||||
table "^5.0.2"
|
table "^5.2.3"
|
||||||
text-table "^0.2.0"
|
text-table "^0.2.0"
|
||||||
|
|
||||||
espree@^5.0.0:
|
espree@^5.0.1:
|
||||||
version "5.0.0"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.0.tgz#fc7f984b62b36a0f543b13fb9cd7b9f4a7f5b65c"
|
resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a"
|
||||||
integrity sha512-1MpUfwsdS9MMoN7ZXqAr9e9UKdVHDcvrJpyx7mm1WuQlx/ygErEQBzgi5Nh5qBHIoYweprhtMkTCb9GhcAIcsA==
|
integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn "^6.0.2"
|
acorn "^6.0.7"
|
||||||
acorn-jsx "^5.0.0"
|
acorn-jsx "^5.0.0"
|
||||||
eslint-visitor-keys "^1.0.0"
|
eslint-visitor-keys "^1.0.0"
|
||||||
|
|
||||||
@ -2726,7 +2730,7 @@ extend@^3.0.0, extend@~3.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||||
|
|
||||||
external-editor@^3.0.0:
|
external-editor@^3.0.3:
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27"
|
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27"
|
||||||
integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==
|
integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==
|
||||||
@ -2793,13 +2797,12 @@ figures@^2.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
escape-string-regexp "^1.0.5"
|
escape-string-regexp "^1.0.5"
|
||||||
|
|
||||||
file-entry-cache@^2.0.0:
|
file-entry-cache@^5.0.1:
|
||||||
version "2.0.0"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361"
|
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c"
|
||||||
integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=
|
integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==
|
||||||
dependencies:
|
dependencies:
|
||||||
flat-cache "^1.2.1"
|
flat-cache "^2.0.1"
|
||||||
object-assign "^4.0.1"
|
|
||||||
|
|
||||||
fileset@^2.0.3:
|
fileset@^2.0.3:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
@ -2864,15 +2867,19 @@ find-up@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
locate-path "^3.0.0"
|
locate-path "^3.0.0"
|
||||||
|
|
||||||
flat-cache@^1.2.1:
|
flat-cache@^2.0.1:
|
||||||
version "1.3.4"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.4.tgz#2c2ef77525cc2929007dfffa1dd314aa9c9dee6f"
|
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
|
||||||
integrity sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==
|
integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==
|
||||||
dependencies:
|
dependencies:
|
||||||
circular-json "^0.3.1"
|
flatted "^2.0.0"
|
||||||
graceful-fs "^4.1.2"
|
rimraf "2.6.3"
|
||||||
rimraf "~2.6.2"
|
write "1.0.3"
|
||||||
write "^0.2.1"
|
|
||||||
|
flatted@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916"
|
||||||
|
integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==
|
||||||
|
|
||||||
fn-name@~2.0.1:
|
fn-name@~2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
@ -3509,21 +3516,21 @@ ini@^1.3.4, ini@~1.3.0:
|
|||||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
||||||
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
|
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
|
||||||
|
|
||||||
inquirer@^6.1.0:
|
inquirer@^6.2.2:
|
||||||
version "6.2.1"
|
version "6.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.1.tgz#9943fc4882161bdb0b0c9276769c75b32dbfcd52"
|
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.2.tgz#46941176f65c9eb20804627149b743a218f25406"
|
||||||
integrity sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==
|
integrity sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-escapes "^3.0.0"
|
ansi-escapes "^3.2.0"
|
||||||
chalk "^2.0.0"
|
chalk "^2.4.2"
|
||||||
cli-cursor "^2.1.0"
|
cli-cursor "^2.1.0"
|
||||||
cli-width "^2.0.0"
|
cli-width "^2.0.0"
|
||||||
external-editor "^3.0.0"
|
external-editor "^3.0.3"
|
||||||
figures "^2.0.0"
|
figures "^2.0.0"
|
||||||
lodash "^4.17.10"
|
lodash "^4.17.11"
|
||||||
mute-stream "0.0.7"
|
mute-stream "0.0.7"
|
||||||
run-async "^2.2.0"
|
run-async "^2.2.0"
|
||||||
rxjs "^6.1.0"
|
rxjs "^6.4.0"
|
||||||
string-width "^2.1.0"
|
string-width "^2.1.0"
|
||||||
strip-ansi "^5.0.0"
|
strip-ansi "^5.0.0"
|
||||||
through "^2.3.6"
|
through "^2.3.6"
|
||||||
@ -5079,7 +5086,7 @@ oauth-sign@~0.9.0:
|
|||||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||||
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
||||||
|
|
||||||
object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||||
@ -5970,7 +5977,7 @@ retry@0.12.0:
|
|||||||
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
|
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
|
||||||
integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
|
integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
|
||||||
|
|
||||||
rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@~2.6.2:
|
rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
|
||||||
version "2.6.3"
|
version "2.6.3"
|
||||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
|
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
|
||||||
integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
|
integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
|
||||||
@ -5994,10 +6001,10 @@ rx@^4.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
|
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
|
||||||
integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=
|
integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=
|
||||||
|
|
||||||
rxjs@^6.1.0:
|
rxjs@^6.4.0:
|
||||||
version "6.3.3"
|
version "6.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz#3c6a7fa420e844a81390fb1158a9ec614f4bad55"
|
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504"
|
||||||
integrity sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==
|
integrity sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.9.0"
|
tslib "^1.9.0"
|
||||||
|
|
||||||
@ -6195,10 +6202,10 @@ slash@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
|
resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
|
||||||
integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==
|
integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==
|
||||||
|
|
||||||
slice-ansi@2.0.0:
|
slice-ansi@^2.1.0:
|
||||||
version "2.0.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.0.0.tgz#5373bdb8559b45676e8541c66916cdd6251612e7"
|
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
|
||||||
integrity sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ==
|
integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-styles "^3.2.0"
|
ansi-styles "^3.2.0"
|
||||||
astral-regex "^1.0.0"
|
astral-regex "^1.0.0"
|
||||||
@ -6406,6 +6413,15 @@ string-width@^1.0.1:
|
|||||||
is-fullwidth-code-point "^2.0.0"
|
is-fullwidth-code-point "^2.0.0"
|
||||||
strip-ansi "^4.0.0"
|
strip-ansi "^4.0.0"
|
||||||
|
|
||||||
|
string-width@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.0.0.tgz#5a1690a57cc78211fffd9bf24bbe24d090604eb1"
|
||||||
|
integrity sha512-rr8CUxBbvOZDUvc5lNIJ+OC1nPVpz+Siw9VBtUjB9b6jZehZLFt0JMCZzShFHIsI8cbhm0EsNIfWJMFV3cu3Ew==
|
||||||
|
dependencies:
|
||||||
|
emoji-regex "^7.0.1"
|
||||||
|
is-fullwidth-code-point "^2.0.0"
|
||||||
|
strip-ansi "^5.0.0"
|
||||||
|
|
||||||
string.prototype.padend@^3.0.0:
|
string.prototype.padend@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0"
|
resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz#f3aaef7c1719f170c5eab1c32bf780d96e21f2f0"
|
||||||
@ -6534,15 +6550,15 @@ synchronous-promise@^2.0.5:
|
|||||||
resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.6.tgz#de76e0ea2b3558c1e673942e47e714a930fa64aa"
|
resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.6.tgz#de76e0ea2b3558c1e673942e47e714a930fa64aa"
|
||||||
integrity sha512-TyOuWLwkmtPL49LHCX1caIwHjRzcVd62+GF6h8W/jHOeZUFHpnd2XJDVuUlaTaLPH1nuu2M69mfHr5XbQJnf/g==
|
integrity sha512-TyOuWLwkmtPL49LHCX1caIwHjRzcVd62+GF6h8W/jHOeZUFHpnd2XJDVuUlaTaLPH1nuu2M69mfHr5XbQJnf/g==
|
||||||
|
|
||||||
table@^5.0.2:
|
table@^5.2.3:
|
||||||
version "5.1.1"
|
version "5.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/table/-/table-5.1.1.tgz#92030192f1b7b51b6eeab23ed416862e47b70837"
|
resolved "https://registry.yarnpkg.com/table/-/table-5.2.3.tgz#cde0cc6eb06751c009efab27e8c820ca5b67b7f2"
|
||||||
integrity sha512-NUjapYb/qd4PeFW03HnAuOJ7OMcBkJlqeClWxeNlQ0lXGSb52oZXGzkO0/I0ARegQ2eUT1g2VDJH0eUxDRcHmw==
|
integrity sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv "^6.6.1"
|
ajv "^6.9.1"
|
||||||
lodash "^4.17.11"
|
lodash "^4.17.11"
|
||||||
slice-ansi "2.0.0"
|
slice-ansi "^2.1.0"
|
||||||
string-width "^2.1.1"
|
string-width "^3.0.0"
|
||||||
|
|
||||||
tar@^4:
|
tar@^4:
|
||||||
version "4.4.8"
|
version "4.4.8"
|
||||||
@ -6707,6 +6723,13 @@ trunc-text@1.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/trunc-text/-/trunc-text-1.0.1.tgz#58f876d8ac59b224b79834bb478b8656e69622b5"
|
resolved "https://registry.yarnpkg.com/trunc-text/-/trunc-text-1.0.1.tgz#58f876d8ac59b224b79834bb478b8656e69622b5"
|
||||||
integrity sha1-WPh22KxZsiS3mDS7R4uGVuaWIrU=
|
integrity sha1-WPh22KxZsiS3mDS7R4uGVuaWIrU=
|
||||||
|
|
||||||
|
ts-invariant@^0.2.1:
|
||||||
|
version "0.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.2.1.tgz#3d587f9d6e3bded97bf9ec17951dd9814d5a9d3f"
|
||||||
|
integrity sha512-Z/JSxzVmhTo50I+LKagEISFJW3pvPCqsMWLamCTX8Kr3N5aMrnGOqcflbe5hLUzwjvgPfnLzQtHZv0yWQ+FIHg==
|
||||||
|
dependencies:
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
tslib@^1.9.0, tslib@^1.9.3:
|
tslib@^1.9.0, tslib@^1.9.3:
|
||||||
version "1.9.3"
|
version "1.9.3"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
|
||||||
@ -7081,10 +7104,10 @@ write-file-atomic@^2.3.0:
|
|||||||
imurmurhash "^0.1.4"
|
imurmurhash "^0.1.4"
|
||||||
signal-exit "^3.0.2"
|
signal-exit "^3.0.2"
|
||||||
|
|
||||||
write@^0.2.1:
|
write@1.0.3:
|
||||||
version "0.2.1"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
|
resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3"
|
||||||
integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=
|
integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==
|
||||||
dependencies:
|
dependencies:
|
||||||
mkdirp "^0.5.1"
|
mkdirp "^0.5.1"
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user