Backblaze #135 - introduced the config setting to choose whether to generate private or public URLs, or to auto-detect. Photos are now displayed from B2.
This commit is contained in:
parent
437fe9fe1f
commit
608442d566
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace App\AlbumSources;
|
namespace App\AlbumSources;
|
||||||
|
|
||||||
use App\Album;
|
|
||||||
use App\Photo;
|
use App\Photo;
|
||||||
use App\Services\BackblazeB2Service;
|
use App\Services\BackblazeB2Service;
|
||||||
use App\Storage;
|
use App\Storage;
|
||||||
@ -10,15 +9,26 @@ use Guzzle\Http\EntityBody;
|
|||||||
|
|
||||||
class BackblazeB2Source extends AlbumSourceBase implements IAlbumSource
|
class BackblazeB2Source extends AlbumSourceBase implements IAlbumSource
|
||||||
{
|
{
|
||||||
|
const BUCKET_TYPE_AUTO = 0;
|
||||||
|
const BUCKET_TYPE_PRIVATE = 1;
|
||||||
|
const BUCKET_TYPE_PUBLIC = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var BackblazeB2Service
|
* @var BackblazeB2Service
|
||||||
*/
|
*/
|
||||||
private $backblaze;
|
private $backblaze;
|
||||||
|
|
||||||
public function __construct()
|
/**
|
||||||
{
|
* Type of bucket which determines what type of URLs to generate to images.
|
||||||
$this->backblaze = new BackblazeB2Service();
|
* @var integer
|
||||||
}
|
*/
|
||||||
|
private $bucketType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token used to download files from a private bucket.
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $downloadToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes an entire album's media contents.
|
* Deletes an entire album's media contents.
|
||||||
@ -68,7 +78,31 @@ class BackblazeB2Source extends AlbumSourceBase implements IAlbumSource
|
|||||||
*/
|
*/
|
||||||
public function getUrlToPhoto(Photo $photo, $thumbnail = null)
|
public function getUrlToPhoto(Photo $photo, $thumbnail = null)
|
||||||
{
|
{
|
||||||
// TODO: Implement getUrlToPhoto() method.
|
$client = $this->getClient();
|
||||||
|
$storagePathToFile = $this->getPathToPhoto($photo, $thumbnail);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* From https://www.backblaze.com/b2/docs/b2_download_file_by_name.html:
|
||||||
|
* The base URL to use comes from the b2_authorize_account call, and looks something like
|
||||||
|
* https://f345.backblazeb2.com. The "f" in the URL stands for "file", and the number is the cluster
|
||||||
|
* number containing your account. To this base, you add "file/", your bucket name, a "/", and then the
|
||||||
|
* name of the file. The file name may itself include more "/" characters.
|
||||||
|
*/
|
||||||
|
$fileDownloadUrl = sprintf('%s/file/%s/%s', $client->getDownloadUrl(), $this->configuration->container_name, $storagePathToFile);
|
||||||
|
|
||||||
|
switch ($this->bucketType)
|
||||||
|
{
|
||||||
|
case self::BUCKET_TYPE_PRIVATE:
|
||||||
|
if (is_null($this->downloadToken))
|
||||||
|
{
|
||||||
|
$this->downloadToken = $client->getDownloadAuthToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf('%s?Authorization=%s', $fileDownloadUrl, $this->downloadToken);
|
||||||
|
|
||||||
|
case self::BUCKET_TYPE_PUBLIC:
|
||||||
|
return $fileDownloadUrl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,15 +122,39 @@ class BackblazeB2Source extends AlbumSourceBase implements IAlbumSource
|
|||||||
public function setConfiguration(Storage $configuration)
|
public function setConfiguration(Storage $configuration)
|
||||||
{
|
{
|
||||||
parent::setConfiguration($configuration);
|
parent::setConfiguration($configuration);
|
||||||
|
|
||||||
$this->backblaze->setCredentials(decrypt($configuration->access_key), decrypt($configuration->secret_key));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getClient()
|
private function getClient()
|
||||||
{
|
{
|
||||||
|
if (is_null($this->backblaze))
|
||||||
|
{
|
||||||
|
$this->backblaze = new BackblazeB2Service();
|
||||||
|
$this->backblaze->setCredentials(decrypt($this->configuration->access_key), decrypt($this->configuration->secret_key));
|
||||||
$this->backblaze->authorizeAccount();
|
$this->backblaze->authorizeAccount();
|
||||||
$this->backblaze->setBucketName($this->configuration->container_name);
|
$this->backblaze->setBucketName($this->configuration->container_name);
|
||||||
|
|
||||||
|
if (intval($this->configuration->b2_bucket_type) == self::BUCKET_TYPE_AUTO)
|
||||||
|
{
|
||||||
|
/* Auto-detect the type of bucket in use on B2 */
|
||||||
|
|
||||||
|
switch ($this->backblaze->getBucketType())
|
||||||
|
{
|
||||||
|
case 'allPrivate':
|
||||||
|
$this->configuration->b2_bucket_type = self::BUCKET_TYPE_PRIVATE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'allPublic':
|
||||||
|
$this->configuration->b2_bucket_type = self::BUCKET_TYPE_PUBLIC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->configuration->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the bucket type
|
||||||
|
$this->bucketType = $this->configuration->b2_bucket_type;
|
||||||
|
}
|
||||||
|
|
||||||
return $this->backblaze;
|
return $this->backblaze;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,8 @@ class StorageController extends Controller
|
|||||||
'container_name',
|
'container_name',
|
||||||
'cdn_url',
|
'cdn_url',
|
||||||
'access_key',
|
'access_key',
|
||||||
'secret_key'
|
'secret_key',
|
||||||
|
'b2_bucket_type'
|
||||||
]));
|
]));
|
||||||
$storage->is_active = true;
|
$storage->is_active = true;
|
||||||
$storage->is_default = (strtolower($request->get('is_default')) == 'on');
|
$storage->is_default = (strtolower($request->get('is_default')) == 'on');
|
||||||
@ -217,7 +218,8 @@ class StorageController extends Controller
|
|||||||
'container_name',
|
'container_name',
|
||||||
'cdn_url',
|
'cdn_url',
|
||||||
'access_key',
|
'access_key',
|
||||||
'secret_key'
|
'secret_key',
|
||||||
|
'b2_bucket_type'
|
||||||
]));
|
]));
|
||||||
$storage->is_active = (strtolower($request->get('is_active')) == 'on');
|
$storage->is_active = (strtolower($request->get('is_active')) == 'on');
|
||||||
$storage->is_default = (strtolower($request->get('is_default')) == 'on');
|
$storage->is_default = (strtolower($request->get('is_default')) == 'on');
|
||||||
|
@ -10,14 +10,46 @@ class BackblazeB2Service
|
|||||||
*/
|
*/
|
||||||
private $accountApiUrl;
|
private $accountApiUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the account in Backblaze B2.
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
private $accountID;
|
private $accountID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base URL for public access to the account's files.
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $downloadUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorisation header for authenticating to the API.
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
private $authHeader;
|
private $authHeader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorisation token for accessing the API post-authentication.
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
private $authToken;
|
private $authToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ID of the bucket.
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
private $bucketId;
|
private $bucketId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of the bucket.
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $bucketType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration related to the Backblaze B2 service.
|
||||||
|
* @var \Illuminate\Config\Repository|mixed
|
||||||
|
*/
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
@ -39,12 +71,41 @@ class BackblazeB2Service
|
|||||||
$this->authToken = $result->authorizationToken;
|
$this->authToken = $result->authorizationToken;
|
||||||
$this->accountApiUrl = $result->apiUrl;
|
$this->accountApiUrl = $result->apiUrl;
|
||||||
$this->accountID = $result->accountId;
|
$this->accountID = $result->accountId;
|
||||||
|
$this->downloadUrl = $result->downloadUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getBucketType()
|
||||||
|
{
|
||||||
|
return $this->bucketType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDownloadAuthToken()
|
||||||
|
{
|
||||||
|
$result = $this->sendRequest(
|
||||||
|
sprintf('%s/b2api/v2/b2_get_download_authorization', $this->accountApiUrl),
|
||||||
|
'POST',
|
||||||
|
[
|
||||||
|
'bucketId' => $this->bucketId,
|
||||||
|
'validDurationInSeconds' => intval($this->config['download_token_lifetime']),
|
||||||
|
'fileNamePrefix' => ''
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return $result->authorizationToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDownloadUrl()
|
||||||
|
{
|
||||||
|
return $this->downloadUrl;
|
||||||
|
}
|
||||||
|
|
||||||
public function setBucketName($bucketName)
|
public function setBucketName($bucketName)
|
||||||
{
|
{
|
||||||
$this->bucketId = $this->getBucketIdFromName($bucketName);
|
$bucketDetails = $this->getBucketDetailsFromName($bucketName);
|
||||||
|
|
||||||
|
$this->bucketId = $bucketDetails->bucketId;
|
||||||
|
$this->bucketType = $bucketDetails->bucketType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCredentials($applicationKeyID, $applicationKey)
|
public function setCredentials($applicationKeyID, $applicationKey)
|
||||||
@ -78,12 +139,17 @@ class BackblazeB2Service
|
|||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $fileContents);
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $fileContents);
|
||||||
|
|
||||||
$result = curl_exec($ch);
|
$result = curl_exec($ch);
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
|
||||||
var_dump($result);
|
if ($httpCode != 200 && $httpCode != 304)
|
||||||
exit();
|
{
|
||||||
|
throw new \Exception(sprintf('Exception from Backblaze B2: %s', $result));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getBucketIdFromName($bucketName)
|
curl_close($ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getBucketDetailsFromName($bucketName)
|
||||||
{
|
{
|
||||||
$result = $this->sendRequest(
|
$result = $this->sendRequest(
|
||||||
sprintf('%s/b2api/v2/b2_list_buckets', $this->accountApiUrl),
|
sprintf('%s/b2api/v2/b2_list_buckets', $this->accountApiUrl),
|
||||||
@ -96,7 +162,7 @@ class BackblazeB2Service
|
|||||||
|
|
||||||
if (isset($result->buckets) && is_array($result->buckets) && count($result->buckets) >= 1)
|
if (isset($result->buckets) && is_array($result->buckets) && count($result->buckets) >= 1)
|
||||||
{
|
{
|
||||||
return $result->buckets[0]->bucketId;
|
return $result->buckets[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new \Exception(sprintf('The bucket \'%s\' was not found or your API key does not have access.', $bucketName));
|
throw new \Exception(sprintf('The bucket \'%s\' was not found or your API key does not have access.', $bucketName));
|
||||||
|
@ -30,7 +30,8 @@ class Storage extends Model
|
|||||||
'container_name',
|
'container_name',
|
||||||
'cdn_url',
|
'cdn_url',
|
||||||
'access_key',
|
'access_key',
|
||||||
'secret_key'
|
'secret_key',
|
||||||
|
'b2_bucket_type'
|
||||||
];
|
];
|
||||||
|
|
||||||
public function albums()
|
public function albums()
|
||||||
|
@ -15,7 +15,8 @@ return [
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
'backblaze_b2' => [
|
'backblaze_b2' => [
|
||||||
'auth_url' => 'https://api.backblazeb2.com/b2api/v2/b2_authorize_account'
|
'auth_url' => 'https://api.backblazeb2.com/b2api/v2/b2_authorize_account',
|
||||||
|
'download_token_lifetime' => 300
|
||||||
],
|
],
|
||||||
|
|
||||||
'gitea' => [
|
'gitea' => [
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddBackblazeStorageColumns extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('storages', function (Blueprint $table)
|
||||||
|
{
|
||||||
|
$table->tinyInteger('b2_bucket_type')->default(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('storages', function (Blueprint $table)
|
||||||
|
{
|
||||||
|
$table->dropColumn('b2_bucket_type');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -101,6 +101,12 @@ return [
|
|||||||
'storage_application_key_id_label' => 'Application key ID:',
|
'storage_application_key_id_label' => 'Application key ID:',
|
||||||
'storage_application_key_label' => 'Application key:',
|
'storage_application_key_label' => 'Application key:',
|
||||||
'storage_auth_url_label' => 'Authentication URL:',
|
'storage_auth_url_label' => 'Authentication URL:',
|
||||||
|
'storage_b2_bucket_type' => [
|
||||||
|
'autodetect' => 'Auto-detect',
|
||||||
|
'label' => 'Bucket type:',
|
||||||
|
'private' => 'Private',
|
||||||
|
'public' => 'Public'
|
||||||
|
],
|
||||||
'storage_bucket_name_label' => 'Bucket name:',
|
'storage_bucket_name_label' => 'Bucket name:',
|
||||||
'storage_cdn_url_label' => 'Public CDN URL (if supported and enabled):',
|
'storage_cdn_url_label' => 'Public CDN URL (if supported and enabled):',
|
||||||
'storage_container_name_label' => 'Container name:',
|
'storage_container_name_label' => 'Container name:',
|
||||||
|
@ -39,4 +39,20 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-control-label" for="b2-bucket-type">@lang('forms.storage_b2_bucket_type.label')</label>
|
||||||
|
<select class="form-control{{ $errors->has('b2_bucket_type') ? ' is-invalid' : '' }}" id="b2-bucket-type" name="b2_bucket_type">
|
||||||
|
<option value="0"{{ old('b2_bucket_type', $storage->b2_bucket_type) === 0 ? ' selected="selected"' : '' }}>@lang('forms.storage_b2_bucket_type.autodetect')</option>
|
||||||
|
<option value="1"{{ old('b2_bucket_type', $storage->b2_bucket_type) === 1 ? ' selected="selected"' : '' }}>@lang('forms.storage_b2_bucket_type.private')</option>
|
||||||
|
<option value="2"{{ old('b2_bucket_type', $storage->b2_bucket_type) === 2 ? ' selected="selected"' : '' }}>@lang('forms.storage_b2_bucket_type.public')</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
@if ($errors->has('b2_bucket_type'))
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
<strong>{{ $errors->first('b2_bucket_type') }}</strong>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
Loading…
Reference in New Issue
Block a user