All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fr.maif.izanami.v1.commons.scala Maven / Gradle / Ivy

package fr.maif.izanami.v1

import fr.maif.izanami.models.RightLevels.RightLevel
import fr.maif.izanami.models.{AtomicRight, RightLevels, TenantRight}
import fr.maif.izanami.utils.syntax.implicits.BetterSyntax
import play.api.libs.json.{JsError, JsSuccess, Reads}


sealed trait Right
case object Read extends Right
case object Update extends Right
case object Create extends Right
case object Delete extends Right

case class AuthorizedPattern(pattern: String, rights: Seq[Right])


object OldCommons {
  def toNewRights(admin: Boolean, patterns: Seq[AuthorizedPattern], projects: Set[String], shouldFilterProjects: Boolean): TenantRight = {
    // TODO handle wildcard in rights (by allowing to read db with regexp ? if so features must be inserted first)
    val projectRights = patterns.map(ap => {
      for (
        filteredProjects <- if(shouldFilterProjects) filterProjects(ap.pattern, projects) else projects;
        right <- oldRightToNewRight(ap.rights.toSet)
      ) yield (filteredProjects, right)
    }).flatMap(_.toSeq).groupBy { case (key, _) => key }
      .view.mapValues(s => s.map{case (_, level) => level}
      .reduce((r1, r2) => if(RightLevels.superiorOrEqualLevels(r1).contains(r2)) r2 else r1))
      .view.mapValues(AtomicRight)

      val tenantRight = if(admin) {
        RightLevels.Admin
      } else if(patterns.map(p => p.pattern).contains("*")) {
        RightLevels.Write
      } else {
        RightLevels.Read
      }

    TenantRight(level=tenantRight, projects = projectRights.toMap)
  }

  def filterProjects(pattern: String, projects: Set[String]): Set[String] = {
    if(pattern.trim == "*") {
      projects
    } else if(pattern.contains("*")) {
      var regexp = pattern.replace("*", ".*")
      if(regexp.endsWith(":.*")) {
        regexp = regexp.dropRight(3).concat("(:.*)?")
      }
      projects.filter(p => regexp.r.matches(p))
    } else {
      // TODO people with right on only one feature should have right on create project if feature is alone in it
      Set()
    }
  }

  implicit val rightReads: Reads[Right] = { json =>
    (for (
      str <- json.asOpt[String];
      if (str.length == 1);
      c <- str.charAt(0).toUpper.option
    ) yield c match {
      case 'R' => JsSuccess(Read)
      case 'U' => JsSuccess(Update)
      case 'C' => JsSuccess(Create)
      case 'D' => JsSuccess(Delete)
      case _ => JsError(s"Unknown right level letter : ${c}")
    }).getOrElse(JsError(s"Right string too long ${json}"))
  }

  def oldRightToNewRight(right: Set[Right]): Option[RightLevel] = {
    val OLD_ALL_RIGHTS: Set[Right] = Set(Read, Update, Delete, Create)

    if (right.isEmpty) {
      None
    } else if (OLD_ALL_RIGHTS.subsetOf(right)) {
      RightLevels.Admin.some
    } else if (right.contains(Read) && right.size == 1) {
      RightLevels.Read.some
    } else {
      RightLevels.Write.some
    }
  }

  implicit val authorizedPatternReads: Reads[AuthorizedPattern] = { json =>
    (for (
      pattern <- (json \ "pattern").asOpt[String];
      rights <- (json \ "rights").asOpt[Seq[Right]]
    ) yield JsSuccess(AuthorizedPattern(pattern = pattern, rights = rights))).getOrElse(JsError("Bad right format"))
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy