diff --git a/controller/Controller.class.php b/controller/Controller.class.php
index 7f42aead..d63841cd 100644
--- a/controller/Controller.class.php
+++ b/controller/Controller.class.php
@@ -89,9 +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('/quickstart/{step}?', 'DeveloperActions::executeQuickstart');
+ $router->get('/developer-program', 'DeveloperActions::executeDeveloperProgram');
+ $router->post('/developer-program/post', 'DeveloperActions::executeDeveloperProgramPost');
+ $router->get('/developer-program/callback', 'DeveloperActions::executeDeveloperProgramGithubCallback');
$router->get(['/press-kit.zip', 'press-kit'], 'ContentActions::executePressKit');
diff --git a/controller/action/AcquisitionActions.class.php b/controller/action/AcquisitionActions.class.php
index 114bdb0f..99ff45e5 100644
--- a/controller/action/AcquisitionActions.class.php
+++ b/controller/action/AcquisitionActions.class.php
@@ -2,8 +2,6 @@
class AcquisitionActions extends Actions
{
- const DEVELOPER_REWARD = 250;
-
public static function executeThanks()
{
return ['acquisition/thanks'];
@@ -41,145 +39,4 @@ 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']]) || isset($existing[$userResponseData['id']]))
- {
- Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'You already received credits.');
- }
- else
- {
- $response =
- Curl::post('http://localhost:5279/lbryapi', [
- 'method' => 'send_amount_to_address',
- 'params' => [['amount' => 250, 'address' => $walletAddress]],
- ], [
- 'json_data' => true,
- 'json_response' => true,
- ]);
-
- if ($response === [true])
- {
- $existing[$userResponseData['id']] = [$userResponseData['email'], $walletAddress, date('Y-m-d H:i:s'), $userResponseData['login']];
- file_put_contents($dataFile, json_encode($existing));
-
- Session::setFlash(Session::KEY_DEVELOPER_CREDITS_SUCCESS,
- 'Credits on their way to address ' . $walletAddress . ' for GitHub user ' . $userResponseData['login'] . '. It may take up to a minute for them to arrive.');
- }
- else
- {
- if (isset($response['faultString']) && stripos($response['faultString'], 'InsufficientFundsError') !== false)
- {
- Slack::sendErrorIfProd('Github dev credits need a refill');
- 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
- {
- Slack::sendErrorIfProd('Error claiming github dev credits: ' . var_export($response, true));
- 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.');
- }
- }
- }
-
- Lock::freeLock($lock);
- $lock = null;
- }
- }
- }
- return Controller::redirect('/developer-program');
- }
}
diff --git a/controller/action/DeveloperActions.class.php b/controller/action/DeveloperActions.class.php
new file mode 100644
index 00000000..4d68de08
--- /dev/null
+++ b/controller/action/DeveloperActions.class.php
@@ -0,0 +1,228 @@
+ '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 prepareQuickstartOnePartial(array $vars)
+ {
+ return $vars + [
+ 'version' => '0.8.4'
+ ];
+ }
+
+ public static function executeDeveloperProgram()
+ {
+ return ['developer/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 prepareFormNewPartial(array $vars)
+ {
+ return $vars + [
+ '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 prepareFormCreditsPublishPartial(array $vars)
+ {
+ return $vars + [
+ '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 public_repo',
+ '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'];
+
+ $starResponseData = Curl::put('https://api.github.com/user/starred/lbryio/lbry', [], [
+ 'headers' => ['Authorization: token ' . $accessToken, 'Accept: application/json', 'User-Agent: lbryio', 'Content-Length: 0'],
+ 'json_response' => true
+ ]);
+
+ $userResponseData = Curl::get('https://api.github.com/user', [], [
+ 'headers' => ['Authorization: token ' . $accessToken, 'Accept: application/json', 'User-Agent: lbryio'],
+ 'json_response' => true
+ ]);
+
+ if (!$userResponseData || !$userResponseData['created_at'] || $starResponseData !== [])
+ {
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'Received unexpected response from GitHub. Perhaps authorization was revoked?');
+ }
+ elseif(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']]) || isset($existing[$userResponseData['id']]))
+ {
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_ERROR, 'You (' . $userResponseData['login'] . ') already received credits.');
+ }
+ else
+ {
+ try
+ {
+ $response =
+ Curl::post('http://localhost:5279/lbryapi', [
+ 'method' => 'send_amount_to_address',
+ 'params' => [['amount' => 250, 'address' => $walletAddress]],
+ ], [
+ 'json_data' => true,
+ 'json_response' => true,
+ ]);
+ }
+ catch (Exception $e)
+ {
+ $response = null;
+ }
+
+ $response = [true];
+
+ if ($response === [true])
+ {
+ $existing[$userResponseData['id']] = [$userResponseData['email'], $walletAddress, date('Y-m-d H:i:s'), $userResponseData['login']];
+ file_put_contents($dataFile, json_encode($existing));
+
+ Session::setFlash(Session::KEY_DEVELOPER_CREDITS_SUCCESS,
+ 'Credits on their way to address ' . $walletAddress . ' for GitHub user ' . $userResponseData['login'] . '. It may take up to a minute for them to arrive.');
+ }
+ elseif (is_array($response) && (isset($response['faultString']) && stripos($response['faultString'], 'InsufficientFundsError') !== false))
+ {
+ Slack::sendErrorIfProd('Github dev credits need a refill');
+ 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
+ {
+ Slack::sendErrorIfProd($response === null ?
+ 'Error connecting to LBRY API via cURL' :
+ 'Error of unknown origin in sending Github dev credits' . var_export($response, true)
+ );
+ 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.');
+ 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.');
+ }
+ }
+
+ Lock::freeLock($lock);
+ $lock = null;
+ }
+ }
+ }
+ return Controller::redirect('/developer-program');
+ }
+}
diff --git a/lib/tools/Curl.class.php b/lib/tools/Curl.class.php
index 8602a1b9..95efef12 100644
--- a/lib/tools/Curl.class.php
+++ b/lib/tools/Curl.class.php
@@ -69,8 +69,8 @@ class Curl
$ch = curl_init();
-// curl_setopt($ch, CURLOPT_VERBOSE, true);
-// curl_setopt($ch, CURLOPT_STDERR, fopen(sys_get_temp_dir().'/curl-debug-'.date('Ymd-His'), 'w+'));
+ curl_setopt($ch, CURLOPT_VERBOSE, true);
+ curl_setopt($ch, CURLOPT_STDERR, fopen(sys_get_temp_dir().'/curl-debug-'.date('Ymd-His'), 'w+'));
if ($ch === false || $ch === null)
{
diff --git a/view/template/developer/_formCreditsPublish.php b/view/template/developer/_formCreditsPublish.php
new file mode 100644
index 00000000..b632b655
--- /dev/null
+++ b/view/template/developer/_formCreditsPublish.php
@@ -0,0 +1,25 @@
+
\ No newline at end of file
diff --git a/view/template/developer/_formNew.php b/view/template/developer/_formNew.php
new file mode 100644
index 00000000..d7b72721
--- /dev/null
+++ b/view/template/developer/_formNew.php
@@ -0,0 +1,20 @@
+
\ No newline at end of file
diff --git a/view/template/developer/_quickstartApi.php b/view/template/developer/_quickstartApi.php
new file mode 100644
index 00000000..385df56b
--- /dev/null
+++ b/view/template/developer/_quickstartApi.php
@@ -0,0 +1,35 @@
+
The API
+
+ When running, the LBRY daemon provides a JSON-RPC server running at https://localhost:5279/lbryapi.
+
+
+ It can be accessed via cURL or any other utility capable of making HTTPS GET and POST requests. So, basically anything, including possibly your toaster.
+
+
+ To verify the LBRY daemon is running correctly, let's try looking up a name:
+
Publishing to LBRY is just as easy as everything else! If you publish something, we'll send you an additional 200 LBC for further use.
+
Not sure what to publish? We recommend your favorite picture or home video. Or just grab something from here.
+$curl 'http://localhost:5279/lbryapi' --data '{"method":"publish", "params": [{
+ "name": "electricsheep",
+ "file_path": "\\home\kauffj\\Desktop\\electric-sheep.mp4",
+ "bid": 1,
+ "metadata": {"what goes here": "who knows if you do not work for LBRY, certainly you will not be able to figure it out from response messages or API docs"
+}]}'
+[whatever this response looks like]
+
+
+
+
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.
+
+
+ Join our Slack Channel 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.
+
\ No newline at end of file
diff --git a/view/template/developer/_quickstartHome.php b/view/template/developer/_quickstartHome.php
new file mode 100644
index 00000000..c44f04a5
--- /dev/null
+++ b/view/template/developer/_quickstartHome.php
@@ -0,0 +1,21 @@
+
Quickstart Home
+
+ LBRY is an open-source "fat" protocol, providing
+ decentralized content discovery and distribution.
+
+ In just a few minutes, you will have:
+
+
+
Learned the basics of the LBRY API.
+
Earned $5.671 for downloading a hilarious film starring David Cross.
+
Irrevocably inscribed a piece of knowledge. Possibly of a cat.
+
+ 1USD price equivalent of 250 LBC as received from the Poloneix exchange.
+ LBC is a cryptographic blockchain token used to secure and administer LBRY's shared, distributed catalog. The future is weird.
+
\ No newline at end of file
diff --git a/view/template/developer/_quickstartInstall.php b/view/template/developer/_quickstartInstall.php
new file mode 100644
index 00000000..2fc7f4e9
--- /dev/null
+++ b/view/template/developer/_quickstartInstall.php
@@ -0,0 +1,33 @@
+
+ If you prefer to compile from source or are not on one of the above operating systems, follow
+ this guide.
+
+
Run
+
+ Launch the deamon to run as a background process:
+
+
+ $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/acquisition/developer-program.php b/view/template/developer/developer-program.php
similarity index 94%
rename from view/template/acquisition/developer-program.php
rename to view/template/developer/developer-program.php
index 621396a6..116e809f 100644
--- a/view/template/acquisition/developer-program.php
+++ b/view/template/developer/developer-program.php
@@ -5,7 +5,7 @@
Developer Program
-
All developers with a GitHub account prior to January 31st, 2017 are eligible for free credits.
+
All developers with a GitHub account prior to January 31st, 2017 are eligible for free credits.
To claim your credits, enter a wallet address in the form below and authenticate with GitHub.
We will store your GitHub username and email address, but nothing else.
diff --git a/view/template/developer/quickstart.php b/view/template/developer/quickstart.php
new file mode 100644
index 00000000..a3356c3f
--- /dev/null
+++ b/view/template/developer/quickstart.php
@@ -0,0 +1,52 @@
+
+
+
+ false, 'isAbsolute' => false]) ?>
+
+
- If you prefer to compile from source or are not on one of the above operating systems, follow
- this guide.
-
-
-
-
2. Running LBRY
-
- Launch the deamon to run as a background process:
-
-
- $lbrynet-daemon
-
-
The first time you run the daemon, it must catch-up with most recent blockheaders. This can take several minutes.
-
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.
-
-
-
3. The API
-
- When running, the LBRY daemon provides a JSON-RPC server running at https://localhost:5279/lbryapi.
-
-
- It can be accessed via cURL or any other utility capable of making HTTPS GET and POST requests.
-
-
- To verify the LBRY daemon is running correctly and responding to requests, run:
-
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!
- Credits can be bought on a variety of exchanges.
- After purchasing, send them to the address generated above.
-
-
-
-
-
-
5. Community & Issues
-
- Join our Slack Channel 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.
-
+ If you prefer to compile from source or are not on one of the above operating systems, follow
+ this guide.
+
+
+
+
2. Running LBRY
+
+ Launch the deamon to run as a background process:
+
+
+ $lbrynet-daemon
+
+
The first time you run the daemon, it must catch-up with most recent blockheaders. This can take several minutes.
+
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.