diff --git a/.env.sample b/.env.sample index 4f36271..eb522f4 100644 --- a/.env.sample +++ b/.env.sample @@ -2,6 +2,12 @@ # HTTPS is assumed for security reasons DAEMON_URL= +# These are for powering the LBRY Developer Program +# /developer-program +GITHUB_APP_ID= +GITHUB_APP_SECRET= +REWARD_URL=api.lbry.io + # https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app # We use this to show the GitHub feed on the homepage GITHUB_OAUTH_TOKEN= diff --git a/app/components/client/devprogram-scripts.js b/app/components/client/devprogram-scripts.js new file mode 100644 index 0000000..0017425 --- /dev/null +++ b/app/components/client/devprogram-scripts.js @@ -0,0 +1,46 @@ +"use strict"; /* global document, history, send, window */ + + + +document.getElementById("get-started").onclick = event => { + event.preventDefault(); + + send({ + message: "auth me with github" + }); +}; + +if (window.location.search.includes("?code=")) { + document.querySelector("developer-program").innerHTML = ` +
+ + + + + +
+ +

Need An Address?

+

To receive your LBC, you'll need a wallet address. While graphical wallets are available, the recommended path for engineers is to:

+ +
    +
  1. Download the LBRY SDK.
  2. +
  3. Launch the command-line utility (./lbrynet start).
  4. +
  5. Run ./lbrynet address list and copy the id field.
  6. +
