Advertisement
Guest User

mutation.js

a guest
Jan 4th, 2019
172
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.73 KB | None | 0 0
  1. const bcrypt = require("bcryptjs");
  2. const jwt = require("jsonwebtoken");
  3. const { randomBytes } = require("crypto");
  4. const { promisify } = require("util");
  5. const { transport, makeANiceEmail } = require("../mail");
  6. const { hasPermission } = require("../utils");
  7. const stripe = require("../stripe");
  8.  
  9. const Mutations = {
  10. async createItem(parent, args, ctx, info) {
  11. if (!ctx.request.userId) {
  12. throw new Error("You must be logged in to do that!");
  13. }
  14.  
  15. const item = await ctx.db.mutation.createItem(
  16. {
  17. data: {
  18. // This is how to create a relationship between the Item and the User
  19. user: {
  20. connect: {
  21. id: ctx.request.userId
  22. }
  23. },
  24. category: {
  25. connect: {
  26. id: ctx.request.categoryId
  27. }
  28. },
  29. ...args
  30. }
  31. },
  32. info
  33. );
  34.  
  35. console.log(item);
  36.  
  37. return item;
  38. },
  39. updateItem(parent, args, ctx, info) {
  40. // first take a copy of the updates
  41. const updates = { ...args };
  42. // remove the ID from the updates
  43. delete updates.id;
  44. // run the update method
  45. return ctx.db.mutation.updateItem(
  46. {
  47. data: updates,
  48. where: {
  49. id: args.id
  50. }
  51. },
  52. info
  53. );
  54. },
  55. async deleteItem(parent, args, ctx, info) {
  56. const where = { id: args.id };
  57. // 1. find the item
  58. const item = await ctx.db.query.item({ where }, `{ id title user { id }}`);
  59. // 2. Check if they own that item, or have the permissions
  60. const ownsItem = item.user.id === ctx.request.userId;
  61. const hasPermissions = ctx.request.user.permissions.some(permission =>
  62. ["ADMIN", "ITEMDELETE"].includes(permission)
  63. );
  64.  
  65. if (!ownsItem && !hasPermissions) {
  66. throw new Error("You don't have permission to do that!");
  67. }
  68.  
  69. // 3. Delete it!
  70. return ctx.db.mutation.deleteItem({ where }, info);
  71. },
  72. async createCategory(parent, args, ctx, info) {
  73. if (!ctx.request.userId) {
  74. throw new Error("You must be logged in to do that!");
  75. }
  76.  
  77. const category = await ctx.db.mutation.createCategory(
  78. {
  79. data: {
  80. // This is how to create a relationship between the Category and the User
  81. user: {
  82. connect: {
  83. id: ctx.request.userId
  84. }
  85. },
  86. ...args
  87. }
  88. },
  89. info
  90. );
  91.  
  92. console.log(category);
  93.  
  94. return category;
  95. },
  96. updateCategory(parent, args, ctx, info) {
  97. // first take a copy of the updates
  98. const updates = { ...args };
  99. // remove the ID from the updates
  100. delete updates.id;
  101. // run the update method
  102. return ctx.db.mutation.updateCategory(
  103. {
  104. data: updates,
  105. where: {
  106. id: args.id
  107. }
  108. },
  109. info
  110. );
  111. },
  112. async deleteCategory(parent, args, ctx, info) {
  113. const where = { id: args.id };
  114. // 1. find the Category
  115. const category = await ctx.db.query.category(
  116. { where },
  117. `{ id title user { id }}`
  118. );
  119. // 2. Check if they own that Category, or have the permissions
  120. const ownsCategory = category.user.id === ctx.request.userId;
  121. const hasPermissions = ctx.request.user.permissions.some(permission =>
  122. ["ADMIN"].includes(permission)
  123. );
  124.  
  125. if (!ownsCategory && !hasPermissions) {
  126. throw new Error("You don't have permission to do that!");
  127. }
  128.  
  129. // 3. Delete it!
  130. return ctx.db.mutation.deleteCategory({ where }, info);
  131. },
  132. async signup(parent, args, ctx, info) {
  133. // lowercase their email
  134. args.email = args.email.toLowerCase();
  135. // hash their password
  136. const password = await bcrypt.hash(args.password, 10);
  137. // create the user in the database
  138. const user = await ctx.db.mutation.createUser(
  139. {
  140. data: {
  141. ...args,
  142. password,
  143. permissions: { set: ["USER"] }
  144. }
  145. },
  146. info
  147. );
  148. // create the JWT token for them
  149. const token = jwt.sign({ userId: user.id }, process.env.APP_SECRET);
  150. // We set the jwt as a cookie on the response
  151. ctx.response.cookie("token", token, {
  152. httpOnly: true,
  153. maxAge: 1000 * 60 * 60 * 24 * 365 // 1 year cookie
  154. });
  155. // Finalllllly we return the user to the browser
  156. return user;
  157. },
  158. async signin(parent, { email, password }, ctx, info) {
  159. // 1. check if there is a user with that email
  160. const user = await ctx.db.query.user({ where: { email } });
  161. if (!user) {
  162. throw new Error(`No such user found for email ${email}`);
  163. }
  164. // 2. Check if their password is correct
  165. const valid = await bcrypt.compare(password, user.password);
  166. if (!valid) {
  167. throw new Error("Invalid Password!");
  168. }
  169. // 3. generate the JWT Token
  170. const token = jwt.sign({ userId: user.id }, process.env.APP_SECRET);
  171. // 4. Set the cookie with the token
  172. ctx.response.cookie("token", token, {
  173. httpOnly: true,
  174. maxAge: 1000 * 60 * 60 * 24 * 365
  175. });
  176. // 5. Return the user
  177. return user;
  178. },
  179. signout(parent, args, ctx, info) {
  180. ctx.response.clearCookie("token");
  181. return { message: "Goodbye!" };
  182. },
  183. async requestReset(parent, args, ctx, info) {
  184. // 1. Check if this is a real user
  185. const user = await ctx.db.query.user({ where: { email: args.email } });
  186. if (!user) {
  187. throw new Error(`No such user found for email ${args.email}`);
  188. }
  189. // 2. Set a reset token and expiry on that user
  190. const randomBytesPromiseified = promisify(randomBytes);
  191. const resetToken = (await randomBytesPromiseified(20)).toString("hex");
  192. const resetTokenExpiry = Date.now() + 3600000; // 1 hour from now
  193. const res = await ctx.db.mutation.updateUser({
  194. where: { email: args.email },
  195. data: { resetToken, resetTokenExpiry }
  196. });
  197. // 3. Email them that reset token
  198. const mailRes = await transport.sendMail({
  199. from: "guest@gmail.com",
  200. to: user.email,
  201. subject: "Your Password Reset Token",
  202. html: makeANiceEmail(`Your Password Reset Token is here!
  203. \n\n
  204. <a href="${
  205. process.env.FRONTEND_URL
  206. }/reset?resetToken=${resetToken}">Click Here to Reset</a>`)
  207. });
  208.  
  209. // 4. Return the message
  210. return { message: "Thanks!" };
  211. },
  212. async resetPassword(parent, args, ctx, info) {
  213. // 1. check if the passwords match
  214. if (args.password !== args.confirmPassword) {
  215. throw new Error("Yo Passwords don't match!");
  216. }
  217. // 2. check if its a legit reset token
  218. // 3. Check if its expired
  219. const [user] = await ctx.db.query.users({
  220. where: {
  221. resetToken: args.resetToken,
  222. resetTokenExpiry_gte: Date.now() - 3600000
  223. }
  224. });
  225. if (!user) {
  226. throw new Error("This token is either invalid or expired!");
  227. }
  228. // 4. Hash their new password
  229. const password = await bcrypt.hash(args.password, 10);
  230. // 5. Save the new password to the user and remove old resetToken fields
  231. const updatedUser = await ctx.db.mutation.updateUser({
  232. where: { email: user.email },
  233. data: {
  234. password,
  235. resetToken: null,
  236. resetTokenExpiry: null
  237. }
  238. });
  239. // 6. Generate JWT
  240. const token = jwt.sign({ userId: updatedUser.id }, process.env.APP_SECRET);
  241. // 7. Set the JWT cookie
  242. ctx.response.cookie("token", token, {
  243. httpOnly: true,
  244. maxAge: 1000 * 60 * 60 * 24 * 365
  245. });
  246. // 8. return the new user
  247. return updatedUser;
  248. },
  249. async updatePermissions(parent, args, ctx, info) {
  250. // 1. Check if they are logged in
  251. if (!ctx.request.userId) {
  252. throw new Error("You must be logged in!");
  253. }
  254. // 2. Query the current user
  255. const currentUser = await ctx.db.query.user(
  256. {
  257. where: {
  258. id: ctx.request.userId
  259. }
  260. },
  261. info
  262. );
  263. // 3. Check if they have permissions to do this
  264. hasPermission(currentUser, ["ADMIN", "PERMISSIONUPDATE"]);
  265. // 4. Update the permissions
  266. return ctx.db.mutation.updateUser(
  267. {
  268. data: {
  269. permissions: {
  270. set: args.permissions
  271. }
  272. },
  273. where: {
  274. id: args.userId
  275. }
  276. },
  277. info
  278. );
  279. },
  280. async addToCart(parent, args, ctx, info) {
  281. // 1. Make sure they are signed in
  282. const { userId } = ctx.request;
  283. if (!userId) {
  284. throw new Error("You must be signed in soooon");
  285. }
  286. // 2. Query the users current cart
  287. const [existingCartItem] = await ctx.db.query.cartItems({
  288. where: {
  289. user: { id: userId },
  290. item: { id: args.id }
  291. }
  292. });
  293. // 3. Check if that item is already in their cart and increment by 1 if it is
  294. if (existingCartItem) {
  295. console.log("This item is already in their cart");
  296. return ctx.db.mutation.updateCartItem(
  297. {
  298. where: { id: existingCartItem.id },
  299. data: { quantity: existingCartItem.quantity + 1 }
  300. },
  301. info
  302. );
  303. }
  304. // 4. If its not, create a fresh CartItem for that user!
  305. return ctx.db.mutation.createCartItem(
  306. {
  307. data: {
  308. user: {
  309. connect: { id: userId }
  310. },
  311. item: {
  312. connect: { id: args.id }
  313. }
  314. }
  315. },
  316. info
  317. );
  318. },
  319. async removeFromCart(parent, args, ctx, info) {
  320. // 1. Find the cart item
  321. const cartItem = await ctx.db.query.cartItem(
  322. {
  323. where: {
  324. id: args.id
  325. }
  326. },
  327. `{ id, user { id }}`
  328. );
  329. // 1.5 Make sure we found an item
  330. if (!cartItem) throw new Error("No CartItem Found!");
  331. // 2. Make sure they own that cart item
  332. if (cartItem.user.id !== ctx.request.userId) {
  333. throw new Error("Cheatin huhhhh");
  334. }
  335. // 3. Delete that cart item
  336. return ctx.db.mutation.deleteCartItem(
  337. {
  338. where: { id: args.id }
  339. },
  340. info
  341. );
  342. },
  343. async createOrder(parent, args, ctx, info) {
  344. // 1. Query the current user and make sure they are signed in
  345. const { userId } = ctx.request;
  346. if (!userId)
  347. throw new Error("You must be signed in to complete this order.");
  348. const user = await ctx.db.query.user(
  349. { where: { id: userId } },
  350. `{
  351. id
  352. name
  353. email
  354. cart {
  355. id
  356. quantity
  357. item { title price id description image largeImage }
  358. }}`
  359. );
  360. // 2. recalculate the total for the price
  361. const amount = user.cart.reduce(
  362. (tally, cartItem) => tally + cartItem.item.price * cartItem.quantity,
  363. 0
  364. );
  365. console.log(`Going to charge for a total of ${amount}`);
  366. // 3. Create the stripe charge (turn token into $$$)
  367. const charge = await stripe.charges.create({
  368. amount,
  369. currency: "USD",
  370. source: args.token
  371. });
  372. // 4. Convert the CartItems to OrderItems
  373. const orderItems = user.cart.map(cartItem => {
  374. const orderItem = {
  375. ...cartItem.item,
  376. quantity: cartItem.quantity,
  377. user: { connect: { id: userId } }
  378. };
  379. delete orderItem.id;
  380. return orderItem;
  381. });
  382.  
  383. // 5. create the Order
  384. const order = await ctx.db.mutation.createOrder({
  385. data: {
  386. total: charge.amount,
  387. charge: charge.id,
  388. items: { create: orderItems },
  389. user: { connect: { id: userId } }
  390. }
  391. });
  392. // 6. Clean up - clear the users cart, delete cartItems
  393. const cartItemIds = user.cart.map(cartItem => cartItem.id);
  394. await ctx.db.mutation.deleteManyCartItems({
  395. where: {
  396. id_in: cartItemIds
  397. }
  398. });
  399. // 7. Return the Order to the client
  400. return order;
  401. }
  402. };
  403.  
  404. module.exports = Mutations;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement