2018-09-27 18:11:26 +02:00
"use strict" ;
2018-11-30 21:46:22 +01:00
// I M P O R T S
2018-09-27 18:11:26 +02:00
2018-11-30 21:46:22 +01:00
import got from "got" ;
import html from "choo/html" ;
2018-09-27 18:11:26 +02:00
2018-10-10 19:56:35 +02:00
// U T I L S
2018-09-27 18:11:26 +02:00
2019-07-10 23:48:45 +02:00
import apiPage from "~view/api" ;
2019-04-12 22:17:39 +02:00
import fetchMetadata from "~helper/fetch-metadata" ;
import { generateGitHubFeed } from "~helper/github" ;
import messageSlack from "~helper/slack" ;
2018-09-27 18:11:26 +02:00
2019-02-22 18:41:50 +01:00
const githubAppId = process . env . GITHUB _APP _ID ;
const githubAppSecret = process . env . GITHUB _APP _SECRET ;
2019-02-21 20:28:09 +01:00
2019-02-22 18:41:50 +01:00
// const githubAppId = process.env.GITHUB_APP_ID_TEST;
// const githubAppSecret = process.env.GITHUB_APP_SECRET_TEST;
2019-02-21 20:28:09 +01:00
2019-02-18 21:31:48 +01:00
2019-02-14 18:07:22 +01:00
// P R O G R A M
2019-02-14 00:08:59 +01:00
2019-07-10 23:48:45 +02:00
export default async ( socket , action ) => {
2019-02-05 00:42:52 +01:00
if ( typeof socket !== "object" && typeof action !== "object" )
return ;
2018-09-27 18:11:26 +02:00
switch ( true ) {
2019-02-08 00:06:03 +01:00
case action . message === "auth me with github" :
2019-02-12 00:47:01 +01:00
getGitHubUserToken ( socket ) ;
2019-02-08 00:06:03 +01:00
break ;
2019-02-21 20:28:09 +01:00
case action . message === "verify github token" :
verifyGitHubToken ( action , socket ) ;
2019-02-14 00:08:59 +01:00
break ;
2018-11-30 21:46:22 +01:00
case action . message === "fetch metadata" :
2018-09-27 18:11:26 +02:00
fetchMetadata ( action , socket ) ;
break ;
2018-11-30 21:46:22 +01:00
case action . message === "landed on homepage" :
2018-09-27 18:11:26 +02:00
generateGitHubFeed ( result => {
2019-02-05 00:42:52 +01:00
send ( socket , {
2018-10-06 22:53:01 +02:00
html : result ,
message : "updated html" ,
selector : "#github-feed"
2019-02-05 00:42:52 +01:00
} ) ;
2018-09-27 18:11:26 +02:00
} ) ;
break ;
2018-11-30 21:46:22 +01:00
case action . message === "landed on playground" :
2018-09-27 18:11:26 +02:00
generateContent ( 1 , result => {
2019-02-05 00:42:52 +01:00
send ( socket , {
2018-10-06 22:53:01 +02:00
html : result ,
message : "updated html" ,
selector : "#playground-loader"
2019-02-05 00:42:52 +01:00
} ) ;
2018-09-27 18:11:26 +02:00
} ) ;
break ;
2018-11-30 21:46:22 +01:00
case action . message === "request for playground, example 1" :
2018-09-27 18:11:26 +02:00
generateContent ( 1 , result => {
2019-02-05 00:42:52 +01:00
send ( socket , {
2018-10-06 22:53:01 +02:00
html : result ,
message : "updated html" ,
selector : "#playground-loader"
2019-02-05 00:42:52 +01:00
} ) ;
2018-09-27 18:11:26 +02:00
} ) ;
break ;
2018-11-30 21:46:22 +01:00
case action . message === "request for playground, example 2" :
2018-09-27 18:11:26 +02:00
generateMemeCreator ( socket ) ;
break ;
2018-11-30 21:46:22 +01:00
case action . message === "request for playground, example 3" :
2018-09-27 18:11:26 +02:00
generateContent ( 3 , result => {
2019-02-05 00:42:52 +01:00
send ( socket , {
2018-10-06 22:53:01 +02:00
html : result ,
message : "updated html" ,
selector : "#playground-loader"
2019-02-05 00:42:52 +01:00
} ) ;
2018-09-27 18:11:26 +02:00
} ) ;
break ;
2018-11-30 21:46:22 +01:00
case action . message === "subscribe" :
2018-09-27 18:11:26 +02:00
newsletterSubscribe ( action , socket ) ;
break ;
2019-07-10 23:48:45 +02:00
case action . message === "view different documentation version" :
send ( socket , {
element : "div" ,
html : await apiPage ( {
params : {
wildcard : action . version . split ( "-" ) [ 0 ]
} ,
tag : action . version . split ( "-" ) [ 1 ]
} ) ,
message : "replace html" ,
parentElement : "main" ,
selector : ".__slate"
} ) ;
break ;
2018-09-27 18:11:26 +02:00
default :
break ;
}
} ;
// H E L P E R S
2018-09-27 20:00:34 +02:00
function generateContent ( exampleNumber , displayTrendingContent ) {
if ( exampleNumber === 1 ) {
return getTrendingContent ( ) . then ( response => {
2019-02-05 00:42:52 +01:00
if ( ! response || ! response . success || response . success !== true || ! response . data )
return "" ;
2018-09-27 20:00:34 +02:00
const rawContentCollection = [ ] ;
const renderedContentCollection = [ ] ;
const trendingContentData = response . data ;
2019-02-05 00:42:52 +01:00
for ( const data of trendingContentData )
rawContentCollection . push ( fetchMetadata ( {
claim : data . url ,
example : exampleNumber ,
method : "resolve"
} ) ) ;
2018-09-27 20:00:34 +02:00
Promise . all ( rawContentCollection ) . then ( collection => {
for ( const part of collection ) {
try {
renderedContentCollection . push ( `
2018-12-05 00:12:39 +01:00
< section class = "playground-content__trend" >
< figure
class = "media__thumb"
data - action = "choose claim"
data - claim - id = "${part.name}"
2019-05-20 14:54:06 +02:00
$ { part . value . thumbnail . url . length ? ` style="background-image: url( ${ makeImageSourceSecure ( part . value . thumbnail . url ) } )" ` : "" }
2019-03-25 16:00:45 +01:00
> < / f i g u r e >
2018-12-05 00:12:39 +01:00
< div class = "media__title" >
2019-05-20 14:54:06 +02:00
$ { part . value . title }
2018-12-05 00:12:39 +01:00
< / d i v >
< div class = "media__subtitle" >
$ { part . channel _name }
< / d i v >
< / s e c t i o n >
2018-09-27 20:00:34 +02:00
` );
2019-02-05 00:42:52 +01:00
} catch ( err ) {
2018-09-27 20:00:34 +02:00
return ; // TODO: Return nice error message
}
}
renderedContentCollection . push ( `
< script >
2018-10-03 22:27:13 +02:00
document . getElementById ( "playground-example-description" ) . innerHTML = document . querySelector ( "[data-action='playground, example 1']" ) . dataset . description
2018-09-27 20:00:34 +02:00
< / s c r i p t >
` );
displayTrendingContent ( renderedContentCollection . join ( "" ) ) ;
} ) ;
} ) ;
}
if ( exampleNumber === 3 ) {
const approvedUrls = [
"LBRY#3db81c073f82fd1bb670c65f526faea3b8546720" ,
"correlation-can-imply-causation#173412f5b1b7aa63a752e8832406aafd9f1ecb4e" ,
2018-09-27 22:46:59 +02:00
"thanos-is-the-protagonist-how-infinity#2a7f5db2678177435b1dee6c9e38e035ead450b6" ,
2018-09-27 20:00:34 +02:00
"epic-arcade-mode-duos-nickatnyte-molt#d81bac6d49b1f92e58c37a5f633a27a45b43405e" ,
"political-correctness-a-force-for-good-a#b4668c0bd096317b44c40738c099b6618095e75f" ,
"10-secrets-hidden-inside-famous-logos#007789cc45cbb4255cf02ba77cbf84ca8e3d7561" ,
"ever-wonder-how-bitcoin-and-other#1ac47b8b3def40a25850dc726a09ce23d09e7009" ,
"bankrupt-pan-am#784b3c215a6f06b663fc1aa292bcb19f29c489bb" ,
"minecraft-in-real-life-iron-man#758dd6497cdfc401ae1f25984738d024d47b50af" ,
"ethan-shows-kyle-warframe-skyvault#8a7401b88d5ed0376d98f16808194d4dcb05b284"
] ;
const rawContentCollection = [ ] ;
const renderedContentCollection = [ ] ;
2018-09-28 21:09:45 +02:00
for ( const url of approvedUrls )
2019-05-20 14:54:06 +02:00
rawContentCollection . push ( fetchMetadata ( { claim : url , method : "resolve" , example : 1 } ) ) ;
2018-09-27 20:00:34 +02:00
2018-09-27 22:46:59 +02:00
return Promise . all ( rawContentCollection ) . then ( collection => {
2018-09-27 20:00:34 +02:00
for ( const part of collection ) {
2018-09-27 22:46:59 +02:00
if (
part &&
part . value &&
2019-05-20 14:54:06 +02:00
part . value . thumbnail . url &&
2018-09-27 22:46:59 +02:00
part . channel _name
) {
2018-09-27 20:00:34 +02:00
renderedContentCollection . push ( `
2018-12-05 00:12:39 +01:00
< section class = "playground-content__trend" >
< figure
class = "media__thumb"
data - action = "choose claim"
data - claim - id = "${part.claim_id}"
data - name = $ { part . name }
2019-05-20 14:54:06 +02:00
style = "background-image: url(${makeImageSourceSecure(part.value.thumbnail.url)})" >
2018-12-05 00:12:39 +01:00
< / f i g u r e >
< div class = "media__title" >
2019-05-20 14:54:06 +02:00
$ { part . value . title }
2018-12-05 00:12:39 +01:00
< / d i v >
< div class = "media__subtitle" >
$ { part . channel _name }
< / d i v >
< / s e c t i o n >
2018-09-27 20:00:34 +02:00
` );
}
}
renderedContentCollection . push ( `
< script >
2018-10-03 22:27:13 +02:00
document . getElementById ( "playground-example-description" ) . innerHTML = document . querySelector ( "[data-action='playground, example 3']" ) . dataset . description
2018-09-27 20:00:34 +02:00
< / s c r i p t >
` );
displayTrendingContent ( renderedContentCollection . join ( "" ) ) ;
} ) ;
}
}
2018-09-27 18:11:26 +02:00
function generateMemeCreator ( socket ) {
const images = [
{
alt : "Carl Sagan" ,
2018-12-12 19:47:53 +01:00
// src: "https://spee.ch/4f6b953e605a602434246743fd246d3e1fd4f5fd/carlsagan2.jpg"
src : "/assets/media/images/carlsagan2.jpg"
2018-09-27 18:11:26 +02:00
} ,
{
alt : "Doge" ,
2018-12-12 19:47:53 +01:00
// src: "https://spee.ch/2f90f2d91441a4d33d3d4eb82bdfc4c56ec742c7/doge-meme.jpg"
src : "/assets/media/images/doge-meme.jpg"
2018-09-27 18:11:26 +02:00
} ,
{
alt : "LBRY Logo With Green Background" ,
2018-12-12 19:47:53 +01:00
// src: "https://spee.ch/40ac6818bbac87a208722bf4467653341d460908/lbry-green.png"
src : "/assets/media/images/lbry-green.png"
2018-09-27 18:11:26 +02:00
}
] ;
const memePlaceholderData = {
bottomLine : {
placeholder : "Top line" ,
value : "that I made"
} ,
description : {
placeholder : "Description" ,
value : "Check out this image I published to LBRY via lbry.tech"
} ,
topLine : {
placeholder : "Top line" ,
value : "This is an example meme"
} ,
title : {
placeholder : "Title" ,
value : "Dank Meme Supreme da Cheese"
}
} ;
const renderedImages = [ ] ;
2018-09-28 21:09:45 +02:00
for ( const image of images )
2018-12-05 00:12:39 +01:00
renderedImages . push ( ` <img alt=" ${ image . alt } " class="playground-content__meme__canvas__thumbnail" src=" ${ image . src } "/> ` ) ;
2018-09-27 18:11:26 +02:00
const memeCreator = html `
2018-12-05 00:12:39 +01:00
< div class = "playground-content__meme__canvas" >
2018-09-27 18:11:26 +02:00
< img alt = "Base image for LBRY meme creator" id = "base-image" style = "height: 0; position: absolute; visibility: hidden;" / >
2018-09-28 23:59:38 +02:00
< canvas id = "meme-canvas" height = "600" width = "800" > Unfortunately , it looks like canvas is < strong > not supported < / s t r o n g > i n y o u r b r o w s e r < / c a n v a s >
2018-09-27 18:11:26 +02:00
$ { renderedImages }
< / d i v >
2018-12-05 00:12:39 +01:00
< form class = "playground-content__meme__editor" >
2018-09-27 18:11:26 +02:00
< fieldset >
2019-02-07 22:17:30 +01:00
< legend > Image Text < / l e g e n d >
2018-09-27 18:11:26 +02:00
2019-02-07 22:17:30 +01:00
< fieldset - section >
< label for = "meme-top-line" > Top line < / l a b e l >
< input id = "meme-top-line" name = "meme-top-line" placeholder = "${memePlaceholderData.topLine.placeholder}" spellcheck = "false" type = "text" value = "${memePlaceholderData.topLine.value}" required / >
< / f i e l d s e t - s e c t i o n >
2018-09-27 18:11:26 +02:00
2019-02-07 22:17:30 +01:00
< fieldset - section >
< label for = "meme-bottom-line" > Bottom line < / l a b e l >
< input id = "meme-bottom-line" name = "meme-bottom-line" placeholder = "${memePlaceholderData.bottomLine.placeholder}" spellcheck = "false" type = "text" value = "${memePlaceholderData.bottomLine.value}" required / >
< / f i e l d s e t - s e c t i o n >
2018-09-27 18:11:26 +02:00
< / f i e l d s e t >
< fieldset >
2019-02-07 22:17:30 +01:00
< legend > Metadata < / l e g e n d >
< fieldset - section >
< label for = "meme-title" > Title < / l a b e l >
< input id = "meme-title" name = "meme-title" placeholder = "${memePlaceholderData.title.placeholder}" spellcheck = "false" type = "text" value = "${memePlaceholderData.title.value}" required / >
< / f i e l d s e t - s e c t i o n >
< fieldset - section >
< label for = "meme-description" > Description < / l a b e l >
< textarea id = "meme-description" name = "meme-description" placeholder = "${memePlaceholderData.description.placeholder}" spellcheck = "false" type = "text" required > $ { memePlaceholderData . description . value } < / t e x t a r e a >
< / f i e l d s e t - s e c t i o n >
< fieldset - section >
< label for = "meme-language" > Language < / l a b e l >
< select id = "meme-language" name = "meme-language" >
< option value = "ar" > Arabic < / o p t i o n >
< option value = "zh" > Chinese ( Mandarin ) < / o p t i o n >
< option value = "en" > English < / o p t i o n >
< option value = "fr" > French < / o p t i o n >
< option value = "de" > German < / o p t i o n >
< option value = "it" > Italian < / o p t i o n >
< option value = "jp" > Japanese < / o p t i o n >
< option value = "ru" > Russian < / o p t i o n >
< option value = "es" > Spanish < / o p t i o n >
< option value = "" > Not specified < / o p t i o n >
< / s e l e c t >
< / f i e l d s e t - s e c t i o n >
< fieldset - section >
< label for = "meme-license" > License < / l a b e l >
< select id = "meme-license" name = "meme-license" required >
< option value = "Public Domain" > Public Domain < / o p t i o n >
< option value = "Creative Commons Attribution 4.0 International" > Creative Commons Attribution 4.0 International < / o p t i o n >
< option value = "Creative Commons Attribution-ShareAlike 4.0 International" > Creative Commons Attribution - ShareAlike 4.0 International < / o p t i o n >
< option value = "Creative Commons Attribution-NoDerivatives 4.0 International" > Creative Commons Attribution - NoDerivatives 4.0 International < / o p t i o n >
< option value = "Creative Commons Attribution-NonCommercial 4.0 International" > Creative Commons Attribution - NonCommercial 4.0 International < / o p t i o n >
< option value = "Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International" > Creative Commons Attribution - NonCommercial - ShareAlike 4.0 International < / o p t i o n >
< option value = "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International" > Creative Commons Attribution - NonCommercial - NoDerivatives 4.0 International < / o p t i o n >
< option value = "None" > None < / o p t i o n >
< / s e l e c t >
< / f i e l d s e t - s e c t i o n >
< fieldset - section >
< checkbox - element >
< input id = "meme-nsfw-flag" name = "nsfw" type = "checkbox" >
< label for = "meme-nsfw-flag" > NSFW < / l a b e l >
< checkbox - toggle / >
< / c h e c k b o x - e l e m e n t >
< button data - action = "upload image" class = "button" type = "button" > Submit < / b u t t o n >
< / f i e l d s e t - s e c t i o n >
2018-09-27 18:11:26 +02:00
< / f i e l d s e t >
< / f o r m >
` ;
2019-02-05 00:42:52 +01:00
return send ( socket , {
2018-10-06 22:53:01 +02:00
example : 2 ,
html : memeCreator ,
message : "updated html" ,
selector : "#playground-loader"
2019-02-05 00:42:52 +01:00
} ) ;
2018-09-27 18:11:26 +02:00
}
2019-02-12 00:47:01 +01:00
function getGitHubUserToken ( socket ) {
send ( socket , {
message : "redirect" ,
2019-02-14 18:07:22 +01:00
url : ` https://github.com/login/oauth/authorize?client_id= ${ githubAppId } &scope=public_repo,user:email `
2019-02-12 00:47:01 +01:00
} ) ;
}
2018-11-21 22:57:43 +01:00
async function getTrendingContent ( ) {
try {
2019-03-19 23:56:32 +01:00
const response = await got ( "https://api.lbry.com/file/list_trending" ) ;
2018-11-21 22:57:43 +01:00
return JSON . parse ( response . body ) ; // eslint-disable-line padding-line-between-statements
2019-02-05 00:42:52 +01:00
} catch ( error ) {
2018-11-21 22:57:43 +01:00
return error ;
}
2018-09-27 18:11:26 +02:00
}
2018-10-10 00:11:22 +02:00
function makeImageSourceSecure ( url ) {
2019-03-25 16:00:45 +01:00
if ( ! url || ! url . length )
return url ;
2018-10-10 00:11:22 +02:00
const originalUrl = new URL ( url ) ;
if ( originalUrl . protocol !== "https" )
return ` https:// ${ originalUrl . host } ${ originalUrl . pathname } ` ;
return originalUrl . href ;
}
2018-11-21 22:57:43 +01:00
async function newsletterSubscribe ( data , socket ) {
2018-09-27 18:11:26 +02:00
const email = data . email ;
2019-02-05 00:42:52 +01:00
if ( ! validateEmail ( email ) ) {
send ( socket , {
class : "error" ,
html : "Your email address is invalid" ,
message : "updated html" ,
selector : "#emailMessage"
} ) ;
}
2018-09-27 18:11:26 +02:00
2018-11-21 22:57:43 +01:00
try {
2019-03-19 23:56:32 +01:00
await got . post ( ` https://api.lbry.com/list/subscribe?email= ${ encodeURIComponent ( email ) } &tag=developer ` ) ;
2018-09-27 18:11:26 +02:00
2019-02-05 00:42:52 +01:00
return send ( socket , {
2018-11-21 22:57:43 +01:00
html : "Thank you! Please confirm subscription in your inbox." ,
message : "updated html" ,
selector : "#emailMessage"
2019-02-05 00:42:52 +01:00
} ) ;
} catch ( error ) {
2018-11-21 22:57:43 +01:00
const response = JSON . parse ( error . body ) ;
2018-09-27 18:11:26 +02:00
2018-11-21 22:57:43 +01:00
if ( ! response . success ) {
2019-02-20 18:11:14 +01:00
messageSlack ( {
message : ` via ${ email } : ${ response . error } ` ,
title : "NEWSLETTER ERROR"
} ) ;
2018-10-10 21:04:16 +02:00
2019-02-05 00:42:52 +01:00
return send ( socket , {
2018-10-10 21:04:16 +02:00
class : "error" ,
2018-11-21 22:57:43 +01:00
html : response . error ,
2018-10-10 21:04:16 +02:00
message : "updated html" ,
selector : "#emailMessage"
2019-02-05 00:42:52 +01:00
} ) ;
2018-10-10 21:04:16 +02:00
}
2019-02-20 18:11:14 +01:00
messageSlack ( {
message : ` via ${ email } (strange error): ${ response . error } ` ,
title : "NEWSLETTER ERROR"
} ) ;
2018-11-21 22:57:43 +01:00
2019-02-05 00:42:52 +01:00
return send ( socket , {
2018-11-21 22:57:43 +01:00
class : "error" ,
html : "Something is terribly wrong" ,
2018-10-10 21:04:16 +02:00
message : "updated html" ,
selector : "#emailMessage"
2019-02-05 00:42:52 +01:00
} ) ;
2018-11-21 22:57:43 +01:00
}
2018-09-27 18:11:26 +02:00
}
2019-02-05 00:42:52 +01:00
export function send ( transport , data ) {
return transport . send ( JSON . stringify ( data ) ) ;
}
2018-09-27 18:11:26 +02:00
function validateEmail ( email ) {
const emailRegex = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\\.,;:\s@"]{2,})$/i ;
2018-11-21 22:57:43 +01:00
return emailRegex . test ( String ( email ) ) ; // eslint-disable-line padding-line-between-statements
2018-09-27 18:11:26 +02:00
}
2019-02-14 18:07:22 +01:00
2019-02-21 20:28:09 +01:00
async function verifyGitHubToken ( data , socket ) {
const code = data . code ;
2019-02-14 18:07:22 +01:00
try {
2019-07-10 23:48:45 +02:00
const result = await got . post ( ` https://github.com/login/oauth/access_token?client_id= ${ githubAppId } &client_secret= ${ githubAppSecret } &code= ${ code } ` , { json : true } ) ;
2019-02-14 18:07:22 +01:00
2019-02-21 20:28:09 +01:00
const response = {
address : data . address ,
code : result . body . access _token
} ;
return send ( socket , {
data : response ,
message : "github token status"
} ) ;
2019-02-14 18:07:22 +01:00
} catch ( verificationError ) {
console . log ( verificationError . body ) ; // eslint-disable-line no-console
2019-02-21 20:28:09 +01:00
return send ( socket , {
details : verificationError . body ,
message : "notification" ,
type : "error"
} ) ;
2019-02-14 18:07:22 +01:00
}
}