diff options
Diffstat (limited to 'stepped-solutions/25/backend')
| -rwxr-xr-x | stepped-solutions/25/backend/datamodel.graphql | 30 | ||||
| -rwxr-xr-x | stepped-solutions/25/backend/src/generated/prisma.graphql | 819 | ||||
| -rwxr-xr-x | stepped-solutions/25/backend/src/index.js | 22 | ||||
| -rwxr-xr-x | stepped-solutions/25/backend/src/resolvers/Mutation.js | 74 | ||||
| -rwxr-xr-x | stepped-solutions/25/backend/src/schema.graphql | 14 |
5 files changed, 959 insertions, 0 deletions
diff --git a/stepped-solutions/25/backend/datamodel.graphql b/stepped-solutions/25/backend/datamodel.graphql new file mode 100755 index 0000000..e1b05ec --- /dev/null +++ b/stepped-solutions/25/backend/datamodel.graphql @@ -0,0 +1,30 @@ +enum Permission { + ADMIN + USER + ITEMCREATE + ITEMUPDATE + ITEMDELETE + PERMISSIONUPDATE +} + +type User { + id: ID! @unique + name: String! + email: String! @unique + password: String! + resetToken: String + resetTokenExpiry: String + permissions: [Permission] +} + +type Item { + id: ID! @unique + title: String! + description: String! + image: String + largeImage: String + price: Int! + # createAt: DateTime! + # updatedAt: DateTime! + # user: User! +} diff --git a/stepped-solutions/25/backend/src/generated/prisma.graphql b/stepped-solutions/25/backend/src/generated/prisma.graphql new file mode 100755 index 0000000..3d27a97 --- /dev/null +++ b/stepped-solutions/25/backend/src/generated/prisma.graphql @@ -0,0 +1,819 @@ +# source: https://us1.prisma.sh/wesbos/siccccccccck-fits/dev +# timestamp: Wed Jul 11 2018 09:57:06 GMT-0400 (EDT) + +type AggregateItem { + count: Int! +} + +type AggregateUser { + count: Int! +} + +type BatchPayload { + """The number of nodes that have been affected by the Batch operation.""" + count: Long! +} + +type Item implements Node { + id: ID! + title: String! + description: String! + image: String + largeImage: String + price: Int! +} + +"""A connection to a list of items.""" +type ItemConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [ItemEdge]! + aggregate: AggregateItem! +} + +input ItemCreateInput { + title: String! + description: String! + image: String + largeImage: String + price: Int! +} + +"""An edge in a connection.""" +type ItemEdge { + """The item at the end of the edge.""" + node: Item! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum ItemOrderByInput { + id_ASC + id_DESC + title_ASC + title_DESC + description_ASC + description_DESC + image_ASC + image_DESC + largeImage_ASC + largeImage_DESC + price_ASC + price_DESC + updatedAt_ASC + updatedAt_DESC + createdAt_ASC + createdAt_DESC +} + +type ItemPreviousValues { + id: ID! + title: String! + description: String! + image: String + largeImage: String + price: Int! +} + +type ItemSubscriptionPayload { + mutation: MutationType! + node: Item + updatedFields: [String!] + previousValues: ItemPreviousValues +} + +input ItemSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [ItemSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [ItemSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [ItemSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: ItemWhereInput +} + +input ItemUpdateInput { + title: String + description: String + image: String + largeImage: String + price: Int +} + +input ItemWhereInput { + """Logical AND on all given filters.""" + AND: [ItemWhereInput!] + + """Logical OR on all given filters.""" + OR: [ItemWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [ItemWhereInput!] + id: ID + + """All values that are not equal to given value.""" + id_not: ID + + """All values that are contained in given list.""" + id_in: [ID!] + + """All values that are not contained in given list.""" + id_not_in: [ID!] + + """All values less than the given value.""" + id_lt: ID + + """All values less than or equal the given value.""" + id_lte: ID + + """All values greater than the given value.""" + id_gt: ID + + """All values greater than or equal the given value.""" + id_gte: ID + + """All values containing the given string.""" + id_contains: ID + + """All values not containing the given string.""" + id_not_contains: ID + + """All values starting with the given string.""" + id_starts_with: ID + + """All values not starting with the given string.""" + id_not_starts_with: ID + + """All values ending with the given string.""" + id_ends_with: ID + + """All values not ending with the given string.""" + id_not_ends_with: ID + title: String + + """All values that are not equal to given value.""" + title_not: String + + """All values that are contained in given list.""" + title_in: [String!] + + """All values that are not contained in given list.""" + title_not_in: [String!] + + """All values less than the given value.""" + title_lt: String + + """All values less than or equal the given value.""" + title_lte: String + + """All values greater than the given value.""" + title_gt: String + + """All values greater than or equal the given value.""" + title_gte: String + + """All values containing the given string.""" + title_contains: String + + """All values not containing the given string.""" + title_not_contains: String + + """All values starting with the given string.""" + title_starts_with: String + + """All values not starting with the given string.""" + title_not_starts_with: String + + """All values ending with the given string.""" + title_ends_with: String + + """All values not ending with the given string.""" + title_not_ends_with: String + description: String + + """All values that are not equal to given value.""" + description_not: String + + """All values that are contained in given list.""" + description_in: [String!] + + """All values that are not contained in given list.""" + description_not_in: [String!] + + """All values less than the given value.""" + description_lt: String + + """All values less than or equal the given value.""" + description_lte: String + + """All values greater than the given value.""" + description_gt: String + + """All values greater than or equal the given value.""" + description_gte: String + + """All values containing the given string.""" + description_contains: String + + """All values not containing the given string.""" + description_not_contains: String + + """All values starting with the given string.""" + description_starts_with: String + + """All values not starting with the given string.""" + description_not_starts_with: String + + """All values ending with the given string.""" + description_ends_with: String + + """All values not ending with the given string.""" + description_not_ends_with: String + image: String + + """All values that are not equal to given value.""" + image_not: String + + """All values that are contained in given list.""" + image_in: [String!] + + """All values that are not contained in given list.""" + image_not_in: [String!] + + """All values less than the given value.""" + image_lt: String + + """All values less than or equal the given value.""" + image_lte: String + + """All values greater than the given value.""" + image_gt: String + + """All values greater than or equal the given value.""" + image_gte: String + + """All values containing the given string.""" + image_contains: String + + """All values not containing the given string.""" + image_not_contains: String + + """All values starting with the given string.""" + image_starts_with: String + + """All values not starting with the given string.""" + image_not_starts_with: String + + """All values ending with the given string.""" + image_ends_with: String + + """All values not ending with the given string.""" + image_not_ends_with: String + largeImage: String + + """All values that are not equal to given value.""" + largeImage_not: String + + """All values that are contained in given list.""" + largeImage_in: [String!] + + """All values that are not contained in given list.""" + largeImage_not_in: [String!] + + """All values less than the given value.""" + largeImage_lt: String + + """All values less than or equal the given value.""" + largeImage_lte: String + + """All values greater than the given value.""" + largeImage_gt: String + + """All values greater than or equal the given value.""" + largeImage_gte: String + + """All values containing the given string.""" + largeImage_contains: String + + """All values not containing the given string.""" + largeImage_not_contains: String + + """All values starting with the given string.""" + largeImage_starts_with: String + + """All values not starting with the given string.""" + largeImage_not_starts_with: String + + """All values ending with the given string.""" + largeImage_ends_with: String + + """All values not ending with the given string.""" + largeImage_not_ends_with: String + price: Int + + """All values that are not equal to given value.""" + price_not: Int + + """All values that are contained in given list.""" + price_in: [Int!] + + """All values that are not contained in given list.""" + price_not_in: [Int!] + + """All values less than the given value.""" + price_lt: Int + + """All values less than or equal the given value.""" + price_lte: Int + + """All values greater than the given value.""" + price_gt: Int + + """All values greater than or equal the given value.""" + price_gte: Int +} + +input ItemWhereUniqueInput { + id: ID +} + +""" +The `Long` scalar type represents non-fractional signed whole numeric values. +Long can represent values between -(2^63) and 2^63 - 1. +""" +scalar Long + +type Mutation { + createUser(data: UserCreateInput!): User! + createItem(data: ItemCreateInput!): Item! + updateUser(data: UserUpdateInput!, where: UserWhereUniqueInput!): User + updateItem(data: ItemUpdateInput!, where: ItemWhereUniqueInput!): Item + deleteUser(where: UserWhereUniqueInput!): User + deleteItem(where: ItemWhereUniqueInput!): Item + upsertUser(where: UserWhereUniqueInput!, create: UserCreateInput!, update: UserUpdateInput!): User! + upsertItem(where: ItemWhereUniqueInput!, create: ItemCreateInput!, update: ItemUpdateInput!): Item! + updateManyUsers(data: UserUpdateInput!, where: UserWhereInput): BatchPayload! + updateManyItems(data: ItemUpdateInput!, where: ItemWhereInput): BatchPayload! + deleteManyUsers(where: UserWhereInput): BatchPayload! + deleteManyItems(where: ItemWhereInput): BatchPayload! +} + +enum MutationType { + CREATED + UPDATED + DELETED +} + +"""An object with an ID""" +interface Node { + """The id of the object.""" + id: ID! +} + +"""Information about pagination in a connection.""" +type PageInfo { + """When paginating forwards, are there more items?""" + hasNextPage: Boolean! + + """When paginating backwards, are there more items?""" + hasPreviousPage: Boolean! + + """When paginating backwards, the cursor to continue.""" + startCursor: String + + """When paginating forwards, the cursor to continue.""" + endCursor: String +} + +enum Permission { + ADMIN + USER + ITEMCREATE + ITEMUPDATE + ITEMDELETE + PERMISSIONUPDATE +} + +type Query { + users(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [User]! + items(where: ItemWhereInput, orderBy: ItemOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): [Item]! + user(where: UserWhereUniqueInput!): User + item(where: ItemWhereUniqueInput!): Item + usersConnection(where: UserWhereInput, orderBy: UserOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): UserConnection! + itemsConnection(where: ItemWhereInput, orderBy: ItemOrderByInput, skip: Int, after: String, before: String, first: Int, last: Int): ItemConnection! + + """Fetches an object given its ID""" + node( + """The ID of an object""" + id: ID! + ): Node +} + +type Subscription { + user(where: UserSubscriptionWhereInput): UserSubscriptionPayload + item(where: ItemSubscriptionWhereInput): ItemSubscriptionPayload +} + +type User implements Node { + id: ID! + name: String! + email: String! + password: String! + resetToken: String + resetTokenExpiry: String + permissions: [Permission!]! +} + +"""A connection to a list of items.""" +type UserConnection { + """Information to aid in pagination.""" + pageInfo: PageInfo! + + """A list of edges.""" + edges: [UserEdge]! + aggregate: AggregateUser! +} + +input UserCreateInput { + name: String! + email: String! + password: String! + resetToken: String + resetTokenExpiry: String + permissions: UserCreatepermissionsInput +} + +input UserCreatepermissionsInput { + set: [Permission!] +} + +"""An edge in a connection.""" +type UserEdge { + """The item at the end of the edge.""" + node: User! + + """A cursor for use in pagination.""" + cursor: String! +} + +enum UserOrderByInput { + id_ASC + id_DESC + name_ASC + name_DESC + email_ASC + email_DESC + password_ASC + password_DESC + resetToken_ASC + resetToken_DESC + resetTokenExpiry_ASC + resetTokenExpiry_DESC + updatedAt_ASC + updatedAt_DESC + createdAt_ASC + createdAt_DESC +} + +type UserPreviousValues { + id: ID! + name: String! + email: String! + password: String! + resetToken: String + resetTokenExpiry: String + permissions: [Permission!]! +} + +type UserSubscriptionPayload { + mutation: MutationType! + node: User + updatedFields: [String!] + previousValues: UserPreviousValues +} + +input UserSubscriptionWhereInput { + """Logical AND on all given filters.""" + AND: [UserSubscriptionWhereInput!] + + """Logical OR on all given filters.""" + OR: [UserSubscriptionWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [UserSubscriptionWhereInput!] + + """ + The subscription event gets dispatched when it's listed in mutation_in + """ + mutation_in: [MutationType!] + + """ + The subscription event gets only dispatched when one of the updated fields names is included in this list + """ + updatedFields_contains: String + + """ + The subscription event gets only dispatched when all of the field names included in this list have been updated + """ + updatedFields_contains_every: [String!] + + """ + The subscription event gets only dispatched when some of the field names included in this list have been updated + """ + updatedFields_contains_some: [String!] + node: UserWhereInput +} + +input UserUpdateInput { + name: String + email: String + password: String + resetToken: String + resetTokenExpiry: String + permissions: UserUpdatepermissionsInput +} + +input UserUpdatepermissionsInput { + set: [Permission!] +} + +input UserWhereInput { + """Logical AND on all given filters.""" + AND: [UserWhereInput!] + + """Logical OR on all given filters.""" + OR: [UserWhereInput!] + + """Logical NOT on all given filters combined by AND.""" + NOT: [UserWhereInput!] + id: ID + + """All values that are not equal to given value.""" + id_not: ID + + """All values that are contained in given list.""" + id_in: [ID!] + + """All values that are not contained in given list.""" + id_not_in: [ID!] + + """All values less than the given value.""" + id_lt: ID + + """All values less than or equal the given value.""" + id_lte: ID + + """All values greater than the given value.""" + id_gt: ID + + """All values greater than or equal the given value.""" + id_gte: ID + + """All values containing the given string.""" + id_contains: ID + + """All values not containing the given string.""" + id_not_contains: ID + + """All values starting with the given string.""" + id_starts_with: ID + + """All values not starting with the given string.""" + id_not_starts_with: ID + + """All values ending with the given string.""" + id_ends_with: ID + + """All values not ending with the given string.""" + id_not_ends_with: ID + name: String + + """All values that are not equal to given value.""" + name_not: String + + """All values that are contained in given list.""" + name_in: [String!] + + """All values that are not contained in given list.""" + name_not_in: [String!] + + """All values less than the given value.""" + name_lt: String + + """All values less than or equal the given value.""" + name_lte: String + + """All values greater than the given value.""" + name_gt: String + + """All values greater than or equal the given value.""" + name_gte: String + + """All values containing the given string.""" + name_contains: String + + """All values not containing the given string.""" + name_not_contains: String + + """All values starting with the given string.""" + name_starts_with: String + + """All values not starting with the given string.""" + name_not_starts_with: String + + """All values ending with the given string.""" + name_ends_with: String + + """All values not ending with the given string.""" + name_not_ends_with: String + email: String + + """All values that are not equal to given value.""" + email_not: String + + """All values that are contained in given list.""" + email_in: [String!] + + """All values that are not contained in given list.""" + email_not_in: [String!] + + """All values less than the given value.""" + email_lt: String + + """All values less than or equal the given value.""" + email_lte: String + + """All values greater than the given value.""" + email_gt: String + + """All values greater than or equal the given value.""" + email_gte: String + + """All values containing the given string.""" + email_contains: String + + """All values not containing the given string.""" + email_not_contains: String + + """All values starting with the given string.""" + email_starts_with: String + + """All values not starting with the given string.""" + email_not_starts_with: String + + """All values ending with the given string.""" + email_ends_with: String + + """All values not ending with the given string.""" + email_not_ends_with: String + password: String + + """All values that are not equal to given value.""" + password_not: String + + """All values that are contained in given list.""" + password_in: [String!] + + """All values that are not contained in given list.""" + password_not_in: [String!] + + """All values less than the given value.""" + password_lt: String + + """All values less than or equal the given value.""" + password_lte: String + + """All values greater than the given value.""" + password_gt: String + + """All values greater than or equal the given value.""" + password_gte: String + + """All values containing the given string.""" + password_contains: String + + """All values not containing the given string.""" + password_not_contains: String + + """All values starting with the given string.""" + password_starts_with: String + + """All values not starting with the given string.""" + password_not_starts_with: String + + """All values ending with the given string.""" + password_ends_with: String + + """All values not ending with the given string.""" + password_not_ends_with: String + resetToken: String + + """All values that are not equal to given value.""" + resetToken_not: String + + """All values that are contained in given list.""" + resetToken_in: [String!] + + """All values that are not contained in given list.""" + resetToken_not_in: [String!] + + """All values less than the given value.""" + resetToken_lt: String + + """All values less than or equal the given value.""" + resetToken_lte: String + + """All values greater than the given value.""" + resetToken_gt: String + + """All values greater than or equal the given value.""" + resetToken_gte: String + + """All values containing the given string.""" + resetToken_contains: String + + """All values not containing the given string.""" + resetToken_not_contains: String + + """All values starting with the given string.""" + resetToken_starts_with: String + + """All values not starting with the given string.""" + resetToken_not_starts_with: String + + """All values ending with the given string.""" + resetToken_ends_with: String + + """All values not ending with the given string.""" + resetToken_not_ends_with: String + resetTokenExpiry: String + + """All values that are not equal to given value.""" + resetTokenExpiry_not: String + + """All values that are contained in given list.""" + resetTokenExpiry_in: [String!] + + """All values that are not contained in given list.""" + resetTokenExpiry_not_in: [String!] + + """All values less than the given value.""" + resetTokenExpiry_lt: String + + """All values less than or equal the given value.""" + resetTokenExpiry_lte: String + + """All values greater than the given value.""" + resetTokenExpiry_gt: String + + """All values greater than or equal the given value.""" + resetTokenExpiry_gte: String + + """All values containing the given string.""" + resetTokenExpiry_contains: String + + """All values not containing the given string.""" + resetTokenExpiry_not_contains: String + + """All values starting with the given string.""" + resetTokenExpiry_starts_with: String + + """All values not starting with the given string.""" + resetTokenExpiry_not_starts_with: String + + """All values ending with the given string.""" + resetTokenExpiry_ends_with: String + + """All values not ending with the given string.""" + resetTokenExpiry_not_ends_with: String +} + +input UserWhereUniqueInput { + id: ID + email: String +} diff --git a/stepped-solutions/25/backend/src/index.js b/stepped-solutions/25/backend/src/index.js new file mode 100755 index 0000000..2edee7e --- /dev/null +++ b/stepped-solutions/25/backend/src/index.js @@ -0,0 +1,22 @@ +const cookieParser = require('cookie-parser'); + +require('dotenv').config({ path: 'variables.env' }); +const createServer = require('./createServer'); +const db = require('./db'); + +const server = createServer(); + +server.express.use(cookieParser()); +// TODO Use express middlware to populate current user + +server.start( + { + cors: { + credentials: true, + origin: process.env.FRONTEND_URL, + }, + }, + deets => { + console.log(`Server is now running on port http://localhost:${deets.port}`); + } +); diff --git a/stepped-solutions/25/backend/src/resolvers/Mutation.js b/stepped-solutions/25/backend/src/resolvers/Mutation.js new file mode 100755 index 0000000..efaa5be --- /dev/null +++ b/stepped-solutions/25/backend/src/resolvers/Mutation.js @@ -0,0 +1,74 @@ +const bcrypt = require('bcryptjs'); +const jwt = require('jsonwebtoken'); + +const Mutations = { + async createItem(parent, args, ctx, info) { + // TODO: Check if they are logged in + + const item = await ctx.db.mutation.createItem( + { + data: { + ...args, + }, + }, + info + ); + + console.log(item); + + return item; + }, + updateItem(parent, args, ctx, info) { + // first take a copy of the updates + const updates = { ...args }; + // remove the ID from the updates + delete updates.id; + // run the update method + return ctx.db.mutation.updateItem( + { + data: updates, + where: { + id: args.id, + }, + }, + info + ); + }, + async deleteItem(parent, args, ctx, info) { + const where = { id: args.id }; + // 1. find the item + const item = await ctx.db.query.item({ where }, `{ id title}`); + // 2. Check if they own that item, or have the permissions + // TODO + // 3. Delete it! + return ctx.db.mutation.deleteItem({ where }, info); + }, + async signup(parent, args, ctx, info) { + // lowercase their email + args.email = args.email.toLowerCase(); + // hash their password + const password = await bcrypt.hash(args.password, 10); + // create the user in the database + const user = await ctx.db.mutation.createUser( + { + data: { + ...args, + password, + permissions: { set: ['USER'] }, + }, + }, + info + ); + // create the JWT token for them + const token = jwt.sign({ userId: user.id }, process.env.APP_SECRET); + // We set the jwt as a cookie on the response + ctx.response.cookie('token', token, { + httpOnly: true, + maxAge: 1000 * 60 * 60 * 24 * 365, // 1 year cookie + }); + // Finalllllly we return the user to the browser + return user; + }, +}; + +module.exports = Mutations; diff --git a/stepped-solutions/25/backend/src/schema.graphql b/stepped-solutions/25/backend/src/schema.graphql new file mode 100755 index 0000000..f3c6d3f --- /dev/null +++ b/stepped-solutions/25/backend/src/schema.graphql @@ -0,0 +1,14 @@ +# import * from './generated/prisma.graphql' + +type Mutation { + createItem(title: String, description: String, price: Int, image: String, largeImage: String): Item! + updateItem(id: ID!, title: String, description: String, price: Int): Item! + deleteItem(id: ID!): Item + signup(email: String!, password: String!, name: String!): User! +} + +type Query { + items(where: ItemWhereInput, orderBy: ItemOrderByInput, skip: Int, first: Int): [Item]! + item(where: ItemWhereUniqueInput!): Item + itemsConnection(where: ItemWhereInput): ItemConnection! +} |
