Skip to content

Commit

Permalink
Merge pull request #7708 from ever-co/fix/file-storage-provider
Browse files Browse the repository at this point in the history
[Fix] Default Enabled Force path style URLs (File Storage)
  • Loading branch information
rahul-rocket authored Mar 28, 2024
2 parents 2f73922 + 3960dfa commit a9a7b2b
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 90 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Component, OnInit } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { FileStorageProviderEnum, HttpStatus, ITenantSetting, IUser, PermissionsEnum, SMTPSecureEnum } from '@gauzy/contracts';
import { combineLatest } from 'rxjs';
import { filter, tap } from 'rxjs/operators';
import { Subject } from 'rxjs/internal/Subject';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { TranslateService } from '@ngx-translate/core';
import { environment } from '@env/environment';
import { FileStorageProviderEnum, HttpStatus, ITenantSetting, IUser, PermissionsEnum, SMTPSecureEnum } from '@gauzy/contracts';
import { isNotEmpty } from '@gauzy/common-angular';
import { filter, tap } from 'rxjs/operators';
import { Subject } from 'rxjs/internal/Subject';
import { ErrorHandlingService, FileStorageService, Store, TenantService, ToastrService } from '../../../@core/services';
import { TranslationBaseComponent } from '../../../@shared/language-base';
import { environment } from './../../../../environments/environment';

@UntilDestroy({ checkProperties: true })
@Component({
Expand All @@ -30,7 +31,7 @@ export class FileStorageComponent extends TranslationBaseComponent
settings: ITenantSetting = new Object();
loading: boolean = false;

public readonly form: UntypedFormGroup = FileStorageComponent.buildForm(this.fb);
public readonly form: UntypedFormGroup = FileStorageComponent.buildForm(this._fb);

/**
*
Expand All @@ -39,7 +40,6 @@ export class FileStorageComponent extends TranslationBaseComponent
*/
static buildForm(fb: UntypedFormBuilder): UntypedFormGroup {
const defaultFileStorageProvider = environment.FILE_PROVIDER.toUpperCase() as FileStorageProviderEnum || FileStorageProviderEnum.LOCAL;

//
const form = fb.group({
fileStorageProvider: [defaultFileStorageProvider, Validators.required],
Expand All @@ -57,15 +57,7 @@ export class FileStorageComponent extends TranslationBaseComponent
wasabi_aws_default_region: ['us-east-1'],
wasabi_aws_service_url: ['https://s3.wasabisys.com'],
wasabi_aws_bucket: ['gauzy'],
wasabi_aws_force_path_style: [false]
}),
// Cloudinary Configuration
CLOUDINARY: fb.group({
cloudinary_cloud_name: [],
cloudinary_api_key: [],
cloudinary_api_secret: [],
cloudinary_api_secure: ['true'],
cloudinary_delivery_url: ['https://res.cloudinary.com']
wasabi_aws_force_path_style: [true]
}),
// DigitalOcean Configuration
DIGITALOCEAN: fb.group({
Expand All @@ -75,7 +67,15 @@ export class FileStorageComponent extends TranslationBaseComponent
digitalocean_service_url: [],
digitalocean_cdn_url: [],
digitalocean_s3_bucket: ['gauzy'],
digitalocean_s3_force_path_style: [false]
digitalocean_s3_force_path_style: [true]
}),
// Cloudinary Configuration
CLOUDINARY: fb.group({
cloudinary_cloud_name: [],
cloudinary_api_key: [],
cloudinary_api_secret: [],
cloudinary_api_secure: ['true'],
cloudinary_delivery_url: ['https://res.cloudinary.com']
}),
});
return form;
Expand All @@ -91,8 +91,8 @@ export class FileStorageComponent extends TranslationBaseComponent
}

constructor(
private readonly fb: UntypedFormBuilder,
public readonly translate: TranslateService,
private readonly _fb: UntypedFormBuilder,
private readonly _store: Store,
private readonly _tenantService: TenantService,
private readonly _fileStorageService: FileStorageService,
Expand All @@ -103,19 +103,17 @@ export class FileStorageComponent extends TranslationBaseComponent
}

