<commit_before>package controllers.crud.labwork

import java.util.UUID

import controllers.crud.AbstractCRUDController
import controllers.crud.labwork.GroupCRUDController._
import models._
import models.labwork._
import models.security.Permissions._
import models.users.{Student, User}
import org.w3.banana.sesame.Sesame
import play.api.libs.json._
import play.api.mvc.Request
import services.{GroupServiceLike, RoleService, SessionHandlingService}
import store.bind.Descriptor.Descriptor
import store.{Namespace, SemanticUtils, SesameRepository}
import utils.{Attempt, Continue, LwmMimeType, Return}

import scala.collection.Map
import scala.util.{Failure, Success, Try}

object GroupCRUDController {
  val labworkAttribute = "labwork"
  val studentAttribute = "student"
  val labelAttribute = "label"
  val countAttribute = "value"
  val minAttribute = "min"
  val maxAttribute = "max"
}

class GroupCRUDController(val repository: SesameRepository, val sessionService: SessionHandlingService, implicit val namespace: Namespace, val roleService: RoleService, val groupService: GroupServiceLike) extends AbstractCRUDController[GroupProtocol, Group, GroupAtom] {

  override implicit val mimeType: LwmMimeType = LwmMimeType.groupV1Json

  override implicit val descriptor: Descriptor[Sesame, Group] = defaultBindings.GroupDescriptor

  override implicit val descriptorAtom: Descriptor[Sesame, GroupAtom] = defaultBindings.GroupAtomDescriptor

  override implicit val uriGenerator: UriGenerator[Group] = Group

  override implicit val reads: Reads[GroupProtocol] = Group.reads

  override implicit val writes: Writes[Group] = Group.writes

  override implicit val writesAtom: Writes[GroupAtom] = Group.writesAtom

  override protected def coAtomic(atom: GroupAtom): Group = Group(atom.label, atom.labwork.id, atom.members map (_.id), atom.invalidated, atom.id)

  override protected def compareModel(input: GroupProtocol, output: Group): Boolean = {
    input.label == output.label && input.members == output.members
  }

  override protected def fromInput(input: GroupProtocol, existing: Option[Group]): Group = existing match {
    case Some(group) => Group(input.label, input.labwork, input.members, group.invalidated, group.id)
    case None => Group(input.label, input.labwork, input.members)
  }

  override protected def contextFrom: PartialFunction[Rule, SecureContext] = {
    case Get => PartialSecureBlock(group.get)
    case _ => PartialSecureBlock(god)
  }

  override protected def restrictedContext(restrictionId: String): PartialFunction[Rule, SecureContext] = {
    case Create => SecureBlock(restrictionId, group.create)
    case Update => SecureBlock(restrictionId, group.update)
    case Delete => SecureBlock(restrictionId, group.delete)
    case Get => SecureBlock(restrictionId, group.get)
    case GetAll => SecureBlock(restrictionId, group.getAll)
  }

  override protected def getWithFilter(queryString: Map[String, Seq[String]])(all: Set[Group]): Try[Set[Group]] = {
    import controllers.crud.labwork.GroupCRUDController._

    queryString.foldRight(Try[Set[Group]](all)) {
      case ((`labworkAttribute`, v), t) => t flatMap (set => Try(UUID.fromString(v.head)).map(p => set.filter(_.labwork == p)))
      case ((`studentAttribute`, v), t) => t flatMap (set => Try(UUID.fromString(v.head)).map(p => set.filter(_.members.contains(p))))
      case ((`labelAttribute`, v), t) => t.map(_.filter(_.label == v.head))
      case ((_, _), set) => Failure(new Throwable("Unknown attribute"))
    }
  }

  // TODO get rid
  def createFrom(course: String, labwork: String) = restrictedContext(course)(Create) asyncContentTypedAction { implicit request =>
    create(NonSecureBlock)(request)
  }

  // TODO get rid
  def createAtomicFrom(course: String, labwork: String) = restrictedContext(course)(Create) asyncContentTypedAction { implicit request =>
    createAtomic(NonSecureBlock)(request)
  }

