migrate firebase storage

This commit is contained in:
2026-03-09 21:57:26 +01:00
parent b6c2fe1645
commit 0203d4ea9d
7 changed files with 46 additions and 28 deletions

View File

@@ -1,12 +1,19 @@
import {TestBed} from '@angular/core/testing'; import {TestBed} from '@angular/core/testing';
import {Storage} from '@angular/fire/storage';
import {FileService} from './file.service'; import {FileService} from './file.service';
import {FileDataService} from './file-data.service';
describe('FileService', () => { describe('FileService', () => {
let service: FileService; let service: FileService;
beforeEach(() => { beforeEach(() => {
void TestBed.configureTestingModule({}); void TestBed.configureTestingModule({
providers: [
{provide: Storage, useValue: {}},
{provide: FileDataService, useValue: {delete: () => Promise.resolve()}},
],
});
service = TestBed.inject(FileService); service = TestBed.inject(FileService);
}); });

View File

@@ -1,6 +1,6 @@
import {Injectable} from '@angular/core'; import {Injectable} from '@angular/core';
import {AngularFireStorage} from '@angular/fire/compat/storage'; import {deleteObject, getDownloadURL, ref, Storage} from '@angular/fire/storage';
import {firstValueFrom, Observable} from 'rxjs'; import {from, Observable} from 'rxjs';
import {FileDataService} from './file-data.service'; import {FileDataService} from './file-data.service';
@Injectable({ @Injectable({
@@ -8,18 +8,16 @@ import {FileDataService} from './file-data.service';
}) })
export class FileService { export class FileService {
public constructor( public constructor(
private storage: AngularFireStorage, private storage: Storage,
private fileDataService: FileDataService private fileDataService: FileDataService
) {} ) {}
public getDownloadUrl(path: string): Observable<string> { public getDownloadUrl(path: string): Observable<string> {
const ref = this.storage.ref(path); return from(getDownloadURL(ref(this.storage, path)));
return ref.getDownloadURL() as Observable<string>;
} }
public delete(path: string, songId: string, fileId: string): void { public delete(path: string, songId: string, fileId: string): void {
const ref = this.storage.ref(path); void deleteObject(ref(this.storage, path));
void firstValueFrom(ref.delete());
void this.fileDataService.delete(songId, fileId); void this.fileDataService.delete(songId, fileId);
} }
} }

View File

@@ -1,9 +1,19 @@
import {TestBed} from '@angular/core/testing'; import {TestBed} from '@angular/core/testing';
import {Storage} from '@angular/fire/storage';
import {UploadService} from './upload.service'; import {UploadService} from './upload.service';
import {FileDataService} from './file-data.service';
describe('UploadServiceService', () => { describe('UploadServiceService', () => {
beforeEach(() => void TestBed.configureTestingModule({})); beforeEach(
() =>
void TestBed.configureTestingModule({
providers: [
{provide: Storage, useValue: {}},
{provide: FileDataService, useValue: {set: () => Promise.resolve('')}},
],
})
);
it('should be created', () => { it('should be created', () => {
const service: UploadService = TestBed.inject(UploadService); const service: UploadService = TestBed.inject(UploadService);

View File

@@ -1,8 +1,7 @@
import {Injectable} from '@angular/core'; import {Injectable} from '@angular/core';
import {Upload} from './upload'; import {Upload} from './upload';
import {FileDataService} from './file-data.service'; import {FileDataService} from './file-data.service';
import {AngularFireStorage} from '@angular/fire/compat/storage'; import {ref, Storage, uploadBytesResumable} from '@angular/fire/storage';
import {finalize} from 'rxjs/operators';
import {FileBase} from './fileBase'; import {FileBase} from './fileBase';
import {FileServer} from './fileServer'; import {FileServer} from './fileServer';
@@ -12,7 +11,7 @@ import {FileServer} from './fileServer';
export class UploadService extends FileBase { export class UploadService extends FileBase {
public constructor( public constructor(
private fileDataService: FileDataService, private fileDataService: FileDataService,
private angularFireStorage: AngularFireStorage private storage: Storage
) { ) {
super(); super();
} }
@@ -22,14 +21,19 @@ export class UploadService extends FileBase {
const filePath = `${directory}/${upload.file.name}`; const filePath = `${directory}/${upload.file.name}`;
upload.path = directory; upload.path = directory;
const ref = this.angularFireStorage.ref(filePath); const storageRef = ref(this.storage, filePath);
const task = ref.put(upload.file); const task = uploadBytesResumable(storageRef, upload.file);
task.percentageChanges().subscribe(percent => (upload.progress = percent ?? 0)); task.on(
task 'state_changed',
.snapshotChanges() snapshot => {
.pipe(finalize(() => void this.saveFileData(songId, upload))) upload.progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
.subscribe(); },
() => {
// Keep current UX: upload errors are ignored by this service.
},
() => void this.saveFileData(songId, upload)
);
} }
private async saveFileData(songId: string, upload: Upload) { private async saveFileData(songId: string, upload: Upload) {

View File

@@ -1,4 +1,5 @@
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
import {Storage} from '@angular/fire/storage';
import {FileComponent} from './file.component'; import {FileComponent} from './file.component';
@@ -9,6 +10,7 @@ describe('FileComponent', () => {
beforeEach(waitForAsync(() => { beforeEach(waitForAsync(() => {
void TestBed.configureTestingModule({ void TestBed.configureTestingModule({
imports: [FileComponent], imports: [FileComponent],
providers: [{provide: Storage, useValue: {}}],
}).compileComponents(); }).compileComponents();
})); }));

View File

@@ -1,7 +1,7 @@
import {Component, Input} from '@angular/core'; import {Component, Input} from '@angular/core';
import {File} from '../../services/file'; import {File} from '../../services/file';
import {AngularFireStorage} from '@angular/fire/compat/storage'; import {getDownloadURL, ref, Storage} from '@angular/fire/storage';
import {Observable} from 'rxjs'; import {from, Observable} from 'rxjs';
import {AsyncPipe} from '@angular/common'; import {AsyncPipe} from '@angular/common';
@Component({ @Component({
@@ -14,12 +14,11 @@ export class FileComponent {
public url$: Observable<string> | null = null; public url$: Observable<string> | null = null;
public name = ''; public name = '';
public constructor(private storage: AngularFireStorage) {} public constructor(private storage: Storage) {}
@Input() @Input()
public set file(file: File) { public set file(file: File) {
const ref = this.storage.ref(file.path + '/' + file.name); this.url$ = from(getDownloadURL(ref(this.storage, file.path + '/' + file.name)));
this.url$ = ref.getDownloadURL() as Observable<string>;
this.name = file.name; this.name = file.name;
} }
} }

View File

@@ -6,13 +6,12 @@ import {bootstrapApplication, BrowserModule} from '@angular/platform-browser';
import {provideAnimations} from '@angular/platform-browser/animations'; import {provideAnimations} from '@angular/platform-browser/animations';
import {AppRoutingModule} from './app/app-routing.module'; import {AppRoutingModule} from './app/app-routing.module';
import {ServiceWorkerModule} from '@angular/service-worker'; import {ServiceWorkerModule} from '@angular/service-worker';
import {AngularFireModule} from '@angular/fire/compat';
import {AngularFireStorageModule} from '@angular/fire/compat/storage';
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome'; import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
import {AppComponent} from './app/app.component'; import {AppComponent} from './app/app.component';
import {getApp, initializeApp, provideFirebaseApp} from '@angular/fire/app'; import {getApp, initializeApp, provideFirebaseApp} from '@angular/fire/app';
import {initializeFirestore, persistentLocalCache, persistentMultipleTabManager, provideFirestore} from '@angular/fire/firestore'; import {initializeFirestore, persistentLocalCache, persistentMultipleTabManager, provideFirestore} from '@angular/fire/firestore';
import {getAuth, provideAuth} from '@angular/fire/auth'; import {getAuth, provideAuth} from '@angular/fire/auth';
import {getStorage, provideStorage} from '@angular/fire/storage';
import {UserService} from './app/services/user/user.service'; import {UserService} from './app/services/user/user.service';
declare global { declare global {
@@ -35,13 +34,12 @@ bootstrapApplication(AppComponent, {
ServiceWorkerModule.register('ngsw-worker.js', { ServiceWorkerModule.register('ngsw-worker.js', {
enabled: environment.production, enabled: environment.production,
}), }),
AngularFireModule.initializeApp(environment.firebase),
AngularFireStorageModule,
FontAwesomeModule FontAwesomeModule
), ),
provideFirebaseApp(() => initializeApp(environment.firebase)), provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAuth(() => getAuth()), provideAuth(() => getAuth()),
provideFirestore(() => initializeFirestore(getApp(), {localCache: persistentLocalCache({tabManager: persistentMultipleTabManager()})})), provideFirestore(() => initializeFirestore(getApp(), {localCache: persistentLocalCache({tabManager: persistentMultipleTabManager()})})),
provideStorage(() => getStorage()),
{provide: MAT_DATE_LOCALE, useValue: 'de-DE'}, {provide: MAT_DATE_LOCALE, useValue: 'de-DE'},
provideAnimations(), provideAnimations(),
], ],