ngOnInit(): void {
this.subject$
.pipe(
tap(() => this.getSetting()),
untilDestroyed(this)
)
.subscribe();
this._store.user$
.pipe(
combineLatest([
this.subject$.pipe(
tap(() => this.getSetting())
),
this._store.user$.pipe(
filter((user: IUser) => !!user),
tap(() => this.subject$.next(true)),
untilDestroyed(this)
tap(() => this.subject$.next(true))
)
.subscribe();
]).pipe(
untilDestroyed(this)
).subscribe();
}

/**
Expand All @@ -124,86 +122,65 @@ export class FileStorageComponent extends TranslationBaseComponent
* If no settings are available, uses the default file storage provider from the environment.
*/
async getSetting(): Promise<void> {
// Set loading state to true while fetching settings
this.loading = true;

try {
this.loading = true; // Set loading state to true while fetching settings

// Fetch tenant settings
const settings = this.settings = await this._tenantService.getSettings();

// Check if settings are available
if (isNotEmpty(settings)) {
// Update file storage provider based on fetched settings
const { fileStorageProvider } = settings;
this.setFileStorageProvider(fileStorageProvider);
} else {
// Use the default file storage provider from the environment if no settings are available
this.setFileStorageProvider((environment.FILE_PROVIDER.toUpperCase() as FileStorageProviderEnum) || FileStorageProviderEnum.LOCAL);
}
// Determine the default file storage provider
const defaultFileStorageProvider = (environment.FILE_PROVIDER.toUpperCase() as FileStorageProviderEnum) || FileStorageProviderEnum.LOCAL;

// Update file storage provider based on fetched settings or use the default one
const fileStorageProvider = isNotEmpty(settings) ? settings.fileStorageProvider : defaultFileStorageProvider;
this.setFileStorageProvider(fileStorageProvider);
} catch (error) {
// Handle any errors that may occur during the fetch operation
console.error('Error fetching tenant settings:', error);
console.error('Error fetching tenant settings:', error); // Log the error
// You can add more specific error handling here if needed
} finally {
// Set loading state to false once fetching is complete
this.loading = false;
this.loading = false; // Set loading state to false once fetching is complete
}
}

/**
* SAVE current tenant file storage setting
*/
async submit() {
if (this.form.invalid) {
return;
}

let settings: ITenantSetting;
try {
if (this.form.invalid) {
return;
}

const { fileStorageProvider = FileStorageProviderEnum.LOCAL } = this.form.getRawValue();
const filesystem: ITenantSetting = this.form.getRawValue();
// Extract the file storage provider and settings from the form data
const { fileStorageProvider = FileStorageProviderEnum.LOCAL, ...filesystem } = this.form.getRawValue();

/**
* If driver is available else use LOCAL file storage
*/
if (fileStorageProvider in filesystem) {
settings = {
// Construct the settings object with the extracted data
const settings: ITenantSetting = {
fileStorageProvider,
...filesystem[fileStorageProvider]
}
} else {
settings = {
fileStorageProvider: FileStorageProviderEnum.LOCAL
}
}
...(fileStorageProvider in filesystem ? filesystem[fileStorageProvider] : {})
};

try {
// Validates Wasabi credentials if the selected file storage provider is Wasabi.
if (fileStorageProvider === FileStorageProviderEnum.WASABI) {
try {
const response = await this._fileStorageService.validateWasabiCredentials(settings);
if (response.status === HttpStatus.BAD_REQUEST) {
// Handle and log errors
this._errorHandlingService.handleError(response);
return;
} else {
this._toastrService.success('TOASTR.MESSAGE.BUCKET_CREATED', {
bucket: `${settings.wasabi_aws_bucket}`,
region: `${settings.wasabi_aws_default_region}`
});
}
} catch (error) {
console.error('Error while validating wasabi credentials', error);
const response = await this._fileStorageService.validateWasabiCredentials(settings);
// Handles errors with the HTTP status code HttpStatus.BAD_REQUEST.
if (response.status === HttpStatus.BAD_REQUEST) {
this._errorHandlingService.handleError(response);
return;
}

this._toastrService.success('TOASTR.MESSAGE.BUCKET_CREATED', {
bucket: `${settings.wasabi_aws_bucket}`,
region: `${settings.wasabi_aws_default_region}`
});
}
} catch (error) {
this._toastrService.danger(error);
return;
}

try {
// Saves the tenant settings and displays a success message upon successful saving.
await this._tenantService.saveSettings(settings);
this._toastrService.success('TOASTR.MESSAGE.SETTINGS_SAVED');
} catch (error) {
this._toastrService.danger(error);
console.error('Error while submitting tenant settings:', error);
this._toastrService.danger('An error occurred while saving settings. Please try again.');
} finally {
this.subject$.next(true);
}
Expand All @@ -215,12 +192,15 @@ export class FileStorageComponent extends TranslationBaseComponent
* @param provider
*/
setFileStorageProvider(provider: FileStorageProviderEnum) {
this.form.get('fileStorageProvider').setValue(provider);
this.form.get('fileStorageProvider').updateValueAndValidity();
const fileStorageProviderControl = this.form.get('fileStorageProvider');

fileStorageProviderControl.setValue(provider);
fileStorageProviderControl.updateValueAndValidity();

if (this.form.contains(provider)) {
this.form.get(provider).patchValue({ ...this.settings });
this.form.get(provider).updateValueAndValidity();
const providerControl = this.form.get(provider);
if (providerControl) {
providerControl.patchValue({ ...this.settings });
providerControl.updateValueAndValidity();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ export class DigitalOceanS3Provider extends Provider<DigitalOceanS3Provider> {
* Whether to force path style URLs for S3 objects
* (e.g., https://s3.amazonaws.com/<bucketName>/<key> instead of https://<bucketName>.s3.amazonaws.com/<key>
*/
forcePathStyle: this.config.digitalocean_s3_force_path_style, // Configures to use subdomain/virtual calling format.
forcePathStyle: this.config.digitalocean_s3_force_path_style || true, // Configures to use subdomain/virtual calling format.
endpoint,
region: this.config.digitalocean_default_region || 'us-east-1',
credentials: {
Expand Down

0 comments on commit a9a7b2b

Please sign in to comment.