Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 73 additions & 75 deletions src/resolvers/index.ts
Original file line number Diff line number Diff line change
@@ -1,168 +1,166 @@
import * as scuid from 'scuid';
import * as scuid from 'scuid'

import { generateAuthToken, getUserId, likelyTopics } from '../utils';
import {
generateAuthToken,
getUserId,
likelyTopics,
predefinedUsers,
} from '../utils'

const DEFAULT_COUNT = 25;
const DEFAULT_COUNT = 25

export default {
Query: {
me: (parent, args, ctx) => {
const userId = getUserId(ctx);
const { faker } = ctx;
const userId = getUserId(ctx)
const { faker } = ctx

return {
id: userId,
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
email: faker.internet.email(),
avatar: faker.image.avatar()
};
avatar: faker.image.avatar(),
}
},

allUsers(parent, { count = DEFAULT_COUNT }, { faker }) {
return new Array(count).fill(0).map(_ => ({
id: scuid(),
allUsers: (parent, { count = DEFAULT_COUNT }, { faker }) =>
predefinedUsers.slice(0, count),

User: (parent, { id }, { faker }) =>
predefinedUsers.filter((user) => user.id === id)[0] || {
id,
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
email: faker.internet.email(),
avatar: faker.image.avatar()
}));
},

User: (parent, { id }, { faker }) => ({
id,
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
email: faker.internet.email(),
avatar: faker.image.avatar()
}),
avatar: faker.image.avatar(),
},

allProducts: (parent, { count = DEFAULT_COUNT }, { faker }) => {
return new Array(count).fill(0).map(_ => ({
return new Array(count).fill(0).map((_) => ({
id: scuid(),
price: faker.commerce.price(),
name: faker.commerce.productName()
}));
name: faker.commerce.productName(),
}))
},

Product: (parent, { id }, { faker }) => ({
id,
price: faker.commerce.price(),
name: faker.commerce.productName()
name: faker.commerce.productName(),
}),

Todo: (parent, { id }, { faker }) => ({
id,
title: faker.random.words(),
completed: faker.random.boolean()
completed: faker.random.boolean(),
}),

allTodos: (parent, { count = DEFAULT_COUNT }, { faker }) => {
return new Array(count).fill(0).map(_ => ({
return new Array(count).fill(0).map((_) => ({
id: scuid(),
title: faker.random.words(),
completed: faker.random.boolean()
}));
completed: faker.random.boolean(),
}))
},

// refactor user relation into Class
Post: (parent, { id }, { faker }) => {
const title = faker.random.words();
const body = faker.lorem.paragraphs();
const firstName = faker.name.firstName();
const lastName = faker.name.lastName();
const title = faker.random.words()
const body = faker.lorem.paragraphs()
const firstName = faker.name.firstName()
const lastName = faker.name.lastName()
return {
id,
title,
body,
published: faker.random.boolean(),
createdAt: faker.date.past(),
createdAt: faker.date.between(
new Date('2019-01-01'),
new Date('2019-12-31'),
),
author: {
id: scuid(),
firstName,
lastName,
email: faker.internet.email(),
avatar: faker.image.avatar()
avatar: faker.image.avatar(),
},
likelyTopics: likelyTopics(
`${firstName} ${lastName}`,
title, body
)
};
likelyTopics: likelyTopics(`${firstName} ${lastName}`, title, body),
}
},

// refactor user relation into Class
allPosts: (parent, { count }, { faker }) => {
return new Array(count).fill(0).map(_ => {
const title = faker.random.words();
const body = faker.lorem.paragraphs();
const firstName = faker.name.firstName();
const lastName = faker.name.lastName();
const usersToUse = predefinedUsers.slice(
0,
count > 200 ? Math.ceil(count / 50) : Math.ceil(count / 20),
)
return new Array(count).fill(0).map((_) => {
const title = faker.random.words()
const body = faker.lorem.paragraphs()
const user = usersToUse[Math.floor(Math.random() * usersToUse.length)]
const firstName = user.firstName
const lastName = user.lastName
return {
id: scuid(),
title,
body,
published: faker.random.boolean(),
createdAt: faker.date.past(),
author: {
id: scuid(),
firstName,
lastName,
email: faker.internet.email(),
avatar: faker.image.avatar()
},
likelyTopics: likelyTopics(
`${firstName} ${lastName}`,
title, body
)
createdAt: faker.date.between(
new Date('2019-01-01'),
new Date('2019-12-31'),
),
author: user,
likelyTopics: likelyTopics(`${firstName} ${lastName}`, title, body),
}
});
}
})
},
},

