Skip to content
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.crafto.crafto_backend.config

import com.crafto.crafto_backend.constant.AppConstants.FileUpload.MAX_FILE_SIZE_MB
import com.crafto.crafto_backend.constant.AppConstants.FileUpload.MAX_REQUEST_SIZE_MB
import jakarta.servlet.MultipartConfigElement
import org.springframework.boot.web.servlet.MultipartConfigFactory
import org.springframework.context.annotation.Bean
Expand All @@ -13,8 +15,8 @@ class FileUploadConfiguration {
@Bean
fun multipartConfigElement(): MultipartConfigElement {
val factory = MultipartConfigFactory()
factory.setMaxFileSize(DataSize.ofMegabytes(4))
factory.setMaxRequestSize(DataSize.ofMegabytes(16))
factory.setMaxFileSize(DataSize.ofMegabytes(MAX_FILE_SIZE_MB.toLong()))
factory.setMaxRequestSize(DataSize.ofMegabytes(MAX_REQUEST_SIZE_MB.toLong()))
return factory.createMultipartConfig()
}
}
27 changes: 18 additions & 9 deletions src/main/kotlin/com/crafto/crafto_backend/config/FirebaseConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,25 @@ import com.google.firebase.FirebaseApp
import com.google.firebase.FirebaseOptions
import com.google.firebase.cloud.StorageClient
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.io.ClassPathResource
import java.io.IOException
import java.io.InputStream
import javax.annotation.PostConstruct

