From 955f4c9e83705fb5a24e1b9dd25d43b15f900783 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sat, 14 Nov 2020 19:44:40 +1100 Subject: [PATCH] issues-95 get saving and forking to work --- api/src/functions/identity-signup.js | 24 +++----------- api/src/graphql/parts.sdl.js | 1 + api/src/services/helpers.js | 14 ++++++++ api/src/services/parts/parts.js | 20 ++++++++++++ web/src/cascade | 2 +- .../IdeCascadeStudio/IdeCascadeStudio.js | 13 +++++++- web/src/components/IdePartCell/IdePartCell.js | 32 +++++++++++++++++-- 7 files changed, 82 insertions(+), 24 deletions(-) diff --git a/api/src/functions/identity-signup.js b/api/src/functions/identity-signup.js index ee6fa0a..326699b 100644 --- a/api/src/functions/identity-signup.js +++ b/api/src/functions/identity-signup.js @@ -1,6 +1,6 @@ import { createUserInsecure } from 'src/services/users/users.js' import { db } from 'src/lib/db' -import { enforceAlphaNumeric } from 'src/services/helpers' +import { enforceAlphaNumeric, generateUniqueString } from 'src/services/helpers' export const handler = async (req, _context) => { const body = JSON.parse(req.body) @@ -58,26 +58,12 @@ export const handler = async (req, _context) => { if (eventType === 'signup') { roles.push('user') - // const hi = { - // email: 'kurt.hutten@gmail.com', - // image: '', - // bio: '' - // } - - const generateUniqueUserName = async (seed, count = 0) => { - const isUnique = !(await db.user.findOne({ + const isUniqueCallback = async (seed) => + db.user.findOne({ where: { userName: seed }, - })) - if (isUnique) { - return seed - } - count += 1 - const newSeed = - count === 1 ? `${seed}_${count}` : seed.slice(0, -1) + count - return generateUniqueUserName(newSeed, count) - } + }) const userNameSeed = enforceAlphaNumeric(email.split('@')[0]) - const userName = await generateUniqueUserName(userNameSeed) // TODO maybe come up with a better default userName? + const userName = await generateUniqueString(userNameSeed, isUniqueCallback) // TODO maybe come up with a better default userName? const input = { email, userName, diff --git a/api/src/graphql/parts.sdl.js b/api/src/graphql/parts.sdl.js index 31dd970..dd46d83 100644 --- a/api/src/graphql/parts.sdl.js +++ b/api/src/graphql/parts.sdl.js @@ -37,6 +37,7 @@ export const schema = gql` type Mutation { createPart(input: CreatePartInput!): Part! + forkPart(input: CreatePartInput!): Part! updatePart(id: String!, input: UpdatePartInput!): Part! deletePart(id: String!): Part! } diff --git a/api/src/services/helpers.js b/api/src/services/helpers.js index c5611eb..8a488bf 100644 --- a/api/src/services/helpers.js +++ b/api/src/services/helpers.js @@ -14,3 +14,17 @@ export const foreignKeyReplacement = (input) => { export const enforceAlphaNumeric = (string) => string.replace(/([^a-zA-Z\d_:])/g, '-') + +export const generateUniqueString = async ( + seed, + isUniqueCallback, + count = 0 +) => { + const isUnique = !(await isUniqueCallback(seed)) + if (isUnique) { + return seed + } + count += 1 + const newSeed = count === 1 ? `${seed}_${count}` : seed.slice(0, -1) + count + return generateUniqueString(newSeed, isUniqueCallback, count) +} diff --git a/api/src/services/parts/parts.js b/api/src/services/parts/parts.js index aad2a72..230de93 100644 --- a/api/src/services/parts/parts.js +++ b/api/src/services/parts/parts.js @@ -2,6 +2,7 @@ import { db } from 'src/lib/db' import { foreignKeyReplacement, enforceAlphaNumeric, + generateUniqueString, } from 'src/services/helpers' import { requireAuth } from 'src/lib/auth' import { requireOwnership } from 'src/lib/owner' @@ -38,6 +39,25 @@ export const createPart = async ({ input }) => { }) } +export const forkPart = async ({ input }) => { + // Only difference between create nda clone part is that clone part will generate a unique title + // (for the user) if there is a conflict + const isUniqueCallback = async (seed) => + db.part.findOne({ + where: { + title_userId: { + title: seed, + userId: input.userId, + }, + }, + }) + const title = await generateUniqueString(input.title, isUniqueCallback) + // TODO change the description to `forked from userName/partName ${rest of description}` + return db.part.create({ + data: foreignKeyReplacement({ ...input, title }), + }) +} + export const updatePart = async ({ id, input }) => { requireAuth() await requireOwnership({ partId: id }) diff --git a/web/src/cascade b/web/src/cascade index 4849635..3cf6e98 160000 --- a/web/src/cascade +++ b/web/src/cascade @@ -1 +1 @@ -Subproject commit 4849635f04ceb1fe4499b7c64e6ad7a0a6cc4084 +Subproject commit 3cf6e98dd7d984ed5765a49083b1179005836130 diff --git a/web/src/components/IdeCascadeStudio/IdeCascadeStudio.js b/web/src/components/IdeCascadeStudio/IdeCascadeStudio.js index 88ce3ed..bac37fe 100644 --- a/web/src/components/IdeCascadeStudio/IdeCascadeStudio.js +++ b/web/src/components/IdeCascadeStudio/IdeCascadeStudio.js @@ -60,7 +60,18 @@ const IdeCascadeStudio = ({ part, saveCode, loading, error }) => { {}} + onSave={() => { + saveCode({ + input: { + code, + title: part?.title, + userId: currentUser?.sub, + description: part?.description, + }, + id: part.id, + isFork: !canEdit, + }) + }} onExport={(type) => threejsViewport[`saveShape${type}`]()} />
diff --git a/web/src/components/IdePartCell/IdePartCell.js b/web/src/components/IdePartCell/IdePartCell.js index c80ba51..de8da61 100644 --- a/web/src/components/IdePartCell/IdePartCell.js +++ b/web/src/components/IdePartCell/IdePartCell.js @@ -26,6 +26,17 @@ const UPDATE_PART_MUTATION = gql` } } ` +const FORK_PART_MUTATION = gql` + mutation ForkPartMutation($input: CreatePartInput!) { + forkPart(input: $input) { + id + title + user { + userName + } + } + } +` export const Loading = () =>
Loading...
@@ -39,10 +50,25 @@ export const Success = ({ part, refetch }) => { addMessage('Part updated.', { classes: 'rw-flash-success' }) }, }) + const [forkPart] = useMutation(FORK_PART_MUTATION, { + onCompleted: ({ forkPart }) => { + navigate( + routes.ide({ + userName: forkPart?.user?.userName, + partTitle: forkPart?.title, + }) + ) + addMessage('Part Forked.', { classes: 'rw-flash-success' }) + }, + }) - const saveCode = (input, id) => { - updatePart({ variables: { id, input } }) - refetch() + const saveCode = ({ input, id, isFork }) => { + if (!isFork) { + updatePart({ variables: { id, input } }) + refetch() + return + } + forkPart({ variables: { input } }) } return (