+ `; + + history.replaceState({}, "", window.location.pathname); // clean up URL bar +} + +if (document.getElementById("creditsAcquire")) { + document.getElementById("creditsAcquire").onclick = () => { + send({ + address: document.getElementById("walletAddress").value, + code: document.getElementById("oauthCode").value, + message: "verify github auth" + }); + + document.querySelector("developer-program").innerHTML = "

Awaiting response from LBRY server...

"; + }; +} diff --git a/app/components/client/playground-scripts.js b/app/components/client/playground-scripts.js index 6173481..7a17f9f 100644 --- a/app/components/client/playground-scripts.js +++ b/app/components/client/playground-scripts.js @@ -111,7 +111,8 @@ function debounce(func, wait, immediate) { const later = () => { timeout = null; - if (!immediate) func.apply(context, args); + if (!immediate) + func.apply(context, args); }; const callNow = immediate && !timeout; @@ -119,7 +120,8 @@ function debounce(func, wait, immediate) { clearTimeout(timeout); timeout = setTimeout(later, wait); - if (callNow) func.apply(context, args); + if (callNow) + func.apply(context, args); }; } @@ -129,9 +131,9 @@ function initializePlayground() { document.querySelector("#fetch-claim-uri").focus(); document.querySelector(".playground-navigation__example:nth-child(1)").classList.add("active"); - send(JSON.stringify({ + send({ message: "landed on playground" - })); + }); setTimeout(() => { document.querySelector(".playground-navigation__example:nth-child(1)").click(); @@ -139,16 +141,17 @@ function initializePlayground() { } function fetchMetadata(exampleNumber, data) { - if (!exampleNumber) return; + if (!exampleNumber) + return; switch(exampleNumber) { case 1: - send(JSON.stringify({ + send({ claim: data, message: "fetch metadata", method: "resolve", example: exampleNumber - })); + }); document.getElementById("fetch-claim-uri").value = data; document.getElementById("playground-results").innerHTML = playgroundResponseForExample1(data); @@ -156,24 +159,24 @@ function fetchMetadata(exampleNumber, data) { break; case 2: - send(JSON.stringify({ + send({ data: data, message: "fetch metadata", method: "publish", example: exampleNumber - })); + }); document.getElementById("playground-results").innerHTML = playgroundResponseForExample2(getMemeInfo()); document.getElementById("playground-loader").style.display = "none"; break; case 3: - send(JSON.stringify({ + send({ claim: data, message: "fetch metadata", method: "claim_tip", example: exampleNumber - })); + }); document.getElementById("fetch-claim-uri").value = data; document.getElementById("playground-results").innerHTML = playgroundResponseForExample3(data); @@ -265,9 +268,7 @@ const handleExamples = debounce(event => { if (document.getElementById("playground-url").style.display === "none") document.getElementById("playground-url").removeAttribute("style"); - for (const example of document.querySelectorAll(".playground-navigation__example")) - example.classList.remove("active"); - + document.querySelectorAll(".playground-navigation__example").forEach(example => example.classList.remove("active")); document.querySelector(".playground-navigation__example:nth-child(1)").classList.add("active"); document.getElementById("playground-loader").innerHTML = ""; @@ -276,9 +277,9 @@ const handleExamples = debounce(event => { document.getElementById("playground-loader").removeAttribute("style"); document.getElementById("playground-results").removeAttribute("style"); - send(JSON.stringify({ + send({ message: `request for ${data.action}` - })); + }); break; @@ -291,9 +292,7 @@ const handleExamples = debounce(event => { document.getElementById("fetch-claim-uri").value = ""; // reset URL bar document.getElementById("playground-url").style.display = "none"; - for (const example of document.querySelectorAll(".playground-navigation__example")) - example.classList.remove("active"); - + document.querySelectorAll(".playground-navigation__example").forEach(example => example.classList.remove("active")); document.querySelector(".playground-navigation__example:nth-child(2)").classList.add("active"); document.getElementById("playground-loader").innerHTML = ""; @@ -302,9 +301,9 @@ const handleExamples = debounce(event => { document.getElementById("playground-loader").removeAttribute("style"); document.getElementById("playground-results").removeAttribute("style"); - send(JSON.stringify({ + send({ message: `request for ${data.action}` - })); + }); break; @@ -320,9 +319,7 @@ const handleExamples = debounce(event => { if (document.getElementById("playground-url").style.display === "none") document.getElementById("playground-url").removeAttribute("style"); - for (const example of document.querySelectorAll(".playground-navigation__example")) - example.classList.remove("active"); - + document.querySelectorAll(".playground-navigation__example").forEach(example => example.classList.remove("active")); document.querySelector(".playground-navigation__example:nth-child(3)").classList.add("active"); document.getElementById("playground-loader").innerHTML = ""; @@ -331,9 +328,9 @@ const handleExamples = debounce(event => { document.getElementById("playground-loader").removeAttribute("style"); document.getElementById("playground-results").removeAttribute("style"); - send(JSON.stringify({ + send({ message: `request for ${data.action}` - })); + }); break; diff --git a/app/components/developer-program.js b/app/components/developer-program.js new file mode 100644 index 0000000..c69085f --- /dev/null +++ b/app/components/developer-program.js @@ -0,0 +1,32 @@ +"use strict"; + + + +// I M P O R T + +import html from "choo/html"; + + + +// E X P O R T + +export default () => { + if ( + !process.env.GITHUB_APP_ID || + !process.env.GITHUB_APP_SECRET || + !process.env.REWARD_URL + ) { + return html` + +

Environment variables required to enable functionality are missing.

