[WIP] - added authentification for a user
This commit is contained in:
parent
56330ff7c7
commit
5ed15e3371
20 changed files with 465 additions and 198 deletions
|
@ -6,14 +6,9 @@ import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
||||||
import com.faraphel.tasks_valider.database.TaskDatabase
|
import com.faraphel.tasks_valider.database.TaskDatabase
|
||||||
import com.faraphel.tasks_valider.ui.screen.scan.qr.ScanBarcodeScreen
|
import com.faraphel.tasks_valider.ui.screen.communication.CommunicationModeSelectionScreen
|
||||||
import com.journeyapps.barcodescanner.BarcodeResult
|
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
@ -28,21 +23,8 @@ class MainActivity : ComponentActivity() {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
this.setContent {
|
this.setContent {
|
||||||
@Composable
|
CommunicationModeSelectionScreen(this)
|
||||||
fun example() {
|
|
||||||
val barcode = remember { mutableStateOf<BarcodeResult?>(null) }
|
|
||||||
if (barcode.value == null) ScanBarcodeScreen(this, barcode)
|
|
||||||
else Text("code: ${barcode.value!!.text}")
|
|
||||||
}
|
|
||||||
|
|
||||||
example()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
this.setContent {
|
|
||||||
CommunicationScreen(this)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package com.faraphel.tasks_valider.connectivity.task
|
package com.faraphel.tasks_valider.connectivity.task
|
||||||
|
|
||||||
import com.faraphel.tasks_valider.connectivity.task.api.TaskSessionManagerApi
|
import com.faraphel.tasks_valider.connectivity.task.api.TaskSessionManagerApi
|
||||||
import com.faraphel.tasks_valider.connectivity.task.session.TaskRole
|
|
||||||
import com.faraphel.tasks_valider.connectivity.task.session.TaskSession
|
|
||||||
import com.faraphel.tasks_valider.connectivity.task.session.TaskSessionManager
|
import com.faraphel.tasks_valider.connectivity.task.session.TaskSessionManager
|
||||||
import com.faraphel.tasks_valider.database.TaskDatabase
|
import com.faraphel.tasks_valider.database.TaskDatabase
|
||||||
import com.faraphel.tasks_valider.database.api.TaskDatabaseApi
|
import com.faraphel.tasks_valider.database.api.TaskDatabaseApi
|
||||||
|
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
||||||
import fi.iki.elonen.NanoHTTPD
|
import fi.iki.elonen.NanoHTTPD
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,30 +15,33 @@ import fi.iki.elonen.NanoHTTPD
|
||||||
*/
|
*/
|
||||||
class TaskServer(
|
class TaskServer(
|
||||||
private val port: Int,
|
private val port: Int,
|
||||||
private val database: TaskDatabase
|
private val database: TaskDatabase,
|
||||||
|
adminPersonEntity: PersonEntity,
|
||||||
) : NanoHTTPD(port) {
|
) : NanoHTTPD(port) {
|
||||||
companion object {
|
private val sessionManager = TaskSessionManager(adminPersonEntity) ///< the session manager
|
||||||
private val TASK_SESSION_ADMIN = TaskSession( ///< the admin default session
|
|
||||||
role = TaskRole.ADMIN
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val sessionManager = TaskSessionManager() ///< the session manager
|
|
||||||
private val adminSessionId = this.sessionManager.newSessionData(TASK_SESSION_ADMIN) ///< default admin session id
|
|
||||||
|
|
||||||
private val sessionManagerApi = TaskSessionManagerApi(this.sessionManager) ///< the api of the session manager
|
|
||||||
private val databaseApi = TaskDatabaseApi(this.database) ///< the api of the database
|
private val databaseApi = TaskDatabaseApi(this.database) ///< the api of the database
|
||||||
|
private val sessionManagerApi = TaskSessionManagerApi(this.sessionManager, this.database) ///< the api of the session manager
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the admin person entity
|
||||||
|
* @return the admin person entity
|
||||||
|
*/
|
||||||
|
fun getAdminPersonEntity(): PersonEntity {
|
||||||
|
return this.sessionManager.getAdminPersonEntity()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a new client that can be used by the admin
|
* Return a new client that can be used by the admin
|
||||||
|
* @return the client
|
||||||
*/
|
*/
|
||||||
fun getClientAdmin(): TaskClient {
|
fun getAdminClient(): TaskClient {
|
||||||
// create the session cookie for the admin
|
// create the session cookie for the admin
|
||||||
val cookieSession = okhttp3.Cookie.Builder()
|
val cookieSession = okhttp3.Cookie.Builder()
|
||||||
.domain("localhost")
|
.domain("localhost")
|
||||||
.name("sessionId")
|
.name("sessionToken")
|
||||||
.value(adminSessionId)
|
.value(this.sessionManager.adminSessionToken)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
// create a new client
|
// create a new client
|
||||||
return TaskClient(
|
return TaskClient(
|
||||||
"localhost",
|
"localhost",
|
||||||
|
@ -54,7 +56,8 @@ class TaskServer(
|
||||||
*/
|
*/
|
||||||
override fun serve(httpSession: IHTTPSession): Response {
|
override fun serve(httpSession: IHTTPSession): Response {
|
||||||
// get the session data of the client
|
// get the session data of the client
|
||||||
val taskSession = this.sessionManager.getOrCreateSessionData(httpSession)
|
val taskSessionData = this.sessionManager.getSessionData(httpSession)
|
||||||
|
val taskSession = taskSessionData?.second
|
||||||
|
|
||||||
// parse the url
|
// parse the url
|
||||||
val uri: String = httpSession.uri.trim('/')
|
val uri: String = httpSession.uri.trim('/')
|
||||||
|
@ -69,11 +72,11 @@ class TaskServer(
|
||||||
)
|
)
|
||||||
|
|
||||||
// get the response from the correct part of the application
|
// get the response from the correct part of the application
|
||||||
val response = when (requestType) {
|
return when (requestType) {
|
||||||
// session requests
|
// session requests
|
||||||
"sessions" -> this.sessionManagerApi.handleRequest(taskSession, httpSession, path)
|
"sessions" -> this.sessionManagerApi.handleRequest(taskSession, httpSession, path)
|
||||||
// entities requests
|
// entities requests
|
||||||
"entities" -> return this.databaseApi.handleRequest(taskSession, httpSession, path)
|
"entities" -> this.databaseApi.handleRequest(taskSession, httpSession, path)
|
||||||
// invalid requests
|
// invalid requests
|
||||||
else ->
|
else ->
|
||||||
newFixedLengthResponse(
|
newFixedLengthResponse(
|
||||||
|
@ -82,9 +85,6 @@ class TaskServer(
|
||||||
"Unknown request type"
|
"Unknown request type"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrap additional information in the response
|
|
||||||
return this.sessionManager.responseSetSessionData(response, httpSession.cookies)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package com.faraphel.tasks_valider.connectivity.task.api
|
package com.faraphel.tasks_valider.connectivity.task.api
|
||||||
|
|
||||||
import com.faraphel.tasks_valider.connectivity.task.session.TaskPermission
|
import com.faraphel.tasks_valider.connectivity.task.session.TaskPermission
|
||||||
import com.faraphel.tasks_valider.connectivity.task.session.TaskRole
|
|
||||||
import com.faraphel.tasks_valider.connectivity.task.session.TaskSession
|
import com.faraphel.tasks_valider.connectivity.task.session.TaskSession
|
||||||
import com.faraphel.tasks_valider.connectivity.task.session.TaskSessionManager
|
import com.faraphel.tasks_valider.connectivity.task.session.TaskSessionManager
|
||||||
|
import com.faraphel.tasks_valider.database.TaskDatabase
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.reflect.TypeToken
|
import com.google.gson.reflect.TypeToken
|
||||||
import fi.iki.elonen.NanoHTTPD
|
import fi.iki.elonen.NanoHTTPD
|
||||||
|
@ -12,7 +12,10 @@ import fi.iki.elonen.NanoHTTPD
|
||||||
/**
|
/**
|
||||||
* the HTTP API for the session manager
|
* the HTTP API for the session manager
|
||||||
*/
|
*/
|
||||||
class TaskSessionManagerApi(private val sessionManager: TaskSessionManager) {
|
class TaskSessionManagerApi(
|
||||||
|
private val sessionManager: TaskSessionManager,
|
||||||
|
private val database: TaskDatabase
|
||||||
|
) {
|
||||||
private val jsonParser = Gson() ///< the json parser
|
private val jsonParser = Gson() ///< the json parser
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,38 +25,41 @@ class TaskSessionManagerApi(private val sessionManager: TaskSessionManager) {
|
||||||
* @param path the path of the request
|
* @param path the path of the request
|
||||||
*/
|
*/
|
||||||
fun handleRequest(
|
fun handleRequest(
|
||||||
taskSession: TaskSession,
|
taskSession: TaskSession?,
|
||||||
httpSession: NanoHTTPD.IHTTPSession,
|
httpSession: NanoHTTPD.IHTTPSession,
|
||||||
path: MutableList<String>,
|
path: MutableList<String>,
|
||||||
): NanoHTTPD.Response {
|
): NanoHTTPD.Response {
|
||||||
// get the target session id
|
val action = path.removeFirstOrNull()
|
||||||
val targetSessionId = path.removeFirstOrNull()
|
|
||||||
|
|
||||||
return if (targetSessionId == null) {
|
return when (action) {
|
||||||
// no specific session targeted
|
"self" -> this.handleRequestSelf(taskSession, httpSession, path)
|
||||||
this.handleRequestGeneric(taskSession, httpSession)
|
"all" -> this.handleRequestAll(taskSession, httpSession, path)
|
||||||
} else {
|
else ->
|
||||||
// a specific session is targeted
|
NanoHTTPD.newFixedLengthResponse(
|
||||||
this.handleRequestSpecific(taskSession, httpSession, targetSessionId)
|
NanoHTTPD.Response.Status.BAD_REQUEST,
|
||||||
|
"text/plain",
|
||||||
|
"Unknown action"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a request with no specific session targeted
|
* Handle an HTTP Api request about the user own session
|
||||||
*/
|
*/
|
||||||
private fun handleRequestGeneric(
|
fun handleRequestSelf(
|
||||||
taskSession: TaskSession,
|
taskSession: TaskSession?,
|
||||||
httpSession: NanoHTTPD.IHTTPSession,
|
httpSession: NanoHTTPD.IHTTPSession,
|
||||||
|
path: MutableList<String>,
|
||||||
): NanoHTTPD.Response {
|
): NanoHTTPD.Response {
|
||||||
when (httpSession.method) {
|
when (httpSession.method) {
|
||||||
// get all the session data
|
// get the session data
|
||||||
NanoHTTPD.Method.GET -> {
|
NanoHTTPD.Method.GET -> {
|
||||||
// check the permission of the session
|
// check if the session is valid
|
||||||
if (taskSession.role.permissions.contains(TaskPermission.READ))
|
if (taskSession == null)
|
||||||
return NanoHTTPD.newFixedLengthResponse(
|
return NanoHTTPD.newFixedLengthResponse(
|
||||||
NanoHTTPD.Response.Status.FORBIDDEN,
|
NanoHTTPD.Response.Status.UNAUTHORIZED,
|
||||||
"text/plain",
|
"text/plain",
|
||||||
"Forbidden"
|
"No session"
|
||||||
)
|
)
|
||||||
|
|
||||||
// return the session data
|
// return the session data
|
||||||
|
@ -63,68 +69,74 @@ class TaskSessionManagerApi(private val sessionManager: TaskSessionManager) {
|
||||||
jsonParser.toJson(taskSession)
|
jsonParser.toJson(taskSession)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// other action are limited
|
|
||||||
else -> {
|
|
||||||
return NanoHTTPD.newFixedLengthResponse(
|
|
||||||
NanoHTTPD.Response.Status.METHOD_NOT_ALLOWED,
|
|
||||||
"text/plain",
|
|
||||||
"Unknown method"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleRequestSpecific(
|
// connect the user to the session
|
||||||
taskSession: TaskSession,
|
|
||||||
httpSession: NanoHTTPD.IHTTPSession,
|
|
||||||
targetSessionId: String,
|
|
||||||
): NanoHTTPD.Response {
|
|
||||||
when (httpSession.method) {
|
|
||||||
// change a specific client session data
|
|
||||||
NanoHTTPD.Method.POST -> {
|
NanoHTTPD.Method.POST -> {
|
||||||
// check the permission of the session
|
// get the user identifiers
|
||||||
if (taskSession.role.permissions.contains(TaskPermission.ADMIN))
|
val identifiers: Map<String, String> = jsonParser.fromJson(
|
||||||
|
httpSession.inputStream.bufferedReader().readText(),
|
||||||
|
object : TypeToken<Map<String, String>>() {}.type
|
||||||
|
)
|
||||||
|
|
||||||
|
// check for the id
|
||||||
|
if (!identifiers.contains("id"))
|
||||||
return NanoHTTPD.newFixedLengthResponse(
|
return NanoHTTPD.newFixedLengthResponse(
|
||||||
NanoHTTPD.Response.Status.FORBIDDEN,
|
NanoHTTPD.Response.Status.BAD_REQUEST,
|
||||||
"text/plain",
|
"text/plain",
|
||||||
"You are not allowed to update a session"
|
"Missing id"
|
||||||
)
|
)
|
||||||
|
|
||||||
// parse the content of the request
|
// get the id of the user (if invalid, return an error)
|
||||||
val targetSession = jsonParser.fromJson(
|
val personId: Long = identifiers["id"]!!.toLongOrNull()
|
||||||
httpSession.inputStream.bufferedReader().readText(),
|
?: return NanoHTTPD.newFixedLengthResponse(
|
||||||
TaskSession::class.java
|
NanoHTTPD.Response.Status.BAD_REQUEST,
|
||||||
)
|
"text/plain",
|
||||||
|
"Invalid id"
|
||||||
|
)
|
||||||
|
|
||||||
// update the session
|
// check for the password
|
||||||
this.sessionManager.setSessionData(targetSessionId, targetSession)
|
if (!identifiers.contains("password"))
|
||||||
|
return NanoHTTPD.newFixedLengthResponse(
|
||||||
|
NanoHTTPD.Response.Status.BAD_REQUEST,
|
||||||
|
"text/plain",
|
||||||
|
"Missing password"
|
||||||
|
)
|
||||||
|
|
||||||
// success message
|
// check if the identifiers are correct
|
||||||
return NanoHTTPD.newFixedLengthResponse(
|
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(
|
||||||
|
NanoHTTPD.Response.Status.UNAUTHORIZED,
|
||||||
|
"text/plain",
|
||||||
|
"Invalid password"
|
||||||
|
)
|
||||||
|
|
||||||
|
// create a new session for the userJHH
|
||||||
|
val (sessionToken, session) = this.sessionManager.newSessionData(person)
|
||||||
|
|
||||||
|
// create the response
|
||||||
|
val response = NanoHTTPD.newFixedLengthResponse(
|
||||||
NanoHTTPD.Response.Status.OK,
|
NanoHTTPD.Response.Status.OK,
|
||||||
"text/plain",
|
"text/plain",
|
||||||
"Session updated"
|
"Session updated"
|
||||||
)
|
)
|
||||||
}
|
|
||||||
// delete the session
|
|
||||||
NanoHTTPD.Method.DELETE -> {
|
|
||||||
// check the permission of the session
|
|
||||||
if (taskSession.role.permissions.contains(TaskPermission.ADMIN))
|
|
||||||
return NanoHTTPD.newFixedLengthResponse(
|
|
||||||
NanoHTTPD.Response.Status.FORBIDDEN,
|
|
||||||
"text/plain",
|
|
||||||
"You are not allowed to delete a session"
|
|
||||||
)
|
|
||||||
|
|
||||||
// delete the target session
|
// set the session token in the cookies
|
||||||
this.sessionManager.deleteSessionData(targetSessionId)
|
this.sessionManager.responseSetSessionData(
|
||||||
|
response,
|
||||||
// success message
|
httpSession.cookies,
|
||||||
return NanoHTTPD.newFixedLengthResponse(
|
sessionToken
|
||||||
NanoHTTPD.Response.Status.OK,
|
|
||||||
"text/plain",
|
|
||||||
"Session deleted"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// return the response
|
||||||
|
return response
|
||||||
}
|
}
|
||||||
// ignore other methods
|
// ignore other methods
|
||||||
else -> {
|
else -> {
|
||||||
|
@ -136,4 +148,86 @@ class TaskSessionManagerApi(private val sessionManager: TaskSessionManager) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Handle an HTTP Api request about all the sessions
|
||||||
|
*/
|
||||||
|
private fun handleRequestAll(
|
||||||
|
taskSession: TaskSession?,
|
||||||
|
httpSession: NanoHTTPD.IHTTPSession,
|
||||||
|
path: MutableList<String>,
|
||||||
|
): NanoHTTPD.Response {
|
||||||
|
// check if the session is valid
|
||||||
|
if (taskSession == null)
|
||||||
|
return NanoHTTPD.newFixedLengthResponse(
|
||||||
|
NanoHTTPD.Response.Status.UNAUTHORIZED,
|
||||||
|
"text/plain",
|
||||||
|
"No session"
|
||||||
|
)
|
||||||
|
|
||||||
|
// check the permission of the session
|
||||||
|
if (taskSession.person.role.permissions.contains(TaskPermission.ADMIN))
|
||||||
|
return NanoHTTPD.newFixedLengthResponse(
|
||||||
|
NanoHTTPD.Response.Status.FORBIDDEN,
|
||||||
|
"text/plain",
|
||||||
|
"You are not allowed to update a session"
|
||||||
|
)
|
||||||
|
|
||||||
|
when (httpSession.method) {
|
||||||
|
// change a specific client session data
|
||||||
|
NanoHTTPD.Method.POST -> {
|
||||||
|
// parse the content of the request
|
||||||
|
val targetSession = jsonParser.fromJson(
|
||||||
|
httpSession.inputStream.bufferedReader().readText(),
|
||||||
|
TaskSession::class.java
|
||||||
|
)
|
||||||
|
|
||||||
|
val targetSessionToken = path.removeFirstOrNull()
|
||||||
|
?: return NanoHTTPD.newFixedLengthResponse(
|
||||||
|
NanoHTTPD.Response.Status.BAD_REQUEST,
|
||||||
|
"text/plain",
|
||||||
|
"Missing session token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// update the session
|
||||||
|
this.sessionManager.updateSessionData(targetSessionToken, targetSession)
|
||||||
|
|
||||||
|
// success message
|
||||||
|
return NanoHTTPD.newFixedLengthResponse(
|
||||||
|
NanoHTTPD.Response.Status.OK,
|
||||||
|
"text/plain",
|
||||||
|
"Session updated"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete the session
|
||||||
|
NanoHTTPD.Method.DELETE -> {
|
||||||
|
val targetSessionToken = path.removeFirstOrNull()
|
||||||
|
?: return NanoHTTPD.newFixedLengthResponse(
|
||||||
|
NanoHTTPD.Response.Status.BAD_REQUEST,
|
||||||
|
"text/plain",
|
||||||
|
"Missing session token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// delete the target session
|
||||||
|
this.sessionManager.deleteSessionData(targetSessionToken)
|
||||||
|
|
||||||
|
// success message
|
||||||
|
return NanoHTTPD.newFixedLengthResponse(
|
||||||
|
NanoHTTPD.Response.Status.OK,
|
||||||
|
"text/plain",
|
||||||
|
"Session deleted"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore other methods
|
||||||
|
else -> {
|
||||||
|
return NanoHTTPD.newFixedLengthResponse(
|
||||||
|
NanoHTTPD.Response.Status.METHOD_NOT_ALLOWED,
|
||||||
|
"text/plain",
|
||||||
|
"Invalid method"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package com.faraphel.tasks_valider.connectivity.task.session
|
package com.faraphel.tasks_valider.connectivity.task.session
|
||||||
|
|
||||||
|
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* store the data of a session in the task system
|
* store the data of a session in the task system
|
||||||
* @param role the role accorded to the session
|
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class TaskSession(
|
data class TaskSession(
|
||||||
var role: TaskRole = TaskRole.STUDENT
|
val person: PersonEntity,
|
||||||
)
|
)
|
|
@ -1,7 +1,6 @@
|
||||||
package com.faraphel.tasks_valider.connectivity.task.session
|
package com.faraphel.tasks_valider.connectivity.task.session
|
||||||
|
|
||||||
import com.google.gson.Gson
|
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
||||||
import com.google.gson.reflect.TypeToken
|
|
||||||
import fi.iki.elonen.NanoHTTPD
|
import fi.iki.elonen.NanoHTTPD
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
@ -9,21 +8,37 @@ import java.util.*
|
||||||
/**
|
/**
|
||||||
* The manager for the session system
|
* The manager for the session system
|
||||||
*/
|
*/
|
||||||
class TaskSessionManager {
|
class TaskSessionManager(///< the admin person entity
|
||||||
|
private val adminPersonEntity: PersonEntity
|
||||||
|
) {
|
||||||
private val sessions = mutableMapOf<String, TaskSession>() ///< sessions specific data
|
private val sessions = mutableMapOf<String, TaskSession>() ///< sessions specific data
|
||||||
|
|
||||||
|
private val adminPersonData = this.newSessionData(this.adminPersonEntity) ///< the session of the admin
|
||||||
|
val adminSessionToken = this.adminPersonData.first ///< the session token of the admin
|
||||||
|
val adminSession = this.adminPersonData.second ///< the session of the admin
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the admin person entity
|
||||||
|
* @return the admin person entity
|
||||||
|
*/
|
||||||
|
fun getAdminPersonEntity(): PersonEntity {
|
||||||
|
return this.adminPersonEntity
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new session
|
* Create a new session
|
||||||
* @param session the data for the session (optional)
|
* @param person the person for the session (optional)
|
||||||
* @param sessionId the session id to use (optional)
|
* @return a new session identifier and the corresponding session
|
||||||
* @return a new session identifier
|
|
||||||
*/
|
*/
|
||||||
fun newSessionData(
|
fun newSessionData(person: PersonEntity): Pair<String, TaskSession> {
|
||||||
session: TaskSession = TaskSession(),
|
// create a new session token that is a secret random string
|
||||||
sessionId: String = UUID.randomUUID().toString()
|
val sessionToken: String = UUID.randomUUID().toString()
|
||||||
): String {
|
// create a new session
|
||||||
this.sessions[sessionId] = session
|
val session = TaskSession(person)
|
||||||
return sessionId
|
// store the session
|
||||||
|
this.sessions[sessionToken] = session
|
||||||
|
// return the session data
|
||||||
|
return Pair(sessionToken, session)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,54 +46,60 @@ class TaskSessionManager {
|
||||||
* @param httpSession the HTTP session
|
* @param httpSession the HTTP session
|
||||||
* @return the session data
|
* @return the session data
|
||||||
*/
|
*/
|
||||||
fun getSessionData(httpSession: NanoHTTPD.IHTTPSession): TaskSession? {
|
fun getSessionData(httpSession: NanoHTTPD.IHTTPSession): Pair<String, TaskSession>? {
|
||||||
val sessionId = httpSession.cookies.read("sessionId") ?: return null
|
// get the session token from the cookies
|
||||||
val sessionData = this.getSessionData(sessionId)
|
val sessionToken = httpSession.cookies.read("sessionToken") ?: return null
|
||||||
|
// get the session data
|
||||||
|
val sessionData = this.getSessionData(sessionToken)
|
||||||
|
// return the session data
|
||||||
return sessionData
|
return sessionData
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get data from a session identifier
|
* Get data from a session identifier
|
||||||
* @param sessionId the identifier of the session
|
* @param sessionToken the identifier of the session
|
||||||
* @return the session data
|
* @return the session data
|
||||||
*/
|
*/
|
||||||
fun getSessionData(sessionId: String): TaskSession? {
|
fun getSessionData(sessionToken: String): Pair<String, TaskSession>? {
|
||||||
return this.sessions[sessionId]
|
// get the session data
|
||||||
|
val session = this.sessions[sessionToken]
|
||||||
|
?: return null
|
||||||
|
// return the session data
|
||||||
|
return Pair(sessionToken, session)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the data of a session
|
* Update the session data
|
||||||
* @param sessionId the identifier of the session
|
* @param sessionToken the identifier of the session
|
||||||
* @param session the session data
|
* @param session the new session data
|
||||||
*/
|
*/
|
||||||
fun setSessionData(sessionId: String, session: TaskSession) {
|
fun updateSessionData(sessionToken: String, session: TaskSession) {
|
||||||
this.sessions[sessionId] = session
|
// update the session
|
||||||
|
this.sessions[sessionToken] = session
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a session
|
* Delete a session
|
||||||
* @param sessionId the identifier of the session
|
* @param sessionToken the identifier of the session
|
||||||
*/
|
*/
|
||||||
fun deleteSessionData(sessionId: String): TaskSession? {
|
fun deleteSessionData(sessionToken: String): Pair<String, TaskSession>? {
|
||||||
return this.sessions.remove(sessionId)
|
// remove the session
|
||||||
|
val session = this.sessions.remove(sessionToken) ?:
|
||||||
|
return null
|
||||||
|
// return the session data
|
||||||
|
return Pair(sessionToken, session)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get data from a http session. If it does not exist, create it.
|
* Get data from a http session. If it does not exist, create it.
|
||||||
* @param httpSession the HTTP session
|
* @param httpSession the HTTP session
|
||||||
*/
|
*/
|
||||||
fun getOrCreateSessionData(httpSession: NanoHTTPD.IHTTPSession): TaskSession {
|
fun getOrCreateSessionData(httpSession: NanoHTTPD.IHTTPSession, person: PersonEntity): Pair<String, TaskSession> {
|
||||||
// try to get the session directly
|
// try to get the session directly
|
||||||
var session = this.getSessionData(httpSession)
|
val sessionData = this.getSessionData(httpSession)
|
||||||
|
?: this.newSessionData(person)
|
||||||
// if the session does not exist, create it
|
// return the session data
|
||||||
if (session == null) {
|
return sessionData
|
||||||
val sessionId = this.newSessionData()
|
|
||||||
session = this.getSessionData(sessionId)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the session
|
|
||||||
return session
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,10 +109,11 @@ class TaskSessionManager {
|
||||||
*/
|
*/
|
||||||
fun responseSetSessionData(
|
fun responseSetSessionData(
|
||||||
response: NanoHTTPD.Response,
|
response: NanoHTTPD.Response,
|
||||||
cookies: NanoHTTPD.CookieHandler
|
cookies: NanoHTTPD.CookieHandler,
|
||||||
|
sessionToken: String
|
||||||
): NanoHTTPD.Response {
|
): NanoHTTPD.Response {
|
||||||
// update the cookie of the user
|
// update the cookie of the user
|
||||||
cookies.set(NanoHTTPD.Cookie("sessionId", this.newSessionData()))
|
cookies.set(NanoHTTPD.Cookie("sessionToken", sessionToken))
|
||||||
// load them in the response
|
// load them in the response
|
||||||
cookies.unloadQueue(response)
|
cookies.unloadQueue(response)
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,18 @@ class TaskDatabaseApi(private val database: TaskDatabase) {
|
||||||
* @param path the path of the request
|
* @param path the path of the request
|
||||||
*/
|
*/
|
||||||
fun handleRequest(
|
fun handleRequest(
|
||||||
taskSession: TaskSession,
|
taskSession: TaskSession?,
|
||||||
httpSession: NanoHTTPD.IHTTPSession,
|
httpSession: NanoHTTPD.IHTTPSession,
|
||||||
path: MutableList<String>
|
path: MutableList<String>
|
||||||
): NanoHTTPD.Response {
|
): NanoHTTPD.Response {
|
||||||
|
// check if the user is authenticated
|
||||||
|
if (taskSession == null)
|
||||||
|
return NanoHTTPD.newFixedLengthResponse(
|
||||||
|
NanoHTTPD.Response.Status.UNAUTHORIZED,
|
||||||
|
"text/plain",
|
||||||
|
"Unauthorized"
|
||||||
|
)
|
||||||
|
|
||||||
// get the entity name
|
// get the entity name
|
||||||
val entityName = path.removeFirstOrNull()
|
val entityName = path.removeFirstOrNull()
|
||||||
?: return NanoHTTPD.newFixedLengthResponse(
|
?: return NanoHTTPD.newFixedLengthResponse(
|
||||||
|
@ -53,7 +61,7 @@ class TaskDatabaseApi(private val database: TaskDatabase) {
|
||||||
// TODO(Faraphel): should only be allowed to read data concerning the current class session
|
// TODO(Faraphel): should only be allowed to read data concerning the current class session
|
||||||
NanoHTTPD.Method.HEAD -> {
|
NanoHTTPD.Method.HEAD -> {
|
||||||
// check the permission of the session
|
// check the permission of the session
|
||||||
if (taskSession.role.permissions.contains(TaskPermission.READ))
|
if (taskSession.person.role.permissions.contains(TaskPermission.READ))
|
||||||
return NanoHTTPD.newFixedLengthResponse(
|
return NanoHTTPD.newFixedLengthResponse(
|
||||||
NanoHTTPD.Response.Status.FORBIDDEN,
|
NanoHTTPD.Response.Status.FORBIDDEN,
|
||||||
"text/plain",
|
"text/plain",
|
||||||
|
@ -65,7 +73,7 @@ class TaskDatabaseApi(private val database: TaskDatabase) {
|
||||||
// get the data from the database
|
// get the data from the database
|
||||||
NanoHTTPD.Method.GET -> {
|
NanoHTTPD.Method.GET -> {
|
||||||
// check the permission of the session
|
// check the permission of the session
|
||||||
if (taskSession.role.permissions.contains(TaskPermission.READ))
|
if (taskSession.person.role.permissions.contains(TaskPermission.READ))
|
||||||
return NanoHTTPD.newFixedLengthResponse(
|
return NanoHTTPD.newFixedLengthResponse(
|
||||||
NanoHTTPD.Response.Status.FORBIDDEN,
|
NanoHTTPD.Response.Status.FORBIDDEN,
|
||||||
"text/plain",
|
"text/plain",
|
||||||
|
@ -77,7 +85,7 @@ class TaskDatabaseApi(private val database: TaskDatabase) {
|
||||||
// insert the data into the database
|
// insert the data into the database
|
||||||
NanoHTTPD.Method.POST -> {
|
NanoHTTPD.Method.POST -> {
|
||||||
// check the permission of the session
|
// check the permission of the session
|
||||||
if (taskSession.role.permissions.contains(TaskPermission.WRITE))
|
if (taskSession.person.role.permissions.contains(TaskPermission.WRITE))
|
||||||
return NanoHTTPD.newFixedLengthResponse(
|
return NanoHTTPD.newFixedLengthResponse(
|
||||||
NanoHTTPD.Response.Status.FORBIDDEN,
|
NanoHTTPD.Response.Status.FORBIDDEN,
|
||||||
"text/plain",
|
"text/plain",
|
||||||
|
@ -89,7 +97,7 @@ class TaskDatabaseApi(private val database: TaskDatabase) {
|
||||||
// delete the data from the database
|
// delete the data from the database
|
||||||
NanoHTTPD.Method.DELETE -> {
|
NanoHTTPD.Method.DELETE -> {
|
||||||
// check the permission of the session
|
// check the permission of the session
|
||||||
if (taskSession.role.permissions.contains(TaskPermission.WRITE))
|
if (taskSession.person.role.permissions.contains(TaskPermission.WRITE))
|
||||||
return NanoHTTPD.newFixedLengthResponse(
|
return NanoHTTPD.newFixedLengthResponse(
|
||||||
NanoHTTPD.Response.Status.FORBIDDEN,
|
NanoHTTPD.Response.Status.FORBIDDEN,
|
||||||
"text/plain",
|
"text/plain",
|
||||||
|
|
|
@ -17,7 +17,7 @@ interface ClassDao : BaseDao<ClassEntity> {
|
||||||
* Get the object from its identifier
|
* Get the object from its identifier
|
||||||
*/
|
*/
|
||||||
@Query("SELECT * FROM ${ClassEntity.TABLE_NAME} WHERE id = :id")
|
@Query("SELECT * FROM ${ClassEntity.TABLE_NAME} WHERE id = :id")
|
||||||
fun getById(id: Long): ClassEntity
|
fun getById(id: Long): ClassEntity?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the sessions this class attended
|
* Get all the sessions this class attended
|
||||||
|
|
|
@ -14,7 +14,7 @@ interface PersonDao : BaseDao<PersonEntity> {
|
||||||
* Get the object from its identifier
|
* Get the object from its identifier
|
||||||
*/
|
*/
|
||||||
@Query("SELECT * FROM ${PersonEntity.TABLE_NAME} WHERE id = :id")
|
@Query("SELECT * FROM ${PersonEntity.TABLE_NAME} WHERE id = :id")
|
||||||
fun getById(id: Long): PersonEntity
|
fun getById(id: Long): PersonEntity?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow to get all the classes the person is attending as a student
|
* Allow to get all the classes the person is attending as a student
|
||||||
|
|
|
@ -19,5 +19,5 @@ interface RelationClassPersonDao : BaseDao<RelationClassPersonEntity> {
|
||||||
"class_id = :classId AND " +
|
"class_id = :classId AND " +
|
||||||
"student_id = :studentId"
|
"student_id = :studentId"
|
||||||
)
|
)
|
||||||
fun getById(classId: Long, studentId: Long): RelationClassPersonEntity
|
fun getById(classId: Long, studentId: Long): RelationClassPersonEntity?
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,5 +14,5 @@ interface SessionDao : BaseDao<SessionEntity> {
|
||||||
* Get the object from its identifier
|
* Get the object from its identifier
|
||||||
*/
|
*/
|
||||||
@Query("SELECT * FROM ${SessionEntity.TABLE_NAME} WHERE id = :id")
|
@Query("SELECT * FROM ${SessionEntity.TABLE_NAME} WHERE id = :id")
|
||||||
fun getById(id: Long): SessionEntity
|
fun getById(id: Long): SessionEntity?
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ interface SubjectDao : BaseDao<SubjectEntity> {
|
||||||
* Get the object from its identifier
|
* Get the object from its identifier
|
||||||
*/
|
*/
|
||||||
@Query("SELECT * FROM ${SubjectEntity.TABLE_NAME} WHERE id = :id")
|
@Query("SELECT * FROM ${SubjectEntity.TABLE_NAME} WHERE id = :id")
|
||||||
fun getById(id: Long): SubjectEntity
|
fun getById(id: Long): SubjectEntity?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the tasks available in a subject
|
* Get all the tasks available in a subject
|
||||||
|
|
|
@ -15,7 +15,7 @@ interface TaskDao : BaseDao<TaskEntity> {
|
||||||
* Get the object from its identifier
|
* Get the object from its identifier
|
||||||
*/
|
*/
|
||||||
@Query("SELECT * FROM ${TaskEntity.TABLE_NAME} WHERE id = :id")
|
@Query("SELECT * FROM ${TaskEntity.TABLE_NAME} WHERE id = :id")
|
||||||
fun getById(id: Long): TaskEntity
|
fun getById(id: Long): TaskEntity?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the validations have been approved for this tasks
|
* Get all the validations have been approved for this tasks
|
||||||
|
|
|
@ -20,5 +20,5 @@ interface ValidationDao : BaseDao<ValidationEntity> {
|
||||||
"student_id = :studentId and " +
|
"student_id = :studentId and " +
|
||||||
"task_id = :taskId"
|
"task_id = :taskId"
|
||||||
)
|
)
|
||||||
fun getById(teacherId: Long, studentId: Long, taskId: Long): ValidationEntity
|
fun getById(teacherId: Long, studentId: Long, taskId: Long): ValidationEntity?
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,61 @@
|
||||||
package com.faraphel.tasks_valider.database.entities
|
package com.faraphel.tasks_valider.database.entities
|
||||||
|
|
||||||
import androidx.compose.ui.text.capitalize
|
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
import com.faraphel.tasks_valider.connectivity.task.session.TaskRole
|
||||||
import com.faraphel.tasks_valider.database.entities.base.BaseEntity
|
import com.faraphel.tasks_valider.database.entities.base.BaseEntity
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import java.security.MessageDigest
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
@Serializable
|
||||||
@Entity(tableName = PersonEntity.TABLE_NAME)
|
@Entity(tableName = PersonEntity.TABLE_NAME)
|
||||||
data class PersonEntity (
|
data class PersonEntity (
|
||||||
@ColumnInfo("id") @PrimaryKey(autoGenerate = true) val id: Long = 0,
|
@ColumnInfo("id") @PrimaryKey(autoGenerate = true) val id: Long = 0,
|
||||||
@ColumnInfo("first_name") val firstName: String,
|
@ColumnInfo("first_name") val firstName: String,
|
||||||
@ColumnInfo("last_name") val lastName: String,
|
@ColumnInfo("last_name") val lastName: String,
|
||||||
@ColumnInfo("card_id") val cardId: UUID,
|
@ColumnInfo("card_id") val cardId: String? = null,
|
||||||
@ColumnInfo("password_hash") val passwordHash: String
|
@ColumnInfo("password_hash") val passwordHash: String? = null,
|
||||||
|
@ColumnInfo("role") val role: TaskRole = TaskRole.STUDENT,
|
||||||
) : BaseEntity() {
|
) : BaseEntity() {
|
||||||
|
companion object {
|
||||||
|
const val TABLE_NAME = "persons"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash a password
|
||||||
|
*/
|
||||||
|
fun hashPassword(password: String): String {
|
||||||
|
val digester = MessageDigest.getInstance("SHA-256")
|
||||||
|
val hash = digester.digest(password.toByteArray())
|
||||||
|
return hash.joinToString("") { byte -> "%02x".format(byte) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor with string password
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
firstName: String,
|
||||||
|
lastName: String,
|
||||||
|
cardId: String? = null,
|
||||||
|
password: String? = null,
|
||||||
|
role: TaskRole,
|
||||||
|
) : this(
|
||||||
|
firstName = firstName,
|
||||||
|
lastName = lastName,
|
||||||
|
cardId = cardId,
|
||||||
|
passwordHash = password?.let { hashPassword(password) },
|
||||||
|
role = role,
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the full name of the person
|
* Return the full name of the person
|
||||||
*/
|
*/
|
||||||
fun fullName(): String = "${this.firstName.capitalize()} ${this.lastName.uppercase()}"
|
fun fullName(): String = "${this.firstName.capitalize(Locale.ROOT)} ${this.lastName.uppercase()}"
|
||||||
|
|
||||||
companion object {
|
/**
|
||||||
const val TABLE_NAME = "persons"
|
* Check if the password is correct
|
||||||
}
|
*/
|
||||||
|
fun checkPassword(password: String): Boolean = this.passwordHash == hashPassword(password)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
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.MutableState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import com.faraphel.tasks_valider.connectivity.task.session.TaskRole
|
||||||
|
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentification screen where the host can give his information
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun AuthentificationServerScreen(personEntity: MutableState<PersonEntity?>) {
|
||||||
|
val firstName = remember { mutableStateOf("") }
|
||||||
|
val lastName = remember { mutableStateOf("") }
|
||||||
|
|
||||||
|
Column {
|
||||||
|
// first name
|
||||||
|
TextField(
|
||||||
|
value = firstName.value,
|
||||||
|
onValueChange = { text -> firstName.value = text },
|
||||||
|
)
|
||||||
|
|
||||||
|
// last name
|
||||||
|
TextField(
|
||||||
|
value = lastName.value,
|
||||||
|
onValueChange = { text -> lastName.value = text },
|
||||||
|
)
|
||||||
|
|
||||||
|
// confirm button
|
||||||
|
Button(onClick = {
|
||||||
|
// create the person entity with the given information
|
||||||
|
personEntity.value = PersonEntity(
|
||||||
|
firstName = firstName.value,
|
||||||
|
lastName = lastName.value,
|
||||||
|
role = TaskRole.ADMIN
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
Text("Submit")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ import com.faraphel.tasks_valider.ui.screen.communication.internet.server.Commun
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommunicationInternetScreen(activity: Activity) {
|
fun CommunicationInternetSelectScreen(activity: Activity) {
|
||||||
val controller = rememberNavController()
|
val controller = rememberNavController()
|
||||||
|
|
||||||
NavHost(navController = controller, startDestination = "mode") {
|
NavHost(navController = controller, startDestination = "mode") {
|
|
@ -19,24 +19,47 @@ import androidx.room.Room
|
||||||
import com.faraphel.tasks_valider.connectivity.task.TaskClient
|
import com.faraphel.tasks_valider.connectivity.task.TaskClient
|
||||||
import com.faraphel.tasks_valider.connectivity.task.TaskServer
|
import com.faraphel.tasks_valider.connectivity.task.TaskServer
|
||||||
import com.faraphel.tasks_valider.database.TaskDatabase
|
import com.faraphel.tasks_valider.database.TaskDatabase
|
||||||
|
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
||||||
|
import com.faraphel.tasks_valider.ui.screen.authentification.AuthentificationServerScreen
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT
|
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.communication.RANGE_SERVER_PORT
|
||||||
import com.faraphel.tasks_valider.ui.screen.task.TaskSessionScreen
|
import com.faraphel.tasks_valider.ui.screen.task.TaskSessionScreen
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screen for the host to configure the server
|
||||||
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun CommunicationInternetServerScreen(activity: Activity) {
|
fun CommunicationInternetServerScreen(activity: Activity) {
|
||||||
|
val adminPersonEntity = remember { mutableStateOf<PersonEntity?>(null) }
|
||||||
|
|
||||||
|
// if the admin person is not created, prompt the user for the admin information
|
||||||
|
if (adminPersonEntity.value == null) {
|
||||||
|
return AuthentificationServerScreen(adminPersonEntity)
|
||||||
|
}
|
||||||
|
|
||||||
val client = remember { mutableStateOf<TaskClient?>(null) }
|
val client = remember { mutableStateOf<TaskClient?>(null) }
|
||||||
|
|
||||||
// if the server is not created, prompt the user for the server configuration
|
// if the client to the server is not created, prompt the user for the server configuration
|
||||||
if (client.value == null) CommunicationInternetServerContent(activity, client)
|
if (client.value == null) {
|
||||||
// else, go to the base tasks screen
|
return CommunicationInternetServerContent(
|
||||||
else TaskSessionScreen(activity, client.value!!)
|
activity,
|
||||||
|
adminPersonEntity.value!!,
|
||||||
|
client
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, go to the base tasks screen
|
||||||
|
return TaskSessionScreen(activity, client.value!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommunicationInternetServerContent(activity: Activity, client: MutableState<TaskClient?>) {
|
fun CommunicationInternetServerContent(
|
||||||
|
activity: Activity,
|
||||||
|
adminPersonEntity: PersonEntity,
|
||||||
|
client: MutableState<TaskClient?>
|
||||||
|
) {
|
||||||
val expandedStudentList = remember { mutableStateOf(false) }
|
val expandedStudentList = remember { mutableStateOf(false) }
|
||||||
val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) }
|
val serverPort = remember { mutableIntStateOf(DEFAULT_SERVER_PORT) }
|
||||||
|
|
||||||
|
@ -73,24 +96,27 @@ fun CommunicationInternetServerContent(activity: Activity, client: MutableState<
|
||||||
)
|
)
|
||||||
|
|
||||||
Button(onClick = {
|
Button(onClick = {
|
||||||
// Reset the database | TODO(Faraphel): only for testing purpose
|
|
||||||
activity.deleteDatabase("local")
|
|
||||||
|
|
||||||
// Create the database
|
|
||||||
val database = Room.databaseBuilder(
|
|
||||||
activity,
|
|
||||||
TaskDatabase::class.java,
|
|
||||||
"local"
|
|
||||||
).build()
|
|
||||||
|
|
||||||
// Create the server
|
|
||||||
Log.i("room-server", "creating the server")
|
|
||||||
Thread { // a thread is used for networking
|
Thread { // a thread is used for networking
|
||||||
val server = TaskServer(serverPort.intValue, database)
|
// Reset the database | TODO(Faraphel): only for testing purpose
|
||||||
|
activity.deleteDatabase("local")
|
||||||
|
|
||||||
|
// Create the database
|
||||||
|
val database = Room.databaseBuilder(
|
||||||
|
activity,
|
||||||
|
TaskDatabase::class.java,
|
||||||
|
"local"
|
||||||
|
).build()
|
||||||
|
|
||||||
|
// Insert the admin in the database
|
||||||
|
database.personDao().insert(adminPersonEntity)
|
||||||
|
|
||||||
|
// Create the server
|
||||||
|
Log.i("room-server", "creating the server")
|
||||||
|
val server = TaskServer(serverPort.intValue, database, adminPersonEntity)
|
||||||
server.start()
|
server.start()
|
||||||
|
|
||||||
// Get the client from the server
|
// Get the client from the server
|
||||||
client.value = server.getClientAdmin()
|
client.value = server.getAdminClient()
|
||||||
}.start()
|
}.start()
|
||||||
}) {
|
}) {
|
||||||
Text("Create")
|
Text("Create")
|
||||||
|
|
|
@ -13,7 +13,7 @@ import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.internet.CommunicationInternetScreen
|
import com.faraphel.tasks_valider.ui.screen.communication.internet.CommunicationInternetSelectScreen
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.CommunicationWifiP2pScreen
|
import com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.CommunicationWifiP2pScreen
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ import com.faraphel.tasks_valider.ui.screen.communication.wifiP2p.CommunicationW
|
||||||
* @param activity: The activity that hosts the communication screen.
|
* @param activity: The activity that hosts the communication screen.
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun CommunicationScreen(activity: Activity) {
|
fun CommunicationModeSelectionScreen(activity: Activity) {
|
||||||
val controller = rememberNavController()
|
val controller = rememberNavController()
|
||||||
|
|
||||||
NavHost(
|
NavHost(
|
||||||
|
@ -35,7 +35,7 @@ fun CommunicationScreen(activity: Activity) {
|
||||||
CommunicationSelectContent(controller, activity)
|
CommunicationSelectContent(controller, activity)
|
||||||
}
|
}
|
||||||
composable("internet") {
|
composable("internet") {
|
||||||
CommunicationInternetScreen(activity)
|
CommunicationInternetSelectScreen(activity)
|
||||||
}
|
}
|
||||||
composable("wifi-p2p") {
|
composable("wifi-p2p") {
|
||||||
val bwfManager = BwfManager.fromActivity(activity)
|
val bwfManager = BwfManager.fromActivity(activity)
|
|
@ -20,6 +20,7 @@ import com.faraphel.tasks_valider.connectivity.bwf.BwfManager
|
||||||
import com.faraphel.tasks_valider.connectivity.task.TaskClient
|
import com.faraphel.tasks_valider.connectivity.task.TaskClient
|
||||||
import com.faraphel.tasks_valider.connectivity.task.TaskServer
|
import com.faraphel.tasks_valider.connectivity.task.TaskServer
|
||||||
import com.faraphel.tasks_valider.database.TaskDatabase
|
import com.faraphel.tasks_valider.database.TaskDatabase
|
||||||
|
import com.faraphel.tasks_valider.database.entities.PersonEntity
|
||||||
import com.faraphel.tasks_valider.ui.screen.communication.DEFAULT_SERVER_PORT
|
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.communication.RANGE_SERVER_PORT
|
||||||
import com.faraphel.tasks_valider.ui.screen.task.TaskSessionScreen
|
import com.faraphel.tasks_valider.ui.screen.task.TaskSessionScreen
|
||||||
|
@ -90,14 +91,25 @@ fun CommunicationWifiP2pServerContent(
|
||||||
"local"
|
"local"
|
||||||
).build()
|
).build()
|
||||||
|
|
||||||
|
// Create the admin
|
||||||
|
// TODO: the admin should be created from the card reader
|
||||||
|
val adminPersonEntity = PersonEntity(
|
||||||
|
"admin",
|
||||||
|
"admin",
|
||||||
|
"123456789",
|
||||||
|
"admin",
|
||||||
|
)
|
||||||
|
|
||||||
|
// Insert the admin in the database
|
||||||
|
database.personDao().insert(adminPersonEntity)
|
||||||
|
|
||||||
bwfManager.recreateGroup {
|
bwfManager.recreateGroup {
|
||||||
// Create the server
|
// Create the server
|
||||||
Log.i("room-server", "creating the server")
|
val server = TaskServer(serverPort.intValue, database, adminPersonEntity)
|
||||||
val server = TaskServer(serverPort.intValue, database)
|
|
||||||
server.start()
|
server.start()
|
||||||
|
|
||||||
// Get the client from the server
|
// Get the client from the server
|
||||||
client.value = server.getClientAdmin()
|
client.value = server.getAdminClient()
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
Text("Create")
|
Text("Create")
|
||||||
|
|
Loading…
Reference in a new issue