Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Tenancy v4 #23

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu-latest, windows-latest]
php: [8.0]
php: [8.2]
stability: [prefer-lowest, prefer-stable]

name: P${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }}
Expand All @@ -33,6 +33,9 @@ jobs:
- name: Activate Pest Composer Plugin
run: composer config --no-plugins allow-plugins.pestphp/pest-plugin true

- name: Composer Authentication
run: composer config github-oauth.github.com ${{ secrets.PRIVATE_PACKAGE_ACCESS_TOKEN }}

- name: Install dependencies
run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction

Expand Down
10 changes: 8 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@
"role": "Developer"
}
],
"repositories": [
{
"type": "vcs",
"url": "https://github.com/tenancy-for-laravel/v4"
}
],
"require": {
"php": "^8.0",
"php": "^8.2",
"aws/aws-sdk-php": "~3.0",
"stancl/tenancy": "^3.4"
"stancl/tenancy": "dev-master"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.0",
Expand Down
4 changes: 2 additions & 2 deletions src/Bootstrappers/TenantBucketBootstrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ public function __construct(Application $app)
$this->orignalBucket = $this->app['config']['filesystems.disks.s3.bucket'];
}

public function bootstrap(Tenant $tenant)
public function bootstrap(Tenant $tenant): void
{
// Select Bucket Name
$bucket = 'tenant'.$tenant->getTenantKey();
$bucket = $tenant->tenant_bucket ?? $bucket;
$this->app['config']['filesystems.disks.s3.bucket'] = $bucket;
}