+
+ `; + } + + return html` + + + This will authenticate you with GitHub to prove eligibility as well as mark you as a follower of LBRY. + + `; +}; diff --git a/app/components/playground.js b/app/components/playground.js index c4463a3..f0a60d7 100644 --- a/app/components/playground.js +++ b/app/components/playground.js @@ -28,10 +28,10 @@ export default () => dedent` function example1() { return html` -
+ lbry:// -
+
diff --git a/app/dist/scripts/api.js b/app/dist/scripts/api.js index bb6f8d2..f9869a7 100644 --- a/app/dist/scripts/api.js +++ b/app/dist/scripts/api.js @@ -45,14 +45,9 @@ function handleApiLanguageToggles(language) { const examples = document.querySelectorAll("[data-api-example-type]"); const toggles = document.querySelectorAll("*[id^='toggle-']"); - for (const example of examples) - example.classList.remove("active"); - - for (const example of codeExamples) - example.classList.add("active"); - - for (const toggle of toggles) - toggle.classList.remove("active"); + examples.forEach(example => example.classList.remove("active")); + codeExamples.forEach(example => example.classList.add("active")); + toggles.forEach(example => example.classList.remove("active")); document.getElementById(`toggle-${language}`).classList.add("active"); }); diff --git a/app/dist/scripts/app.js b/app/dist/scripts/app.js index 3528f98..50a96f5 100755 --- a/app/dist/scripts/app.js +++ b/app/dist/scripts/app.js @@ -26,6 +26,9 @@ if ( // Smooth scroll document.querySelectorAll("a[href^='#']").forEach(anchor => { + if (anchor.classList.contains("no-smooth")) // Ignore smooth scroll functionality + return; + anchor.addEventListener("click", event => { event.preventDefault(); @@ -60,10 +63,10 @@ document.querySelector("[data-action='subscribe to newsletter']").onclick = () = document.getElementById("emailMessage").classList.remove("error"); - send(JSON.stringify({ + send({ email: email, message: "subscribe" - })); + }); }; @@ -87,6 +90,5 @@ function scrollToElementOnLoad() { function validateEmail(email) { const emailRegex = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\\.,;:\s@"]{2,})$/i; - - return emailRegex.test(String(email)); + return emailRegex.test(String(email)); // eslint-disable-line padding-line-between-statements } diff --git a/app/dist/scripts/plugins/jets.js b/app/dist/scripts/plugins/jets.js index 0b1a750..23eca43 100644 --- a/app/dist/scripts/plugins/jets.js +++ b/app/dist/scripts/plugins/jets.js @@ -224,7 +224,7 @@ ;(function(doc, proto) { try { doc.querySelector(":scope body"); - } catch (err) { + } catch(err) { ["querySelector", "querySelectorAll"].forEach(method => { const nativ = proto[method]; diff --git a/app/dist/scripts/sockets.js b/app/dist/scripts/sockets.js index 409bca8..3e236a2 100644 --- a/app/dist/scripts/sockets.js +++ b/app/dist/scripts/sockets.js @@ -1,4 +1,4 @@ -"use strict"; /* global document, location, WebSocket */ +"use strict"; /* global document, location, WebSocket, window */ @@ -12,22 +12,36 @@ document.addEventListener("DOMContentLoaded", () => { let ws = null; function checkWebSocketConnection() { - if (!ws || ws.readyState === 3) initializeWebSocketConnection(); + if (!ws || ws.readyState === 3) + initializeWebSocketConnection(); } function initializeWebSocketConnection() { ws = new WebSocket(location.origin.replace(/^http/, "ws")); - ws.onopen = () => { - console.log("WebSocket connection established"); // eslint-disable-line - }; + // ws.onopen = () => console.log("WebSocket connection established"); // eslint-disable-line no-console ws.onmessage = socket => { const data = JSON.parse(socket.data); switch(true) { + case data.message === "notification": // TODO: Make work with appending so multiple notifications can be sent + document.getElementById("flash-container").innerHTML = + `
${data.details}
`; + + setTimeout(() => { + document.getElementById("flash-container").innerHTML = ""; + }, 2100); + + break; + + case data.message === "redirect": + window.location.href = data.url; + break; + case data.message === "show result": - if (!data.example) return; + if (!data.example) + return; document.querySelector(data.selector).innerHTML = data.html; @@ -60,8 +74,8 @@ function initializeWebSocketConnection() { } if (data.example === 2) { - detectLanguageAndUpdate(); // eslint-disable-line - initCanvas(); // eslint-disable-line + detectLanguageAndUpdate(); // eslint-disable-line no-undef + initCanvas(); // eslint-disable-line no-undef setTimeout(() => { document.querySelector(".playground-content__meme__canvas__thumbnail").click(); @@ -83,36 +97,24 @@ function initializeWebSocketConnection() { break; - case data.message === "notification": // TODO: Make work with appending so multiple notifications can be sent - document.getElementById("flash-container").innerHTML = - `
${data.details}
`; - - setTimeout(() => { - document.getElementById("flash-container").innerHTML = ""; - }, 2100); - - break; - default: - console.log(data); // eslint-disable-line + console.log(data); // eslint-disable-line no-console break; } }; - ws.onclose = () => { - console.log("WebSocket connection lost"); // eslint-disable-line - checkWebSocketConnection(); // reconnect now - }; + ws.onclose = () => checkWebSocketConnection(); // reconnect now } -function send(msg) { // eslint-disable-line - socketReady(ws, () => ws.send(msg)); +function send(msg) { // eslint-disable-line no-unused-vars + socketReady(ws, () => ws.send(JSON.stringify(msg))); } function socketReady(socket, callback) { setTimeout(() => { if (socket && socket.readyState === 1) { - if (callback !== undefined) callback(); + if (callback !== undefined) + callback(); return; } diff --git a/app/helpers/fetch-metadata.js b/app/helpers/fetch-metadata.js index 7a957d0..0b16a3c 100644 --- a/app/helpers/fetch-metadata.js +++ b/app/helpers/fetch-metadata.js @@ -11,16 +11,16 @@ import stringifyObject from "stringify-object"; // U T I L S -import randomString from "./random-string"; import messageSlack from "./slack"; - import publishMeme from "./publish-meme"; +import randomString from "./random-string"; +import { send } from "@socket"; import uploadImage from "./upload-image"; const allowedQueryMethods = [ + "claim_tip", "publish", - "resolve", - "claim_tip" + "resolve" ]; const approvedContentIdsForTipping = [ @@ -60,11 +60,11 @@ export default async(data, socket) => { const resolveMethod = data.method; if (allowedQueryMethods.indexOf(resolveMethod) < 0) { - return socket.send(JSON.stringify({ + return send(socket, { details: "Unallowed resolve method for tutorial", message: "notification", type: "error" - })); + }); } body.authorization = process.env.LBRY_DAEMON_ACCESS_TOKEN; @@ -77,7 +77,7 @@ export default async(data, socket) => { // E X A M P L E case resolveMethod === "claim_tip": if (!approvedContentIdsForTipping.includes(claimAddress)) { - return socket.send(JSON.stringify({ + return send(socket, { example: data.example, html: raw(`

Response

@@ -85,7 +85,7 @@ export default async(data, socket) => { `), message: "show result", selector: `#example${data.example}-result` - })); + }); } apiRequestMethod = "POST"; @@ -140,7 +140,7 @@ export default async(data, socket) => { "json" ); - return socket.send(JSON.stringify({ + return send(socket, { example: data.example, html: raw(`

Response

@@ -149,15 +149,15 @@ export default async(data, socket) => { `), message: "show result", selector: `#example${data.example}-result` - })); + }); } catch(memePublishError) { - socket.send(JSON.stringify({ + send(socket, { details: "Meme publish failed", message: "notification", type: "error" - })); + }); if (process.env.NODE_ENV !== "development") { messageSlack({ @@ -172,11 +172,11 @@ export default async(data, socket) => { } catch(imageUploadError) { - socket.send(JSON.stringify({ + send(socket, { details: "Image upload failed", message: "notification", type: "error" - })); + }); if (process.env.NODE_ENV !== "development") { messageSlack({ @@ -241,7 +241,7 @@ export default async(data, socket) => { "json" ); - return socket.send(JSON.stringify({ + return send(socket, { example: data.example, html: raw(`

Response

@@ -250,7 +250,7 @@ export default async(data, socket) => { `), message: "show result", selector: `#example${data.example}-result` - })); + }); } return response.body.result[Object.keys(response.body.result)[0]].claim; diff --git a/app/helpers/github.js b/app/helpers/github.js index 2beaf95..6add98a 100644 --- a/app/helpers/github.js +++ b/app/helpers/github.js @@ -30,13 +30,13 @@ String.prototype.escape = function() { let client; -if (typeof process.env.GITHUB_OAUTH_TOKEN !== "undefined") { +if (process.env.GITHUB_OAUTH_TOKEN) { octokit = new Octokit({ auth: `token ${process.env.GITHUB_OAUTH_TOKEN}` }); } else process.stdout.write(`${color.red("[missing]")} GitHub token`); -if (typeof process.env.REDISCLOUD_URL !== "undefined") { +if (process.env.REDISCLOUD_URL) { client = redis.createClient(process.env.REDISCLOUD_URL); client.on("error", redisError => { @@ -258,7 +258,7 @@ function generateEvent(event) { } function generateGitHubFeed(displayGitHubFeed) { - if (typeof process.env.REDISCLOUD_URL !== "undefined") { + if (process.env.REDISCLOUD_URL) { client.zrevrange("events", 0, 9, (err, reply) => { if (err) return; // TODO: Render a div with nice error message @@ -346,8 +346,10 @@ function updateGithubFeed() { const eventString = JSON.stringify(item); client.zrank("events", eventString, (err, reply) => { - if (reply === null) client.zadd("events", item.id, eventString, callback); - else callback(); + if (reply === null) + client.zadd("events", item.id, eventString, callback); + else + callback(); }); }, () => client.zremrangebyrank("events", 0, -51)); // Keep the latest 50 events }) diff --git a/app/helpers/publish-meme.js b/app/helpers/publish-meme.js index 358273d..57ab4c0 100644 --- a/app/helpers/publish-meme.js +++ b/app/helpers/publish-meme.js @@ -28,7 +28,7 @@ export default async(publishMetadata) => { try { const response = await got.put(queryUrl, options); return response.body; // eslint-disable-line padding-line-between-statements - } catch (error) { + } catch(error) { return error; } }; diff --git a/app/helpers/upload-image.js b/app/helpers/upload-image.js index 5239fe1..ccebd3a 100644 --- a/app/helpers/upload-image.js +++ b/app/helpers/upload-image.js @@ -28,7 +28,7 @@ export default async(imageSource) => { try { const response = await got.post(queryUrl, options); return response.body; // eslint-disable-line padding-line-between-statements - } catch (error) { + } catch(error) { return error; } }; diff --git a/app/sass/bundle.scss b/app/sass/bundle.scss index 08374c0..bc3f413 100755 --- a/app/sass/bundle.scss +++ b/app/sass/bundle.scss @@ -22,6 +22,7 @@ @import "pages/api"; @import "pages/contributing"; +@import "pages/developer"; @import "pages/documentation"; @import "pages/home"; @import "pages/page"; diff --git a/app/sass/init/_markdown.scss b/app/sass/init/_markdown.scss index 910bd36..0a9394b 100644 --- a/app/sass/init/_markdown.scss +++ b/app/sass/init/_markdown.scss @@ -164,7 +164,7 @@ padding-left: 0.1rem; li { - list-style-type: lower-roman; + list-style-type: decimal; } } diff --git a/app/sass/pages/_developer.scss b/app/sass/pages/_developer.scss new file mode 100644 index 0000000..cd23817 --- /dev/null +++ b/app/sass/pages/_developer.scss @@ -0,0 +1,14 @@ +developer-program { + @extend %markdown; + + .button { + margin: 1rem auto; + display: block; + } + + small { + display: block; + font-size: 0.8rem; + text-align: center; + } +} diff --git a/app/sockets.js b/app/sockets.js index 6654f2a..502e264 100644 --- a/app/sockets.js +++ b/app/sockets.js @@ -13,45 +13,56 @@ import fetchMetadata from "@helper/fetch-metadata"; import { generateGitHubFeed } from "@helper/github"; import messageSlack from "@helper/slack"; - +let apiUrl = process.env.REWARD_URL; +let githubAppId = process.env.GITHUB_APP_ID; +let githubAppSecret = process.env.GITHUB_APP_SECRET; // P R O G R A M export default (socket, action) => { - if (typeof socket !== "object" && typeof action !== "object") return; + if (typeof socket !== "object" && typeof action !== "object") + return; switch(true) { + case action.message === "auth me with github": + getGitHubUserToken(socket); + break; + + case action.message === "verify github auth": + syncWithApi(action, socket); + break; + case action.message === "fetch metadata": fetchMetadata(action, socket); break; case action.message === "landed on homepage": generateGitHubFeed(result => { - socket.send(JSON.stringify({ + send(socket, { html: result, message: "updated html", selector: "#github-feed" - })); + }); }); break; case action.message === "landed on playground": generateContent(1, result => { - socket.send(JSON.stringify({ + send(socket, { html: result, message: "updated html", selector: "#playground-loader" - })); + }); }); break; case action.message === "request for playground, example 1": generateContent(1, result => { - socket.send(JSON.stringify({ + send(socket, { html: result, message: "updated html", selector: "#playground-loader" - })); + }); }); break; @@ -61,11 +72,11 @@ export default (socket, action) => { case action.message === "request for playground, example 3": generateContent(3, result => { - socket.send(JSON.stringify({ + send(socket, { html: result, message: "updated html", selector: "#playground-loader" - })); + }); }); break; @@ -85,15 +96,19 @@ export default (socket, action) => { function generateContent(exampleNumber, displayTrendingContent) { if (exampleNumber === 1) { return getTrendingContent().then(response => { - if (!response || !response.success || response.success !== true || !response.data) return ""; + if (!response || !response.success || response.success !== true || !response.data) + return ""; const rawContentCollection = []; const renderedContentCollection = []; const trendingContentData = response.data; - for (const data of trendingContentData) { - rawContentCollection.push(fetchMetadata({ claim: data.url, method: "resolve", example: exampleNumber })); - } + for (const data of trendingContentData) + rawContentCollection.push(fetchMetadata({ + claim: data.url, + example: exampleNumber, + method: "resolve" + })); Promise.all(rawContentCollection).then(collection => { for (const part of collection) { @@ -116,7 +131,7 @@ function generateContent(exampleNumber, displayTrendingContent) { `); - } catch (err) { + } catch(err) { return; // TODO: Return nice error message } } @@ -315,19 +330,26 @@ function generateMemeCreator(socket) { `; - return socket.send(JSON.stringify({ + return send(socket, { example: 2, html: memeCreator, message: "updated html", selector: "#playground-loader" - })); + }); +} + +function getGitHubUserToken(socket) { + send(socket, { + message: "redirect", + url: `https://github.com/login/oauth/authorize?client_id=${githubAppId}&scope=public_repo,user:email` + }); } async function getTrendingContent() { try { const response = await got("https://api.lbry.io/file/list_trending"); return JSON.parse(response.body); // eslint-disable-line padding-line-between-statements - } catch (error) { + } catch(error) { return error; } } @@ -344,22 +366,24 @@ function makeImageSourceSecure(url) { async function newsletterSubscribe(data, socket) { const email = data.email; - if (!validateEmail(email)) return socket.send(JSON.stringify({ - class: "error", - html: "Your email address is invalid", - message: "updated html", - selector: "#emailMessage" - })); + if (!validateEmail(email)) { + send(socket, { + class: "error", + html: "Your email address is invalid", + message: "updated html", + selector: "#emailMessage" + }); + } try { await got.post(`https://api.lbry.io/list/subscribe?email=${encodeURIComponent(email)}&tag=developer`); - return socket.send(JSON.stringify({ + return send(socket, { html: "Thank you! Please confirm subscription in your inbox.", message: "updated html", selector: "#emailMessage" - })); - } catch (error) { + }); + } catch(error) { const response = JSON.parse(error.body); if (!response.success) { @@ -369,12 +393,12 @@ async function newsletterSubscribe(data, socket) { `> _Cause: ${email} interacted with the form_\n` ); - return socket.send(JSON.stringify({ + return send(socket, { class: "error", html: response.error, message: "updated html", selector: "#emailMessage" - })); + }); } messageSlack( @@ -383,12 +407,56 @@ async function newsletterSubscribe(data, socket) { `> _Cause: ${email} interacted with the form_\n` ); - return socket.send(JSON.stringify({ + return send(socket, { class: "error", html: "Something is terribly wrong", message: "updated html", selector: "#emailMessage" - })); + }); + } +} + +export function send(transport, data) { + return transport.send(JSON.stringify(data)); +} + +async function syncWithApi(data, socket) { + const tokenResponse = await verifyGitHubToken(data.code); + + if (tokenResponse === null) { + return send(socket, { + html: "

There was an issue with accessing GitHub's API. Please try again later.

", + message: "updated html", + selector: "developer-program" + }); + } + + try { + let result = await got(`https://${apiUrl}/reward/new?github_token=${tokenResponse}&reward_type=github_developer&wallet_address=${data.address}`, { json: true }); + + result = result.body.data; + + return send(socket, { + html: `

Success! Your wallet has been credited with ${result.reward_amount} LBC.

We have a great reference for the LBRY SDK here to help you get started.

You can see proof of this transaction on our Blockain Explorer.

`, + message: "updated html", + selector: "developer-program" + }); + } catch(error) { + if (!error.body) { + return send(socket, { + html: "

LBRY API is down. Please try again later.

", + message: "updated html", + selector: "developer-program" + }); + } + + console.log(error.body); // eslint-disable-line no-console + + return send(socket, { + html: "

You have already claimed this reward. This reward is limited to ONE per person. Your enthusiasm is appreciated.

", + message: "updated html", + selector: "developer-program" + }); } } @@ -396,3 +464,15 @@ function validateEmail(email) { const emailRegex = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\\.,;:\s@"]{2,})$/i; return emailRegex.test(String(email)); // eslint-disable-line padding-line-between-statements } + +async function verifyGitHubToken(code) { + try { + let result = await got.post(`https://github.com/login/oauth/access_token?client_id=${githubAppId}&client_secret=${githubAppSecret}&code=${code}`, { json: true }); + + result = result.body; + return result.access_token; + } catch(verificationError) { + console.log(verificationError.body); // eslint-disable-line no-console + return null; + } +} diff --git a/app/views/home.js b/app/views/home.js index 62899e4..fb8af66 100644 --- a/app/views/home.js +++ b/app/views/home.js @@ -96,9 +96,7 @@ export default () => html` "; + switch(true) { + case partialPath === "developer-program": + pageScript = renderClientScript("devprogram-scripts"); + break; - if (partialPath === "overview") - pageScript = - ""; + case partialPath === "glossary": + pageScript = renderClientScript("glossary-scripts"); + break; - if (partialPath === "playground") - pageScript = - ""; + case partialPath === "overview": + pageScript = renderClientScript("ecosystem-scripts"); + break; + + case partialPath === "playground": + pageScript = renderClientScript("playground-scripts"); + break; + + default: + break; + } return html`
@@ -93,3 +95,15 @@ export default (state, emit) => { // eslint-disable-line
`; }; + + + +// H E L P E R + +function renderClientScript(clientScriptFileName) { + return ` + + `; +} diff --git a/documents/developer-program.md b/documents/developer-program.md new file mode 100644 index 0000000..d34f13a --- /dev/null +++ b/documents/developer-program.md @@ -0,0 +1,13 @@ +--- +title: Developer Program +--- + +LBRY offers a complimentary 100 LBC to qualified engineers to facilitate exploration, development, and testing. + +To qualify you must: + +- Have a GitHub account prior to January 1st, 2018. +- Have made a public pull request within the past year. + +### Claim LBC + diff --git a/package.json b/package.json index dd6e952..7a45bdd 100755 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "@helper": "app/helpers", "@module": "app/modules", "@root": ".", + "@socket": "app/sockets.js", "@view": "app/views" }, "author": "LBRY Team", @@ -94,8 +95,8 @@ "css": "sass --load-path=node_modules --update app/sass:app/dist --style compressed", "format": "eslint '**/*.js' --fix --ignore-pattern '/app/dist/'", "postinstall": "link-module-alias", - "preinstall": "command -v link-module-alias && link-module-alias clean || true", - "start": "npm run css && npm i && NODE_ENV=production node index.js", + "preinstall": "command -v link-module-alias; link-module-alias clean || true", + "start": "npm run css; npm i; NODE_ENV=production node index.js", "test": "run-s test:*", "test:dependencies": "updates --update ./ --exclude fastify,prismjs", "test:lint": "standardx --verbose | snazzy",