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

Image carousel revive #763

Open
wants to merge 9 commits into
base: staging
Choose a base branch
from
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
60 changes: 0 additions & 60 deletions backend/.kotlin/errors/errors-1724509699010.log

This file was deleted.

5 changes: 4 additions & 1 deletion backend/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ group = "hu.bme.sch"
version = "4.8.0"
java.sourceCompatibility = JavaVersion.VERSION_21

springBoot {
buildInfo()
}

tasks {
bootJar {
archiveFileName.set("cmsch.jar")
Expand Down Expand Up @@ -78,4 +82,3 @@ tasks.withType<KotlinCompile> {
tasks.withType<Test> {
useJUnitPlatform()
}

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +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"

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

Expand Down Expand Up @@ -45,6 +47,7 @@ fun GenerateOverview.extra(): String {
OVERVIEW_TYPE_TEXT -> ", \"vertAlign\":\"middle\""
OVERVIEW_TYPE_DATE -> ", \"vertAlign\":\"middle\",\"formatter\":\"datetime\""
OVERVIEW_TYPE_BOOLEAN -> ", \"formatter\":\"tickCross\", \"width\":120"
OVERVIEW_TYPE_CDN_IMAGE -> ", \"formatter\":\"image\", \"width\":120, \"formatterParams\":{\"height\":\"100px\"}"
OVERVIEW_TYPE_TIME -> ", \"vertAlign\":\"middle\""
OVERVIEW_TYPE_NUMBER -> ", \"vertAlign\":\"middle\""
OVERVIEW_TYPE_ICON -> ", \"vertAlign\":\"middle\", \"formatter\":\"enumIconsFormatter\", \"width\":120"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package hu.bme.sch.cmsch.admin
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import hu.bme.sch.cmsch.controller.admin.ControlAction
import org.hibernate.Hibernate
import java.io.ByteArrayOutputStream
import kotlin.reflect.KClass
import kotlin.reflect.KProperty1
Expand Down Expand Up @@ -35,7 +34,12 @@ class OverviewBuilder<T : Any>(val type: KClass<T>) {
}

private fun formatValue(type: GenerateOverview, value: Any?): String {
return if (type.renderer == OVERVIEW_TYPE_TEXT || type.renderer == OVERVIEW_TYPE_ICON) {
return if (type.renderer == OVERVIEW_TYPE_CDN_IMAGE) {
if (value is String && !value.isNullOrBlank())
"\"/cdn/${type.cdnImageFolder}/${value}\""
else
"\"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\"" // empty image
} else if (type.renderer == OVERVIEW_TYPE_TEXT || type.renderer == OVERVIEW_TYPE_ICON) {
"\"${(value ?: "").toString().replace("\"", "")}\""
} else {
(value ?: "0").toString().replace("\"", "")
Expand Down Expand Up @@ -79,4 +83,4 @@ object DetailsHelper {
return inputs.map { it.second.type }.distinct().toList()
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,46 +9,36 @@ import hu.bme.sch.cmsch.service.AdminMenuService
import hu.bme.sch.cmsch.service.AuditLogService
import hu.bme.sch.cmsch.service.ImplicitPermissions
import hu.bme.sch.cmsch.util.getUser
import hu.bme.sch.cmsch.util.transaction
import org.slf4j.LoggerFactory
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.security.core.Authentication
import org.springframework.stereotype.Controller
import org.springframework.transaction.PlatformTransactionManager
import org.springframework.transaction.TransactionDefinition
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.atomic.LongAdder
import javax.imageio.ImageIO
import kotlin.jvm.optionals.getOrNull

private const val SELECTOR_TYPE = "selectorType"

private const val VIEW = "task-disc-optimize"

const val EXPORT_PATH = "export"

@Controller
@RequestMapping("/admin/control/$VIEW")
@ConditionalOnBean(value = [TaskComponent::class])
class TaskDiscOptimizerDashboard(
adminMenuService: AdminMenuService,
applicationComponent: TaskComponent,
auditLogService: AuditLogService,
private val platformTransactionManager: PlatformTransactionManager,
private val taskSubmissionsRepository: Optional<SubmittedTaskRepository>,
private val startupPropertyConfig: StartupPropertyConfig,
private val imageRescaleService: TaskImageRescaleService
) : DashboardPage(
view = VIEW,
title = "Disc Optimize",
title = "Disc Optimizer",
description = "",
wide = false,
adminMenuService = adminMenuService,
Expand All @@ -69,6 +59,7 @@ class TaskDiscOptimizerDashboard(

internal val processStatus = AtomicReference("nincs exportálva")
internal val processCount = LongAdder()
internal val processReduction = LongAdder()
internal val processRunning = AtomicBoolean(false)

private val threadFactory = ThreadFactoryBuilder()
Expand All @@ -91,13 +82,14 @@ class TaskDiscOptimizerDashboard(
private fun exportStatus(): DashboardTableCard {
return DashboardTableCard(
id = 2,
title = "Export eredménye",
description = "Ha üres, akkor még nem volt exportálva",
title = "Optimalizálás eredménye",
description = "Ha üres, akkor még nem volt optimalizálva",
header = listOf("Kulcs", "Érték"),
content = listOf(
listOf("Exportálás folyamatban", if (processRunning.get()) "igen" else "nem"),
listOf("Exportálás státusza", processStatus.get()),
listOf("Counter", processCount.sum().toString()),
listOf("Spórolás (byte)", processReduction.sum().toString()),
),
wide = wide,
exportable = false
Expand All @@ -108,7 +100,7 @@ class TaskDiscOptimizerDashboard(
return DashboardFormCard(
id = 3,
wide = wide,
title = "Exportálás indítása",
title = "Optimalizálás indítása",
description = "",
content = listOf(
),
Expand All @@ -132,11 +124,10 @@ class TaskDiscOptimizerDashboard(
return dashboardPage(view = VIEW, card = 2, message = "Már fut exportálás")
processRunning.set(true)
executorService.submit(TaskImageOptimizerTask(
platformTransactionManager = platformTransactionManager,
taskSubmissionsRepository = taskSubmissionsRepository,
processStatus = processStatus,
processRunning = processRunning,
processCount = processCount,
processReduction = processReduction,
startupPropertyConfig = startupPropertyConfig,
imageRescaleService = imageRescaleService,
))
Expand All @@ -156,74 +147,57 @@ class TaskDiscOptimizerDashboard(
}

class TaskImageOptimizerTask(
private val platformTransactionManager: PlatformTransactionManager,
taskSubmissionsRepository: Optional<SubmittedTaskRepository>,

private val processStatus: AtomicReference<String>,
private val processRunning: AtomicBoolean,
private val processCount: LongAdder,
private val processReduction: LongAdder,
private val startupPropertyConfig: StartupPropertyConfig,

private val imageRescaleService: TaskImageRescaleService,
) : Runnable {

private val taskSubmissionsRepository = taskSubmissionsRepository.getOrNull()

override fun run() {
processStatus.set("Optimizer elindult")

try {
val tasks = platformTransactionManager.transaction(readOnly = true, isolation = TransactionDefinition.ISOLATION_READ_COMMITTED) {
taskSubmissionsRepository!!.findAll()
}
imgonnakillmyself@for (selectedTask in tasks) {
if (selectedTask.imageUrlAnswer.isNotBlank()) {
println("NOT BLANK ${selectedTask.id} for ${selectedTask.task?.id}")
val newName = resizeImage(selectedTask.imageUrlAnswer)

if (newName != null) {
selectedTask.imageUrlAnswer = newName
platformTransactionManager.transaction(readOnly = false) {
taskSubmissionsRepository!!.save(selectedTask)
println(" - SAVED $newName")
}
processCount.increment()
break@imgonnakillmyself
} else {
println(" - SMALL ENOUGH")
}
} else {
println("BLANK ${selectedTask.id}")
}
Files.walk(Path.of(startupPropertyConfig.external, "task"))
.filter {
val fileName = it.fileName.toString().lowercase()
val image = fileName.endsWith(".png") || fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")
println("$fileName $image")
return@filter image
}
.forEach { !resizeImage(it.toFile()) }

} catch (e: Exception) {
e.printStackTrace()
}
processStatus.set("Optimizer kész")
processRunning.set(false)
}

private fun resizeImage(fileFromCdn: String): String? {
val inputFile = File(startupPropertyConfig.external, fileFromCdn)
println("RESCALE $fileFromCdn ${inputFile.length()}")
private fun resizeImage(inputFile: File): Boolean {
processCount.increment()
val oldLength = inputFile.length()
println("RESCALE $inputFile $oldLength")
val MAX_HEIGHT_WIDTH = 1000

val megaByte = 1024 * 1024
if (inputFile.length() < (1 * megaByte)) {
val kiloByte = 1024
if (inputFile.length() > (120 * kiloByte)) {
val inputImage = ImageIO.read(inputFile)
val resizedImage = imageRescaleService.resizeImage(inputImage, 800, 800)
var outputPath = Path.of(startupPropertyConfig.external, fileFromCdn).toString()
outputPath = outputPath.substringBeforeLast(".") + ".jpg"
val outputFile = File(outputPath)

println(" - OUTPUT: $outputPath")
// TODO: DELETE original
ImageIO.write(resizedImage, "jpg", outputFile)
println(" - LENGTH: ${outputFile.length()}")
return fileFromCdn.substringBeforeLast(".") + ".jpg"
if (inputImage.height > (MAX_HEIGHT_WIDTH + 1) || inputImage.width > (MAX_HEIGHT_WIDTH + 1)) {
val resizedImage = imageRescaleService.resizeImage(inputImage, MAX_HEIGHT_WIDTH, MAX_HEIGHT_WIDTH)
val format = inputFile.name.substringAfterLast(".").lowercase()
println(" - FORMAT: $format")

ImageIO.write(resizedImage, format, inputFile)
val newLength = inputFile.length()
val diff = oldLength - newLength
println(" - NEW LENGTH: $newLength DIFF: $diff")
processReduction.add(diff)
return true
}
println(" - SMALL ENOUGH by scale")
return false
} else {
println(" - SMALL ENOUGH")
return null
println(" - SMALL ENOUGH by volume")
return false
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package hu.bme.sch.cmsch.component.team

import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.context.annotation.Configuration

@Configuration
@ConditionalOnBean(TeamComponent::class)
@EntityScan(basePackageClasses = [TeamComponent::class])
class TeamComponentEntityConfiguration
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ data class TeamIntroductionEntity(
var introduction: String = "",

@property:GenerateInput(order = 19, label = "Logó url", enabled = true)
@property:GenerateOverview(visible = false)
@property:GenerateOverview(columnName = "Logó", renderer = OVERVIEW_TYPE_CDN_IMAGE, cdnImageFolder = "team")
@property:ImportFormat
var logo: String? = null,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,15 +243,21 @@ open class TeamService(
val members = if (teamComponent.showTeamMembersPublicly.isValueTrue() || ownTeam) mapMembers(team, user?.id) else null
val requests = if (user != null && user.role.value >= RoleType.PRIVILEGED.value && ownTeam) mapRequests(team) else null

val introduction = teamIntroductionRepository.findIntroductionsForGroup(team.id)
.firstOrNull { it.approved }
val introductions = teamIntroductionRepository.findIntroductionsForGroup(team.id)
val latestIntro = introductions.firstOrNull { it.approved }
val latestRejectedIntro = introductions.firstOrNull { it.rejected }

// if there is a newer introduction that is rejected than the latest accepted, we should display the reason
val descriptionRejected = (latestRejectedIntro?.creationDate ?: 0) > (latestIntro?.creationDate ?: 0)
val rejectionReason = if (descriptionRejected) latestRejectedIntro?.rejectionReason else null
return TeamView(
id = team.id,
name = team.name,
coverUrl = team.coverImageUrl,
description = introduction?.introduction ?: "",
logo = introduction?.logo ?: "",
description = latestIntro?.introduction ?: "",
descriptionRejected = if (ownTeam) descriptionRejected else false,
descriptionRejectionReason = if (ownTeam) rejectionReason else null,
logo = latestIntro?.logo ?: "",
points = score,
members = members,
applicants = requests,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ data class TeamView(
var name: String = "",
val coverUrl: String = "",
val description: String = "",
var descriptionRejected: Boolean,
val descriptionRejectionReason: String?,
val logo: String? = null,
var points: Int? = null,
var members: List<TeamMemberView>? = null,
Expand Down
Loading