From 0203d4ea9d32f86b6bddb421878f6b60d1214343 Mon Sep 17 00:00:00 2001 From: benjamin Date: Mon, 9 Mar 2026 21:57:26 +0100 Subject: [PATCH] migrate firebase storage --- .../songs/services/file.service.spec.ts | 9 ++++++- .../modules/songs/services/file.service.ts | 12 ++++------ .../songs/services/upload.service.spec.ts | 12 +++++++++- .../modules/songs/services/upload.service.ts | 24 +++++++++++-------- .../songs/song/file/file.component.spec.ts | 2 ++ .../modules/songs/song/file/file.component.ts | 9 ++++--- src/main.ts | 6 ++--- 7 files changed, 46 insertions(+), 28 deletions(-) diff --git a/src/app/modules/songs/services/file.service.spec.ts b/src/app/modules/songs/services/file.service.spec.ts index a75c9e0..07e94a9 100644 --- a/src/app/modules/songs/services/file.service.spec.ts +++ b/src/app/modules/songs/services/file.service.spec.ts @@ -1,12 +1,19 @@ import {TestBed} from '@angular/core/testing'; +import {Storage} from '@angular/fire/storage'; import {FileService} from './file.service'; +import {FileDataService} from './file-data.service'; describe('FileService', () => { let service: FileService; beforeEach(() => { - void TestBed.configureTestingModule({}); + void TestBed.configureTestingModule({ + providers: [ + {provide: Storage, useValue: {}}, + {provide: FileDataService, useValue: {delete: () => Promise.resolve()}}, + ], + }); service = TestBed.inject(FileService); }); diff --git a/src/app/modules/songs/services/file.service.ts b/src/app/modules/songs/services/file.service.ts index 350d72a..fcd7ed2 100644 --- a/src/app/modules/songs/services/file.service.ts +++ b/src/app/modules/songs/services/file.service.ts @@ -1,6 +1,6 @@ import {Injectable} from '@angular/core'; -import {AngularFireStorage} from '@angular/fire/compat/storage'; -import {firstValueFrom, Observable} from 'rxjs'; +import {deleteObject, getDownloadURL, ref, Storage} from '@angular/fire/storage'; +import {from, Observable} from 'rxjs'; import {FileDataService} from './file-data.service'; @Injectable({ @@ -8,18 +8,16 @@ import {FileDataService} from './file-data.service'; }) export class FileService { public constructor( - private storage: AngularFireStorage, + private storage: Storage, private fileDataService: FileDataService ) {} public getDownloadUrl(path: string): Observable { - const ref = this.storage.ref(path); - return ref.getDownloadURL() as Observable; + return from(getDownloadURL(ref(this.storage, path))); } public delete(path: string, songId: string, fileId: string): void { - const ref = this.storage.ref(path); - void firstValueFrom(ref.delete()); + void deleteObject(ref(this.storage, path)); void this.fileDataService.delete(songId, fileId); } } diff --git a/src/app/modules/songs/services/upload.service.spec.ts b/src/app/modules/songs/services/upload.service.spec.ts index 11d88b0..6662f95 100644 --- a/src/app/modules/songs/services/upload.service.spec.ts +++ b/src/app/modules/songs/services/upload.service.spec.ts @@ -1,9 +1,19 @@ import {TestBed} from '@angular/core/testing'; +import {Storage} from '@angular/fire/storage'; import {UploadService} from './upload.service'; +import {FileDataService} from './file-data.service'; describe('UploadServiceService', () => { - beforeEach(() => void TestBed.configureTestingModule({})); + beforeEach( + () => + void TestBed.configureTestingModule({ + providers: [ + {provide: Storage, useValue: {}}, + {provide: FileDataService, useValue: {set: () => Promise.resolve('')}}, + ], + }) + ); it('should be created', () => { const service: UploadService = TestBed.inject(UploadService); diff --git a/src/app/modules/songs/services/upload.service.ts b/src/app/modules/songs/services/upload.service.ts index c25c29b..4905f8f 100644 --- a/src/app/modules/songs/services/upload.service.ts +++ b/src/app/modules/songs/services/upload.service.ts @@ -1,8 +1,7 @@ import {Injectable} from '@angular/core'; import {Upload} from './upload'; import {FileDataService} from './file-data.service'; -import {AngularFireStorage} from '@angular/fire/compat/storage'; -import {finalize} from 'rxjs/operators'; +import {ref, Storage, uploadBytesResumable} from '@angular/fire/storage'; import {FileBase} from './fileBase'; import {FileServer} from './fileServer'; @@ -12,7 +11,7 @@ import {FileServer} from './fileServer'; export class UploadService extends FileBase { public constructor( private fileDataService: FileDataService, - private angularFireStorage: AngularFireStorage + private storage: Storage ) { super(); } @@ -22,14 +21,19 @@ export class UploadService extends FileBase { const filePath = `${directory}/${upload.file.name}`; upload.path = directory; - const ref = this.angularFireStorage.ref(filePath); - const task = ref.put(upload.file); + const storageRef = ref(this.storage, filePath); + const task = uploadBytesResumable(storageRef, upload.file); - task.percentageChanges().subscribe(percent => (upload.progress = percent ?? 0)); - task - .snapshotChanges() - .pipe(finalize(() => void this.saveFileData(songId, upload))) - .subscribe(); + task.on( + 'state_changed', + snapshot => { + upload.progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; + }, + () => { + // Keep current UX: upload errors are ignored by this service. + }, + () => void this.saveFileData(songId, upload) + ); } private async saveFileData(songId: string, upload: Upload) { diff --git a/src/app/modules/songs/song/file/file.component.spec.ts b/src/app/modules/songs/song/file/file.component.spec.ts index ceb111e..7dba811 100644 --- a/src/app/modules/songs/song/file/file.component.spec.ts +++ b/src/app/modules/songs/song/file/file.component.spec.ts @@ -1,4 +1,5 @@ import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; +import {Storage} from '@angular/fire/storage'; import {FileComponent} from './file.component'; @@ -9,6 +10,7 @@ describe('FileComponent', () => { beforeEach(waitForAsync(() => { void TestBed.configureTestingModule({ imports: [FileComponent], + providers: [{provide: Storage, useValue: {}}], }).compileComponents(); })); diff --git a/src/app/modules/songs/song/file/file.component.ts b/src/app/modules/songs/song/file/file.component.ts index 1122949..4ece8f8 100644 --- a/src/app/modules/songs/song/file/file.component.ts +++ b/src/app/modules/songs/song/file/file.component.ts @@ -1,7 +1,7 @@ import {Component, Input} from '@angular/core'; import {File} from '../../services/file'; -import {AngularFireStorage} from '@angular/fire/compat/storage'; -import {Observable} from 'rxjs'; +import {getDownloadURL, ref, Storage} from '@angular/fire/storage'; +import {from, Observable} from 'rxjs'; import {AsyncPipe} from '@angular/common'; @Component({ @@ -14,12 +14,11 @@ export class FileComponent { public url$: Observable | null = null; public name = ''; - public constructor(private storage: AngularFireStorage) {} + public constructor(private storage: Storage) {} @Input() public set file(file: File) { - const ref = this.storage.ref(file.path + '/' + file.name); - this.url$ = ref.getDownloadURL() as Observable; + this.url$ = from(getDownloadURL(ref(this.storage, file.path + '/' + file.name))); this.name = file.name; } } diff --git a/src/main.ts b/src/main.ts index 296a640..e8939e7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,13 +6,12 @@ import {bootstrapApplication, BrowserModule} from '@angular/platform-browser'; import {provideAnimations} from '@angular/platform-browser/animations'; import {AppRoutingModule} from './app/app-routing.module'; 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 {AppComponent} from './app/app.component'; import {getApp, initializeApp, provideFirebaseApp} from '@angular/fire/app'; import {initializeFirestore, persistentLocalCache, persistentMultipleTabManager, provideFirestore} from '@angular/fire/firestore'; import {getAuth, provideAuth} from '@angular/fire/auth'; +import {getStorage, provideStorage} from '@angular/fire/storage'; import {UserService} from './app/services/user/user.service'; declare global { @@ -35,13 +34,12 @@ bootstrapApplication(AppComponent, { ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production, }), - AngularFireModule.initializeApp(environment.firebase), - AngularFireStorageModule, FontAwesomeModule ), provideFirebaseApp(() => initializeApp(environment.firebase)), provideAuth(() => getAuth()), provideFirestore(() => initializeFirestore(getApp(), {localCache: persistentLocalCache({tabManager: persistentMultipleTabManager()})})), + provideStorage(() => getStorage()), {provide: MAT_DATE_LOCALE, useValue: 'de-DE'}, provideAnimations(), ],