  def updateFrom(course: String, labwork: String, group: String) = restrictedContext(course)(Update) asyncContentTypedAction { implicit request =>
    update(group, NonSecureBlock)(rebase(group))
  }

  def updateAtomicFrom(course: String, labwork: String, group: String) = restrictedContext(course)(Update) asyncContentTypedAction { implicit request =>
    updateAtomic(group, NonSecureBlock)(rebase(group))
  }

  def allFrom(course: String, labwork: String) = restrictedContext(course)(GetAll) asyncAction { implicit request =>
    all(NonSecureBlock)(rebase(labworkAttribute -> Seq(labwork)))
  }

  def allAtomicFrom(course: String, labwork: String) = restrictedContext(course)(GetAll) asyncAction { implicit request =>
    allAtomic(NonSecureBlock)(rebase(labworkAttribute -> Seq(labwork)))
  }

  def getFrom(course: String, labwork: String, group: String) = restrictedContext(course)(Get) asyncAction { implicit request =>
    get(group, NonSecureBlock)(rebase(group))
  }

  def getAtomicFrom(course: String, labwork: String, group: String) = restrictedContext(course)(Get) asyncAction { implicit request =>
    getAtomic(group, NonSecureBlock)(rebase(group))
  }

  def deleteFrom(course: String, labwork: String, group: String) = restrictedContext(course)(Delete) asyncAction { implicit request =>
    delete(group, NonSecureBlock)(rebase(group))
  }

  def createWithRange(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    groupBy(labwork)(applyRange)
      .flatMap(addLots)
      .mapResult(list => Created(Json.toJson(list.toSet)).as(mimeType))
  }

  def createWithCount(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    groupBy(labwork)(applyCount)
      .flatMap(addLots)
      .mapResult(list => Created(Json.toJson(list.toSet)).as(mimeType))
  }

  def createAtomicWithRange(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    groupBy(labwork)(applyRange)
      .flatMap(addLots)
      .flatMap(list => retrieveLots[GroupAtom](list map Group.generateUri))
      .mapResult(set => Created(Json.toJson(set)).as(mimeType))
  }

  def createAtomicWithCount(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    groupBy(labwork)(applyCount)
      .flatMap(addLots)
      .flatMap(list => retrieveLots[GroupAtom](list map Group.generateUri))
      .mapResult(set => Created(Json.toJson(set)).as(mimeType))
  }

  def previewWithCount(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    import models.labwork.Group.protocolWrites

    groupBy(labwork)(applyCount)
      .map(_ map (g => GroupProtocol(g.label, g.labwork, g.members)))
      .mapResult(set => Ok(Json.toJson(set)).as(mimeType))
  }

  def previewAtomicWithCount(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    groupBy(labwork)(applyCount)
      .flatMap(atomic)
      .mapResult(set => Ok(Json.toJson(set)).as(mimeType))
  }

  def previewWithRange(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    import models.labwork.Group.protocolWrites

    groupBy(labwork)(applyRange)
      .map(_ map (g => GroupProtocol(g.label, g.labwork, g.members)))
      .mapResult(set => Ok(Json.toJson(set)).as(mimeType))
  }

  def previewAtomicWithRange(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    groupBy(labwork)(applyRange)
      .flatMap(atomic)
      .mapResult(set => Ok(Json.toJson(set)).as(mimeType))
  }