Mutation: {
register: async (
parent,
{ email, password, expiresIn = '2d' },
{ jwtSecret },
info
info,
) => ({
token: await generateAuthToken(
{ userId: scuid(), email },
jwtSecret,
expiresIn
)
expiresIn,
),
}),

login: async (
parent,
{ email, password, expiresIn = '2d' },
{ jwtSecret },
info
info,
) => ({
token: await generateAuthToken(
{ email, userId: scuid() },
jwtSecret,
expiresIn
)
expiresIn,
),
}),

updateUser: (parent, { id, firstName, lastName, email, avatar }, ctx) => {
const userId = getUserId(ctx);
const { faker } = ctx;
const userId = getUserId(ctx)
const { faker } = ctx

return {
id: userId,
firstName: firstName === undefined ? faker.name.firstName() : firstName,
lastName: lastName === undefined ? faker.name.lastName() : lastName,
email: email === undefined ? faker.internet.email() : email,
avatar: avatar === undefined ? faker.image.avatar() : avatar
};
avatar: avatar === undefined ? faker.image.avatar() : avatar,
}
},

// No authentication for demo purposes
createTodo: (parent, { title, completed }, { faker }) => {
const id = scuid();
const id = scuid()

// pubsub.publish('todoAdded', {
// todoAdded: {
Expand All @@ -175,10 +173,10 @@ export default {
return {
id,
title,
completed: completed === undefined ? faker.random.boolean() : completed
};
}
}
completed: completed === undefined ? faker.random.boolean() : completed,
}
},
},

// Subscription: {
// todoAdded: {
Expand All @@ -196,4 +194,4 @@ export default {
// }
// }
// }
};
}
77 changes: 47 additions & 30 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import * as jwt from 'jsonwebtoken';
import * as scuid from 'scuid'
import * as jwt from 'jsonwebtoken'
import * as faker from 'faker/locale/en'
import { create } from 'domain'

export const generateAuthToken = (payload, secret, expiresIn) =>
jwt.sign(payload, secret, {
expiresIn
});
expiresIn,
})

export const getUserId = ctx => {
const Authorization = ctx.request.get('Authorization');
export const getUserId = (ctx) => {
const Authorization = ctx.request.get('Authorization')

if (Authorization) {
const token = Authorization.replace('Bearer ', '');
const { userId } = jwt.verify(token, process.env.JWT_SECRET);
return userId;
const token = Authorization.replace('Bearer ', '')
const { userId } = jwt.verify(token, process.env.JWT_SECRET)
return userId
}

throw new Error('Not Authorized');
};
throw new Error('Not Authorized')
}

// Ten randomly-chosen but consistent topic nouns.
export const topicWords = [
Expand All @@ -28,37 +31,51 @@ export const topicWords = [
'community',
'celebrity',
'birthday',
'potato'
];
'potato',
]

export const likelyTopics = (user, title, body) => {
// create a custom order over the topics, based on letters as they appear in
// the user's name, post title, and post body, for variability
const alphabet = `${title} ${user} ${body}`;
const alphabet = `${title} ${user} ${body}`
const topicLabels = topicWords.sort((a, b) => {
for (let i = 0; i < Math.min(a.length, b.length); i++) {
const aValue = alphabet.indexOf(a[i]);
const bValue = alphabet.indexOf(b[i]);
const aValue = alphabet.indexOf(a[i])
const bValue = alphabet.indexOf(b[i])
if (aValue !== bValue) {
return bValue - aValue;
return bValue - aValue
}
}
return b.length - a.length;
return b.length - a.length
})
// compute a biased probability distribution
const likelihoods = [];
let total = 0;
const likelihoods = []
let total = 0
for (let i = 0; i < topicLabels.length; i++) {
const weight = Math.random() * Math.log(i + 2);
total += weight;
likelihoods.push(weight);
const weight = Math.random() * Math.log(i + 2)
total += weight
likelihoods.push(weight)
}
likelihoods.reverse();
likelihoods.reverse()
// and associate each likelihood with a probability
return likelihoods.map((weight, i) => {
return {
likelihood: weight / total,
label: topicLabels[i]
}
}).sort((a, b) => b.likelihood - a.likelihood);
};
return likelihoods
.map((weight, i) => {
return {
likelihood: weight / total,
label: topicLabels[i],
}
})
.sort((a, b) => b.likelihood - a.likelihood)
}

export const createFullUser = () => ({
id: scuid(),
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
email: faker.internet.email(),
avatar: faker.image.avatar(),
})

export const predefinedUsers = new Array(1000)
.fill(null)
.map((_) => createFullUser())