fixed connection over internet

This commit is contained in:
Faraphel 2024-06-16 17:59:22 +02:00
parent 0e4f9010ae
commit 30c7fb1b2a
25 changed files with 371 additions and 141 deletions

View file

@ -1,5 +1,6 @@
package com.faraphel.tasks_valider.connectivity.task
import com.faraphel.tasks_valider.connectivity.task.api.TaskSessionManagerClientApi
import com.faraphel.tasks_valider.database.api.client.TaskEntityHttpClient
import com.faraphel.tasks_valider.database.api.client.entities.*
@ -17,13 +18,19 @@ class TaskClient(
) {
private val httpClient = TaskEntityHttpClient(address, port, baseCookies)
val clientApi = ClassClientApi(httpClient)
val personApi = PersonClientApi(httpClient)
val sessionApi = SessionClientApi(httpClient)
val subjectApi = SubjectClientApi(httpClient)
val taskApi = TaskClientApi(httpClient)
val validationApi = ValidationClientApi(httpClient)
// all the entities API
class Entities(httpClient: TaskEntityHttpClient) {
val client = ClassClientApi(httpClient)
val person = PersonClientApi(httpClient)
val session = SessionClientApi(httpClient)
val subject = SubjectClientApi(httpClient)
val task = TaskClientApi(httpClient)
val validation = ValidationClientApi(httpClient)
val relationClassPersonApi = RelationClassPersonClientApi(httpClient)
val relationPersonSessionSubjectApi = RelationPersonSessionSubjectClientApi(httpClient)
}
val relationClassPerson = RelationClassPersonClientApi(httpClient)
val relationPersonSessionSubject = RelationPersonSessionSubjectClientApi(httpClient)
}
val entities = Entities(httpClient)
val session = TaskSessionManagerClientApi(httpClient)
}

View file

