/* * Copyright 2024 Dominic Grimm * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.dergrimm.keycloak.providers.events.mqtt import org.keycloak.events.Event import org.keycloak.events.admin.AdminEvent import org.keycloak.models.KeycloakSession import org.keycloak.events.admin.ResourceType import io.bullet.borer.{Codec, Encoder} import io.bullet.borer.derivation.MapBasedCodecs._ import io.bullet.borer.NullOptions.given object Payload extends FromEvent[Payload]: def fromEvent(event: Event, session: KeycloakSession): Payload = val error: Option[String] = Option(event.getError()) val realmId: String = event.getRealmId() Payload( admin = false, time = event.getTime(), realm = session.realms().getRealm(realmId).getName(), realmId, authDetails = PayloadAuthDetails.fromEvent(event, session), resourceType = None, operationType = event.getType().toString(), resourcePath = None, representation = None, error ) end fromEvent def fromEvent(event: AdminEvent, session: KeycloakSession): Payload = val resourceType: Option[String] = Option(event.getResourceType()).map(_.toString()) val representation: Option[String] = Option(event.getRepresentation()) val error: Option[String] = Option(event.getError()) val realmId: String = event.getRealmId() Payload( admin = true, time = event.getTime(), realm = session.realms().getRealm(realmId).getName(), realmId, authDetails = PayloadAuthDetails.fromEvent(event, session), resourceType, operationType = event.getOperationType().toString(), resourcePath = Some(event.getResourcePath()), representation, error ) end fromEvent end Payload private final case class Payload( admin: Boolean, time: Long, realm: String, realmId: String, authDetails: PayloadAuthDetails, resourceType: Option[String], operationType: String, resourcePath: Option[String], representation: Option[String], error: Option[String] ) derives Codec: private def result: String = if error.isDefined then "error" else "success" def topic: String = if admin then resourceType match case Some(rType) => s"admin/${realm}/${result}/${rType.toLowerCase()}/${operationType.toLowerCase()}" case None => throw new IllegalStateException else s"client/${realm}/${result}/${authDetails.clientId}/${operationType.toLowerCase()}" end topic end Payload