Compare commits

..

14 Commits

Author SHA1 Message Date
8af255bea0 Merge branch 'main' of https://git-repo.eu/maiora/backend-api-DSU
# Conflicts:
#	src/main/kotlin/eu/maiora/plugins/Routing.kt
2025-04-01 08:57:18 +02:00
e0e93f93d0 Merge pull request '0002358-endpoint-composizioni' (#5) from 0002358-endpoint-composizioni into dev
Reviewed-on: #5
2025-04-01 06:55:19 +00:00
a633d1aac6 Merge branch '0002358-endpoint-composizioni' of https://git-repo.eu/maiora/backend-api-DSU into 0002358-endpoint-composizioni
# Conflicts:
#	src/main/kotlin/eu/maiora/plugins/Routing.kt
2025-04-01 08:53:27 +02:00
3585ec9ad6 implementazione endpoint composizioni
recupero senza filtri, viene restituita la lista di tutte le composizioni dei vassoi
2025-04-01 08:52:41 +02:00
5ae17aa8a8 Merge remote-tracking branch 'upstream/dev' into dev 2025-04-01 08:48:19 +02:00
dfa518383a Merge pull request '0002393-endpoint-valorePasti' (#3) from 0002393-endpoint-valorePasti into dev
Reviewed-on: #3
2025-04-01 06:47:44 +00:00
3f8ecb0370 recupero prezzo e punti
dati una tessera, un vassoio e una data
2025-04-01 08:45:33 +02:00
0e061c9eca ripristino plugin CallLogging
permette di stampare nei log la risposta HTTP inviata da Ktor
2025-03-27 17:35:19 +01:00
7b8eaa6261 rimozione plugin CallLogging
non utilizzato (usiamo logback)
2025-03-27 17:04:17 +01:00
7f6e1fc6cb gestione rolling logs
di default ogni file di log è giornaliero e può essere al max 100MB. Il totale dei files di log può essere di 5GB e i files verranno cancellati ogni 15 giorni
2025-03-27 16:08:25 +01:00
71443ff6f3 implementazione endpoint composizioni
recupero senza filtri, viene restituita la lista di tutte le composizioni dei vassoi
2025-03-26 10:10:02 +01:00
57597c3d94 Merge remote-tracking branch 'upstream/dev' into dev
# Conflicts:
#	src/main/kotlin/eu/maiora/plugins/Routing.kt
2025-03-24 11:47:52 +01:00
28a9ec86af Merge remote-tracking branch 'upstream/dev' into dev 2025-03-05 11:59:38 +01:00
ea4edcdcee Merge remote-tracking branch 'upstream/dev' into dev 2025-03-05 09:52:55 +01:00
12 changed files with 214 additions and 10 deletions

View File

@ -1,9 +1,6 @@
package eu.maiora.db package eu.maiora.db
import eu.maiora.model.Accounts import eu.maiora.model.*
import eu.maiora.model.Movimenti
import eu.maiora.model.Parametri
import eu.maiora.model.Tessere
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass import org.jetbrains.exposed.dao.IntEntityClass
@ -62,6 +59,15 @@ object MovimentiTable : IdTable<Long>("view_movimenti_api"){
val puntiPost = integer("punti_post") val puntiPost = integer("punti_post")
} }
object ComposizioniTable : IdTable<Long>("view_composizioni"){
override val id = long("id").entityId()
val idVassoio = long("id_vassoio")
val vassoio = varchar("vassoio", 255)
val idCategoria = long("id_categoria")
val categoria = varchar("categoria", 255)
val quantita = integer("quantita")
}
class AccountsDAO(id: EntityID<Int>) :IntEntity(id) { class AccountsDAO(id: EntityID<Int>) :IntEntity(id) {
companion object : IntEntityClass<AccountsDAO>(AccountsTable) companion object : IntEntityClass<AccountsDAO>(AccountsTable)
@ -104,6 +110,16 @@ class MovimentiDao(id: EntityID<Long>) :LongEntity(id) {
var puntiPost by MovimentiTable.puntiPost var puntiPost by MovimentiTable.puntiPost
} }
class ComposizioniDao(id: EntityID<Long>) :LongEntity(id){
companion object : LongEntityClass<ComposizioniDao>(ComposizioniTable)
var idVassoio by ComposizioniTable.idVassoio
var vassoio by ComposizioniTable.vassoio
var idCategoria by ComposizioniTable.idCategoria
var categoria by ComposizioniTable.categoria
var quantita by ComposizioniTable.quantita
}
fun accountsDaoToModel(dao: AccountsDAO) = Accounts( fun accountsDaoToModel(dao: AccountsDAO) = Accounts(
dao.id.value, dao.id.value,
@ -148,6 +164,15 @@ fun movimentiDaoToModel(dao: MovimentiDao) :Movimenti{
) )
} }
fun composizioniDaoToModel(dao: ComposizioniDao) =Composizioni(
dao.id.value,
dao.idVassoio,
dao.vassoio,
dao.idCategoria,
dao.categoria,
dao.quantita
)

View File

@ -0,0 +1,13 @@
package eu.maiora.model
import kotlinx.serialization.Serializable
@Serializable
data class Composizioni(
val id: Long,
val idVassoio : Long,
val vassoio : String,
val idCategoria : Long,
val categoria : String,
val quantita : Int
)

View File

@ -0,0 +1,5 @@
package eu.maiora.model
interface ComposizioniRepository {
suspend fun listaComposizioni(): List<Composizioni>
}

View File

@ -0,0 +1,14 @@
package eu.maiora.model
import eu.maiora.db.*
import org.jetbrains.exposed.sql.SortOrder
class ComposizioniRepositoryImpl : ComposizioniRepository {
override suspend fun listaComposizioni(): List<Composizioni> = suspendTransaction {
// Cerca la lista di composizioni
ComposizioniDao.all()
.toList()
.map { composizioniDaoToModel(it) } // Converte il DAO in un oggetto Composizioni
}
}

View File

@ -0,0 +1,12 @@
package eu.maiora.model
import kotlinx.serialization.Serializable
@Serializable
data class ValorePasti(
val idTessera : Long,
val idVassoio : Long,
val data : String,
val prezzo : Double,
val punti : Int
)

View File

@ -0,0 +1,5 @@
package eu.maiora.model
interface ValorePastiRepository {
suspend fun valorePastoByTessVassData(idTessera : String, idVassoio : String, data : String): String
}

View File

@ -0,0 +1,31 @@
package eu.maiora.model
import eu.maiora.db.*
import org.jetbrains.exposed.sql.LongColumnType
import org.jetbrains.exposed.sql.SqlExpressionBuilder
import org.jetbrains.exposed.sql.VarCharColumnType
class ValorePastiRepositoryImpl : ValorePastiRepository {
override suspend fun valorePastoByTessVassData(idTessera : String, idVassoio : String, data : String): String = suspendTransaction {
// Cerca valore del pasto e punti in base alla tessera, al vassoio e al giorno
val result = exec("SELECT SIR.trova_tariffa(?, ?, ?) FROM dual",
listOf(
Pair(LongColumnType(), idTessera),
Pair(LongColumnType(), idVassoio),
Pair(VarCharColumnType(), data)
)){ rs ->
var resultString: String? = null
// Processiamo il ResultSet restituito dalla query
if (rs.next()) {
resultString = rs.getString(1) // Leggiamo il primo risultato
}
resultString
}
result ?: "Nessun risultato"
}
}

View File

@ -1,12 +1,15 @@
package eu.maiora.plugins package eu.maiora.plugins
import eu.maiora.model.*
import eu.maiora.model.AccountsRepositoryImpl import eu.maiora.model.AccountsRepositoryImpl
import eu.maiora.model.MovimentiRepositoryImpl import eu.maiora.model.MovimentiRepositoryImpl
import eu.maiora.model.ParametriRepositoryImpl import eu.maiora.model.ParametriRepositoryImpl
import eu.maiora.model.TessereRepositoryImpl import eu.maiora.model.TessereRepositoryImpl
import eu.maiora.routes.auth import eu.maiora.routes.auth
import eu.maiora.routes.composizioni
import eu.maiora.routes.movimenti import eu.maiora.routes.movimenti
import eu.maiora.routes.tessere import eu.maiora.routes.tessere
import eu.maiora.routes.valorePasti
import io.ktor.server.application.* import io.ktor.server.application.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
@ -20,5 +23,7 @@ fun Application.configureRouting() {
auth(AccountsRepositoryImpl()) auth(AccountsRepositoryImpl())
tessere(TessereRepositoryImpl()) tessere(TessereRepositoryImpl())
movimenti(MovimentiRepositoryImpl()) movimenti(MovimentiRepositoryImpl())
composizioni(ComposizioniRepositoryImpl())
valorePasti(ValorePastiRepositoryImpl())
} }
} }

