-
Notifications
You must be signed in to change notification settings - Fork 8
/
get_course_pages_from_lms.js
292 lines (253 loc) · 20 KB
/
get_course_pages_from_lms.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
'use strict';
/*
Script to generate course landing pages from TalentLMS API.
For each course in the API, generates a course landing page
with the link to the LMS.
API token required. Set `LMS_API_TOKEN`
*/
const https = require('https');
const LMS_API_TOKEN = process.env.LMS_API_TOKEN;
/*
* This is the course data we care about. The LMS will have other courses. This is the detail about the courses
* we need to display on the site.
* We'll pull the courses from TalentLMS and pare that list down to this list.
* The "code" field is the course code in the LMS - that's the "key" that maps this data to LMS data.
*/
const courseData = [
{code: '101_go', main: true, language: "Go", banner: "![Temporal Go SDK](/img/sdk_banners/banner_go.png)", filename: "temporal_101/go.md", index: 1,
keywords: "[Temporal, Workflows, Activities, Go SDK, external service, recovery, execution model, event history, Temporal Web UI, command-line tools, business process, application lifecycle]",
metaDescription: "Discover the essentials of Temporal application development in this course, focusing on Workflows, Activities, and the Go SDK. You'll develop a small app, recover from failures, and use Temporal's execution model and tools to manage your application lifecycle effectively."
},
{code: '101_typescript', language: "TypeScript", banner: "![Temporal TypeScript SDK](/img/sdk_banners/banner_typescript.png)", filename: "temporal_101/typescript.md", index: 3,
keywords: "[Temporal, Workflows, Activities, TypeScript SDK, external service, recovery, execution model, event history, Temporal Web UI, command-line tools, business process, application lifecycle]",
metaDescription: "Discover the essentials of Temporal application development in this course, focusing on Workflows, Activities, and the TypeScript SDK. You'll develop a small app, recover from failures, and use Temporal's execution model and tools to manage your application lifecycle effectively."
},
{code: '101_java', language: "Java", banner: "![Temporal Java SDK](/img/sdk_banners/banner_java.png)", filename: "temporal_101/java.md", index: 2,
keywords: "[Temporal, Workflows, Activities, Java SDK, external service, recovery, execution model, event history, Temporal Web UI, command-line tools, business process, application lifecycle]",
metaDescription: "Discover the essentials of Temporal application development in this course, focusing on Workflows, Activities, and the Java SDK. You'll develop a small app, recover from failures, and use Temporal's execution model and tools to manage your application lifecycle effectively."
},
{code: '101_python', language: "Python", banner: "![Temporal Python SDK](/img/sdk_banners/banner_python.png)", filename: "temporal_101/python.md", index: 4,
keywords: "[Temporal, Workflows, Activities, Python SDK, external service, recovery, execution model, event history, Temporal Web UI, command-line tools, business process, application lifecycle]",
metaDescription: "Discover the essentials of Temporal application development in this course, focusing on Workflows, Activities, and the Python SDK. You'll develop a small app, recover from failures, and use Temporal's execution model and tools to manage your application lifecycle effectively."
},
{code: '102_go_r2', main: true, language: "Go", banner: "![Temporal Go SDK](/img/sdk_banners/banner_go.png)", filename: "temporal_102/go.md", index: 1,
keywords: "[Temporal, application development, durable execution, development lifecycle, testing, debugging, deployment, best practices, automated testing, event history, workflow execution, production updates]",
metaDescription: "Go beyond the basics and gain a deeper understand of how Temporal works as you explore Temporal's event history, application lifecycle, write tests, and explore Durable Execution."
},
{code: '102_java', language: "Java", banner: "![Temporal Java SDK](/img/sdk_banners/banner_java.png)", filename: "temporal_102/java.md", index: 2,
keywords: "[Temporal, application development, durable execution, development lifecycle, testing, debugging, deployment, best practices, automated testing, event history, workflow execution, production updates]",
metaDescription: "Go beyond the basics and gain a deeper understand of how Temporal works as you explore Temporal's event history, application lifecycle, write tests, and explore Durable Execution."
},
{code: '102_ts', language: "TypeScript", banner: "![Temporal TypeScript SDK](/img/sdk_banners/banner_typescript.png)", filename: "temporal_102/typescript.md", index: 3,
keywords: "[Temporal, application development, durable execution, development lifecycle, testing, debugging, deployment, best practices, automated testing, event history, workflow execution, production updates]",
metaDescription: "Go beyond the basics and gain a deeper understand of how Temporal works as you explore Temporal's event history, application lifecycle, write tests, and explore Durable Execution."
},
{code: '102_python', language: "Python", banner: "![Temporal Python SDK](/img/sdk_banners/banner_python.png)", filename: "temporal_102/python.md", index: 4,
keywords: "[Temporal, application development, durable execution, development lifecycle, testing, debugging, deployment, best practices, automated testing, event history, workflow execution, production updates]",
metaDescription: "Go beyond the basics and gain a deeper understand of how Temporal works as you explore Temporal's event history, application lifecycle, write tests, and explore Durable Execution."
},
{
code: 'versioning_go', main: true, language: "Go", banner: "![Temporal Go SDK](/img/sdk_banners/banner_go.png)", filename: "versioning/go.md", index: 1,
keywords: "[Temporal, application development, durable execution, development lifecycle, testing, debugging, deployment, best practices, automated testing, event history, workflow execution, production updates]",
metaDescription: "In this course, you'll go beyond the fundamentals, learning how to safely evolve your Temporal application code in production. There are three primary approaches to versioning Temporal Workflows."
},
{
code: 'versioning_java', language: "Java", banner: "![Temporal Java SDK](/img/sdk_banners/banner_java.png)", filename: "versioning/java.md", index: 2,
keywords: "[Temporal, application development, durable execution, development lifecycle, testing, debugging, deployment, best practices, automated testing, event history, workflow execution, production updates]",
metaDescription: "In this course, you'll go beyond the fundamentals, learning how to safely evolve your Temporal application code in production. There are three primary approaches to versioning Temporal Workflows."
},
{
code: 'versioning_ts', language: "TypeScript", banner: "![Temporal TypeScript SDK](/img/sdk_banners/banner_typescript.png)", filename: "versioning/typescript.md", index: 3,
keywords: "[Temporal, application development, durable execution, development lifecycle, testing, debugging, deployment, best practices, automated testing, event history, workflow execution, production updates]",
metaDescription: "In this course, you'll go beyond the fundamentals, learning how to safely evolve your Temporal application code in production. There are three primary approaches to versioning Temporal Workflows."
},
{
code: 'versioning_python', language: "Python", banner: "![Temporal Python SDK](/img/sdk_banners/banner_python.png)", filename: "versioning/python.md", index: 4,
keywords: "[Temporal, application development, durable execution, development lifecycle, testing, debugging, deployment, best practices, automated testing, event history, workflow execution, production updates]",
metaDescription: "In this course, you'll go beyond the fundamentals, learning how to safely evolve your Temporal application code in production. There are three primary approaches to versioning Temporal Workflows."
},
{
code: 'appdatasec_go', main: true, language: "Go", banner: "![Temporal Go SDK](/img/sdk_banners/banner_go.png)", filename: "appdatasec/go.md", index: 1,
keywords: "[Temporal, application development, security, converters, deployment, best practices, codecs, compression, encryption, encoding, decoding, serialization, key rotation]",
metaDescription: "In this course, you'll implement Custom Data Conversion for your Temporal Workflows. By implementing Custom Data Converters and a Codec Server, you can expand this behavior to support a variety of complex input and output data."
},
{
code: 'appdatasec_java', language: "Java", banner: "![Temporal Java SDK](/img/sdk_banners/banner_java.png)", filename: "appdatasec/java.md", index: 2,
keywords: "[Temporal, application development, security, converters, deployment, best practices, codecs, compression, encryption, encoding, decoding, serialization, key rotation]",
metaDescription: "In this course, you'll implement Custom Data Conversion for your Temporal Workflows. By implementing Custom Data Converters and a Codec Server, you can expand this behavior to support a variety of complex input and output data."
},
{
code: 'appdatasec_ts', language: "TypeScript", banner: "![Temporal TypeScript SDK](/img/sdk_banners/banner_typescript.png)", filename: "appdatasec/typescript.md", index: 3,
keywords: "[Temporal, application development, security, converters, deployment, best practices, codecs, compression, encryption, encoding, decoding, serialization, key rotation]",
metaDescription: "In this course, you'll implement Custom Data Conversion for your Temporal Workflows. By implementing Custom Data Converters and a Codec Server, you can expand this behavior to support a variety of complex input and output data."
},
{
code: 'appdatasec_python', language: "Python", banner: "![Temporal Python SDK](/img/sdk_banners/banner_python.png)", filename: "appdatasec/python.md", index: 4,
keywords: "[Temporal, application development, security, converters, deployment, best practices, codecs, compression, encryption, encoding, decoding, serialization, key rotation]",
metaDescription: "In this course, you'll implement Custom Data Conversion for your Temporal Workflows. By implementing Custom Data Converters and a Codec Server, you can expand this behavior to support a variety of complex input and output data."
},
{
code: `intro2cld`, main: true, language: "Temporal Cloud", banner: "", filename: "intro_to_temporal_cloud/index.md", index: 3,
keywords: '[Temporal Cloud, Web UI, Temporal Platform, Namespaces, user management, roles and permissions, custom Search Attribute, third-party observability tool, account-level usage, Namespace-level usage, evaluating Temporal Cloud]',
metaDescription: "Master the essentials of Temporal Cloud with this comprehensive course. Dive into Web UI navigation, Namespace setup, user management, custom Search Attribute definition, and more. Perfect for newcomers, it simplifies onboarding and benefits even those evaluating Temporal Cloud's potential."
},
{
code: `interactwf_ts`, main: true, language: "TypeScript", banner: "![Temporal TypeScript SDK](/img/sdk_banners/banner_typescript.png)", filename: "interacting_with_workflows/typescript.md", index: 3, keywords: '[Temporal, application development, best practices, signals, queries, asynchronous activity completion, async activity completion, cancellations, search attributes]', metaDescription: "In this course, you’ll expand your ability to write dynamic Workflows by interacting with them and enabling them to respond to external stimuli."
},
{
code: `interactwf_go`, main: true, language: "Go", banner: "![Temporal Go SDK](/img/sdk_banners/banner_go.png)", filename: "interacting_with_workflows/go.md", index: 3,keywords: '[Temporal, application development, best practices, signals, queries, asynchronous activity completion, async activity completion, cancellations, search attributes]', metaDescription: "In this course, you’ll expand your ability to write dynamic Workflows by interacting with them and enabling them to respond to external stimuli."
},
{
code: `interactwf_java`, main: true, language: "Java", banner: "![Temporal Java SDK](/img/sdk_banners/banner_java.png)", filename: "interacting_with_workflows/java.md", index: 3,keywords: '[Temporal, application development, best practices, signals, queries, asynchronous activity completion, async activity completion, cancellations, search attributes]', metaDescription: "In this course, you’ll expand your ability to write dynamic Workflows by interacting with them and enabling them to respond to external stimuli."
},
{
code: `interactwf_python`, main: true, language: "Python", banner: "![Temporal Python SDK](/img/sdk_banners/banner_python.png)", filename: "interacting_with_workflows/python.md", index: 3, keywords: '[Temporal, application development, best practices, signals, queries, asynchronous activity completion, async activity completion, cancellations, search attributes]', metaDescription: "In this course, you’ll expand your ability to write dynamic Workflows by interacting with them and enabling them to respond to external stimuli."
},
{
code: `errstrat_typescript`,
main: true,
language: "TypeScript",
banner: "![Temporal TypeScript SDK](/img/sdk_banners/banner_typescript.png)",
filename: "errstrat/typescript.md",
index: 4,
keywords: '[Temporal, application development, best practices, failures, errors, timeouts, retry policies, heartbeats, saga pattern, non-retryable errors, idempotence]',
metaDescription: "In this course, you will design and implement effective error handling strategies that map your business logic to the Temporal platform. You will explore the nature of different types of failures and investigate the support that Temporal provides for addressing them. Along the way, you will learn essential concepts and techniques, such as idempotence, Heartbeating, and the Saga Pattern, which will help you to ensure the correctness and responsiveness of your application."
},
{
code: `errstrat_go`,
main: true,
language: "Go",
banner: "![Temporal Go SDK](/img/sdk_banners/banner_go.png)",
filename: "errstrat/go.md",
index: 1,
keywords: '[Temporal, application development, best practices, failures, errors, timeouts, retry policies, heartbeats, saga pattern, non-retryable errors, idempotence]',
metaDescription: "In this course, you will design and implement effective error handling strategies that map your business logic to the Temporal platform. You will explore the nature of different types of failures and investigate the support that Temporal provides for addressing them. Along the way, you will learn essential concepts and techniques, such as idempotence, Heartbeating, and the Saga Pattern, which will help you to ensure the correctness and responsiveness of your application."
},
{
code: `errstrat_java`,
main: true,
language: "Java",
banner: "![Temporal Java SDK](/img/sdk_banners/banner_java.png)",
filename: "errstrat/java.md",
index: 2,
keywords: '[Temporal, application development, best practices, failures, errors, timeouts, retry policies, heartbeats, saga pattern, non-retryable errors, idempotence]',
metaDescription: "In this course, you will design and implement effective error handling strategies that map your business logic to the Temporal platform. You will explore the nature of different types of failures and investigate the support that Temporal provides for addressing them. Along the way, you will learn essential concepts and techniques, such as idempotence, Heartbeating, and the Saga Pattern, which will help you to ensure the correctness and responsiveness of your application."
},
{
code: `errstrat_python`,
main: true,
language: "Python",
banner: "![Temporal Python SDK](/img/sdk_banners/banner_python.png)",
filename: "errstrat/python.md",
index: 3,
keywords: '[Temporal, application development, best practices, failures, errors, timeouts, retry policies, heartbeats, saga pattern, non-retryable errors, idempotence]',
metaDescription: "In this course, you will design and implement effective error handling strategies that map your business logic to the Temporal platform. You will explore the nature of different types of failures and investigate the support that Temporal provides for addressing them. Along the way, you will learn essential concepts and techniques, such as idempotence, Heartbeating, and the Saga Pattern, which will help you to ensure the correctness and responsiveness of your application."
},
]
const options = {
hostname: 'temporal.talentlms.com',
auth: `${LMS_API_TOKEN}:`,
path: '/api/v1/courses',
port: 443,
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
};
const req = https.request(options, res => {
// console.log(`statusCode: ${res.statusCode}`);
let data = "";
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function() {
const baseURL = 'https://temporal.talentlms.com/catalog';
// console.log(data)
let courses = JSON.parse(data);
//console.log(courses)
// only get the courses we care about.
let allowlist = courseData.map(c => c.code)
courses = courses.filter(course => allowlist.includes(course.code) );
// iterate over courses and fill out metadata to generate individual pages.
for (let course of courses) {
let metadata = courseData.find(c => c.code === course.code);
// push the fields from the LMS into the metadata
metadata.hours = convertHours(course.custom_field_2);
metadata.description = course.description;
metadata.name = course.name;
metadata.status = course.status;
metadata.shared = course.shared;
metadata.id = course.id;
metadata.last_update_on = course.last_update_on;
metadata.filepath = `docs/courses/${metadata.filename}`;
generateCoursePage(metadata, baseURL)
}
});
});
req.on('error', error => {
console.error(error);
});
req.end();
function convertHours(hours) {
let result = "";
if (parseInt(hours) > 1) {
result = `⏱️ ${hours} hours`
}else {
result = `⏱️ ${hours} hour`
}
return(result);
}
/* generate the markdown for the course.
*
* Takes the course data and base URL.
*/
function generateCoursePage(metadata, baseURL) {
const today = (new Date()).toString().split(' ').splice(1,3).join(' ');
const active = metadata.status === "active";
const url = `${baseURL}/info/id:${metadata.id}`;
const apidate = metadata.last_update_on;
const dateparts = apidate.split(",")[0];
const [dd,mm,yy] = dateparts.split("/");
const date = `${yy}-${mm}-${dd}`;
const hours = metadata.hours;
// parse text from LMS and massage
const description = metadata.description.replace("Prerequisites:", "### Prerequisites:")
let str = `---
title: "${metadata.name}"
sidebar_position: ${metadata.index}
sidebar_label: "${metadata.name}"
draft: ${!active}
tags: [courses, ${metadata.language}]
keywords: ${metadata.keywords}
description: "${metadata.metaDescription}"
custom_edit_url: null
hide_table_of_contents: true
last_update:
date: ${date}
image: /img/temporal-logo-twitter-card.png
---
<!-- Generated ${today} -->
<!-- DO NOT edit this file directly. -->
${metadata.banner}
**Estimated time**: ~${hours}, self-paced.
**Cost**: Free
`
if (!active) {
str += `:::info Course coming soon!
We're still building this course. The course outcomes and content are subject to change.
<a className="button button--primary" href="https://pages.temporal.io/get-updates-education">Get notified when we launch this course!</a>
:::
`
}
str += "## Description\n\n" + description + '\n\n';
if (active) {
str += ` <a className="button button--primary" href="${url}">Go to Course</a> `;
}else{
str += "This course is coming soon.\n\n"
str += ` <a className="button button--primary" href="https://pages.temporal.io/get-updates-education">Get notified when we launch this course!</a> `;
}
// write it
const fs = require('fs');
console.log(metadata.filepath)
fs.writeFileSync(metadata.filepath, str);
}