MiniDigger/Hangar

View on GitHub
orePlayCommon/app/models/viewhelper/OrganizationData.scala

Summary

Maintainability
A
0 mins
Test Coverage
package models.viewhelper

import scala.language.higherKinds

import ore.db.access.ModelView
import ore.db.impl.OrePostgresDriver.api._
import ore.db.impl.schema.{ProjectRoleTable, ProjectTableMain}
import ore.models.project.Project
import ore.models.user.role.{OrganizationUserRole, ProjectUserRole}
import ore.models.user.{User, UserOwned}
import ore.db.{DbRef, Model, ModelService}
import ore.models.organization.Organization
import ore.permission.role.RoleCategory
import util.syntax._

import cats.{MonadError, Parallel}
import cats.data.OptionT
import cats.syntax.all._
import slick.lifted.TableQuery

case class OrganizationData(
    joinable: Model[Organization],
    members: Seq[(Model[OrganizationUserRole], Model[User])], // TODO sorted/reverse
    projectRoles: Seq[(Model[ProjectUserRole], Model[Project])]
) extends JoinableData[OrganizationUserRole, Organization] {

  def orga: Model[Organization] = joinable

  def roleCategory: RoleCategory = RoleCategory.Organization

  override def ownerInstance: UserOwned[Organization] = UserOwned[Organization]
}

object OrganizationData {

  def cacheKey(orga: Model[Organization]): String = "organization" + orga.id

  def of[F[_], G[_]](orga: Model[Organization])(
      implicit service: ModelService[F],
      F: MonadError[F, Throwable],
      par: Parallel[F, G]
  ): F[OrganizationData] = {
    import cats.instances.vector._
    for {
      members <- orga.memberships.members(orga)
      members <- members.toVector.traverse { userId =>
        val orgaRole = orga.memberships.getRoles(orga)(userId).map(_.maxBy(_.role.permissions: Long))
        val users =
          ModelView.now(User).get(userId).getOrElseF(F.raiseError(new Exception("Member of organization not found")))
        (orgaRole, users).parTupled
      }
      projectRoles <- service.runDBIO(queryProjectRoles(orga.id).result)
    } yield OrganizationData(orga, members, projectRoles)
  }

  private def queryProjectRoles(userId: DbRef[User]) =
    for {
      (role, project) <- TableQuery[ProjectRoleTable].join(TableQuery[ProjectTableMain]).on(_.projectId === _.id)
      if role.userId === userId
    } yield (role, project)

  def of[F[_], G[_]](orga: Option[Model[Organization]])(
      implicit service: ModelService[F],
      F: MonadError[F, Throwable],
      par: Parallel[F, G]
  ): OptionT[F, OrganizationData] = OptionT.fromOption[F](orga).semiflatMap(of[F, G])
}