@ -1,6 +1,6 @@
package com.faraphel.tasks_valider.connectivity.task
import com.faraphel.tasks_valider.connectivity.task.api.TaskSessionManagerApi
import com.faraphel.tasks_valider.connectivity.task.api.TaskSessionManagerServerApi
import com.faraphel.tasks_valider.connectivity.task.session.TaskSessionManager
import com.faraphel.tasks_valider.database.TaskDatabase
import com.faraphel.tasks_valider.database.api.server.DatabaseApi
@ -24,7 +24,7 @@ class TaskServer(
) : NanoHTTPD(port) {
private val sessionManager = TaskSessionManager(adminPersonEntity) ///< the session manager
private val databaseApi = DatabaseApi(this.database, session) ///< the api of the database
private val sessionManagerApi = TaskSessionManagerApi(this.sessionManager, this.database) ///< the api of the session manager
private val sessionManagerApi = TaskSessionManagerServerApi(this.sessionManager, this.database) ///< the api of the session manager
/**
* Get the admin person entity

View file

@ -0,0 +1,58 @@
package com.faraphel.tasks_valider.connectivity.task.api
import com.faraphel.tasks_valider.connectivity.task.session.TaskSession
import com.faraphel.tasks_valider.database.api.client.TaskEntityHttpClient
import com.faraphel.tasks_valider.database.entities.SessionEntity
import com.faraphel.tasks_valider.database.entities.error.HttpException
import com.faraphel.tasks_valider.utils.parser
/**
* Interface to communicate with the server session manager
*/
class TaskSessionManagerClientApi(private val client: TaskEntityHttpClient) {
/**
* Create a new session
* @param cardId the id of the user's card
* @param password the password of the user
*/
fun newFromCardId(cardId: String, password: String): TaskSession {
val response = this.client.post(
"sessions/self",
parser.toJson(mapOf(
"card_id" to cardId,
"password" to password
))
)
// in case of error, notify it
if (!response.isSuccessful)
throw HttpException(response.code)
val data = response.body.string()
// parse the result
return parser.fromJson(
data,
TaskSession::class.java
)
}
/**
* Get the current session
*/
fun getSelf(): TaskSession {
val response = this.client.get("sessions/self")
// in case of error, notify it
if (!response.isSuccessful)
throw HttpException(response.code)
// parse the result
return parser.fromJson(
response.body.string(),
TaskSession::class.java
)
}
}

View file

@ -4,6 +4,8 @@ import com.faraphel.tasks_valider.connectivity.task.session.TaskPermission
import com.faraphel.tasks_valider.connectivity.task.session.TaskSession
import com.faraphel.tasks_valider.connectivity.task.session.TaskSessionManager
import com.faraphel.tasks_valider.database.TaskDatabase
import com.faraphel.tasks_valider.database.entities.PersonEntity
import com.faraphel.tasks_valider.utils.getBody
import com.faraphel.tasks_valider.utils.parser
import com.google.gson.reflect.TypeToken
import fi.iki.elonen.NanoHTTPD
@ -12,7 +14,7 @@ import fi.iki.elonen.NanoHTTPD
/**
* the HTTP API for the session manager
*/
class TaskSessionManagerApi(
class TaskSessionManagerServerApi(
private val sessionManager: TaskSessionManager,
private val database: TaskDatabase
) {
@ -72,25 +74,44 @@ class TaskSessionManagerApi(
NanoHTTPD.Method.POST -> {
// get the user identifiers
val identifiers: Map<String, String> = parser.fromJson(
httpSession.inputStream.bufferedReader().readText(),
httpSession.getBody(),
object : TypeToken<Map<String, String>>() {}.type
)
val person: PersonEntity
// check for the id
if (!identifiers.contains("id"))
if (identifiers.contains("id")) {
// get the id of the user (if invalid, return an error)
val personId: Long = identifiers["id"]!!.toLongOrNull()
?: return NanoHTTPD.newFixedLengthResponse(
NanoHTTPD.Response.Status.BAD_REQUEST,
"text/plain",
"Invalid id"
)
// check if the identifiers are correct
person = this.database.personDao().getById(personId)
?: return NanoHTTPD.newFixedLengthResponse(
NanoHTTPD.Response.Status.BAD_REQUEST,
"text/plain",
"No person with this id"
)
} else if (identifiers.contains("card_id")) {
// check if the identifiers are correct
person = this.database.personDao().getByCardId(identifiers["card_id"]!!)
?: return NanoHTTPD.newFixedLengthResponse(
NanoHTTPD.Response.Status.BAD_REQUEST,
"text/plain",
"No person with this id"
)
} else {
return NanoHTTPD.newFixedLengthResponse(
NanoHTTPD.Response.Status.BAD_REQUEST,
"text/plain",
"Missing id"
)
// get the id of the user (if invalid, return an error)
val personId: Long = identifiers["id"]!!.toLongOrNull()
?: return NanoHTTPD.newFixedLengthResponse(
NanoHTTPD.Response.Status.BAD_REQUEST,
"text/plain",
"Invalid id"
"Missing id or card_id"
)
}
// check for the password
if (!identifiers.contains("password"))
@ -100,14 +121,6 @@ class TaskSessionManagerApi(
"Missing password"
)
// check if the identifiers are correct
val person = this.database.personDao().getById(personId)
?: return NanoHTTPD.newFixedLengthResponse(
NanoHTTPD.Response.Status.BAD_REQUEST,
"text/plain",
"No person with this id"
)
// check if the password is correct
if (!person.checkPassword(identifiers["password"]!!))
return NanoHTTPD.newFixedLengthResponse(
@ -119,11 +132,11 @@ class TaskSessionManagerApi(
// create a new session for the userJHH
val (sessionToken, session) = this.sessionManager.newSessionData(person)
// create the response
// create the response with the session data
val response = NanoHTTPD.newFixedLengthResponse(
NanoHTTPD.Response.Status.OK,
"text/plain",
"Session updated"
"application/json",
parser.toJson(session)
)
// set the session token in the cookies

View file

@ -1,6 +1,7 @@
package com.faraphel.tasks_valider.connectivity.task.session
import com.faraphel.tasks_valider.database.entities.PersonEntity
import com.google.gson.annotations.Expose
import kotlinx.serialization.Serializable
@ -9,5 +10,5 @@ import kotlinx.serialization.Serializable
*/
@Serializable
data class TaskSession(
val person: PersonEntity,
)
@Expose val person: PersonEntity,
)

View file

@ -18,6 +18,12 @@ interface PersonDao : BaseTaskDao<PersonEntity> {
@Query("SELECT * FROM ${PersonEntity.TABLE_NAME} WHERE id = :id")
fun getById(id: Long): PersonEntity?
/**
* Get the object from its card identifier
*/
@Query("SELECT * FROM ${PersonEntity.TABLE_NAME} WHERE card_id = :cardId")
fun getByCardId(cardId: String): PersonEntity?
@Query(
"SELECT * FROM ${PersonEntity.TABLE_NAME} " +
"WHERE id IN (" +

View file

@ -4,12 +4,13 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.faraphel.tasks_valider.database.entities.base.BaseEntity
import com.google.gson.annotations.Expose
@Entity(tableName = ClassEntity.TABLE_NAME)
data class ClassEntity (
@ColumnInfo("id") @PrimaryKey(autoGenerate = true) val id: Long = 0,
@ColumnInfo("name") val name: String,
@ColumnInfo("id") @PrimaryKey(autoGenerate = true) @Expose val id: Long = 0,
@ColumnInfo("name") @Expose val name: String,
) : BaseEntity() {
companion object {
const val TABLE_NAME = "classes"

View file

@ -5,6 +5,7 @@ import androidx.room.Entity
import androidx.room.PrimaryKey
import com.faraphel.tasks_valider.connectivity.task.session.TaskRole
import com.faraphel.tasks_valider.database.entities.base.BaseEntity
import com.google.gson.annotations.Expose
import kotlinx.serialization.Serializable
import java.security.MessageDigest
import java.util.*
@ -12,12 +13,13 @@ import java.util.*
@Serializable
@Entity(tableName = PersonEntity.TABLE_NAME)
data class PersonEntity (
@ColumnInfo("id") @PrimaryKey(autoGenerate = true) val id: Long = 0,
@ColumnInfo("first_name") val firstName: String,
@ColumnInfo("last_name") val lastName: String,
@ColumnInfo("card_id") val cardId: String? = null,
@ColumnInfo("id") @PrimaryKey(autoGenerate = true) @Expose val id: Long = 0,
@ColumnInfo("first_name") @Expose val firstName: String,
@ColumnInfo("last_name") @Expose val lastName: String,
@ColumnInfo("card_id") @Expose val cardId: String? = null,
@ColumnInfo("password_hash") val passwordHash: String? = null,
@ColumnInfo("role") val role: TaskRole = TaskRole.STUDENT,
@ColumnInfo("role") @Expose val role: TaskRole = TaskRole.STUDENT,
) : BaseEntity() {
companion object {
const val TABLE_NAME = "persons"

View file

@ -4,6 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import com.faraphel.tasks_valider.database.entities.base.BaseEntity
import com.google.gson.annotations.Expose
@Entity(
tableName = RelationClassPersonEntity.TABLE_NAME,
@ -27,8 +28,8 @@ import com.faraphel.tasks_valider.database.entities.base.BaseEntity
]
)
data class RelationClassPersonEntity (
@ColumnInfo("student_id", index = true) val studentId: Long,
@ColumnInfo("class_id", index = true) val classId: Long,
@ColumnInfo("student_id", index = true) @Expose val studentId: Long,
@ColumnInfo("class_id", index = true) @Expose val classId: Long,
) : BaseEntity() {
companion object {
const val TABLE_NAME = "relation_class_person"

View file

@ -4,6 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import com.faraphel.tasks_valider.database.entities.base.BaseEntity
import com.google.gson.annotations.Expose
/**
@ -38,9 +39,9 @@ import com.faraphel.tasks_valider.database.entities.base.BaseEntity
]
)
data class RelationPersonSessionSubjectEntity (
@ColumnInfo("student_id", index = true) val studentId: Long,
@ColumnInfo("session_id", index = true) val sessionId: Long,
@ColumnInfo("subject_id", index = true) val subjectId: Long,
@ColumnInfo("student_id", index = true) @Expose val studentId: Long,
@ColumnInfo("session_id", index = true) @Expose val sessionId: Long,
@ColumnInfo("subject_id", index = true) @Expose val subjectId: Long,
) : BaseEntity() {
companion object {
const val TABLE_NAME = "relation_person_session_subject"

View file

@ -5,6 +5,7 @@ import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import com.faraphel.tasks_valider.database.entities.base.BaseEntity
import com.google.gson.annotations.Expose
import java.time.Instant
@Entity(
@ -19,9 +20,9 @@ import java.time.Instant
]
)
data class SessionEntity (
@ColumnInfo("id") @PrimaryKey(autoGenerate = true) val id: Long = 0,
@ColumnInfo("name") val name: String? = null,
@ColumnInfo("start") val start: Instant,
@ColumnInfo("id") @PrimaryKey(autoGenerate = true) @Expose val id: Long = 0,
@ColumnInfo("name") @Expose val name: String? = null,
@ColumnInfo("start") @Expose val start: Instant,
@ColumnInfo("class_id", index = true) val classId: Long? = null,
) : BaseEntity() {

View file

@ -4,11 +4,12 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.faraphel.tasks_valider.database.entities.base.BaseEntity
import com.google.gson.annotations.Expose
@Entity(tableName = SubjectEntity.TABLE_NAME)
data class SubjectEntity (
@ColumnInfo("id") @PrimaryKey(autoGenerate = true) val id: Long = 0,
@ColumnInfo("name") val name: String,
@ColumnInfo("id") @PrimaryKey(autoGenerate = true) @Expose val id: Long = 0,
@ColumnInfo("name") @Expose val name: String,
) : BaseEntity() {
companion object {
const val TABLE_NAME = "subjects"

View file

@ -5,6 +5,7 @@ import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import com.faraphel.tasks_valider.database.entities.base.BaseEntity
import com.google.gson.annotations.Expose
@Entity(
tableName = TaskEntity.TABLE_NAME,
@ -18,12 +19,12 @@ import com.faraphel.tasks_valider.database.entities.base.BaseEntity
]
)
data class TaskEntity (
@ColumnInfo("id") @PrimaryKey(autoGenerate = true) val id: Long = 0,
@ColumnInfo("title") val title: String,
@ColumnInfo("description") val description: String? = null,
@ColumnInfo("order") val order: Int, ///< the order of the task in the list of the subject
@ColumnInfo("id") @PrimaryKey(autoGenerate = true) @Expose val id: Long = 0,
@ColumnInfo("title") @Expose val title: String,
@ColumnInfo("description") @Expose val description: String? = null,
@ColumnInfo("order") @Expose val order: Int, ///< the order of the task in the list of the subject
@ColumnInfo("subject_id", index = true) val subjectId: Long,
@ColumnInfo("subject_id", index = true) @Expose val subjectId: Long,
) : BaseEntity() {
companion object {
const val TABLE_NAME = "tasks"

View file

@ -4,6 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import com.faraphel.tasks_valider.database.entities.base.BaseEntity
import com.google.gson.annotations.Expose
import java.time.Instant
@Entity(
@ -35,11 +36,11 @@ import java.time.Instant
]
)
data class ValidationEntity (
@ColumnInfo("teacher_id", index = true) val teacherId: Long,
@ColumnInfo("student_id", index = true) val studentId: Long,
@ColumnInfo("task_id", index = true) val taskId: Long,
@ColumnInfo("teacher_id", index = true) @Expose val teacherId: Long,
@ColumnInfo("student_id", index = true) @Expose val studentId: Long,
@ColumnInfo("task_id", index = true) @Expose val taskId: Long,
@ColumnInfo("date") val date: Instant,
@ColumnInfo("date") @Expose val date: Instant,
) : BaseEntity() {
companion object {
const val TABLE_NAME = "validations"

View file

@ -3,4 +3,8 @@ package com.faraphel.tasks_valider.database.entities.error
class HttpException(
private val code: Int,
) : Exception("Http Exception: $code")
) : Exception("Http Exception: $code") {
fun getCode(): Int {
return code
}
}

View file

@ -0,0 +1,146 @@
package com.faraphel.tasks_valider.ui.screen.authentication
import android.app.Activity
import android.widget.Toast
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.faraphel.tasks_valider.connectivity.task.TaskClient
import com.faraphel.tasks_valider.connectivity.task.session.TaskSession
import com.faraphel.tasks_valider.database.entities.error.HttpException
import com.faraphel.tasks_valider.ui.screen.scan.qr.ScanBarcodeScreen
import com.journeyapps.barcodescanner.BarcodeResult
import okhttp3.HttpUrl.Companion.toHttpUrl
/**
* Authentification screen where the client can give his information
*/
@Composable
fun AuthenticationClientScreen(activity: Activity, client: TaskClient, session: MutableState<TaskSession?>) {
val controller = rememberNavController()
val barcode = remember { mutableStateOf<BarcodeResult?>(null) }
NavHost(navController = controller, startDestination = "main") {
composable("main") {
AuthenticationClientContent(activity, controller, client, session, barcode)
}
composable("scan") {
if (barcode.value == null) ScanBarcodeScreen(activity, barcode)
else controller.navigate("main")
}
}
}
@Composable
fun AuthenticationClientContent(
activity: Activity,
controller: NavController,
client: TaskClient,
session: MutableState<TaskSession?>,
barcode: MutableState<BarcodeResult?>,
) {
val cardId = remember { mutableStateOf("") }
val password = remember { mutableStateOf("") }
// check if the barcode contain information about the card
var defaultCardId = ""
if (barcode.value != null) {
val studentUrl = barcode.value!!.text.toHttpUrl()
cardId.value = studentUrl.pathSegments[0]
}
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
// title
Text(
text = "Authentication",
fontSize = 32.sp
)
// separator
Spacer(modifier = Modifier.height(24.dp))
// card identifier
Row {
// text
TextField(
value = cardId.value,
placeholder = { Text("Card Id") },
onValueChange = { text -> cardId.value = text },
)
// button to scan the card
Button(onClick = {
barcode.value = null
controller.navigate("scan")
}) {
Text("Scan")
}
}
// password
TextField(
value = password.value,
visualTransformation = PasswordVisualTransformation(),
placeholder = { Text("Password") },
onValueChange = { text -> password.value = text },
)
// separator
Spacer(modifier = Modifier.height(24.dp))
// submit button
Button(onClick = {
Thread { authenticate(activity, client, cardId.value, password.value, session) }.start()
}) {
Text("Submit")
}
}
}
fun authenticate(
activity: Activity,
client: TaskClient,
cardId: String,
password: String,
session: MutableState<TaskSession?>
) {
try {
// try to get a session from the identifiers
session.value = client.session.newFromCardId(cardId, password)
} catch (exception: HttpException) {
// in case of error, show a message to the user
when (exception.getCode()) {
401 -> {
activity.runOnUiThread {
Toast.makeText(activity, "Invalid card id or password", Toast.LENGTH_SHORT).show()
}
}
else -> {
activity.runOnUiThread {
Toast.makeText(activity, "Unknown error: $exception", Toast.LENGTH_SHORT).show()
}
}
}
}
}

View file

@ -1,4 +1,4 @@
package com.faraphel.tasks_valider.ui.screen.authentification
package com.faraphel.tasks_valider.ui.screen.authentication
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
@ -20,7 +20,7 @@ import com.faraphel.tasks_valider.database.entities.PersonEntity
* Authentification screen where the host can give his information
*/
@Composable
fun AuthentificationServerScreen(personEntity: MutableState<PersonEntity?>) {
fun AuthenticationServerScreen(personEntity: MutableState<PersonEntity?>) {
val firstName = remember { mutableStateOf("") }
val lastName = remember { mutableStateOf("") }

View file

@ -1,40 +0,0 @@
package com.faraphel.tasks_valider.ui.screen.authentification
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.text.input.PasswordVisualTransformation
/**
* Authentification screen where the client can give his information
*/
@Composable
fun AuthentificationClientScreen() {
val cardId = remember { mutableStateOf("") }
val password = remember { mutableStateOf("") }
Column {
// card identifier
TextField(
value = cardId.value,
onValueChange = { text -> cardId.value = text },
)
// password
TextField(
value = password.value,
visualTransformation = PasswordVisualTransformation(),
onValueChange = { text -> password.value = text },
)
// button
Button(onClick = { /* do something */ }) {
Text("Submit")
}
}
}

View file

@ -1,9 +1,7 @@
package com.faraphel.tasks_valider.ui.screen.communication.internet
import android.app.Activity
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Button
import androidx.compose.material3.Text
@ -13,21 +11,38 @@ import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.faraphel.tasks_valider.connectivity.task.TaskClient
import com.faraphel.tasks_valider.connectivity.task.session.TaskSession
import com.faraphel.tasks_valider.ui.screen.authentication.AuthenticationClientScreen
import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_ADDRESS
import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT
import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT
import com.faraphel.tasks_valider.ui.screen.task.TaskSessionController
@RequiresApi(Build.VERSION_CODES.O)
@Composable
fun CommunicationInternetClientScreen(activity: Activity) {
val client = remember { mutableStateOf<TaskClient?>(null) }
val session = remember { mutableStateOf<TaskSession?>(null) }
// TODO(Faraphel): fix and get a user
// if (client.value == null) CommunicationInternetClientContent(client)
// else TaskSessionScreen(activity, client.value!!, user)
// if the client is not connected, show the connection screen
if (client.value == null)
return CommunicationInternetClientContent(client)
// if the user is not authenticated, show the authentication screen
if (session.value == null)
return AuthenticationClientScreen(activity, client.value!!, session)
// show the main screen
TaskSessionController(
activity,
client.value!!,
session.value!!.person,
)
}
@ -36,18 +51,31 @@ fun CommunicationInternetClientContent(client: MutableState<TaskClient?>) {
val serverAddress = remember { mutableStateOf(DEFAULT_SERVER_ADDRESS) }
val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) }
Column {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
// title
Text(
text = "Connection",
fontSize = 32.sp
)
// separator
Spacer(modifier = Modifier.height(24.dp))
// server address
TextField(
value = serverAddress.value,
onValueChange = { text ->
serverAddress.value = text
}
placeholder = { Text("server IP") },
onValueChange = { text -> serverAddress.value = text }
)
// server port
TextField(
value = serverPort.intValue.toString(),
placeholder = { Text("server port") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
onValueChange = { text ->
val port = text.toInt()
@ -57,6 +85,10 @@ fun CommunicationInternetClientContent(client: MutableState<TaskClient?>) {
}
)
// separator
Spacer(modifier = Modifier.height(24.dp))
// connect button
Button(onClick = {
// TODO(Faraphel): check if the server is reachable
client.value = TaskClient(serverAddress.value, serverPort.intValue)

View file

@ -27,7 +27,7 @@ import com.faraphel.tasks_valider.database.entities.ClassEntity
import com.faraphel.tasks_valider.database.entities.PersonEntity
import com.faraphel.tasks_valider.database.entities.SessionEntity
import com.faraphel.tasks_valider.database.populateSubjectSessionPersonTest
import com.faraphel.tasks_valider.ui.screen.authentification.AuthentificationServerScreen
import com.faraphel.tasks_valider.ui.screen.authentication.AuthenticationServerScreen
import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT
import com.faraphel.tasks_valider.ui.screen.communication.RANGE_SERVER_PORT
import com.faraphel.tasks_valider.ui.screen.task.TaskSessionController
@ -37,7 +37,6 @@ import java.time.Instant
/**
* Screen for the host to configure the server
*/
@RequiresApi(Build.VERSION_CODES.O)
@Composable
fun CommunicationInternetServerScreen(
activity: Activity,
@ -52,7 +51,7 @@ fun CommunicationInternetServerScreen(
NavHost(navController = controller, startDestination = "authentication") {
composable("authentication") {
// if the admin person is not created, prompt the user for the admin information
if (adminPersonEntityRaw.value == null) AuthentificationServerScreen(adminPersonEntityRaw)
if (adminPersonEntityRaw.value == null) AuthenticationServerScreen(adminPersonEntityRaw)
else controller.navigate("configuration")
}
composable("configuration") {

View file

@ -33,7 +33,6 @@ import com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.CommunicationW
* @param activity: The activity that hosts the communication screen.
* @param database: the database.
*/
@RequiresApi(Build.VERSION_CODES.O)
@Composable
fun CommunicationModeSelectionScreen(activity: Activity, database: TaskDatabase) {
val controller = rememberNavController()

View file

@ -66,7 +66,7 @@ fun quickValidation(
}
// requests all the persons
val allPersons = client.personApi.getAll()
val allPersons = client.entities.person.getAll()
// get the person with the matching card
val person = allPersons.firstOrNull { person -> person.cardId == cardId }
@ -79,19 +79,19 @@ fun quickValidation(
}
// requests all the relation persons - subjects
val allRelationsPersonSubject = client.relationPersonSessionSubjectApi.getAll()
val allRelationsPersonSubject = client.entities.relationPersonSessionSubject.getAll()
// get the corresponding relation
val relationPersonSubject = allRelationsPersonSubject.first { relation -> relation.studentId == person.id }
// requests all the tasks
val allTasks = client.taskApi.getAll()
val allTasks = client.entities.task.getAll()
// get the corresponding tasks
val tasks = allTasks
.filter { task -> task.subjectId == relationPersonSubject.subjectId }
.sortedBy { task -> task.order }
// requests all the validations
val allValidations = client.validationApi.getAll()
val allValidations = client.entities.validation.getAll()
// get the corresponding relation
val validations = allValidations.filter { validation -> validation.studentId == person.id }
@ -112,7 +112,7 @@ fun quickValidation(
}
// create a new validation on the server
client.validationApi.save(
client.entities.validation.save(
ValidationEntity(
teacherId=user.id,
studentId=person.id,

View file

@ -1,13 +1,8 @@
package com.faraphel.tasks_valider.ui.screen.task
import android.app.Activity
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Environment
import android.util.Log
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.Text
@ -125,7 +120,7 @@ fun refreshStudents(
) {
try {
// try to get all the persons in that session
students.value = client.personApi.getAll()
students.value = client.entities.person.getAll()
} catch (exception: Exception) {
// in case of error, show a message
return activity.runOnUiThread {
@ -141,12 +136,12 @@ fun exportToFile(
client: TaskClient,
) {
// get all the values to export
val allPersons = client.personApi.getAll()
val allPersons = client.entities.person.getAll()
val allStudents = allPersons.filter { student -> student.role == TaskRole.STUDENT }
val allRelationsStudentSessionSubject = client.relationPersonSessionSubjectApi.getAll()
val allSubjects = client.subjectApi.getAll()
val allTasks = client.taskApi.getAll()
val allValidations = client.validationApi.getAll()
val allRelationsStudentSessionSubject = client.entities.relationPersonSessionSubject.getAll()
val allSubjects = client.entities.subject.getAll()
val allTasks = client.entities.task.getAll()
val allValidations = client.entities.validation.getAll()
// for each student

View file

@ -125,7 +125,7 @@ fun refreshTasksValidations(
validations: MutableState<List<ValidationEntity>?>,
) {
// try to obtain the list of subject
val allRelationsPersonSessionSubject = client.relationPersonSessionSubjectApi.getAll()
val allRelationsPersonSessionSubject = client.entities.relationPersonSessionSubject.getAll()
// get the subject that the student is using
val relationPersonSessionSubject = allRelationsPersonSessionSubject.firstOrNull { relation ->
relation.studentId == student.id
@ -136,7 +136,7 @@ fun refreshTasksValidations(
return activity.runOnUiThread { Toast.makeText(activity, "No subject assigned", Toast.LENGTH_LONG).show() }
// try to obtain the list of tasks
val allTasks = client.taskApi.getAll()
val allTasks = client.entities.task.getAll()
// get the tasks that are linked to this subject
tasks.value = allTasks
@ -144,7 +144,7 @@ fun refreshTasksValidations(
.sortedBy { task -> task.order }
// try to obtain the list of validations
val allValidations = client.validationApi.getAll()
val allValidations = client.entities.validation.getAll()
// filter only the interesting validations
validations.value = allValidations.filter { validation ->
validation.studentId == student.id &&
@ -156,8 +156,8 @@ fun refreshTasksValidations(
fun updateValidation(client: TaskClient, checked: Boolean, validation: ValidationEntity) {
if (checked)
// if the validation is not set, create it
client.validationApi.save(validation)
client.entities.validation.save(validation)
else
// if the validation is set, delete it
client.validationApi.delete(validation)
client.entities.validation.delete(validation)
}

View file

@ -8,4 +8,5 @@ import java.time.Instant
val parser: Gson = GsonBuilder()
.registerTypeAdapter(Instant::class.java, InstantConverter())
.excludeFieldsWithoutExposeAnnotation()
.create()