Skip to content

Commit

Permalink
Improve conference management (#34)
Browse files Browse the repository at this point in the history
* Send and react to "LEAVE_CONFERENCE" Messages.

* Detect closed ConferenceWindow and delete conference after 60s if still empty.

* Remove SetOnce property.

* Remove SetOnce property.

* Time conference deletion in backend.
Delete 20s after the last user left, if the conference is still empty.
Closes #7

* Global error handling in web-ui

* Send and react to "LEAVE_CONFERENCE" Messages.

* Detect closed ConferenceWindow and delete conference after 60s if still empty.

* Remove SetOnce property.

Remove SetOnce property.

* Time conference deletion in backend.
Delete 20s after the last user left, if the conference is still empty.
Closes #7

* Global error handling in web-ui

* Handle multiple conferences in client. #46

* Debug configuration uses localhost:4200 as address.

* Basic display of conferences. TODO: Styling.

* Backend stores multiple conferences per User

* Fixed conference references

* Only take first conference info and check only if its not empty. This assures, that the inviting user has joined a conference before sending the invitation. Fixes #37, #27.

* Only list users in classroom when socket connection is established.

* Change logging levels. Move messages from debug -> trace.

* Fixed problem with exception when calling "last()" on empty Flux.

* Refactoring + Send event when conference is closed.

* Remove priority from create-ticket form.

* Use NotificationService instead of Snackbar.

* Fix typo in component name

* Create conferences via dialog to set name.
Conferences for tickets are created with ticket name.
Fixed ClassroomInfo propagation.

Part of #62, #46.
Step towards #16.

* Refactor classroom-component

* move sorting function

* Fixes #64

* Example env-file.

* Conference + ConferenceInfo hold attendees.

* Ktlint introduction.

* User visibility changeable.
Conference attendence per user is calculated in client to reduce network messages and enable future adjustment via BBB API. #56

* fixed invitation problem.

* tutor PW in Create XML

* Choose which conference to invite to.

* sort users #2

* remove debug log

* [web-gui][UserDisplay] fix linting error

Co-authored-by: Max Stephan <[email protected]>
  • Loading branch information
snicki13 and mxsph authored Sep 28, 2021
1 parent f20333d commit c7edb4a
Show file tree
Hide file tree
Showing 115 changed files with 1,304 additions and 1,053 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ out/
### VS Code ###
.vscode/
/src/main/resources/static/

*.env
!example.env
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ RUN gradle build -i --stacktrace -x npm_run_clean -x npm_run_build
FROM openjdk:11-jdk-slim
COPY --from=build-gradle /build/build/libs/*.jar /app/digital-classroom.jar
EXPOSE 8085
ENTRYPOINT ["java","-jar","/app/digital-classroom.jar"]
ENTRYPOINT ["java","-jar","/app/digital-classroom.jar"]
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ plugins {
kotlin("jvm") version "1.4.32"
kotlin("plugin.spring") version "1.4.32"
kotlin("kapt") version "1.4.32"
id("org.jlleitschuh.gradle.ktlint") version "10.2.0"
id("org.jlleitschuh.gradle.ktlint-idea") version "10.2.0"
}

group = "de.thm.mni.ii"
Expand Down
11 changes: 11 additions & 0 deletions examples/docker-compose/example.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CLASSROOM_BBB_UPSTREAM_URL=https://fk-vv.mni.thm.de/bigbluebutton/api
CLASSROOM_BBB_UPSTREAM_SECRET=8Dsupersecurekeydf0
CLASSROOM_SECRET=8Dsupersecurekeydf0
CLASSROOM_HOST=http://localhost:8085
CLASSROOM_PORT=8085
CLASSROOM_JWT_SECRET=8Dsupersecurekeydf0
CLASSROOM_JWT_EXPIRATION=900
CLASSROOM_SSL_ENABLED=true
CLASSROOM_KEYSTORE_PATH=classpath:keystore.p12
CLASSROOM_KEYSTORE_TYPE=PKCS12
CLASSROOM_KEYSTORE_PASS=passwd
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package de.thm.mni.ii.classroom

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.boot.runApplication


@SpringBootApplication
@ConfigurationPropertiesScan("de.thm.mni.ii.classroom.properties")
class DigitalClassroomApplication
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package de.thm.mni.ii.classroom.config

import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.*
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
Expand All @@ -14,7 +18,7 @@ import java.time.Instant
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.util.*
import java.util.Locale

/**
* DateTimeFormatter for BBB API-like responses.
Expand All @@ -25,7 +29,7 @@ val bbbFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("EEE MMM dd HH
* Configuration for XML & JSON related serialization with Jackson (JSON) or JAX-B (XML).
*/
@Configuration
class SerializationConfig: WebFluxConfigurer {
class SerializationConfig : WebFluxConfigurer {

/**
* Jackson object mapper for JSON serialization.
Expand All @@ -43,14 +47,13 @@ class SerializationConfig: WebFluxConfigurer {
configurer.customCodecs().register(Jaxb2XmlDecoder())
configurer.customCodecs().register(Jaxb2XmlEncoder())
}

}

/**
* Jackson Json Serializer for ZonedDateTime as milliseconds since epoch.
* @see JsonSerializer
*/
class ZonedDateTimeMillisSerializer: JsonSerializer<ZonedDateTime>() {
class ZonedDateTimeMillisSerializer : JsonSerializer<ZonedDateTime>() {
override fun serialize(dateTime: ZonedDateTime, gen: JsonGenerator, provider: SerializerProvider) {
gen.writeNumber(dateTime.toInstant().toEpochMilli())
}
Expand All @@ -60,8 +63,8 @@ class ZonedDateTimeMillisSerializer: JsonSerializer<ZonedDateTime>() {
* Jackson Json Deserializer for ZonedDateTime from milliseconds since epoch.
* @see JsonDeserializer
*/
class ZonedDateTimeMillisDeserializer: JsonDeserializer<ZonedDateTime>() {
class ZonedDateTimeMillisDeserializer : JsonDeserializer<ZonedDateTime>() {
override fun deserialize(parser: JsonParser, context: DeserializationContext?): ZonedDateTime {
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(parser.longValue), ZoneId.systemDefault())
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package de.thm.mni.ii.classroom.controller

import de.thm.mni.ii.classroom.exception.api.ApiException
import de.thm.mni.ii.classroom.model.api.*
import de.thm.mni.ii.classroom.model.api.CreateRoomBBB
import de.thm.mni.ii.classroom.model.api.JoinRoomBBBResponse
import de.thm.mni.ii.classroom.model.api.MessageBBB
import de.thm.mni.ii.classroom.model.api.ReturnCodeBBB
import de.thm.mni.ii.classroom.services.DownstreamApiService
import org.slf4j.LoggerFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.MediaType
import org.springframework.web.reactive.function.server.*
import org.springframework.web.reactive.function.server.ServerRequest
import org.springframework.web.reactive.function.server.ServerResponse
import org.springframework.web.reactive.function.server.queryParamOrNull
import org.springframework.web.reactive.function.server.router
import reactor.core.publisher.Mono
import java.net.URI

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package de.thm.mni.ii.classroom.controller

import de.thm.mni.ii.classroom.security.jwt.ClassroomAuthentication
import org.slf4j.LoggerFactory
import org.springframework.web.bind.annotation.*
import org.springframework.web.bind.annotation.CrossOrigin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import reactor.core.publisher.Mono

@RestController
Expand All @@ -21,5 +24,4 @@ class ClassroomApiController {
fun joinClassroom(auth: ClassroomAuthentication) = Mono.empty<String>().doOnNext {
logger.info("${auth.principal.fullName} joined classroom ${auth.principal.classroomId}.")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,12 @@ import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.io.Resource
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.*
import org.springframework.web.bind.annotation.CrossOrigin
import org.springframework.web.reactive.function.server.RequestPredicates
import org.springframework.web.reactive.function.server.RouterFunction
import org.springframework.web.reactive.function.server.RouterFunctions
import org.springframework.web.reactive.function.server.ServerResponse
import reactor.core.publisher.Mono
import java.net.URI

@Configuration
@CrossOrigin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class ConferenceController(private val conferenceService: ConferenceService) {
return conferenceService.joinConferenceOfUser(joiningUser, conferencingUser)
}

@MessageMapping("socket/conference/leave")
fun leaveConference(@AuthenticationPrincipal user: User, @Payload conferenceInfo: ConferenceInfo): Mono<Void> {
return conferenceService.leaveConference(user, conferenceInfo)
}

@MessageMapping("socket/conference/end")
fun endConference(@AuthenticationPrincipal user: User, @Payload conferenceInfo: ConferenceInfo): Mono<Void> {
TODO("NOT YET IMPLEMENTED")
Expand All @@ -38,5 +43,4 @@ class ConferenceController(private val conferenceService: ConferenceService) {
fun inviteToConference(@AuthenticationPrincipal user: User, @Payload invitationEvent: InvitationEvent): Mono<Void> {
return conferenceService.forwardInvitation(user, invitationEvent)
}

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package de.thm.mni.ii.classroom.controller

import de.thm.mni.ii.classroom.event.ClassroomEvent
import de.thm.mni.ii.classroom.model.classroom.*
import de.thm.mni.ii.classroom.model.classroom.ClassroomInfo
import de.thm.mni.ii.classroom.model.classroom.ConferenceInfo
import de.thm.mni.ii.classroom.model.classroom.Ticket
import de.thm.mni.ii.classroom.model.classroom.User
import de.thm.mni.ii.classroom.model.classroom.UserDisplay
import de.thm.mni.ii.classroom.services.ClassroomEventReceiverService
import de.thm.mni.ii.classroom.services.ClassroomUserService
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.messaging.handler.annotation.MessageMapping
import org.springframework.messaging.handler.annotation.Payload
import org.springframework.messaging.rsocket.RSocketRequester
Expand All @@ -20,8 +22,6 @@ class UserWebSocketController(
private val userService: ClassroomUserService,
private val classroomEventReceiverService: ClassroomEventReceiverService
) {
private val logger: Logger = LoggerFactory.getLogger(this::class.java)

@ConnectMapping
fun connect(@AuthenticationPrincipal user: User, requester: RSocketRequester): Mono<Void> {
return userService.userConnected(user, requester)
Expand All @@ -39,20 +39,16 @@ class UserWebSocketController(

@MessageMapping("socket/init-tickets")
fun initTickets(@AuthenticationPrincipal user: User): Flux<Ticket> {
logger.info("Ticket init!")
return userService.getTickets(user)
}

@MessageMapping("socket/init-users")
fun initUsers(@AuthenticationPrincipal user: User): Flux<UserDisplay> {
return userService.getUserDisplays(user).doOnNext {
logger.info("${it.fullName}, ${it.userId}")
}
return userService.getUserDisplays(user)
}

@MessageMapping("socket/init-conferences")
fun initConferences(@AuthenticationPrincipal user: User): Flux<ConferenceInfo> {
return Flux.empty()
return userService.getConferences(user)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import java.io.Serializable
JsonSubTypes.Type(value = TicketEvent::class, name = "TicketEvent"),
JsonSubTypes.Type(value = ConferenceEvent::class, name = "ConferenceEvent"),
JsonSubTypes.Type(value = InvitationEvent::class, name = "InvitationEvent"),
)
abstract class ClassroomEvent(@field:SuppressWarnings("unused") private val eventName: String): Serializable
)
abstract class ClassroomEvent(@field:SuppressWarnings("unused") private val eventName: String) : Serializable

data class MessageEvent(val message: String): ClassroomEvent(MessageEvent::class.simpleName!!)
data class MessageEvent(val message: String) : ClassroomEvent(MessageEvent::class.simpleName!!)
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import de.thm.mni.ii.classroom.model.classroom.ConferenceInfo
data class ConferenceEvent(
val conferenceInfo: ConferenceInfo,
val conferenceAction: ConferenceAction
): ClassroomEvent(ConferenceEvent::class.simpleName!!)
) : ClassroomEvent(ConferenceEvent::class.simpleName!!)

enum class ConferenceAction {
CREATE,
CLOSE,
PUBLISH,
HIDE
HIDE,
USER_CHANGE
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ data class InvitationEvent(
val inviter: User,
val invitee: User,
val conferenceInfo: ConferenceInfo
): ClassroomEvent(InvitationEvent::class.simpleName!!)
) : ClassroomEvent(InvitationEvent::class.simpleName!!)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import de.thm.mni.ii.classroom.model.classroom.Ticket
data class TicketEvent(
val ticket: Ticket,
val ticketAction: TicketAction,
): ClassroomEvent(TicketEvent::class.simpleName!!)
) : ClassroomEvent(TicketEvent::class.simpleName!!)

enum class TicketAction {
CREATE,
Expand Down
11 changes: 4 additions & 7 deletions src/main/kotlin/de/thm/mni/ii/classroom/event/UserEvent.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package de.thm.mni.ii.classroom.event

import de.thm.mni.ii.classroom.model.classroom.User
import de.thm.mni.ii.classroom.model.classroom.UserDisplay

data class UserEvent(
val user: User,
val inConference: Boolean = false,
val conferenceId: String? = null,
val user: UserDisplay,
val userAction: UserAction
): ClassroomEvent(UserEvent::class.simpleName!!)
) : ClassroomEvent(UserEvent::class.simpleName!!)

enum class UserAction {
JOIN,
JOIN_CONFERENCE,
LEAVE_CONFERENCE,
VISIBILITY_CHANGE,
LEAVE
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ open class ApiException(
val bbbMessageKey: String = "InternalServerError",
cause: Throwable? = null,
val bbbMessage: String = "An error occurred: ${cause?.message}",
): Exception(bbbMessage, cause)
) : Exception(bbbMessage, cause)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package de.thm.mni.ii.classroom.exception.api

class ClassroomNotFoundException(
meetingID: String = "",
bbbMessageKey: String = "meetingDoesNotExist",
bbbMessage: String = "MeetingID $meetingID does not exist!"
): ApiException(bbbMessageKey, null, bbbMessage)
meetingID: String = "",
bbbMessageKey: String = "meetingDoesNotExist",
bbbMessage: String = "MeetingID $meetingID does not exist!"
) : ApiException(bbbMessageKey, null, bbbMessage)
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ class InvalidMeetingPasswordException(
meetingID: String,
bbbMessageKey: String = "invalidMeetingPassword",
bbbMessage: String = "Given password does not match any valid for meeting $meetingID!"
): ApiException(bbbMessageKey, null, bbbMessage)
) : ApiException(bbbMessageKey, null, bbbMessage)
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ package de.thm.mni.ii.classroom.exception.api
class MissingMeetingIDException(
bbbMessageKey: String = "missingParamMeetingID",
bbbMessage: String = "You must specify a meeting ID for the meeting."
): ApiException(bbbMessageKey, null, bbbMessage)
) : ApiException(bbbMessageKey, null, bbbMessage)
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ package de.thm.mni.ii.classroom.exception.api
class NoPasswordSpecifiedException(
bbbMessageKey: String = "noPasswordSpecified",
bbbMessage: String = "No password for joining a meeting was specified!"
): ApiException(bbbMessageKey, null, bbbMessage)
) : ApiException(bbbMessageKey, null, bbbMessage)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package de.thm.mni.ii.classroom.exception.api

class NoUsernameSpecifiedException (
class NoUsernameSpecifiedException(
bbbMessageKey: String = "noUsernameSpecified",
bbbMessage: String = "You must specify a full name for a user to join a meeting."
): ApiException(bbbMessageKey, null, bbbMessage)
) : ApiException(bbbMessageKey, null, bbbMessage)
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ class UnknownUserException(
meetingId: String,
bbbMessageKey: String = "userUnknownToClassroom",
bbbMessage: String = "User $userId unknown to classroom $meetingId!"
): ApiException(bbbMessageKey, null, bbbMessage)
) : ApiException(bbbMessageKey, null, bbbMessage)
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package de.thm.mni.ii.classroom.exception.classroom

open class ClassroomException(message: String): Exception(message)
open class ClassroomException(message: String) : Exception(message)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package de.thm.mni.ii.classroom.exception.classroom

class ConferenceNotFoundException(conferenceId: String) : Exception("Conference with id $conferenceId does not exist!")
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ package de.thm.mni.ii.classroom.exception.classroom
import de.thm.mni.ii.classroom.event.InvitationEvent
import de.thm.mni.ii.classroom.model.classroom.User

class InvitationException(user: User, invitationEvent: InvitationEvent)
: ClassroomException("Sender ${user.userId} does not match inviter ${invitationEvent.inviter.userId}!")
class InvitationException(user: User, invitationEvent: InvitationEvent) :
ClassroomException("Sender ${user.userId} does not match inviter ${invitationEvent.inviter.userId}!")
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ package de.thm.mni.ii.classroom.exception.classroom

import de.thm.mni.ii.classroom.model.classroom.Ticket

class TicketAlreadyExistsException(ticket: Ticket): ClassroomException("Similar ticket \"${ticket.description}\" already exists!")
class TicketAlreadyExistsException(ticket: Ticket) : ClassroomException("Similar ticket \"${ticket.description}\" already exists!")
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package de.thm.mni.ii.classroom.exception.classroom

import de.thm.mni.ii.classroom.model.classroom.Ticket

class TicketNotFoundException(ticket: Ticket):
class TicketNotFoundException(ticket: Ticket) :
ClassroomException("Ticket ${ticket.classroomId}/${ticket.ticketId} not found!")
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ package de.thm.mni.ii.classroom.model
interface ClassroomDependent {

val classroomId: String

}
Loading

0 comments on commit c7edb4a

Please sign in to comment.