Instantly share code, notes, and snippets.
Created
May 16, 2023 21:45
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save zacjones93/eba945eb8fb98809133061762ce40588 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Name: patch-course-with-tags | |
// Author: Zac Jones | |
import "@johnlindquist/kit" | |
let groq = await npm("groq") | |
let { nanoid } = await npm("nanoid"); | |
let { GraphQLClient, gql } = await npm("graphql-request"); | |
const sanityClient = await npm("@sanity/client"); | |
let courses = [ | |
{ | |
"title": "Web Frameworks in 60 Seconds", | |
"id": "3ypwSb3ypP19JXKlBywUBB", | |
"externalId": 463764, | |
"path": "/courses/web-frameworks-in-60-seconds-964d25d0" | |
}, | |
{ | |
"title": "Introduction to GROQ Query Language", | |
"id": "4gDjzUvEKfujb6v67Np3i3", | |
"externalId": 530989, | |
"path": "/playlists/introduction-to-groq-query-language-6e9c6fc0" | |
}, | |
{ | |
"path": "/courses/complex-state-management-in-react-with-jotai-and-xstate-3be0a740", | |
"title": "Complex State Management in React with Jotai and XState", | |
"id": "5W5y8hHOeG4Agb4ATAW1AF", | |
"externalId": 559208 | |
}, | |
{ | |
"title": "RTK Query Basics: Query Endpoints, Data Flow and TypeScript", | |
"id": "7qTSuQFyBbm5ZzRcafurQa", | |
"externalId": 758014, | |
"path": "/courses/rtk-query-basics-query-endpoints-data-flow-and-typescript-57ea3c43" | |
}, | |
{ | |
"title": "Use Playwright to Test and Automate Web Applications", | |
"id": "HQYdIp2QSy5DOYjimsOjjc", | |
"externalId": 564894, | |
"path": "/courses/use-playwright-to-test-and-automate-web-applications-74b97e59" | |
}, | |
{ | |
"title": "ECommerce Product Management & Storefront with GraphCMS, Snipcart, & Next.js", | |
"id": "JpYdTkBvGzoSqquyXGk1Kf", | |
"externalId": 565756, | |
"path": "/playlists/ecommerce-product-management-storefront-with-graphcms-snipcart-next-js-13cc0534" | |
}, | |
{ | |
"path": "/courses/statechart-driven-ui-components-with-zag-js-53f85394", | |
"title": "Statechart Driven UI Components with Zag.js", | |
"id": "LvrLN9S6qcv4vwBROfZqNN", | |
"externalId": 867426 | |
}, | |
{ | |
"id": "O2AFlvx3XYyEZlCFJx0g1N", | |
"externalId": 432643, | |
"path": "/courses/react-flux-architecture-es5", | |
"title": "React: Flux Architecture (ES5)" | |
}, | |
{ | |
"externalId": 432580, | |
"path": "/courses/learn-protractor-testing-for-angularjs", | |
"title": "Learn Protractor Testing for AngularJS", | |
"id": "O2AFlvx3XYyEZlCFJx0w7Z" | |
}, | |
{ | |
"id": "O2AFlvx3XYyEZlCFJx1MPV", | |
"externalId": 432571, | |
"path": "/courses/build-your-first-react-js-app", | |
"title": "Build Your First React.js App" | |
}, | |
{ | |
"title": "Build a Modern CMS Driven Web Applications using Strapi and Next.js", | |
"id": "VANHjM361yQTdCFeHkE2sP", | |
"externalId": 637139, | |
"path": "/courses/build-a-modern-cms-driven-web-applications-using-strapi-and-next-js-93cc0972" | |
}, | |
{ | |
"title": "Build a Book Club Bot with Discord.js", | |
"id": "WkyEpya1yHHgmrwhPKlGm4", | |
"externalId": 911473, | |
"path": "/courses/build-a-book-club-bot-with-discord-js-501f5be9" | |
}, | |
{ | |
"id": "Xbd6dlzpsM4jgsEjN5mt4n", | |
"externalId": 526728, | |
"path": "/playlists/graphql-and-vue-3-8152749d", | |
"title": "Create a GraphQL Powered Vue 3 Application" | |
}, | |
{ | |
"path": "/courses/create-a-bar-chart-with-react-and-d3-0c18265f", | |
"title": "Create A Bar Chart with React and D3", | |
"id": "Z0P9ATO9qMAufoLhum96ww", | |
"externalId": 569317 | |
}, | |
{ | |
"externalId": 524764, | |
"path": "/playlists/build-a-react-app-with-authorization-and-authentication-8bbacfe9", | |
"title": "Build a React App with Authorization and Authentication with AWS Amplify", | |
"id": "bt3XuDpyeXlu6EKcoSaDN0" | |
}, | |
{ | |
"path": "/courses/build-your-first-react-js-app", | |
"title": "Build Your First React.js App", | |
"id": "drafts.O2AFlvx3XYyEZlCFJx1MPV", | |
"externalId": 432571 | |
}, | |
{ | |
"externalId": 828299, | |
"path": "/courses/custom-authentication-flows-for-modern-applications-with-auth0-actions-c51aa3bc", | |
"title": "Custom Authentication Flows for Modern Applications with Auth0 Actions", | |
"id": "drafts.gdclvnU1lHmBFD9wNSNbIm" | |
}, | |
{ | |
"externalId": 429296, | |
"path": "/courses/build-an-accessible-audio-player-with-react-d867", | |
"title": "Create an Accessible Audio Player with the HTML Media Element and React", | |
"id": "gdclvnU1lHmBFD9wNNKx52" | |
}, | |
{ | |
"title": "Custom Authentication Flows for Modern Applications with Auth0 Actions", | |
"id": "gdclvnU1lHmBFD9wNSNbIm", | |
"externalId": 828299, | |
"path": "/courses/custom-authentication-flows-for-modern-applications-with-auth0-actions-c51aa3bc" | |
}, | |
{ | |
"title": "Build a Realtime Chat App with Remix and Supabase", | |
"id": "gi4158dmNt3U3tH38Y4zbu", | |
"externalId": 783263, | |
"path": "/playlists/build-a-realtime-chat-app-with-remix-and-supabase-d36e2618" | |
}, | |
{ | |
"id": "pGgJd3yvYGy4mA95Dj8afc", | |
"externalId": 904804, | |
"path": "/courses/build-full-stack-web-applications-with-angular-and-firebase-2b531c4e", | |
"title": "Build Full Stack Web Applications with Angular and Firebase" | |
}, | |
{ | |
"path": "/courses/adopting-rtk-query-into-an-existing-redux-application-c22acd56", | |
"title": "Adopting RTK Query into an Existing Redux Application", | |
"id": "vj2ZWfgAvv2A8WOEhjRUc8", | |
"externalId": 886517 | |
} | |
] | |
let coursesWithSlug = courses.map(course => { | |
return { | |
...course, | |
slug: course.path.split("/").pop() | |
} | |
}) | |
/* | |
## Set up clients | |
*/ | |
let eggheadUserToken = await env("EGGHEAD_AUTH_TOKEN"); | |
let key = await env("SANITY_READ_WRITE_KEY"); | |
export const eggheadAuthHeaders = { | |
Authorization: `Bearer ${eggheadUserToken}`, | |
}; | |
const eggheadSanityClient = sanityClient({ | |
projectId: "sb1i5dlc", | |
dataset: "production", | |
token: key, | |
apiVersion: '2021-10-21', | |
useCdn: false, // `false` if you want to ensure fresh data | |
}); | |
const eggheadGraphQLClient = new GraphQLClient( | |
"https://app.egghead.io/graphql", | |
{ | |
headers: { | |
Authorization: `Bearer ${eggheadUserToken}`, | |
}, | |
} | |
); | |
/* | |
## Queries | |
*/ | |
const playlistQuery = gql` | |
query getPlaylist($slug: String!) { | |
playlist: playlist(slug: $slug) { | |
externalId: id | |
tags { | |
name | |
} | |
} | |
} | |
`; | |
async function queryEggheadForPlaylist(slug) { | |
return await eggheadGraphQLClient.request(playlistQuery, { | |
slug, | |
}); | |
} | |
/* | |
## Convert to Sanity Format | |
*/ | |
let createSanityTags = (c) => { | |
return c.tags.map((tag) => { | |
return { | |
"_key": nanoid(), | |
"_type": "versioned-software-library", | |
"library": { | |
"_ref": `software-library-${tag.name.toLowerCase()}`, | |
"_type": "reference" | |
} | |
} | |
}) | |
} | |
/* | |
## Post to Sanity | |
*/ | |
try { | |
coursesWithSlug.map(async course => { | |
let { playlist } = await queryEggheadForPlaylist(course.slug) | |
let courseQuery = groq`*[_type == 'resource' && externalId == ${playlist.externalId}][0]{ | |
title, | |
'id': _id, | |
'dependencies': softwareLibraries[]{ | |
version, | |
...library->{ | |
description, | |
'slug': slug.current, | |
path, | |
name, | |
'label': name, | |
'image_url': image.url | |
} | |
} | |
}`; | |
let sanityTags = createSanityTags(playlist) | |
let sanityCourse = await eggheadSanityClient.fetch(courseQuery); | |
let res = await eggheadSanityClient | |
.patch(sanityCourse.id) // Document ID to patch | |
.setIfMissing({softwareLibraries: sanityTags}) // Shallow merge | |
.commit() // Perform the patch and return a promise | |
}) | |
} catch (err){ | |
if(err.statusCode === 409) { | |
console.log(err.response.body.error.items[0].error.referenceID) | |
widget("Tag " + err.response.body.error.items[0].error.referenceID + " does not exist.") | |
} else { | |
console.log(err); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment