mirror of
https://github.com/LBRYFoundation/lbry.com.git
synced 2025-08-30 08:51:34 +00:00
Merge branch 'quickstart'
* quickstart: send credits fixes quickstart almost gtg first steps
This commit is contained in:
commit
8f0a53624c
10 changed files with 403 additions and 6 deletions
|
@ -89,6 +89,10 @@ class Controller
|
|||
$router->get(['/ios', 'get-ios'], 'DownloadActions::executeGet');
|
||||
$router->get('/roadmap', 'ContentActions::executeRoadmap');
|
||||
|
||||
$router->get('/developer-program', 'AcquisitionActions::executeDeveloperProgram');
|
||||
$router->post('/developer-program/post', 'AcquisitionActions::executeDeveloperProgramPost');
|
||||
$router->get('/developer-program/callback', 'AcquisitionActions::executeDeveloperProgramGithubCallback');
|
||||
|
||||
$router->get(['/press-kit.zip', 'press-kit'], 'ContentActions::executePressKit');
|
||||
|
||||
$router->post('/postcommit', 'OpsActions::executePostCommit');
|
||||
|
|
|
@ -6,6 +6,9 @@ class Session
|
|||
KEY_DOWNLOAD_ALLOWED = 'beta_download_allowed2',
|
||||
KEY_PREFINERY_USER_ID = 'prefinery_user_id',
|
||||
KEY_PREFINER_USED_CUSTOM_CODE = 'prefinery_used_custom_code',
|
||||
KEY_DEVELOPER_CREDITS_ERROR = 'developer_credits_error',
|
||||
KEY_DEVELOPER_CREDITS_SUCCESS = 'developer_credits_success',
|
||||
KEY_DEVELOPER_CREDITS_WALLET_ADDRESS = 'developer_credits_wallet_address',
|
||||
KEY_LIST_SUB_ERROR = 'list_error',
|
||||
KEY_USER_CULTURE = 'user_culture';
|
||||
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
|
||||
class AcquisitionActions extends Actions
|
||||
{
|
||||
const DEVELOPER_REWARD = 250;
|
||||
|
||||
public static function executeThanks()
|
||||
{
|
||||
return ['acquisition/thanks'];
|
||||
}
|
||||
|
||||
|
||||
public static function executeYouTubeSub()
|
||||
{
|
||||
if (!Request::isPost())
|
||||
|
@ -40,4 +41,138 @@ class AcquisitionActions extends Actions
|
|||
}
|
||||
return [$template];
|
||||
}
|
||||
|
||||
public static function executeDeveloperProgram()
|
||||
{
|
||||
return ['acquisition/developer-program', [
|
||||
'defaultWalletAddress' => Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS),
|
||||
'error' => Session::getFlash(Session::KEY_DEVELOPER_CREDITS_ERROR),
|
||||
'success' => Session::getFlash(Session::KEY_DEVELOPER_CREDITS_SUCCESS)
|
||||
]];
|
||||
}
|
||||
|
||||
public static function executeDeveloperProgramPost()
|
||||
{
|
||||
$walletAddress = trim(Request::getPostParam('wallet'));
|
||||
Session::set(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS, $walletAddress);
|
||||
|
||||
if (!$walletAddress)
|
||||
{
|
||||
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Please provide a wallet address.');
|
||||
}
|
||||
elseif (!preg_match('/^b[1-9A-HJ-NP-Za-km-z]{33}$/', $walletAddress))
|
||||
{
|
||||
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This does not appear to be a valid wallet address.');
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Config::get('github_developer_credits_client_id'))
|
||||
{
|
||||
throw new Exception('no github client id');
|
||||
}
|
||||
|
||||
$githubParams = [
|
||||
'client_id' => Config::get('github_developer_credits_client_id'),
|
||||
'redirect_uri' => Request::getHostAndProto() . '/developer-program/callback',
|
||||
'scope' => 'user:email',
|
||||
'allow_signup' => false
|
||||
];
|
||||
return Controller::redirect('https://github.com/login/oauth/authorize?' . http_build_query($githubParams));
|
||||
}
|
||||
return Controller::redirect('/developer-program');
|
||||
}
|
||||
|
||||
public static function executeDeveloperProgramGithubCallback()
|
||||
{
|
||||
$code = Request::getParam('code');
|
||||
$walletAddress = Session::get(Session::KEY_DEVELOPER_CREDITS_WALLET_ADDRESS);
|
||||
|
||||
if (!$walletAddress)
|
||||
{
|
||||
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Your wallet address disappeared while authenticated with GitHub.');
|
||||
}
|
||||
elseif (!$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('github_developer_credits_client_id'),
|
||||
'client_secret' => Config::get('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
|
||||
{
|
||||
$accessToken = $authResponseData['access_token'];
|
||||
$userResponseData = Curl::get('https://api.github.com/user', [], [
|
||||
'headers' => ['Authorization: token ' . $accessToken, 'Accept: application/json', 'User-Agent: lbryio'],
|
||||
'json_response' => true
|
||||
]);
|
||||
|
||||
if (date('Y-m-d', strtotime($userResponseData['created_at'])) > '2017-01-30')
|
||||
{
|
||||
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'This GitHub account is too recent.');
|
||||
}
|
||||
else
|
||||
{
|
||||
$lockName = 'github_dev_credits_write';
|
||||
$dataFile = ROOT_DIR . '/data/writeable/github_developer_credits';
|
||||
|
||||
$lock = Lock::getLock($lockName, true); // EXCLUSIVE LOCK. IF SENDING CREDITS IS SLOW, THIS COULD BLOCK USERS
|
||||
|
||||
$existing = is_file($dataFile) ? json_decode(file_get_contents($dataFile), true) : [];
|
||||
|
||||
if (isset($existing[$userResponseData['login']]))
|
||||
{
|
||||
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'You account already received credits.');
|
||||
}
|
||||
else
|
||||
{
|
||||
list($code, $out, $err) =
|
||||
Shell::exec('/usr/bin/lbrynet-cli send_amount_to_address amount=250 ' . escapeshellarg('address=' . $walletAddress));
|
||||
|
||||
if ($code != 0)
|
||||
{
|
||||
if (stripos($out, 'InsufficientFundsError') !== false)
|
||||
{
|
||||
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR,
|
||||
'Our wallet is running low on funds. Please ping jeremy@lbry.io so he can refill it, then try again.');
|
||||
}
|
||||
else
|
||||
{
|
||||
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR,
|
||||
'Failed to send credits. This is an error on our side. Please email jeremy@lbry.io if it persists.');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$existing[$userResponseData['login']] = [$userResponseData['email'], $walletAddress, date('Y-m-d H:i:s')];
|
||||
file_put_contents($dataFile, json_encode($existing));
|
||||
|
||||
Session::setFlash(Session::KEY_DEVELOPER_CREDITS_SUCCESS,
|
||||
'Send credits to GitHub user ' . $userResponseData['login'] . ' (' . $userResponseData['email'] . ') at wallet address ' .
|
||||
$walletAddress);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Lock::freeLock($lock);
|
||||
$lock = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Controller::redirect('/developer-program');
|
||||
}
|
||||
}
|
70
lib/tools/Lock.class.php
Normal file
70
lib/tools/Lock.class.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
/* HOW TO USE
|
||||
|
||||
$lockFile = Lock::getLock('lock-name');
|
||||
if (is_resource($lockFile)) {
|
||||
|
||||
// you have a lock here, do whatever you want
|
||||
|
||||
Lock::freeLock($lockFile);
|
||||
}
|
||||
else {
|
||||
// you could not get the lock. show a message or throw an exception or whatever
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
class Lock
|
||||
{
|
||||
/**
|
||||
* Creates a lockfile and acquires an exclusive lock on it.
|
||||
*
|
||||
* @param string $name The name of the lockfile.
|
||||
* @param boolean $blocking Block until lock becomes available (default: don't block, just fail)
|
||||
* @return mixed Returns the lockfile, or FALSE if a lock could not be acquired.
|
||||
*/
|
||||
public static function getLock($name, $blocking = false)
|
||||
{
|
||||
if (!preg_match('/^[A-Za-z0-9\.\-_]+$/', $name))
|
||||
{
|
||||
throw new InvalidArgumentException('Invalid lock name: "' . $name . '"');
|
||||
}
|
||||
|
||||
$filename = static::getLockDir() . '/' . $name;
|
||||
if (!preg_match('/\.lo?ck$/', $filename))
|
||||
{
|
||||
$filename .= '.lck';
|
||||
}
|
||||
if (!file_exists($filename))
|
||||
{
|
||||
file_put_contents($filename, '');
|
||||
chmod($filename, 0666); // if the file cant be opened for writing later, getting the lock will fail
|
||||
}
|
||||
$lockFile = fopen($filename, 'w+');
|
||||
if (!flock($lockFile, $blocking ? LOCK_EX : LOCK_EX|LOCK_NB))
|
||||
{
|
||||
fclose($lockFile);
|
||||
return false;
|
||||
}
|
||||
return $lockFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a lock.
|
||||
*
|
||||
* @param resource $lockFile
|
||||
*/
|
||||
public static function freeLock($lockFile)
|
||||
{
|
||||
if ($lockFile)
|
||||
{
|
||||
flock($lockFile, LOCK_UN);
|
||||
fclose($lockFile);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getLockDir()
|
||||
{
|
||||
return sys_get_temp_dir();
|
||||
}
|
||||
}
|
31
view/template/acquisition/developer-program.php
Normal file
31
view/template/acquisition/developer-program.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php NavActions::setNavUri('/learn') ?>
|
||||
<?php Response::setMetaDescription('Be up and running with the LBRY API in just a few minutes.') ?>
|
||||
<?php Response::setMetaTitle('LBRY Quickstart') ?>
|
||||
<?php echo View::render('nav/_header', ['isDark' => false, 'isAbsolute' => false]) ?>
|
||||
<main >
|
||||
<div class="content content-light markdown">
|
||||
<h1>Developer Program</h1>
|
||||
<p>All developers with a GitHub account prior to January 31st, 2017 are eligible for <?php echo AcquisitionActions::DEVELOPER_REWARD ?> free credits.</p>
|
||||
<p>To claim your credits, enter a wallet address in the form below and authenticate with GitHub.</p>
|
||||
<p>
|
||||
We will store your GitHub username and email address, but nothing else.
|
||||
</p>
|
||||
<form method="POST" action="/developer-program/post" class="form-inset">
|
||||
<h3 style="margin-top: 0">Receive Credits</h3>
|
||||
<?php if ($error): ?>
|
||||
<div class="notice notice-error spacer1"><?php echo $error ?></div>
|
||||
<?php elseif ($success): ?>
|
||||
<div class="notice notice-success spacer1"><?php echo $success ?></div>
|
||||
<?php endif ?>
|
||||
<div class="form-row">
|
||||
<label for="wallet">Wallet Address</label>
|
||||
<div class="form-input">
|
||||
<input type="text" name="wallet" value="<?php echo $defaultWalletAddress ?>"
|
||||
class="required standard input-wallet" placeholder="bYnFQUPTTDM1BYNCxgxKEav4FFQsrgDBoE">
|
||||
</div>
|
||||
</div>
|
||||
<input type="submit" value="Continue to GitHub" class="btn-primary">
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
<?php echo View::render('nav/_footer') ?>
|
|
@ -47,11 +47,9 @@
|
|||
<?php foreach(Response::getMetaImages() as $image): ?>
|
||||
<meta property="og:image" content="<?php echo $image ?>" />
|
||||
<?php endforeach ?>
|
||||
|
||||
|
||||
<base target="_parent" />
|
||||
</head>
|
||||
<body>
|
||||
<body>
|
||||
<?php echo $content ?>
|
||||
<div class="hide">
|
||||
<div id="fb-root"></div>
|
||||
|
|
137
view/template/page/quickstart.php
Normal file
137
view/template/page/quickstart.php
Normal file
|
@ -0,0 +1,137 @@
|
|||
<?php NavActions::setNavUri('/learn') ?>
|
||||
<?php Response::setMetaDescription('Be up and running with the LBRY API in just a few minutes.') ?>
|
||||
<?php Response::setMetaTitle('LBRY Quickstart') ?>
|
||||
<?php echo View::render('nav/_header', ['isDark' => false, 'isAbsolute' => false]) ?>
|
||||
<main class="content content-light markdown">
|
||||
<h1>Quickstart</h1>
|
||||
<p>This step-by-step guide will have running LBRY and interacting with the API in just a few minutes.</p>
|
||||
<p>This guide is for programmers and other technical users. For consumer usage of LBRY, please <a href="/get" class="link-primary">go here</a>.</p>
|
||||
<h3>What's Covered</h3>
|
||||
<ol class="table-of-contents">
|
||||
<li><a href="#installation" class="link-primary">Installation</a></li>
|
||||
<li><a href="#running-lbry" class="link-primary">Running LBRY</a></li>
|
||||
<li><a href="#api" class="link-primary">The API</a></li>
|
||||
<li><a href="#credits" class="link-primary">Credits</a></li>
|
||||
<li><a href="#community" class="link-primary">Community & Issues</a></li>
|
||||
</ol>
|
||||
<section>
|
||||
<h3 id="installation">1. Installation</h3>
|
||||
<p>The easiest way to install LBRY is to use a pre-packaged binary. We provide binaries for Windows, macOS, and Debian-based Linux.</p>
|
||||
<table class="content">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>macOS <span class="icon-apple"></span></th>
|
||||
<th>Linux <span class="icon-linux"></span></th>
|
||||
<th>Windows <span class="icon-windows"></span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="https://lbry.io/get/lbry.dmg">Download DMG</a></td>
|
||||
<td><a href="https://lbry.io/get/lbry.deb">Download DEB</a></td>
|
||||
<td><a href="https://lbry.io/get/lbry.msi">Download MSI</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
If you prefer to compile from source or are not on one of the above operating systems, follow
|
||||
<a class="link-primary" href="https://github.com/lbryio/lbry/blob/master/INSTALL.md">this guide</a>.
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<h3 id="running-lbry">2. Running LBRY</h3>
|
||||
<p>
|
||||
Launch the deamon to run as a background process:
|
||||
</p>
|
||||
<p>
|
||||
<code>
|
||||
lbrynet-daemon --no-launch
|
||||
</code>
|
||||
</p>
|
||||
<p>The first time you run the daemon, it must catch-up with most recent blockheaders. This can take several minutes.</p>
|
||||
</section>
|
||||
<section>
|
||||
<h3 id="api">3. The API</h3>
|
||||
<p>
|
||||
When running, the LBRY daemon provides a JSON-RPC server running at <code>https://localhost:5279/lbryapi</code>.
|
||||
</p>
|
||||
<p>
|
||||
It can be accessed via cURL or any other utility capable of making HTTPS GET and POST requests.
|
||||
</p>
|
||||
<p>
|
||||
To verify the LBRY daemon is running correctly and responding to requests, run:
|
||||
</p>
|
||||
<pre><code>curl 'http://localhost:5279/lbryapi' --data '{"method":"status","params":[]}'
|
||||
[
|
||||
{
|
||||
"connection_status": {
|
||||
"message": "No connection problems detected",
|
||||
"code": "connected"
|
||||
},
|
||||
"is_first_run": false,
|
||||
"is_running": true,
|
||||
"blocks_behind": 0,
|
||||
"startup_status": {
|
||||
"message": "Started lbrynet",
|
||||
"code": "started"
|
||||
},
|
||||
"lbry_id": "7J75jSuxU9eizREuxk1r"
|
||||
}
|
||||
]</code></pre>
|
||||
<p>This makes it easy to interact with the LBRY API in the programming language of your choice. Here's another example:</p>
|
||||
<pre><code>curl 'http://localhost:5279/lbryapi' --data '{"method":"resolve_name","params":[{"name":"what"}]}'
|
||||
[
|
||||
{
|
||||
"ver": "0.0.3",
|
||||
"description": "What is LBRY? An introduction with Alex Tabarrok",
|
||||
"license": "LBRY inc",
|
||||
"title": "What is LBRY?",
|
||||
"author": "Samuel Bryan",
|
||||
"language": "en",
|
||||
"sources": {
|
||||
"lbry_sd_hash": "d5169241150022f996fa7cd6a9a1c421937276a3275eb912790bd07ba7aec1fac5fd45431d226b8fb402691e79aeb24b"
|
||||
},
|
||||
"content_type": "video\/mp4",
|
||||
"nsfw": false,
|
||||
"thumbnail": "https:\/\/s3.amazonaws.com\/files.lbry.io\/logo.png"
|
||||
}
|
||||
]</code></pre>
|
||||
<p>LBRY can be used to build everything from a censorship-proof image host, to a store for 3D printing files, to distribute large files or datasets, or use cases even we can't imagine!</p>
|
||||
<p><a class="btn-alt" href="http://lbryio.github.io/lbry/api/">View Full API Documentation</a></p>
|
||||
</section>
|
||||
<section>
|
||||
<h3 id="credits">4. Getting Credits</h3>
|
||||
<p>Many actions, such as reserving a name or purchasing paid content, require credits.</p>
|
||||
<p>To receive credits, first generate a wallet address:</p>
|
||||
<pre><code>curl 'http://localhost:5279/lbryapi' --data '{"method":"wallet_new_address","params":[]}'
|
||||
["bbFxRyWCFRkA9YcuuZD8nE7XTLUxYnddTs"]</code></pre>
|
||||
<p>Use this address to get credits in one of two ways:</p>
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<h4>4a) Receive Free Credits</h4>
|
||||
<p>
|
||||
All developers with a valid GitHub account are eligible to receive <?php echo AcquisitionActions::DEVELOPER_REWARD ?> free credits.
|
||||
</p>
|
||||
<a href="/developer-program" class="btn-alt">Claim Your Free Credits</a>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<h4>4b) Purchase Credits</h4>
|
||||
<p>
|
||||
Credits can be bought on <a href="https://lbry.io/faq/exchanges" class="link-primary">a variety of exchanges</a>.
|
||||
After purchasing, send them to the address generated above.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<h3 id="community">5. Community & Issues</h3>
|
||||
<p>
|
||||
<a href="http://slack.lbry.io" class="link-primary">Join our Slack Channel</a> to interact with LBRY developers and other community members. Please visit the #dev room (note: this is not a default channel).
|
||||
</p>
|
||||
<p>
|
||||
Visit our <a href="https://github.com/lbryio" class="link-primary">GitHub page</a> to view the source code or report issues.
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
<?php echo View::render('nav/_footer') ?>
|
|
@ -10,7 +10,7 @@
|
|||
<br>
|
||||
|
||||
<?php echo View::render('nav/_flashes') ?>
|
||||
|
||||
|
||||
<form action="<?php echo Request::getRelativeUri() ?>" method="POST">
|
||||
<?php echo View::render('form/_formRow', [
|
||||
'field' => 'name',
|
||||
|
|
|
@ -128,6 +128,11 @@
|
|||
&:last-child { margin-bottom: $spacing-vertical / 2; }
|
||||
padding-left: 2em;
|
||||
counter-reset: li-counter;
|
||||
&.table-of-contents > li
|
||||
{
|
||||
line-height: 2em;
|
||||
&:before { top: -0.1em; }
|
||||
}
|
||||
> li
|
||||
{
|
||||
position: relative;
|
||||
|
@ -138,7 +143,7 @@
|
|||
&:before
|
||||
{
|
||||
position: absolute;
|
||||
top: -0.25em;
|
||||
top: -0.35em;
|
||||
left: -1em;
|
||||
width: 0.8em;
|
||||
|
||||
|
|
|
@ -21,6 +21,15 @@ form {
|
|||
margin-bottom: $line-height;
|
||||
}
|
||||
|
||||
form.form-inset
|
||||
{
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
background: #eee;
|
||||
padding: $spacing-vertical;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
label[for], .label-radio
|
||||
{
|
||||
cursor: pointer;
|
||||
|
@ -72,6 +81,11 @@ input[type="date"] {
|
|||
vertical-align: middle;
|
||||
}
|
||||
|
||||
input.input-wallet
|
||||
{
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: auto;
|
||||
min-height: 60px;
|
||||
|
|
Loading…
Add table
Reference in a new issue