summaryrefslogtreecommitdiffstats
path: root/backend/src
diff options
context:
space:
mode:
authorWes Bos <wesbos@gmail.com>2018-04-12 16:31:01 -0400
committerWes Bos <wesbos@gmail.com>2018-04-12 16:31:01 -0400
commit97b6de6aa437f7a913a33b9e6aa18a919faf2caf (patch)
tree431e12a535baf1d2ad59601ee7c5e8084ae7a263 /backend/src
parentd22616d5a675f5a381c741784333151255713b45 (diff)
a whole bunch of things that should be in their own commits
Diffstat (limited to 'backend/src')
-rw-r--r--backend/src/index.js6
-rw-r--r--backend/src/mail.js18
-rw-r--r--backend/src/resolvers/Mutation.js95
-rw-r--r--backend/src/resolvers/Query.js48
-rw-r--r--backend/src/schema.graphql3
-rw-r--r--backend/src/utils.js35
6 files changed, 107 insertions, 98 deletions
diff --git a/backend/src/index.js b/backend/src/index.js
index 8cf48fc..9f759ef 100644
--- a/backend/src/index.js
+++ b/backend/src/index.js
@@ -30,9 +30,3 @@ server.express.use(async (req, res, next) => {
server.start({ port: 4444 }, deets => {
console.log(`Server is running on http://localhost:${deets.port}`);
});
-
-// overwrite console.log
-const chalk = require('chalk');
-
-// global.console.l = (...butta) => console.log(chalk.bold.yellow(...butta));
-global.console.l = console.log;
diff --git a/backend/src/mail.js b/backend/src/mail.js
index 3159fe2..fc4a47b 100644
--- a/backend/src/mail.js
+++ b/backend/src/mail.js
@@ -9,4 +9,20 @@ const transport = nodemailer.createTransport({
},
});
-module.exports = transport;
+const makeANiceEmail = text => `
+ <div className="email" style="
+ border:1px solid black;
+ padding: 20px;
+ font-family: sans-serif;
+ line-height: 2;
+ font-size: 20px;
+ ">
+ <h2>Hello There</h2>
+ <p>${text}</p>
+
+ <p>😘 Wes Bos</p>
+ </div>
+`;
+
+exports.transport = transport;
+exports.makeANiceEmail = makeANiceEmail;
diff --git a/backend/src/resolvers/Mutation.js b/backend/src/resolvers/Mutation.js
index daaa7de..5886595 100644
--- a/backend/src/resolvers/Mutation.js
+++ b/backend/src/resolvers/Mutation.js
@@ -1,13 +1,11 @@
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
-const { getUserId, Context, hasPermission } = require('../utils');
+const { hasPermission } = require('../utils');
const { randomBytes } = require('crypto');
const { promisify } = require('util');
const mail = require('../mail');
const stripe = require('../stripe');
-const wait = amount => new Promise(resolve => setTimeout(resolve, amount));
-
const mutations = {
// Signup Mutations
async signup(parent, args, ctx, info) {
@@ -29,7 +27,6 @@ const mutations = {
async signin(parent, { email, password }, ctx, info) {
const user = await ctx.db.query.user({ where: { email } });
- console.log(user);
if (!user) {
throw new Error(`No such user found for email: ${email}`);
}
@@ -44,7 +41,7 @@ const mutations = {
};
},
- // Creation of Post Mutations
+ // Create An Item
async createItem(parent, args, ctx, info) {
if (!ctx.request.userId) {
throw new Error('You must be logged in to create an item');
@@ -63,7 +60,6 @@ const mutations = {
},
info
);
- console.log(item);
return item;
},
@@ -85,19 +81,23 @@ const mutations = {
async updateItem(parent, args, ctx, info) {
const user = ctx.request.user;
const item = await ctx.db.query.item({ where: { id: args.id } }, `{ user { id } }`);
- if (item.user.id !== user.id || !user.permissions.includes('ADMIN')) {
+
+ if (item.user.id !== user.id || !hasPermission(user, ['ADMIN'])) {
throw new Error('You are not allowed to update that item!');
}
const updates = { ...args };
// remove the ID because you can't update that
delete updates.id;
- return ctx.db.mutation.updateItem({
- where: { id: args.id },
- data: {
- ...updates,
+ return ctx.db.mutation.updateItem(
+ {
+ where: { id: args.id },
+ data: {
+ ...updates,
+ },
},
- });
+ info
+ );
},
// Send password request
@@ -117,14 +117,17 @@ const mutations = {
data: { resetToken, resetTokenExpiry },
});
- console.log(res);
// 3. Send them their token via email
- const mailRes = await mail.sendMail({
+ const mailRes = await mail.transport.sendMail({
from: 'wesbos@gmail.com',
to: user.email,
subject: 'Your password reset token',
// TODO: don't hardcore localhost here
- html: `Here is your reset link: http://localhost:3000/reset?resetToken=${resetToken}`,
+ html: mail.makeANiceEmail(
+ `Your password reset link is here! \n\n<a href="${ctx.request.protocol}://${ctx.request.get(
+ 'host'
+ )}/reset?resetToken=${resetToken}">Click Here to reset</a>s`
+ ),
});
console.log(mailRes);
return res.updateUser;
@@ -175,8 +178,8 @@ const mutations = {
Add to cart
*/
async addToCart(parent, args, ctx, info) {
- console.l('Add to cart called');
- const userId = getUserId(ctx);
+ const userId = ctx.request.userId;
+
if (!userId) {
throw new Error('You must be signed in to add to cart!');
}
@@ -190,7 +193,6 @@ const mutations = {
});
if (existingCartItem) {
- console.log('Existing');
return ctx.db.mutation.updateCartItem(
{
where: { id: existingCartItem.id },
@@ -220,40 +222,46 @@ const mutations = {
// delete that cart item
async removeFromCart(parent, args, ctx, info) {
- // TODO: add userId to where
- return ctx.db.mutation.deleteCartItem({
- where: { id: args.id },
- });
+ return ctx.db.mutation.deleteManyCartItems(
+ {
+ where: {
+ id: args.id,
+ user: {
+ id: ctx.request.userId,
+ },
+ },
+ },
+ info
+ );
},
async createOrder(parent, args, ctx, info) {
- const userId = getUserId(ctx);
+ const userId = ctx.request.userId;
const user = await ctx.db.query.user(
{ where: { id: userId } },
// TODO - can we just pass info here?
'{ id, name, email, cart { id, quantity, item { title, price, id, description, image } }}'
);
// 1. Recalculate the total for the price
- const amount = user.cart.reduce((tally, cartItem) => tally + cartItem.item.price * cartItem.quantity, 0);
- // TODO Error Handling
- // 2.1 Create a Stripe Customer
- const customer = await stripe.customers.create({
- email: user.email,
- });
- // 2.3 Charge the stripe token
+ const amount = user.cart.reduce(
+ (tally, cartItem) => tally + cartItem.item.price * cartItem.quantity,
+ 0
+ );
+ // 2. Create a stripe charge
const charge = await stripe.charges.create({
amount,
currency: 'usd',
source: args.token,
});
+ // 3. convert the items they want to OrderItems
const orderItems = user.cart.map(cartItem => {
const orderItem = {
quantity: cartItem.quantity,
// copy all the item details so it's there forever
...cartItem.item,
item: {
- // realtionship to the Item incase we need it
+ // relationship to the Item incase we need it
connect: { id: cartItem.item.id },
},
user: { connect: { id: user.id } },
@@ -263,7 +271,7 @@ const mutations = {
return orderItem;
});
- // Create the Order
+ // 4. Create the Order
const order = await ctx.db.mutation.createOrder({
data: {
total: charge.amount,
@@ -279,8 +287,8 @@ const mutations = {
},
},
});
- console.log('Gonna delete some items');
- // 6. Clean up, clear the users cart adn send back { user, order }
+
+ // 5. Clean up, clear the users cart and send back { user, order }
// Delete the users current cart items
const cartItemIds = user.cart.map(cartItem => cartItem.id);
await ctx.db.mutation.deleteManyCartItems({
@@ -289,21 +297,24 @@ const mutations = {
},
});
- // 5. Send the order back to the client
+ // 6. Send the order back to the client
return order;
- // 4. TODO: Send an email with their order
},
+
async updateUser(parent, args, ctx, info) {
- const userId = getUserId(ctx);
- const updatedUser = await ctx.db.mutation.updateUser({
- data: args,
- where: { id: userId },
- });
+ const userId = ctx.request.userId;
+ const updatedUser = await ctx.db.mutation.updateUser(
+ {
+ data: args,
+ where: { id: userId },
+ },
+ info
+ );
return updatedUser;
},
async updatePermissions(parent, args, ctx, info) {
- const userId = getUserId(ctx);
+ const userId = ctx.request.userId;
const currentUser = await ctx.db.query.user({ where: { id: userId } }, info);
if (!currentUser) throw new Error('You Must be logged in to updat permissions!');
hasPermission(currentUser, ['ADMIN', 'PERMISSIONUPDATE']);
diff --git a/backend/src/resolvers/Query.js b/backend/src/resolvers/Query.js
index 22dcd2a..276f7fa 100644
--- a/backend/src/resolvers/Query.js
+++ b/backend/src/resolvers/Query.js
@@ -1,26 +1,52 @@
-const { getUserId, Context, checkForUserId } = require('../utils');
+const { hasPermission } = require('../utils');
+
const { forwardTo } = require('prisma-binding');
const Query = {
items(parent, args, ctx, info) {
- console.log('ITEMS!');
- // check auth
return ctx.db.query.items({ ...args }, info);
},
itemsConnection: forwardTo('db'),
// TODO: Make sure they own this order before looking it up
- order: forwardTo('db'),
+ // order: forwardTo('db'),
+ async order(parent, args, ctx, info) {
+ // 1. make sure they are signed in
+ if (!ctx.request.userId) {
+ throw new Error('You Must be signed in to view an order');
+ }
+
+ // 2. Create the query
+ const where = {
+ id: args.id,
+ user: {
+ id: ctx.request.userId,
+ },
+ };
+ // 3. Fire off the query
+ const [order] = await ctx.db.query.orders({ where }, info);
+
+ // 4. Check that they are allowed to view the order
+ if (order.user.id !== ctx.request.userId || hasPermission(ctx.request.user, ['ADMIN'])) {
+ throw new Error("You don't have permission");
+ }
+ // 5. If everything checks out, return the order
+ return order;
+ },
me(parent, args, ctx, info) {
const Authorization = ctx.request.get('Authorization');
if (!Authorization || Authorization === 'null') {
- console.log('Authorization is null');
- return null;
+ return null; // don't error out, just return nothing
}
- const id = getUserId(ctx);
- return ctx.db.query.user({ where: { id } }, info);
+
+ return ctx.db.query.user(
+ {
+ where: { id: ctx.request.userId },
+ },
+ info
+ );
},
async orders(parent, args, ctx, info) {
@@ -37,12 +63,6 @@ const Query = {
info
);
},
-
- async users(parent, args, ctx, info) {
- // TODO Permissions
- const userId = getUserId(ctx);
- return ctx.db.query.users({}, info);
- },
};
module.exports = Query;
diff --git a/backend/src/schema.graphql b/backend/src/schema.graphql
index 6613004..4318d2a 100644
--- a/backend/src/schema.graphql
+++ b/backend/src/schema.graphql
@@ -1,4 +1,4 @@
-# import Permission, Order, OrderItem, CartItem, ItemWhereInput, ItemOrderByInput, allItems, Item, ItemCreateInput, ItemOrderByInput, ItemWhereInput, Query.order, Query.orders, Query.users from './generated/prisma.graphql'
+# import Permission, Order, OrderItem, CartItem, ItemWhereInput, ItemOrderByInput, allItems, Item, ItemCreateInput, ItemOrderByInput, ItemWhereInput, Query.orders, Query.users from './generated/prisma.graphql'
type Query {
me: User
@@ -17,6 +17,7 @@ type Query {
skip: Int
first: Int
): [Item]!
+ order(id: ID!): Order!
}
# import Mutation from './generated/prisma.graphql'
diff --git a/backend/src/utils.js b/backend/src/utils.js
index 2988b3d..faf028b 100644
--- a/backend/src/utils.js
+++ b/backend/src/utils.js
@@ -1,16 +1,3 @@
-const jwt = require('jsonwebtoken');
-
-function getUserId(ctx) {
- const Authorization = ctx.request.get('Authorization');
- if (Authorization) {
- const token = Authorization.replace('Bearer ', '');
- const { userId } = jwt.verify(token, process.env.APP_SECRET);
- return userId;
- }
- // TODO: Don't throw when they aren't logged in
- // throw new Error('Sorry, you must be logged in to do that!');
-}
-
function hasPermission(user, permissionsNeeded) {
const matchedPermissions = user.permissions.filter(permissionTheyHave =>
permissionsNeeded.includes(permissionTheyHave)
@@ -27,24 +14,4 @@ function hasPermission(user, permissionsNeeded) {
}
}
-function checkForUserId(ctx) {
- const Authorization = ctx.request.get('Authorization');
- if (Authorization) {
- const token = Authorization.replace('Bearer ', '');
- const { userId } = jwt.verify(token, process.env.APP_SECRET);
- return userId;
- }
-}
-
-class AuthError extends Error {
- constructor() {
- super('Not authorized');
- }
-}
-
-module.exports = {
- getUserId,
- AuthError,
- checkForUserId,
- hasPermission,
-};
+exports.hasPermission = hasPermission;