@Configuration
@EnableConfigurationProperties(FirebaseStorageProperties::class)
class FirebaseConfig {
@Value("\${firebase.bucket-name}")
private lateinit var bucketName: String

@Bean
fun firebaseStorage(): StorageClient {
@Value("\${firebase.config.path}")
private lateinit var firebaseConfigPath: String

@PostConstruct
fun initializeFirebase() {
try {
val serviceAccount: InputStream = ClassPathResource("firebase-service-account.json").inputStream
val serviceAccount = ClassPathResource(firebaseConfigPath).inputStream

val options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
Expand All @@ -28,11 +32,16 @@ class FirebaseConfig {

if (FirebaseApp.getApps().isEmpty()) {
FirebaseApp.initializeApp(options)
println("Firebase initialized successfully with bucket: $bucketName")
}

return StorageClient.getInstance()
} catch (e: IOException) {
throw RuntimeException("Failed to initialize Firebase Storage", e)
} catch (e: Exception) {
println("Error initializing Firebase: ${e.message}")
throw RuntimeException("Failed to initialize Firebase", e)
}
}

@Bean
fun storageClient(): StorageClient {
return StorageClient.getInstance()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.crafto.crafto_backend.config

import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties(prefix = "firebase.storage")
data class FirebaseStorageProperties(
val bucket: String,
val downloadUrl: String
) {
fun generateUrl(filePath: String): String {
return String.format(downloadUrl, bucket, filePath)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ object AppConstants {

// File upload limits
object FileUpload {
const val MAX_FILE_SIZE_MB = 4
const val MAX_FILE_SIZE_MB = 5
const val MAX_REQUEST_SIZE_MB = 16
const val MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024
const val MAX_REQUEST_SIZE_BYTES = MAX_REQUEST_SIZE_MB * 1024 * 1024
val ALLOWED_IMAGE_TYPES = listOf("image/jpeg", "image/png", "image/jpg")
val allowedMimeTypes = mapOf(
"image/jpeg" to "jpg",
"image/jpg" to "jpg",
"image/png" to "png",
"image/webp" to "webp",
)
val ALLOWED_IMAGE_EXTENSIONS = listOf("jpg", "jpeg", "png")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
import com.crafto.crafto_backend.service.exception.UserNotFoundException
import com.crafto.crafto_backend.utils.getFileExtension
import com.crafto.crafto_backend.utils.validateImageFile
import com.crafto.crafto_backend.utils.validateImageFiles
import org.apache.coyote.BadRequestException

Check warning on line 25 in src/main/kotlin/com/crafto/crafto_backend/service/CraftsmanService.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this unused import.

See more on https://sonarcloud.io/project/issues?id=Crafto-Android_crafto_backend&issues=AZsTCGLwUApUWBXNxwVG&open=AZsTCGLwUApUWBXNxwVG&pullRequest=15
import org.bson.types.ObjectId
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
Expand Down Expand Up @@ -108,15 +109,15 @@

try {
// Upload new files
newIdFrontUrl = firebaseStorageService.uploadFile(
newIdFrontUrl = firebaseStorageService.uploadImage(
file = idCardFront,
folder = AppConstants.StoragePaths.craftsmanIdCards(craftsmanId),
folderName = AppConstants.StoragePaths.craftsmanIdCards(craftsmanId),
fileName = "id-front-${System.currentTimeMillis()}.${getFileExtension(idCardFront)}"
)

newIdBackUrl = firebaseStorageService.uploadFile(
newIdBackUrl = firebaseStorageService.uploadImage(
file = idCardBack,
folder = AppConstants.StoragePaths.craftsmanIdCards(craftsmanId),
folderName = AppConstants.StoragePaths.craftsmanIdCards(craftsmanId),
fileName = "id-back-${System.currentTimeMillis()}.${getFileExtension(idCardBack)}"
)

Expand Down Expand Up @@ -165,9 +166,9 @@

// Upload new work images
val workUrls = workImages.mapIndexed { index, file ->
firebaseStorageService.uploadFile(
firebaseStorageService.uploadImage(
file = file,
folder = AppConstants.StoragePaths.craftsmanWorkPortfolio(craftsmanId),
folderName = AppConstants.StoragePaths.craftsmanWorkPortfolio(craftsmanId),
fileName = "work-${System.currentTimeMillis()}-$index.${getFileExtension(file)}"
)
}
Expand Down Expand Up @@ -205,9 +206,9 @@
}

// Upload new profile picture
val profilePictureUrl = firebaseStorageService.uploadFile(
val profilePictureUrl = firebaseStorageService.uploadImage(
file = profilePicture,
folder = AppConstants.StoragePaths.craftsmanProfilePicture(craftsmanId),
folderName = AppConstants.StoragePaths.craftsmanProfilePicture(craftsmanId),
fileName = "profile-${System.currentTimeMillis()}.${getFileExtension(profilePicture)}"
)

Expand Down Expand Up @@ -278,30 +279,6 @@
return craftsman
}

private fun validateImageFiles(
files: List<MultipartFile>,
fileType: String = "Image",
maxSizeBytes: Int = AppConstants.FileUpload.MAX_FILE_SIZE_BYTES
) {
files.forEach { file ->
if (file.isEmpty) {
throw BadRequestException("Empty file uploaded") //////
}

if (!AppConstants.FileUpload.ALLOWED_IMAGE_TYPES.contains(file.contentType)) {
throw BadRequestException(
"$fileType must be ${AppConstants.FileUpload.ALLOWED_IMAGE_EXTENSIONS} format"
)
}

if (file.size > maxSizeBytes) {
throw BadRequestException(
"$fileType ${file.originalFilename} exceeds ${AppConstants.FileUpload.MAX_FILE_SIZE_MB} MB limit"
)
}
}
}

private fun validateWorkImages(files: List<MultipartFile>) {
validateImageFiles(files, fileType = "Work image")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ class CustomerService(
private val customerRepository: CustomerRepository,
private val customerIssueRepository: CustomerIssueRepository,
private val categoryRepository: CategoryRepository,
private val imageStorageService: ImageStorageService,
private val offerRepository: CraftsmanOfferRepository,
private val firebaseStorageService: FirebaseStorageService
) {
Expand Down Expand Up @@ -104,7 +103,7 @@ class CustomerService(
fun uploadProductImages(customer: Customer, files: List<MultipartFile>): List<String> {
val imageUrls = mutableListOf<String>()
files.forEach { file ->
val imageUrl = imageStorageService.uploadImage(
val imageUrl = firebaseStorageService.uploadImage(
file = file,
fileName = "${customer.id}-${file.originalFilename}",
folderName = IMAGE_FOLDER_NAME
Expand Down Expand Up @@ -180,9 +179,9 @@ class CustomerService(
}

// Upload new photo
val profilePictureUrl = firebaseStorageService.uploadFile(
val profilePictureUrl = firebaseStorageService.uploadImage(
file = profilePicture,
folder = AppConstants.StoragePaths.customerProfilePicture(customerId),
folderName = AppConstants.StoragePaths.customerProfilePicture(customerId),
fileName = "profile-${System.currentTimeMillis()}.${getFileExtension(profilePicture)}"
)

Expand Down
Loading