All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.gu.permissions.PermissionsProvider.scala Maven / Gradle / Ivy
package com.gu.permissions
import java.util.Locale
import java.util.concurrent.{Executors, TimeUnit}
import com.amazonaws.services.s3.AmazonS3ClientBuilder
import org.slf4j.LoggerFactory
import play.api.libs.json.Json
import scala.concurrent.duration.FiniteDuration
import scala.util.control.NonFatal
trait PermissionsProvider {
def storeIsEmpty: Boolean
def hasPermission(permission: PermissionDefinition, user: String): Boolean
def listPermissions(user: String): Map[PermissionDefinition, Boolean]
def allUserEmails(): Set[String]
}
case class UserEntry(
permission: PermissionDefinition,
active: Boolean,
isCasualNotOnShift: Boolean = false
)
class CachedPermissionsProvider(cache: PermissionsProvider.Cache)
extends PermissionsProvider {
private val logger = LoggerFactory.getLogger(this.getClass)
final override def storeIsEmpty: Boolean = cache.isEmpty
final override def hasPermission(
permission: PermissionDefinition,
user: String
): Boolean = {
val maybeUserPermission: Option[UserEntry] =
get(user).find(b => b.permission == permission)
val userHasPermission = maybeUserPermission.exists(_.active)
val userIsCasualAndNotOnShift =
maybeUserPermission.exists(_.isCasualNotOnShift)
if (userHasPermission && userIsCasualAndNotOnShift) {
logger.info(
s"[PermissionsProvider.hasPermission] User $user has permission ${permission.name} but is a casual not currently on shift."
)
}
userHasPermission
}
final override def listPermissions(
user: String
): Map[PermissionDefinition, Boolean] = get(user).map {
case UserEntry(permission, active, _) =>
permission -> active
}.toMap
final override def allUserEmails(): Set[String] = cache.keySet
private def get(user: String): List[UserEntry] = {
cache.getOrElse(user.toLowerCase(Locale.UK), List.empty)
}
}
class S3PermissionsProvider(
s3Bucket: String,
s3Key: String,
refreshFrequency: FiniteDuration,
s3Client: PermissionsS3
) extends PermissionsProvider {
private val logger = LoggerFactory.getLogger(this.getClass)
private val refreshScheduler = Executors.newScheduledThreadPool(1)
@volatile private var cache: PermissionsProvider =
new CachedPermissionsProvider(Map.empty)
final override def storeIsEmpty: Boolean = cache.storeIsEmpty
final override def hasPermission(
permission: PermissionDefinition,
user: String
): Boolean = cache.hasPermission(permission, user)
final override def listPermissions(
user: String
): Map[PermissionDefinition, Boolean] = cache.listPermissions(user)
final override def allUserEmails(): Set[String] = cache.allUserEmails()
def start(): Unit = {
refresh()
refreshScheduler.scheduleAtFixedRate(
new Runnable() {
override def run(): Unit = {
refresh()
}
},
refreshFrequency.toMillis,
refreshFrequency.toMillis,
TimeUnit.MILLISECONDS
)
}
private def refresh(): Unit = try {
logger.info(s"Load permissions from s3 bucket: s3://$s3Bucket/$s3Key")
val (inputStream, lastModified) = s3Client.getObject(s3Bucket, s3Key)
val json = Json.parse(inputStream)
val definitions = json.as[List[PermissionWithUsers]]
this.cache = new CachedPermissionsProvider(
PermissionsProvider.buildCache(definitions)
)
logger.info(
s"Permissions successfully retrieved from S3, last modified: $lastModified"
)
} catch {
case NonFatal(err) =>
logger.error("Could not refresh permissions from S3", err)
}
}
object PermissionsProvider {
type Cache = Map[String, List[UserEntry]]
private val empty = Map.empty[String, List[UserEntry]]
def apply(config: PermissionsConfig): PermissionsProvider = {
val fileKey = PermissionsConfig.getPermissionsFileKey(config)
val s3Client = AmazonS3ClientBuilder
.standard()
.withRegion(config.region)
.withCredentials(config.awsCredentials)
.build()
val provider = new S3PermissionsProvider(
config.s3Bucket,
fileKey,
config.refreshFrequency,
PermissionsS3(s3Client)
)
// kick off a refresh and schedule refreshing in the background
provider.start()
provider
}
def buildCache(definitions: List[PermissionWithUsers]): Cache = {
definitions.foldLeft(empty) {
case (acc, PermissionWithUsers(permission, overrides)) =>
overrides.foldLeft(acc) {
case (acc, UserSetting(user, active, isCasualNotOnShift)) =>
val normalisedUser = user.toLowerCase(Locale.UK)
val before = acc.getOrElse(normalisedUser, List.empty)
val after =
before :+ UserEntry(permission, active, isCasualNotOnShift)
acc + (normalisedUser -> after)
}
}
}
}