<commit_before>/*
 * Copyright (C) 2020 MapRoulette contributors (see CONTRIBUTORS.md).
 * Licensed under the Apache License, Version 2.0 (see LICENSE).
 */
package org.maproulette.controllers.api

import java.io._
import java.sql.Connection
import java.util.zip.{ZipEntry, ZipOutputStream}

import akka.util.ByteString
import javax.inject.Inject
import org.apache.commons.lang3.StringUtils
import org.joda.time.DateTime
import org.maproulette.Config
import org.maproulette.controllers.ParentController
import org.maproulette.data._
import org.maproulette.exception.{
  InvalidException,
  MPExceptionUtil,
  NotFoundException,
  StatusMessage
}
import org.maproulette.framework.model._
import org.maproulette.framework.psql.Paging
import org.maproulette.framework.service.{ServiceManager, TagService}
import org.maproulette.models._
import org.maproulette.models.dal._
import org.maproulette.models.dal.mixin.TagDALMixin
import org.maproulette.permissions.Permission
import org.maproulette.provider.ChallengeProvider
import org.maproulette.session.{SearchParameters, SessionManager}
import org.maproulette.utils.Utils
import play.api.http.HttpEntity
import play.api.libs.Files
import play.api.libs.json._
import play.api.libs.ws.WSClient
import play.api.mvc._
import play.shaded.oauth.oauth.signpost.exception.OAuthNotAuthorizedException

import scala.concurrent.{Future, Promise}
import scala.io.Source
import scala.util.{Failure, Success}

/**
  * The challenge controller handles all operations for the Challenge objects.
  * This includes CRUD operations and searching/listing.
  * See ParentController for more details on parent object operations
  * See CRUDController for more details on CRUD object operations
  *
  * @author cuthbertm
  */