  private def applyRange(people: Vector[UUID], params: Map[String, Seq[String]]) = {
    def range(min: Int, max: Int, s: Int): Int = ((min to max) reduce { (prev, curr) =>
      if (prev % s < curr % s) curr
      else prev
    }) + 1

    for {
      min <- Try(params(minAttribute).head.toInt)
      max <- Try(params(maxAttribute).head.toInt) if min <= max
    } yield range(min, max, people.size)
  }
<commit_msg>removed +1 constant from group creation, when using range<commit_after>package controllers.crud.labwork

import java.util.UUID

import controllers.crud.AbstractCRUDController
import controllers.crud.labwork.GroupCRUDController._
import models._
import models.labwork._
import models.security.Permissions._
import models.users.{Student, User}
import org.w3.banana.sesame.Sesame
import play.api.libs.json._
import play.api.mvc.Request
import services.{GroupServiceLike, RoleService, SessionHandlingService}
import store.bind.Descriptor.Descriptor
import store.{Namespace, SemanticUtils, SesameRepository}
import utils.{Attempt, Continue, LwmMimeType, Return}

import scala.collection.Map
import scala.util.{Failure, Success, Try}

object GroupCRUDController {
  val labworkAttribute = "labwork"
  val studentAttribute = "student"
  val labelAttribute = "label"
  val countAttribute = "value"
  val minAttribute = "min"
  val maxAttribute = "max"
}

class GroupCRUDController(val repository: SesameRepository, val sessionService: SessionHandlingService, implicit val namespace: Namespace, val roleService: RoleService, val groupService: GroupServiceLike) extends AbstractCRUDController[GroupProtocol, Group, GroupAtom] {

  override implicit val mimeType: LwmMimeType = LwmMimeType.groupV1Json

  override implicit val descriptor: Descriptor[Sesame, Group] = defaultBindings.GroupDescriptor

  override implicit val descriptorAtom: Descriptor[Sesame, GroupAtom] = defaultBindings.GroupAtomDescriptor

  override implicit val uriGenerator: UriGenerator[Group] = Group

  override implicit val reads: Reads[GroupProtocol] = Group.reads

  override implicit val writes: Writes[Group] = Group.writes

  override implicit val writesAtom: Writes[GroupAtom] = Group.writesAtom

  override protected def coAtomic(atom: GroupAtom): Group = Group(atom.label, atom.labwork.id, atom.members map (_.id), atom.invalidated, atom.id)

  override protected def compareModel(input: GroupProtocol, output: Group): Boolean = {
    input.label == output.label && input.members == output.members
  }

  override protected def fromInput(input: GroupProtocol, existing: Option[Group]): Group = existing match {
    case Some(group) => Group(input.label, input.labwork, input.members, group.invalidated, group.id)
    case None => Group(input.label, input.labwork, input.members)
  }

  override protected def contextFrom: PartialFunction[Rule, SecureContext] = {
    case Get => PartialSecureBlock(group.get)
    case _ => PartialSecureBlock(god)
  }

  override protected def restrictedContext(restrictionId: String): PartialFunction[Rule, SecureContext] = {
    case Create => SecureBlock(restrictionId, group.create)
    case Update => SecureBlock(restrictionId, group.update)
    case Delete => SecureBlock(restrictionId, group.delete)
    case Get => SecureBlock(restrictionId, group.get)
    case GetAll => SecureBlock(restrictionId, group.getAll)
  }

  override protected def getWithFilter(queryString: Map[String, Seq[String]])(all: Set[Group]): Try[Set[Group]] = {
    import controllers.crud.labwork.GroupCRUDController._

    queryString.foldRight(Try[Set[Group]](all)) {
      case ((`labworkAttribute`, v), t) => t flatMap (set => Try(UUID.fromString(v.head)).map(p => set.filter(_.labwork == p)))
      case ((`studentAttribute`, v), t) => t flatMap (set => Try(UUID.fromString(v.head)).map(p => set.filter(_.members.contains(p))))
      case ((`labelAttribute`, v), t) => t.map(_.filter(_.label == v.head))
      case ((_, _), set) => Failure(new Throwable("Unknown attribute"))
    }
  }

  // TODO get rid
  def createFrom(course: String, labwork: String) = restrictedContext(course)(Create) asyncContentTypedAction { implicit request =>
    create(NonSecureBlock)(request)
  }

  // TODO get rid
  def createAtomicFrom(course: String, labwork: String) = restrictedContext(course)(Create) asyncContentTypedAction { implicit request =>
    createAtomic(NonSecureBlock)(request)
  }

  def updateFrom(course: String, labwork: String, group: String) = restrictedContext(course)(Update) asyncContentTypedAction { implicit request =>
    update(group, NonSecureBlock)(rebase(group))
  }