View File

@ -31,7 +31,7 @@ fun Route.auth(accountsRepository: AccountsRepositoryImpl) {
logger.info( logger.info(
"param: " + "param: " +
receivedResponse.param receivedResponse.param
); )
// Decodifica la stringa da Base64 a oggetto Credentials // Decodifica la stringa da Base64 a oggetto Credentials
val decodedBytes = Base64.getDecoder().decode(receivedResponse.param) val decodedBytes = Base64.getDecoder().decode(receivedResponse.param)

View File

@ -0,0 +1,20 @@
package eu.maiora.routes
import eu.maiora.model.ComposizioniRepositoryImpl
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
fun Route.composizioni(composizioniRepository: ComposizioniRepositoryImpl){
route("/api/composizioni"){
authenticate("auth-jwt") {
get(){
val listaComposizioni = composizioniRepository.listaComposizioni()
call.respond(listaComposizioni)
}
}
}
}

View File

@ -0,0 +1,50 @@
package eu.maiora.routes
import eu.maiora.model.TessereRepositoryImpl
import eu.maiora.model.ValorePasti
import eu.maiora.model.ValorePastiRepository
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
fun Route.valorePasti(valorePastiRepository: ValorePastiRepository){
route("/api/valorePasti"){
authenticate("auth-jwt") {
get(){
// Ottieni i parametri dal percorso
val idTessera = call.parameters["idTessera"]
val idVassoio = call.parameters["idVassoio"]
val data = call.parameters["data"]
if (idTessera == null) {
call.respondText("ID tessera non valido", status = HttpStatusCode.BadRequest)
return@get
}
if (idVassoio == null) {
call.respondText("ID vassoio non valido", status = HttpStatusCode.BadRequest)
return@get
}
if (data == null) {
call.respondText("data non valida", status = HttpStatusCode.BadRequest)
return@get
}
// Cerca la tessera per codice fiscale
val valorePasto = valorePastiRepository.valorePastoByTessVassData(idTessera, idVassoio, data)
val prezzo = valorePasto.split("#").get(0)
val punti = valorePasto.split("#").get(1)
call.respond( ValorePasti(idTessera.toLong(),
idVassoio.toLong(), data,
prezzo.replace(',', '.').toDouble(),
punti.toInt()))
}
}
}
}

View File

@ -1,19 +1,43 @@
<configuration> <configuration>
<!-- Appender per la console -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder> <encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder> </encoder>
</appender> </appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>./logFile.log</file> <!-- Appender per il file di log con rotazione basata su tempo e dimensione -->
<appender name="ROLLING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>./log/logFile.log</file> <!-- File di log principale -->
<append>true</append> <append>true</append>
<!-- RollingPolicy per dimensione e tempo -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- Pattern per il nome dei file ruotati: include la data -->
<FileNamePattern>./log/logFile.%d{yyyy-MM-dd}.%i.log</FileNamePattern> <!-- %i è il numero di file generato -->
<!-- Limita la dimensione del file a 100MB -->
<maxFileSize>100MB</maxFileSize> <!-- Ruota il file quando raggiunge 100MB -->
<!-- Conserva i log per due settimane -->
<maxHistory>15</maxHistory> <!-- Limita a 15 giorni i log archiviati -->
<!-- Limita la dimensione totale dei file di log a 5GB -->
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<encoder> <encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder> </encoder>
</appender> </appender>
<root level="trace">
<appender-ref ref="FILE"/> <!-- Configurazione del livello di log -->
<root level="DEBUG">
<appender-ref ref="ROLLING_FILE"/>
<appender-ref ref="STDOUT"/> <appender-ref ref="STDOUT"/>
</root> </root>
<logger name="io.netty" level="INFO"/> <logger name="io.netty" level="INFO"/>
</configuration>
</configuration>