Skip to content

Instantly share code, notes, and snippets.

@zacjones93
Created May 16, 2023 21:45
Show Gist options
  • Save zacjones93/eba945eb8fb98809133061762ce40588 to your computer and use it in GitHub Desktop.
Save zacjones93/eba945eb8fb98809133061762ce40588 to your computer and use it in GitHub Desktop.
// 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