  def updateAtomicFrom(course: String, labwork: String, group: String) = restrictedContext(course)(Update) asyncContentTypedAction { implicit request =>
    updateAtomic(group, NonSecureBlock)(rebase(group))
  }

  def allFrom(course: String, labwork: String) = restrictedContext(course)(GetAll) asyncAction { implicit request =>
    all(NonSecureBlock)(rebase(labworkAttribute -> Seq(labwork)))
  }

  def allAtomicFrom(course: String, labwork: String) = restrictedContext(course)(GetAll) asyncAction { implicit request =>
    allAtomic(NonSecureBlock)(rebase(labworkAttribute -> Seq(labwork)))
  }

  def getFrom(course: String, labwork: String, group: String) = restrictedContext(course)(Get) asyncAction { implicit request =>
    get(group, NonSecureBlock)(rebase(group))
  }

  def getAtomicFrom(course: String, labwork: String, group: String) = restrictedContext(course)(Get) asyncAction { implicit request =>
    getAtomic(group, NonSecureBlock)(rebase(group))
  }

  def deleteFrom(course: String, labwork: String, group: String) = restrictedContext(course)(Delete) asyncAction { implicit request =>
    delete(group, NonSecureBlock)(rebase(group))
  }

  def createWithRange(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    groupBy(labwork)(applyRange)
      .flatMap(addLots)
      .mapResult(list => Created(Json.toJson(list.toSet)).as(mimeType))
  }

  def createWithCount(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    groupBy(labwork)(applyCount)
      .flatMap(addLots)
      .mapResult(list => Created(Json.toJson(list.toSet)).as(mimeType))
  }

  def createAtomicWithRange(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    groupBy(labwork)(applyRange)
      .flatMap(addLots)
      .flatMap(list => retrieveLots[GroupAtom](list map Group.generateUri))
      .mapResult(set => Created(Json.toJson(set)).as(mimeType))
  }

  def createAtomicWithCount(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    groupBy(labwork)(applyCount)
      .flatMap(addLots)
      .flatMap(list => retrieveLots[GroupAtom](list map Group.generateUri))
      .mapResult(set => Created(Json.toJson(set)).as(mimeType))
  }

  def previewWithCount(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    import models.labwork.Group.protocolWrites

    groupBy(labwork)(applyCount)
      .map(_ map (g => GroupProtocol(g.label, g.labwork, g.members)))
      .mapResult(set => Ok(Json.toJson(set)).as(mimeType))
  }

  def previewAtomicWithCount(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    groupBy(labwork)(applyCount)
      .flatMap(atomic)
      .mapResult(set => Ok(Json.toJson(set)).as(mimeType))
  }

  def previewWithRange(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    import models.labwork.Group.protocolWrites

    groupBy(labwork)(applyRange)
      .map(_ map (g => GroupProtocol(g.label, g.labwork, g.members)))
      .mapResult(set => Ok(Json.toJson(set)).as(mimeType))
  }

  def previewAtomicWithRange(course: String, labwork: String) = restrictedContext(course)(Create) action { implicit request =>
    groupBy(labwork)(applyRange)
      .flatMap(atomic)
      .mapResult(set => Ok(Json.toJson(set)).as(mimeType))
  }

  private def applyRange(people: Vector[UUID], params: Map[String, Seq[String]]) = {
    def range(min: Int, max: Int, s: Int): Int = (min to max) reduce { (prev, curr) =>
      if (prev % s < curr % s) curr
      else prev
    }

    for {
      min <- Try(params(minAttribute).head.toInt)
      max <- Try(params(maxAttribute).head.toInt) if min <= max
    } yield range(min, max, people.size)
  }

{'fraction_non_alphanumeric': 0.12246800049707966, 'fraction_numerical': 0.0003728097427612775, 'mean_word_length': 5.117445838084379, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 101, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1786787', 'n_tokens_mistral': 4856, 'n_tokens_neox': 4743, 'n_words': 1079}