Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use dedicated object storage #879

Merged
merged 15 commits into from
Mar 26, 2025
Merged
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
1 change: 1 addition & 0 deletions backend/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@ repositories {

dependencies {
implementation("com.google.firebase:firebase-admin:9.3.0")
implementation("software.amazon.awssdk:s3:2.30.32")
implementation("jakarta.xml.bind:jakarta.xml.bind-api:4.0.2")
implementation("org.springframework.boot:spring-boot-configuration-processor")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
2 changes: 2 additions & 0 deletions backend/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
org.gradle.jvmargs=-Xmx4G
kotlin.daemon.jvmargs=-Xmx4G
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default is 0.5G. Why do we need that much?

Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ const val OVERVIEW_TYPE_BOOLEAN = "boolean"
const val OVERVIEW_TYPE_ICON = "icon"
const val OVERVIEW_TYPE_TIME = "time"
const val OVERVIEW_TYPE_NUMBER = "number"
const val OVERVIEW_TYPE_CDN_IMAGE = "cdn-image"
const val OVERVIEW_TYPE_IMAGE = "image"

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
@@ -17,7 +17,6 @@ annotation class GenerateOverview(
val centered: Boolean = false,
val order: Int = 0,
val renderer: String = OVERVIEW_TYPE_TEXT,
val cdnImageFolder: String = "",
val useForSearch: Boolean = true
)

@@ -42,9 +41,9 @@ fun GenerateOverview.sorter(): String {
}

fun GenerateOverview.formatValue(value: Any?): Any =
if (renderer == OVERVIEW_TYPE_CDN_IMAGE) {
if (renderer == OVERVIEW_TYPE_IMAGE) {
if (value is String && value.isNotBlank())
"/cdn/${cdnImageFolder}/${value}"
value
else
"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" // empty image
} else if (renderer == OVERVIEW_TYPE_TEXT || renderer == OVERVIEW_TYPE_ICON) {
@@ -59,7 +58,7 @@ fun GenerateOverview.extra(): Array<Pair<String, Any>> {
OVERVIEW_TYPE_TEXT -> arrayOf("vertAlign" to "middle")
OVERVIEW_TYPE_DATE -> arrayOf("vertAlign" to "middle", "formatter" to "datetime")
OVERVIEW_TYPE_BOOLEAN -> arrayOf("formatter" to "tickCross", "width" to 120)
OVERVIEW_TYPE_CDN_IMAGE -> arrayOf(
OVERVIEW_TYPE_IMAGE -> arrayOf(
"formatter" to "image",
"width" to 120,
"formatterParams" to mapOf("height" to "100px")
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@ import hu.bme.sch.cmsch.model.RoleType
import hu.bme.sch.cmsch.service.*
import hu.bme.sch.cmsch.setting.SettingType
import hu.bme.sch.cmsch.util.getUser
import hu.bme.sch.cmsch.util.uploadFile
import org.slf4j.LoggerFactory
import org.springframework.security.core.Authentication
import org.springframework.ui.Model
@@ -27,7 +26,8 @@ abstract class ComponentApiBase(
private val insertComponentCategory: Boolean = true,
private val componentCategory: String = componentClass.simpleName,
private val menuService: MenuService,
private val auditLogService: AuditLogService
private val auditLogService: AuditLogService,
private val storageService: StorageService
) {

private val log = LoggerFactory.getLogger(javaClass)
@@ -100,9 +100,10 @@ abstract class ComponentApiBase(
SettingType.IMAGE -> {
multipartRequest.fileMap[setting.property]?.let {
if (it.size > 0) {
log.info("Uploading image {}.{} size: {}", setting.component, setting.property, it.size)
newValues.append(setting.property).append("=size@").append(it.size).append(", ")
it.uploadFile("manifest", setting.rawValue.split("/").last())
val (path, name) = setting.rawValue.split("/")
val url = storageService.saveNamedObject(path, name, it)
log.info("Uploading image {}.{} url: {}", setting.component, setting.property, url)
newValues.append(setting.property).append("=url@").append(url).append(", ")
}
}
}
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ import hu.bme.sch.cmsch.controller.admin.SimpleEntityPage
import hu.bme.sch.cmsch.model.IdentifiableEntity
import hu.bme.sch.cmsch.service.AdminMenuService
import hu.bme.sch.cmsch.service.AuditLogService
import hu.bme.sch.cmsch.service.StorageService
import hu.bme.sch.cmsch.service.ImportService
import hu.bme.sch.cmsch.service.StaffPermissions.PERMISSION_EXPORT_ADMISSION
import hu.bme.sch.cmsch.service.StaffPermissions.PERMISSION_VALIDATE_ADMISSION
@@ -51,7 +52,8 @@ class AdmissionByFormController(
auditLog: AuditLogService,
objectMapper: ObjectMapper,
transactionManager: PlatformTransactionManager,
env: Environment
env: Environment,
storageService: StorageService
) : SimpleEntityPage<AdmissionFormEntry>(
"admission-by-form",
AdmissionFormEntry::class, ::AdmissionFormEntry,
@@ -71,6 +73,7 @@ class AdmissionByFormController(

importService,
adminMenuService,
storageService,
component,
auditLog,
objectMapper,
@@ -137,4 +140,3 @@ class AdmissionByFormController(
}

}

Original file line number Diff line number Diff line change
@@ -14,7 +14,8 @@ class AdmissionComponentController(
adminMenuService: AdminMenuService,
component: AdmissionComponent,
menuService: MenuService,
auditLogService: AuditLogService
auditLogService: AuditLogService,
storageService: StorageService
) : ComponentApiBase(
adminMenuService,
AdmissionComponent::class.java,
@@ -23,7 +24,8 @@ class AdmissionComponentController(
componentCategoryName = "Beléptetés",
componentMenuName = "Jogosultságok",
menuService = menuService,
auditLogService = auditLogService
auditLogService = auditLogService,
storageService = storageService
) {
init {
adminMenuService.registerEntry(AdmissionComponent::class.java.simpleName, AdminMenuEntry(
Original file line number Diff line number Diff line change
@@ -3,10 +3,7 @@ package hu.bme.sch.cmsch.component.admission
import com.fasterxml.jackson.databind.ObjectMapper
import hu.bme.sch.cmsch.controller.admin.OneDeepEntityPage
import hu.bme.sch.cmsch.controller.admin.calculateSearchSettings
import hu.bme.sch.cmsch.service.AdminMenuService
import hu.bme.sch.cmsch.service.AuditLogService
import hu.bme.sch.cmsch.service.ImportService
import hu.bme.sch.cmsch.service.StaffPermissions
import hu.bme.sch.cmsch.service.*
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.core.env.Environment
import org.springframework.stereotype.Controller
@@ -25,6 +22,7 @@ class AdmissionController(
objectMapper: ObjectMapper,
env: Environment,
transactionManager: PlatformTransactionManager,
storageService: StorageService,
) : OneDeepEntityPage<AdmissionEntryEntity>(
"admission-entries",
AdmissionEntryEntity::class, ::AdmissionEntryEntity,
@@ -35,6 +33,7 @@ class AdmissionController(
repo,
importService,
adminMenuService,
storageService,
component,
auditLog,
objectMapper,
Original file line number Diff line number Diff line change
@@ -3,10 +3,7 @@ package hu.bme.sch.cmsch.component.admission
import com.fasterxml.jackson.databind.ObjectMapper
import hu.bme.sch.cmsch.controller.admin.OneDeepEntityPage
import hu.bme.sch.cmsch.controller.admin.calculateSearchSettings
import hu.bme.sch.cmsch.service.AdminMenuService
import hu.bme.sch.cmsch.service.AuditLogService
import hu.bme.sch.cmsch.service.ImportService
import hu.bme.sch.cmsch.service.StaffPermissions
import hu.bme.sch.cmsch.service.*
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.core.env.Environment
import org.springframework.stereotype.Controller
@@ -25,6 +22,7 @@ class TicketController(
objectMapper: ObjectMapper,
env: Environment,
transactionManager: PlatformTransactionManager,
storageService: StorageService
) : OneDeepEntityPage<TicketEntity>(
"tickets",
TicketEntity::class, ::TicketEntity,
@@ -35,6 +33,7 @@ class TicketController(
repo,
importService,
adminMenuService,
storageService,
component,
auditLog,
objectMapper,
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import hu.bme.sch.cmsch.component.ComponentApiBase
import hu.bme.sch.cmsch.service.AdminMenuCategory
import hu.bme.sch.cmsch.service.AdminMenuService
import hu.bme.sch.cmsch.service.AuditLogService
import hu.bme.sch.cmsch.service.StorageService
import hu.bme.sch.cmsch.service.ControlPermissions.PERMISSION_CONTROL_APP
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.core.env.Environment
@@ -18,7 +19,8 @@ class ApplicationComponentController(
component: ApplicationComponent,
menuService: MenuService,
private val env: Environment,
auditLogService: AuditLogService
auditLogService: AuditLogService,
storageService: StorageService
) : ComponentApiBase(
adminMenuService,
ApplicationComponent::class.java,
@@ -30,7 +32,8 @@ class ApplicationComponentController(
menuService = menuService,
insertComponentCategory = false,
componentCategory = ApplicationComponent.FUNCTIONALITIES_CATEGORY,
auditLogService = auditLogService
auditLogService = auditLogService,
storageService = storageService
) {

override fun onUpdate() {
@@ -66,4 +69,3 @@ class ApplicationComponentController(
}

}

Original file line number Diff line number Diff line change
@@ -22,7 +22,8 @@ class ExtraMenuController(
auditLog: AuditLogService,
objectMapper: ObjectMapper,
transactionManager: PlatformTransactionManager,
env: Environment
env: Environment,
storageService: StorageService
) : OneDeepEntityPage<ExtraMenuEntity>(
"extra-menus",
ExtraMenuEntity::class, ::ExtraMenuEntity,
@@ -33,6 +34,7 @@ class ExtraMenuController(
repo,
importService,
adminMenuService,
storageService,
component,
auditLog,
objectMapper,
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ package hu.bme.sch.cmsch.component.app
import hu.bme.sch.cmsch.component.ComponentApiBase
import hu.bme.sch.cmsch.service.AdminMenuService
import hu.bme.sch.cmsch.service.AuditLogService
import hu.bme.sch.cmsch.service.StorageService
import hu.bme.sch.cmsch.service.ControlPermissions
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.stereotype.Controller
@@ -15,7 +16,8 @@ class FooterComponentController(
adminMenuService: AdminMenuService,
component: FooterComponent,
menuService: MenuService,
auditLogService: AuditLogService
auditLogService: AuditLogService,
storageService: StorageService
) : ComponentApiBase(
adminMenuService,
FooterComponent::class.java,
@@ -26,5 +28,6 @@ class FooterComponentController(
menuService = menuService,
insertComponentCategory = false,
componentCategory = ApplicationComponent.STYLING_CATEGORY,
auditLogService = auditLogService
)
auditLogService = auditLogService,
storageService = storageService
)
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
package hu.bme.sch.cmsch.component.app

import hu.bme.sch.cmsch.service.StorageService
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

const val IMAGE_PNG = "image/png"

@RestController
@RequestMapping("/manifest")
@ConditionalOnBean(ApplicationComponent::class)
class ManifestApiController(
private val manifestComponent: ManifestComponent,
private val applicationComponent: ApplicationComponent
private val storageService: StorageService,
) {

@GetMapping("/manifest.json")
fun manifestJson(): ManifestJsonView {
val baseUrl = applicationComponent.adminSiteUrl.getValue()
return ManifestJsonView(
theme_color = manifestComponent.themeColor.getValue(),
background_color = manifestComponent.backgroundColor.getValue(),
@@ -29,25 +28,28 @@ class ManifestApiController(
description = manifestComponent.description.getValue(),
icons = listOf(
ManifestIconView(
src = "${baseUrl}cdn/manifest/icon-192x192.png",
src = storageService.getObjectUrl("manifest/icon-192x192.png").orElse(""),
sizes = "192x192",
type = IMAGE_PNG),
type = MediaType.IMAGE_PNG_VALUE
),
ManifestIconView(
src = "${baseUrl}cdn/manifest/icon-256x256.png",
src = storageService.getObjectUrl("manifest/icon-256x256.png").orElse(""),
sizes = "256x256",
type = IMAGE_PNG),
type = MediaType.IMAGE_PNG_VALUE
),
ManifestIconView(
src = "${baseUrl}cdn/manifest/icon-384x384.png",
src = storageService.getObjectUrl("manifest/icon-384x384.png").orElse(""),
sizes = "384x384",
type = IMAGE_PNG),
type = MediaType.IMAGE_PNG_VALUE
),
ManifestIconView(
src = "${baseUrl}cdn/manifest/icon-512x512.png",
src = storageService.getObjectUrl("manifest/icon-512x512.png").orElse(""),
sizes = "512x512",
type = IMAGE_PNG),
type = MediaType.IMAGE_PNG_VALUE
),
)
)
}

}

data class ManifestJsonView(
@@ -63,7 +65,5 @@ data class ManifestJsonView(
)

data class ManifestIconView(
val src: String,
val sizes: String,
val type: String
val src: String, val sizes: String, val type: String
)
Original file line number Diff line number Diff line change
@@ -111,31 +111,31 @@ class ManifestComponent(
)

val favicon = SettingProxy(componentSettingService, component,
"favicon", "/cdn/manifest/favicon.ico",
"favicon", "manifest/favicon.ico",
type = SettingType.IMAGE, serverSideOnly = true, persist = false,
fieldName = "Favicon", description = "16x16-os ico fájl"
)

val icon192 = SettingProxy(componentSettingService, component,
"icon192", "/cdn/manifest/icon-192x192.png",
"icon192", "manifest/icon-192x192.png",
type = SettingType.IMAGE, serverSideOnly = true, persist = false,
fieldName = "Ikon 192", description = "192x192 pixeles png fájl"
)

val icon256 = SettingProxy(componentSettingService, component,
"icon256", "/cdn/manifest/icon-256x256.png",
"icon256", "manifest/icon-256x256.png",
type = SettingType.IMAGE, serverSideOnly = true, persist = false,
fieldName = "Ikon 256", description = "256x256 pixeles png fájl"
)

val icon384 = SettingProxy(componentSettingService, component,
"icon384", "/cdn/manifest/icon-384x384.png",
"icon384", "manifest/icon-384x384.png",
type = SettingType.IMAGE, serverSideOnly = true, persist = false,
fieldName = "Ikon 384", description = "384x384 pixeles png fájl"
)

val icon512 = SettingProxy(componentSettingService, component,
"icon512", "/cdn/manifest/icon-512x512.png",
"icon512", "manifest/icon-512x512.png",
type = SettingType.IMAGE, serverSideOnly = true, persist = false,
fieldName = "Ikon 512", description = "512x512 pixeles png fájl"
)
Loading