From c6e5c9465eee229cbab1383710d40f2f66a02305 Mon Sep 17 00:00:00 2001 From: Thomas Zarebczan Date: Tue, 27 Nov 2018 14:45:48 -0500 Subject: [PATCH] Revert "Delete quickstart and other instances (#889)" (#892) This reverts commit fe7bb8db9dd699d74d9e888ea1e6e5782763ba13. --- controller/Controller.class.php | 4 + controller/action/DeveloperActions.class.php | 126 ++++++++++++++++++ controller/action/DownloadActions.class.php | 6 +- .../developer/_formCreditsPublish.php | 28 ++++ .../developer/_formNewDeveloperReward.php | 26 ++++ view/template/developer/_quickstartApi.php | 65 +++++++++ .../template/developer/_quickstartCredits.php | 76 +++++++++++ view/template/developer/_quickstartHome.php | 16 +++ .../template/developer/_quickstartInstall.php | 33 +++++ view/template/developer/quickstart.php | 53 ++++++++ web/js/quickstart.js | 82 ++++++++++++ web/scss/_quickstart.scss | 99 ++++++++++++++ web/scss/all.scss | 1 + 13 files changed, 612 insertions(+), 3 deletions(-) create mode 100644 controller/action/DeveloperActions.class.php create mode 100644 view/template/developer/_formCreditsPublish.php create mode 100644 view/template/developer/_formNewDeveloperReward.php create mode 100644 view/template/developer/_quickstartApi.php create mode 100644 view/template/developer/_quickstartCredits.php create mode 100644 view/template/developer/_quickstartHome.php create mode 100644 view/template/developer/_quickstartInstall.php create mode 100644 view/template/developer/quickstart.php create mode 100644 web/js/quickstart.js create mode 100644 web/scss/_quickstart.scss diff --git a/controller/Controller.class.php b/controller/Controller.class.php index 9a69d3b0..9093542d 100644 --- a/controller/Controller.class.php +++ b/controller/Controller.class.php @@ -86,6 +86,10 @@ class Controller } $router->get('/roadmap', 'ContentActions::executeRoadmap'); + $router->post('/quickstart/auth', 'DeveloperActions::executeQuickstartAuth'); + $router->get('/quickstart/{step}?', 'DeveloperActions::executeQuickstart'); + $router->get('/quickstart/github/callback', 'DeveloperActions::executeQuickstartGithubCallback'); + $router->post('/postcommit', 'OpsActions::executePostCommit'); $router->post('/log-upload', 'OpsActions::executeLogUpload'); $router->get(static::CACHE_CLEAR_PATH, 'OpsActions::executeClearCache'); diff --git a/controller/action/DeveloperActions.class.php b/controller/action/DeveloperActions.class.php new file mode 100644 index 00000000..2b43a264 --- /dev/null +++ b/controller/action/DeveloperActions.class.php @@ -0,0 +1,126 @@ + 'Home', + 'install' => 'Installation', + 'api' => 'The API', + 'credits' => 'Credits' + ]; + $allSteps = array_keys($stepLabels); + $currentStep = $step ?: $allSteps[0]; + + $viewParams = [ + 'currentStep' => $currentStep, + 'stepLabels' => $stepLabels + ]; + + if ($currentStep !== 'all') { + if (!isset($stepLabels[$currentStep])) { + Controller::redirect('/quickstart'); + } + + $stepNum = array_flip($allSteps)[$currentStep]; + + $viewParams += [ + 'stepNum' => $stepNum, + 'prevStep' => $stepNum === 0 ? null : $allSteps[$stepNum - 1], + 'nextStep' => $stepNum + 1 >= count($allSteps) ? null : $allSteps[$stepNum + 1], + ]; + } + + return ['developer/quickstart', $viewParams]; + } + + public static function prepareQuickstartHomePartial(array $vars) + { + return $vars + [ + 'usdValue' => static::DEVELOPER_REWARD * LBRY::getLBCtoUSDRate() + ]; + } + + + public static function prepareQuickstartInstallPartial(array $vars) + { + return $vars + ['versions' => [ + Os::OS_LINUX => Github::getDaemonReleaseProperty(OS::OS_LINUX, 'tag_name'), + Os::OS_OSX => Github::getDaemonReleaseProperty(OS::OS_OSX, 'tag_name'), + Os::OS_WINDOWS => Github::getDaemonReleaseProperty(OS::OS_WINDOWS, 'tag_name'), + ]]; + } + + public static function prepareFormNewDeveloperRewardPartial(array $vars) + { + return $vars + [ + 'defaultWalletAddress' => Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS), + 'error' => Session::get(Session::KEY_DEVELOPER_LAST_FORM) == "new_developer" ? Session::getFlash(Session::KEY_DEVELOPER_CREDITS_ERROR) : '', + 'apiUrl' => LBRY::getApiUrl('/reward/new?reward_type=new_developer') + ]; + } + + public static function prepareFormCreditsPublishPartial(array $vars) + { + return $vars + [ + 'defaultWalletAddress' => Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS), + 'error' => Session::get(Session::KEY_DEVELOPER_LAST_FORM) == "new_publish" ? Session::getFlash(Session::KEY_DEVELOPER_CREDITS_ERROR) : '', + 'apiUrl' => LBRY::getApiUrl('/reward/new?reward_type=first_publish') + ]; + } + + public static function executeQuickstartAuth() + { + Session::set(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS, trim(Request::getPostParam('wallet_address'))); + Session::set(Session::KEY_DEVELOPER_LAST_FORM, Request::getPostParam('formName')); + + if (Request::getPostParam('returnUrl')) { + Session::set(Session::KEY_DEVELOPER_RETURN_URL_SUCCESS, Request::getPostParam('returnUrl')); + } + + if (!Config::get(Config::GITHUB_DEVELOPER_CREDITS_CLIENT_ID)) { + throw new Exception('no github client id'); + } + + $gitHubParams = [ + 'client_id' => Config::get(Config::GITHUB_DEVELOPER_CREDITS_CLIENT_ID), + 'redirect_uri' => Request::getHostAndProto() . '/quickstart/github/callback', + 'scope' => 'user:email', + 'allow_signup' => false + ]; + + return Controller::redirect('https://github.com/login/oauth/authorize?' . http_build_query($gitHubParams)); + } + + public static function executeQuickstartGithubCallback() + { + $code = Request::getParam('code'); + + if (!$code) { + Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This does not appear to be a valid response from GitHub.'); + } else { + $authResponseData = Curl::post('https://github.com/login/oauth/access_token', [ + 'code' => $code, + 'client_id' => Config::get(Config::GITHUB_DEVELOPER_CREDITS_CLIENT_ID), + 'client_secret' => Config::get(Config::GITHUB_DEVELOPER_CREDITS_CLIENT_SECRET) + ], [ + 'headers' => ['Accept: application/json'], + 'json_response' => true + ]); + + if (!$authResponseData || !isset($authResponseData['access_token'])) { + Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Request to GitHub failed.'); + } elseif (isset($authResponseData['error_description'])) { + Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'GitHub replied: ' . $authResponseData['error_description']); + } else { + Session::set(Session::KEY_GITHUB_ACCESS_TOKEN, $authResponseData['access_token']); + } + } + + return Controller::redirect(Session::get(Session::KEY_DEVELOPER_RETURN_URL_SUCCESS, '/quickstart/credits')); + } +} diff --git a/controller/action/DownloadActions.class.php b/controller/action/DownloadActions.class.php index 90c9aea2..101b8e86 100644 --- a/controller/action/DownloadActions.class.php +++ b/controller/action/DownloadActions.class.php @@ -23,11 +23,11 @@ class DownloadActions extends Actions if (isset($oses[$os])) { $uri = GitHub::getDaemonDownloadUrl($os); - } - return Controller::redirect($uri, 302); - } } + return Controller::redirect($uri ?: '/quickstart', 302); + } + /* * this is a quick fix to add android, prob not proper design */ diff --git a/view/template/developer/_formCreditsPublish.php b/view/template/developer/_formCreditsPublish.php new file mode 100644 index 00000000..87d47874 --- /dev/null +++ b/view/template/developer/_formCreditsPublish.php @@ -0,0 +1,28 @@ + +lbry.quickstartForm('#form-new-publish-reward', ""); + +
+

Publishing Reward

+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ + + + +
+
diff --git a/view/template/developer/_formNewDeveloperReward.php b/view/template/developer/_formNewDeveloperReward.php new file mode 100644 index 00000000..99f7d440 --- /dev/null +++ b/view/template/developer/_formNewDeveloperReward.php @@ -0,0 +1,26 @@ + + lbry.quickstartForm('#form-new-developer-reward', ""); + +
+

Receive Credits

+
+
+
+ +
+ +
+
+
+ + + + +
+
+ We require a GitHub account to prevent abuse. This will record your email (no spam) and mark you as interested in the lbry repo. + No GitHub account or no public commits? No problem! Join our Discord chat and + post an introduction in #tech. +
+
diff --git a/view/template/developer/_quickstartApi.php b/view/template/developer/_quickstartApi.php new file mode 100644 index 00000000..d336b035 --- /dev/null +++ b/view/template/developer/_quickstartApi.php @@ -0,0 +1,65 @@ +

API Basics

+

+ When running, the LBRY daemon provides a JSON-RPC server running at http://localhost:5279. +

+

+ It can be accessed by any utility capable of making HTTPS GET and POST requests, such as cURL or possibly your toaster. On Windows? You can also use PowerShell. Learn more. +

+

+ To verify the LBRY daemon is running correctly, let's try looking up a URI: +

+$curl 'http://localhost:5279' --data '{"method":"resolve","params":{"uri":"what"}}' +[ + { + "author": "Samuel Bryan", + "content_type": "video/mp4", + "description": "What is LBRY? An introduction with Alex Tabarrok", + "language": "en", + "license": "LBRY inc", + "nsfw": false, + "sources": { + "lbry_sd_hash": "d5169241150022f996fa7cd6a9a1c421937276a3275eb912790bd07ba7aec1fac5fd45431d226b8fb402691e79aeb24b" + }, + "thumbnail": "https://s3.amazonaws.com/files.lbry.io/logo.png", + "title": "What is LBRY?", + "ver": "0.0.3" + } +] +

First Download

+

+ Above, we called the method + resolve + for the URL lbry://what. This returned the metadata associated with the URL. +

+ +

+ Now let's download it. This time we're going to call the method get with the same parameters. +

+$curl 'http://localhost:5279' --data '{"method":"get","params":{"uri":"what"} }' +[ + { + //some response fields omitted for brevity + "claim_id": "7b670f0034d0eb119c32acfe8b19ae6622dd218f", //a claim ID is persistent for a piece of content. It stays the same if the original publisher updates the entry. + "download_directory": "/home/kauffj/Downloads", + "download_path": "/home/kauffj/Downloads/LBRY100.mp4", + "file_name": "LBRY100.mp4", + "metadata": { ... }, //same dictionary as above + "outpoint": "6e224057a9dfa3417bb3890da2c4b4e9d2471641185c6c8b33cb57d61365a4f0:1", //an outpoint is a frozen-in-time pointer to a specific piece of content. It changes if the content changes. + "total_bytes": 158433904, + "written_bytes": 0 //will increase as the file downloads + } +] +

This file will download in the background to the download_directory specified in the returned data. Subsequent calls to get or file_list will return the status.

+

The LBRY API consists of about 50 calls, all related to discovering, distributing, and purchasing content. View the full API documentation.

+

You can also list all of the commands available by calling the help command.

+$curl 'http://localhost:5279' --data '{"method":"help"}' + +

Windows

+

If you are running Windows and would like to follow this guide you could substitute curl with a PowerShell console and the following code. +

+$Invoke-RestMethod -Uri 'http://localhost:5279' -Body 'THE_JSON_DATA' -Method POST | ConvertTo-Json + +

If PowerShell does not work and you want to continue with cURL, you'll need to escape inner double quotes with a \ to pass the JSON properly via Command Prompt. +

+$curl "http://localhost:5279" --data "{\"method\":\"get\",\"params\":{\"uri\":\"what\"} }" + diff --git a/view/template/developer/_quickstartCredits.php b/view/template/developer/_quickstartCredits.php new file mode 100644 index 00000000..42259bcb --- /dev/null +++ b/view/template/developer/_quickstartCredits.php @@ -0,0 +1,76 @@ +

Credits

+ +

So far, everything we've done with LBRY has been free. However, some actions, such as reserving a name or purchasing paid content, require credits.

+

+ There are several ways to obtain credits. See this page for options. We also reward + testers and contributors, so join our Discord Chat if you'd like to help. +

+ +

To receive credits, you will need to generate a wallet address:

+$curl 'http://localhost:5279' --data '{"method":"wallet_new_address"}' +["bbFxRyWCFRkA9YcuuZD8nE7XTLUxYnddTs"] + +

Once you have received or purchased some credits, confirm your balance by calling wallet_balance:

+$curl 'http://localhost:5279' --data '{"method":"wallet_balance"}' +[50.00000000] + + +

Publishing

+

Publishing to LBRY is just as easy as everything else!

+

Not sure what to publish? We recommend your favorite picture or home video. Or just grab something from here.

+$curl 'http://localhost:5279' --data '{"method":"publish", "params": { + "name": "electricsheep", + "file_path": "/home/kauffj/Desktop/electric-sheep.mp4", + "bid": 1, + "metadata": { + "description": "Some interesting content", + "title": "My interesting content", + "author": "Video shot by me@example.com", + "language": "en", + "license": "LBRY Inc", + "nsfw": false + } //this should match the metadata returned by resolve_name +}}' +[ + { + "claim_id": "2081486f32dc493980c77bdaa0502950b532af13", + "fee": 0.000329, + "nout": 0, + "tx": "0100000001a2dcee285b3f552fb8b3eef416c9f17...", + "txid": "d71d63ebb3e10067bfd0b302433bc1ab09fbdd5dc9bc687f50aeb6809d1770fe" //this is the value you need to copy + } +] + + +

Enjoy a Hollywood Film

+

It's a Disaster starring David Cross is just one of tens of thousands of great pieces of content available. Check it out!

+

Note! This will cost you LBC. Run the resolve command to see the cost.

+$curl 'http://localhost:5279' --data '{"method":"get","params":{"uri":"itsadisaster"} }' +[ + { + //some response fields omitted for brevity + "claim_id": "bd970a51249cba542a9acfb130147294a6326ee2", + "download_directory": "/home/kauffj/Downloads", + "download_path": "/home/kauffj/Downloads/It's A Disaster_Feature.mp4", + "metadata": { + "author": "Written and directed by Todd Berger", + "content_type": "video/mp4", + "description": "Four couples meet for Sunday brunch only to discover they are stuck in a house together as the world may be about to end." + } + } +] + + +

Try the UI

+

LBRY comes with a fully-featured UI so that normal people can use it too. You can download it here.

+

You Did It! What's Next?

+

+ Start building something awesome! LBRY works as a discovery and distribution backend for everything from films to CAD files. + View the full API documentation. +

+

+ Join our Discord chat to interact with LBRY developers and other community members. Please visit the #dev room (note: this is not a default channel). +

+

+ Visit our GitHub page to view the source code or report issues. +

diff --git a/view/template/developer/_quickstartHome.php b/view/template/developer/_quickstartHome.php new file mode 100644 index 00000000..992f1eb6 --- /dev/null +++ b/view/template/developer/_quickstartHome.php @@ -0,0 +1,16 @@ +
Quickstart Home
+

+ LBRY is an open-source "fat" protocol, providing + decentralized content discovery and distribution.

+

+ In just a few minutes, you will have: +

+ +

+ Begin the Guide +

+
Not a guide lover? Here it is all on one page.
diff --git a/view/template/developer/_quickstartInstall.php b/view/template/developer/_quickstartInstall.php new file mode 100644 index 00000000..48878f8f --- /dev/null +++ b/view/template/developer/_quickstartInstall.php @@ -0,0 +1,33 @@ +

Download

+ + + + + + + + + + + + + + + +
macOS Linux Windows
Download Download Download
+

+ If you prefer to compile from source or are not on one of the above operating systems, follow + this guide. +

+

Run

+

+ Unzip and launch the daemon: +

+

+ $lbrynet-daemon +

+

While running, the daemon will provide a JSON-RPC interface on localhost. We'll learn how to interact with that next.

+macOS and Windows do not currently bundle the daemon separately. Just launch the full app and the API will still be available. This will be resolved in v0.9. +
The first time you run the daemon, it must catch-up with most recent blockheaders. This can take a few minutes.
+ */ ?> \ No newline at end of file diff --git a/view/template/developer/quickstart.php b/view/template/developer/quickstart.php new file mode 100644 index 00000000..21c47e2e --- /dev/null +++ b/view/template/developer/quickstart.php @@ -0,0 +1,53 @@ + + + + + false, 'isAbsolute' => false]) ?> +
+
+
+ +
+ +

Quickstart

+
+ +
+
+ +
+
+ + 0): ?> +
+

Quickstart:

+
+
    + + $stepLabel): ?> +
  1. + +
  2. + +
+
+
+ +
+ +
+ Next: » +
+ +
+ +
+ array_keys($stepLabels)[1] + ]) ?> +
+ +
+
+
+ diff --git a/web/js/quickstart.js b/web/js/quickstart.js new file mode 100644 index 00000000..3151396f --- /dev/null +++ b/web/js/quickstart.js @@ -0,0 +1,82 @@ +lbry.quickstartForm = function (selector, apiUrl) { + var form = $(selector), + accessToken = form.find(':input[name="access_token"]').val(), + walletAddressInput = form.find(':input[name="wallet_address"]'), + transactionIdInput = form.find(':input[name="transaction_id"]'), + storageKey = form.attr('id') + "SuccessHTML", + submitButton = form.find(':input[type="submit"]'), + isAutomaticSubmit = false, + isSubmitting = false; + + function resetFormState() { + isSubmitting = false; + walletAddressInput.attr('readonly', null); + transactionIdInput.attr('readonly', null); + submitButton.val(submitButton.data('submitLabel')).attr('disabled', null); + } + + if (window.localStorage.getItem(storageKey)) { + form.find('.notice-success').html(window.localStorage.getItem(storageKey)).show(); + form.find('.form-row, .submit-row').hide(); + } else if (accessToken) { + form.submit(function (event) { + if (isSubmitting) { + return false; + } + + var postData = { + access_token: accessToken, + wallet_address: walletAddressInput.val() + }; + + form.find('.notice-success, .notice-error').hide(); + + if (!walletAddressInput.val()) { + resetFormState(); + if (!isAutomaticSubmit) { + form.find('.notice-error').html("Please supply a wallet address.").show(); + } + return false; + } + + if (transactionIdInput.length) { + if (!transactionIdInput.val()) { + resetFormState(); + if (!isAutomaticSubmit) { + form.find('.notice-error').html("Please supply a transaction ID.").show(); + } + return false; + } + postData.transaction_id = transactionIdInput.val(); + } + + event.preventDefault(); + + walletAddressInput.attr('readonly', 'readonly'); + transactionIdInput.attr('readonly', 'readonly'); + submitButton.val(submitButton.data('submittingLabel')).attr('disabled', 'disabled'); + + $.post(apiUrl, postData) + .done(function (responseData) { + var data = responseData.data; + var anchor = $(''); + anchor.attr("href", "https://explorer.lbry.io/tx/" + data.TransactionID); + anchor.html(data.TransactionID) + form.find('.notice-success') + .html(data.RewardAmount + " credits sent in transaction ") + .append(anchor) + .show(); + window.localStorage.setItem(storageKey, form.find('.notice-success').html()); + }) + .fail(function (xhr) { + var responseData = $.parseJSON(xhr.responseText); + form.find('.notice-error').html(responseData.error.length ? responseData.error : "Something went wrong. Please email grin@lbry.io").show(); + }) + .always(resetFormState); + }) + + isAutomaticSubmit = true; + form.submit(); + isAutomaticSubmit = false; + } +} \ No newline at end of file diff --git a/web/scss/_quickstart.scss b/web/scss/_quickstart.scss new file mode 100644 index 00000000..4c5bad69 --- /dev/null +++ b/web/scss/_quickstart.scss @@ -0,0 +1,99 @@ +@import "global"; + +.quickstart +{ + max-width: 860px; +} + +.quickstart__table +{ + margin: 0 auto $spacing-vertical; + td, th + { + border-right: 1px dotted #eee; + padding: 4px 20px; + &:last-child + { + border-right: 0 none; + } + } +} + +.quickstart__section +{ + margin-bottom: $spacing-vertical * 3; +} + +.quickstart__claim-form +{ + margin: $spacing-vertical * 2 0; + input[type="text"] { width: 100%; } +} + +.quickstart__progress-bar +{ + margin: $spacing-vertical * 3 80px; + background: #ddd; + display: flex; + height: 16px; + list-style: none; + padding: 0; + position: relative; + + > li { + flex: auto; + list-style: none; + position: relative; + + &:first-child { + max-width: 0; + + > a { + // arbitrary values + // since % won't work + right: -30px; + width: 60px; + } + } + + &:before { + background: #ddd; + border-radius: 50%; + content: ""; + display: block; + height: 24px; + right: -12px; + position: absolute; + top: -4px; + width: 24px; + } + } + a { + cursor: pointer; + color: #ccc; + padding: 4px 0; + position: absolute; + right: -25%; + text-align: center; + text-decoration: underline; + top: -36px; + width: 50%; + } + $color-indicator: #777; + .completed { + background: lighten($color-indicator, 10%); + + &:before { + background: lighten($color-indicator, 10%); + } + } + .active { + a { font-weight: bold; } + background: lighten($color-indicator, 10%); + + &:before { + background: lighten($color-indicator, 16%); + box-shadow: 0 1px 1px rgba(0,0,0,0.3); + } + } +} \ No newline at end of file diff --git a/web/scss/all.scss b/web/scss/all.scss index 6abf0a4b..7cf86083 100644 --- a/web/scss/all.scss +++ b/web/scss/all.scss @@ -16,6 +16,7 @@ @import "blog"; @import "bounty"; @import "roadmap"; +@import "quickstart"; @import "social"; @import "home"; @import "slider";