public function revert()
public function revert(): void
{
//
$this->app['config']['filesystems.disks.s3.bucket'] = $this->orignalBucket;
Expand Down
130 changes: 55 additions & 75 deletions src/Bucket.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,70 +3,65 @@
namespace Vidwan\TenantBuckets;

use Aws\Credentials\Credentials;

use Aws\Exception\AwsException;
use Aws\S3\S3Client;
use Illuminate\Support\Facades\Log;
use Stancl\Tenancy\Contracts\TenantWithDatabase;
use Stancl\Tenancy\Contracts\Tenant;
use Vidwan\TenantBuckets\Events\CreatedBucket;
use Vidwan\TenantBuckets\Events\CreatingBucket;
use Vidwan\TenantBuckets\Events\DeletedBucket;
use Vidwan\TenantBuckets\Events\DeletingBucket;
use Vidwan\TenantBuckets\Exceptions\CreateBucketException;
use Vidwan\TenantBuckets\Exceptions\DeleteBucketException;

class Bucket
{
/**
* @access public
* @var Stancl\Tenancy\Contracts\TenantWithDatabase Tenant
* @var AWS Credentials Object
* @var AWS/Minio Endpoint
* @var AWS/Minio Region
* @var Use Path style endpoint (used for minio)
* @access protected
* @var string|null Name of the Created Bucket
* @var Aws\Exception\AwsException|null Exception Error Bag
*/
public $tenant;
public $credentials;
public $endpoint;
public $region;
public string $version = "2006-03-01";
public bool $pathStyle = false;
protected string|null $createdBucketName;
protected AwsException|null $e;
* @var \AWS\Credentials\Credentials Credentials Object
*/
protected $credentials;

/**
* Setup the Bucket Object
*
* @access public
* @param Stancl\Tenancy\Contracts\TenantWithDatabase $tenant Current Teanant
* @param Aws\Credentials\Credentials $credentials Aws Credentials Object
* @param string $endpoint Aws/Minio Endpoint
* @param bool $pathStyle Use Path Style Endpoint (set `true` for minio, default: false)
* @return void
*/
* @var string AWS/Minio Endpoint
*/
protected $endpoint;

/**
* @var string AWS/Minio Region
*/
protected $region;

protected string $version = "2006-03-01";

/**
* @var bool Use Path style endpoint (used for minio)
*/
protected bool $pathStyle = false;

/**
* @var string|null Name of the Created Bucket
*/
protected string|null $bucketName;

public function __construct(
TenantWithDatabase $tenant,
?Credentials $credentials = null,
?string $region = null,
?string $endpoint = null,
?bool $pathStyle = null
protected Tenant $tenant
) {
$this->tenant = $tenant;
$this->credentials = $credentials ?? new Credentials(
$this->setupCredentials();
}

private function setupCredentials()
{
$this->credentials = new Credentials(
config('filesystems.disks.s3.key'),
config('filesystems.disks.s3.secret')
);
$this->region = $region ?? config('filesystems.disks.s3.region');
$this->endpoint = $endpoint ?? config('filesystems.disks.s3.endpoint');
$pathStyle = $pathStyle ?? config('filesystems.disks.s3.use_path_style_endpoint');
$this->pathStyle = $pathStyle ?? $this->pathStyle;
$this->region = config('filesystems.disks.s3.region');
$this->endpoint = config('filesystems.disks.s3.endpoint');
$this->pathStyle = config('filesystems.disks.s3.use_path_style_endpoint', false);
}

/**
* Create Tenant Specific Bucket
*
* @access public
* @return self $this
*/
public function createTenantBucket(): self
Expand All @@ -79,7 +74,6 @@ public function createTenantBucket(): self
/**
* Delete Tenant Specific Bucket
*
* @access public
* @return self $this
*/
public function deleteTenantBucket(): self
Expand All @@ -93,8 +87,7 @@ public function deleteTenantBucket(): self
* Create a New Bucket
*
* @param string $name Name of the S3 Bucket
* @param Aws\Credentials\Credentials $credentials AWS Credentials Object
* @access public
* @param \Aws\Credentials\Credentials $credentials AWS Credentials Object
* @return self $this
*/
public function createBucket(string $name, Credentials $credentials): self
Expand All @@ -108,21 +101,21 @@ public function createBucket(string $name, Credentials $credentials): self
"version" => $this->version,
"use_path_style_endpoint" => $this->pathStyle,
];
$this->bucketName = $this->formatBucketName($name);

$client = new S3Client($params);

try {
$exec = $client->createBucket([
'Bucket' => $name,
$client->createBucket([
'Bucket' => $this->bucketName,
]);
$this->createdBucketName = $name;

// Update Tenant
$this->tenant->tenant_bucket = $name;
$this->tenant->tenant_bucket = $this->bucketName;
$this->tenant->save();
} catch (AwsException $e) {
$this->e = $e;
Log::error($this->getErrorMessage());
// We catch to set the error bag
throw new CreateBucketException($this->tenant, $this->bucketName, $e);
}

event(new CreatedBucket($this->tenant));
Expand All @@ -134,13 +127,12 @@ public function createBucket(string $name, Credentials $credentials): self
* Create a New Bucket
*
* @param string $name Name of the S3 Bucket
* @param Aws\Credentials\Credentials $credentials AWS Credentials Object
* @access public
* @param \Aws\Credentials\Credentials $credentials AWS Credentials Object
* @return self $this
*/
public function deleteBucket(string $name, Credentials $credentials): self
{
event(new DeletingBucket($this->tenant));
event(new DeletingBucket(tenant: $this->tenant));

$params = [
"credentials" => $credentials,
Expand All @@ -153,12 +145,12 @@ public function deleteBucket(string $name, Credentials $credentials): self
$client = new S3Client($params);

try {
$exec = $client->deleteBucket([
$client->deleteBucket([
'Bucket' => $name,
]);
} catch (AwsException $e) {
$this->e = $e;
Log::error($this->getErrorMessage());
// We catch to set the error bag
throw new DeleteBucketException($this->tenant, $name, $e);
}

event(new DeletedBucket($this->tenant));
Expand All @@ -173,28 +165,16 @@ public function deleteBucket(string $name, Credentials $credentials): self
*/
public function getBucketName(): string|null
{
return $this->createdBucketName;
}

/**
* Get Error Messsge
*
* @return string|null
*/
public function getErrorMessage(): string|null
{
return ($this->e) ?
"Error: " . $this->e->getAwsErrorMessage() :
null;
return $this->bucketName;
}

/**
* Get Error Bag
*
* @return AwsException|null
* Format Bucket Name according to AWS S3 Bucket Naming Rules
* @see https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html
* @param string $name
*/
public function getErrorBag(): AwsException|null
protected function formatBucketName(string $name): string
{
return $this->e ? $this->e : null;
return str(preg_replace('/[^a-zA-Z0-9]/', '', $name))->lower()->toString();
}
}
29 changes: 29 additions & 0 deletions src/Exceptions/BaseException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Vidwan\TenantBuckets\Exceptions;

use Aws\Exception\AwsException;
use Exception;
use Throwable;

abstract class BaseException extends Exception
{
protected array $data;

protected AwsException $awsException;

public function __construct(string $message = "", int $code = 0, Throwable|null $previous = null)
{
parent::__construct($message, $code, $previous);
}

public function getAwsException(): AwsException
{
return $this->awsException;
}

public function getData(): array
{
return $this->data;
}
}
34 changes: 34 additions & 0 deletions src/Exceptions/CreateBucketException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Vidwan\TenantBuckets\Exceptions;

use Aws\Exception\AwsException;
use Stancl\Tenancy\Contracts\Tenant;

class CreateBucketException extends BaseException
{
public function __construct(
protected Tenant $tenant,
protected string $bucketName,
protected AwsException $awsException
) {
$message = "[tenant-buckets] Error: (Tenant ID: {$tenant->id}) {$awsException->getAwsErrorMessage()}";
parent::__construct($message, $awsException->getCode(), $awsException);

$this->setData();
}

private function setData(): static
{
$this->data = [
'tenant' => $this->tenant->id,
'bucket' => $this->bucketName,
'error_code' => $this->awsException->getAwsErrorCode(),
'error_type' => $this->awsException->getAwsErrorType(),
'error_message' => $this->awsException->getAwsErrorMessage(),
'response' => $this->awsException->getResponse(),
];

return $this;
}
}
34 changes: 34 additions & 0 deletions src/Exceptions/DeleteBucketException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Vidwan\TenantBuckets\Exceptions;

use Aws\Exception\AwsException;
use Stancl\Tenancy\Contracts\Tenant;

class DeleteBucketException extends BaseException
{
public function __construct(
protected Tenant $tenant,
protected string $bucketName,
protected AwsException $awsException
) {
$message = "[tenant-buckets] Error: (Tenant ID: {$tenant->id}) {$awsException->getAwsErrorMessage()}";
parent::__construct($message, $awsException->getCode(), $awsException);

$this->setData();
}

private function setData(): static
{
$this->data = [
'tenant' => $this->tenant->id,
'bucket' => $this->bucketName,
'error_code' => $this->awsException->getAwsErrorCode(),
'error_type' => $this->awsException->getAwsErrorType(),
'error_message' => $this->awsException->getAwsErrorMessage(),
'response' => $this->awsException->getResponse(),
];

return $this;
}
}
Loading
Loading