class ChallengeController @Inject() (
    override val childController: TaskController,
    override val sessionManager: SessionManager,
    override val actionManager: ActionManager,
    override val dal: ChallengeDAL,
    dalManager: DALManager,
    override val tagService: TagService,
    challengeProvider: ChallengeProvider,
    serviceManager: ServiceManager,
    wsClient: WSClient,
    permission: Permission,
    config: Config,
    components: ControllerComponents,
    override val bodyParsers: PlayBodyParsers,
    implicit val snapshotManager: SnapshotManager
) extends AbstractController(components)
    with ParentController[Challenge, Task]
    with TagsMixin[Challenge] {

  import scala.concurrent.ExecutionContext.Implicits.global

  // json reads for automatically reading Challenges from a posted json body
  override implicit val tReads: Reads[Challenge] = Challenge.reads.challengeReads
  // json writes for automatically writing Challenges to a json body response
  override implicit val tWrites: Writes[Challenge] = Challenge.writes.challengeWrites
  // json writes for automatically writing Tasks to a json body response
  override protected val cWrites: Writes[Task] = Task.TaskFormat
  // json reads for automatically reading tasks from a posted json body
  override protected val cReads: Reads[Task] = Task.TaskFormat
  // The type of object that this controller deals with.
  override implicit val itemType: ItemType = ChallengeType()
  override implicit val tableName: String  = this.dal.tableName

  // implicit writes used for various JSON responses
  implicit val commentWrites                                    = Comment.writes
  implicit val pointWrites                                      = ClusteredPoint.pointWrites
  implicit val clusteredPointWrites                             = ClusteredPoint.clusteredPointWrites
  implicit val taskClusterWrites                                = TaskCluster.taskClusterWrites
  implicit val searchLocationWrites                             = SearchParameters.locationWrites
  implicit val challengeListingWrites: Writes[ChallengeListing] = Json.writes[ChallengeListing]

  override def dalWithTags: TagDALMixin[Challenge] = dal

  /**
    * Function can be implemented to extract more information than just the default create data,
    * to build other objects with the current object at the core. No data will be returned from this
    * function, it purely does work in the background AFTER creating the current object
    *
    * @param body          The Json body of data
    * @param createdObject The object that was created by the create function
    * @param user          The user that is executing the function
    */
  override def extractAndCreate(body: JsValue, createdObject: Challenge, user: User)(
      implicit c: Option[Connection] = None
  ): Unit = {
    val localJson = (body \ "localGeoJSON").asOpt[JsValue] match {
      case Some(local) => Some(Json.stringify(local))
      case None        => None
    }
    if (!this.challengeProvider.buildTasks(user, createdObject, localJson)) {
      super.extractAndCreate(body, createdObject, user)
    }
    // we need to elevate the user permissions to super users to extract and create the tags
    this.extractTags(body, createdObject, User.superUser)<commit_msg>Apply bounds priority rules on challenge create<commit_after>/*
 * Copyright (C) 2020 MapRoulette contributors (see CONTRIBUTORS.md).
 * Licensed under the Apache License, Version 2.0 (see LICENSE).
 */
package org.maproulette.controllers.api

import java.io._
import java.sql.Connection
import java.util.zip.{ZipEntry, ZipOutputStream}

import akka.util.ByteString
import javax.inject.Inject
import org.apache.commons.lang3.StringUtils
import org.joda.time.DateTime
import org.maproulette.Config
import org.maproulette.controllers.ParentController
import org.maproulette.data._
import org.maproulette.exception.{
  InvalidException,
  MPExceptionUtil,
  NotFoundException,
  StatusMessage
}
import org.maproulette.framework.model._
import org.maproulette.framework.psql.Paging
import org.maproulette.framework.service.{ServiceManager, TagService}
import org.maproulette.models._
import org.maproulette.models.dal._
import org.maproulette.models.dal.mixin.TagDALMixin
import org.maproulette.permissions.Permission
import org.maproulette.provider.ChallengeProvider
import org.maproulette.session.{SearchParameters, SessionManager}
import org.maproulette.utils.Utils
import play.api.http.HttpEntity
import play.api.libs.Files
import play.api.libs.json._
import play.api.libs.ws.WSClient
import play.api.mvc._
import play.shaded.oauth.oauth.signpost.exception.OAuthNotAuthorizedException

import scala.concurrent.{Future, Promise}
import scala.io.Source
import scala.util.{Failure, Success}

/**
  * The challenge controller handles all operations for the Challenge objects.
  * This includes CRUD operations and searching/listing.
  * See ParentController for more details on parent object operations
  * See CRUDController for more details on CRUD object operations
  *
  * @author cuthbertm
  */
class ChallengeController @Inject() (
    override val childController: TaskController,
    override val sessionManager: SessionManager,
    override val actionManager: ActionManager,
    override val dal: ChallengeDAL,
    dalManager: DALManager,
    override val tagService: TagService,
    challengeProvider: ChallengeProvider,
    serviceManager: ServiceManager,
    wsClient: WSClient,
    permission: Permission,
    config: Config,
    components: ControllerComponents,
    override val bodyParsers: PlayBodyParsers,
    implicit val snapshotManager: SnapshotManager
) extends AbstractController(components)
    with ParentController[Challenge, Task]
    with TagsMixin[Challenge] {

  import scala.concurrent.ExecutionContext.Implicits.global

  // json reads for automatically reading Challenges from a posted json body
  override implicit val tReads: Reads[Challenge] = Challenge.reads.challengeReads
  // json writes for automatically writing Challenges to a json body response
  override implicit val tWrites: Writes[Challenge] = Challenge.writes.challengeWrites
  // json writes for automatically writing Tasks to a json body response
  override protected val cWrites: Writes[Task] = Task.TaskFormat
  // json reads for automatically reading tasks from a posted json body
  override protected val cReads: Reads[Task] = Task.TaskFormat
  // The type of object that this controller deals with.
  override implicit val itemType: ItemType = ChallengeType()
  override implicit val tableName: String  = this.dal.tableName

  // implicit writes used for various JSON responses
  implicit val commentWrites                                    = Comment.writes
  implicit val pointWrites                                      = ClusteredPoint.pointWrites
  implicit val clusteredPointWrites                             = ClusteredPoint.clusteredPointWrites
  implicit val taskClusterWrites                                = TaskCluster.taskClusterWrites
  implicit val searchLocationWrites                             = SearchParameters.locationWrites
  implicit val challengeListingWrites: Writes[ChallengeListing] = Json.writes[ChallengeListing]

  override def dalWithTags: TagDALMixin[Challenge] = dal

  /**
    * Function can be implemented to extract more information than just the default create data,
    * to build other objects with the current object at the core. No data will be returned from this
    * function, it purely does work in the background AFTER creating the current object
    *
    * @param body          The Json body of data
    * @param createdObject The object that was created by the create function
    * @param user          The user that is executing the function
    */
  override def extractAndCreate(body: JsValue, createdObject: Challenge, user: User)(
      implicit c: Option[Connection] = None
  ): Unit = {
    val localJson = (body \ "localGeoJSON").asOpt[JsValue] match {
      case Some(local) => Some(Json.stringify(local))
      case None        => None
    }
    if (!this.challengeProvider.buildTasks(user, createdObject, localJson)) {
      super.extractAndCreate(body, createdObject, user)
    }
    // we need to elevate the user permissions to super users to extract and create the tags
    this.extractTags(body, createdObject, User.superUser)

    //we need to reapply task priority rules since task locations were updated
    Future {
      this.dal.updateTaskPriorities(user)(createdObject.id)
    }
{'fraction_non_alphanumeric': 0.06697683435107105, 'fraction_numerical': 0.0013569836192691674, 'mean_word_length': 3.8418582824964806, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '136362', 'n_tokens_mistral': 2740, 'n_tokens_neox': 2668, 'n_words': 871}