asfoury/projmag

View on GitHub
app/src/main/java/com/sdp13epfl2021/projmag/database/impl/firebase/FirebaseFileDatabase.kt

Summary

Maintainability
A
0 mins
Test Coverage
B
85%
package com.sdp13epfl2021.projmag.database.impl.firebase

import android.net.Uri
import androidx.core.net.toUri
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.storage.FirebaseStorage
import com.google.firebase.storage.StorageReference
import com.sdp13epfl2021.projmag.database.interfaces.FileDatabase
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.File
import java.io.IOException
import java.util.*

/**
 * An implementation of FileDatabase using Firebase storage.
 */
class FirebaseFileDatabase(
    private val storage: FirebaseStorage,
    private val auth: FirebaseAuth
) : FileDatabase {

    /**
     * Reference of the root of users in Firebase Storage
     */
    private val rootRef = storage.reference.child("users")


    override fun getFile(
        fileUrl: String,
        destinationFolder: File,
        onSuccess: (File) -> Unit,
        onFailure: (Exception) -> Unit
    ) {
        val fileRef: StorageReference
        val destinationFile: File

        try {
            if (!destinationFolder.mkdirs() && !destinationFolder.isDirectory) {
                GlobalScope.launch { onFailure(IOException("The destination folder \"${destinationFolder.path}\" can't be created.")) }
                return
            }
            fileRef = storage.getReferenceFromUrl(fileUrl)
            destinationFile = File(destinationFolder, fileRef.name)
        } catch (e: Exception) {
            GlobalScope.launch { onFailure(e) }
            return
        }

        if (destinationFile.exists()) {
            GlobalScope.launch { onSuccess(destinationFile) }
            return
        }

        fileRef
            .getFile(destinationFile)
            .addOnSuccessListener { onSuccess(destinationFile) }
            .addOnFailureListener(onFailure)
    }


    override fun pushFile(
        file: File,
        onSuccess: (Uri) -> Unit,
        onFailure: (Exception) -> Unit
    ) {
        if (!file.exists() || !file.isFile) {
            GlobalScope.launch { onFailure(IOException("The file \"${file.path}\" can't be read.")) }
            return
        }

        pushFileFromUriWithName(
            file.toUri(),
            "${UUID.randomUUID()}_${file.name}",
            onSuccess,
            onFailure
        )
    }

    override fun pushFileFromUri(
        uri: Uri,
        onSuccess: (Uri) -> Unit,
        onFailure: (Exception) -> Unit
    ) {
        pushFileFromUriWithName(
            uri,
            UUID.randomUUID().toString(),
            onSuccess,
            onFailure
        )
    }

    private fun pushFileFromUriWithName(
        uri: Uri,
        filename: String,
        onSuccess: (Uri) -> Unit,
        onFailure: (Exception) -> Unit
    ) {

        val user = auth.currentUser
        if (user == null) {
            GlobalScope.launch { onFailure(SecurityException("Pushing file can only be done by authenticated user.")) }
            return
        }

        val fileRef = rootRef
            .child(user.uid)
            .child(filename)

        fileRef
            .putFile(uri)
            .continueWithTask { task ->
                if (!task.isSuccessful) {
                    task.exception?.let {
                        throw it
                    }
                }
                fileRef.downloadUrl
            }
            .addOnSuccessListener(onSuccess)
            .addOnFailureListener(onFailure)
    }


    override fun deleteFile(
        fileUrl: String,
        onSuccess: () -> Unit,
        onFailure: (Exception) -> Unit
    ) {
        storage
            .getReferenceFromUrl(fileUrl)
            .delete()
            .addOnSuccessListener { onSuccess() }
            .addOnFailureListener(onFailure)
    }

    override fun getFileName(fileUrl: String): String? {

        try {
            return storage.getReferenceFromUrl(fileUrl).name
        } catch (e: IllegalArgumentException) {
            return null
        }
    }

}