diff --git a/app/org/maproulette/controllers/api/ChallengeController.scala b/app/org/maproulette/controllers/api/ChallengeController.scala index d8e99213..48332160 100644 --- a/app/org/maproulette/controllers/api/ChallengeController.scala +++ b/app/org/maproulette/controllers/api/ChallengeController.scala @@ -1192,6 +1192,7 @@ class ChallengeController @Inject() ( jsonBody = Utils.insertIntoJson(jsonBody, "taskWidgetLayout", JsObject.empty)(jsValueWrites) jsonBody = Utils.insertIntoJson(jsonBody, "updateTasks", false)(BooleanWrites) jsonBody = Utils.insertIntoJson(jsonBody, "changesetUrl", false)(BooleanWrites) + jsonBody = Utils.insertIntoJson(jsonBody, "requireConfirmation", false)(BooleanWrites) // if we can't find the parent ID, just use the user's default project instead (jsonBody \ "parent").asOpt[Long] match { case Some(v) => jsonBody diff --git a/app/org/maproulette/framework/controller/ProjectController.scala b/app/org/maproulette/framework/controller/ProjectController.scala index 0650270b..d0379d32 100644 --- a/app/org/maproulette/framework/controller/ProjectController.scala +++ b/app/org/maproulette/framework/controller/ProjectController.scala @@ -69,6 +69,7 @@ class ProjectController @Inject() ( jsonBody = Utils.insertIntoJson(jsonBody, "featured", false)(BooleanWrites) jsonBody = Utils.insertIntoJson(jsonBody, "enabled", true)(BooleanWrites) jsonBody = Utils.insertIntoJson(jsonBody, "isArchived", false)(BooleanWrites) + jsonBody = Utils.insertIntoJson(jsonBody, "requireConfirmation", false)(BooleanWrites) jsonBody .validate[Project] .fold( diff --git a/app/org/maproulette/framework/model/Challenge.scala b/app/org/maproulette/framework/model/Challenge.scala index bc331628..d9b36866 100644 --- a/app/org/maproulette/framework/model/Challenge.scala +++ b/app/org/maproulette/framework/model/Challenge.scala @@ -138,7 +138,8 @@ case class ChallengeExtra( taskWidgetLayout: Option[JsValue] = None, datasetUrl: Option[String] = None, systemArchivedAt: Option[DateTime] = None, - presets: Option[List[String]] = None + presets: Option[List[String]] = None, + requireConfirmation: Boolean = false ) extends DefaultWrites case class ChallengeListing( @@ -163,6 +164,7 @@ case class Challenge( override val description: Option[String] = None, deleted: Boolean = false, isGlobal: Boolean = false, + requireConfirmation: Boolean = false, infoLink: Option[String] = None, general: ChallengeGeneral, creation: ChallengeCreation, @@ -331,6 +333,7 @@ object Challenge extends CommonField { None, false, false, + false, None, ChallengeGeneral(-1, -1, ""), ChallengeCreation(), diff --git a/app/org/maproulette/framework/model/Project.scala b/app/org/maproulette/framework/model/Project.scala index 68e9891b..85926d66 100644 --- a/app/org/maproulette/framework/model/Project.scala +++ b/app/org/maproulette/framework/model/Project.scala @@ -33,7 +33,8 @@ case class Project( deleted: Boolean = false, isVirtual: Option[Boolean] = Some(false), featured: Boolean = false, - isArchived: Boolean = false + isArchived: Boolean = false, + requireConfirmation: Boolean = false ) extends CacheObject[Long] with Identifiable { def grantsToType(granteeType: ItemType) = diff --git a/app/org/maproulette/framework/model/User.scala b/app/org/maproulette/framework/model/User.scala index 5aa535dd..b8d27570 100644 --- a/app/org/maproulette/framework/model/User.scala +++ b/app/org/maproulette/framework/model/User.scala @@ -178,7 +178,8 @@ case class UserSettings( allowFollowing: Option[Boolean] = None, theme: Option[Int] = None, customBasemaps: Option[List[CustomBasemap]] = None, - seeTagFixSuggestions: Option[Boolean] = None + seeTagFixSuggestions: Option[Boolean] = None, + disableTaskConfirm: Option[Boolean] = None ) { def getTheme: String = theme match { case Some(t) => diff --git a/app/org/maproulette/framework/repository/ChallengeRepository.scala b/app/org/maproulette/framework/repository/ChallengeRepository.scala index 2d5649b9..b9c0bdda 100644 --- a/app/org/maproulette/framework/repository/ChallengeRepository.scala +++ b/app/org/maproulette/framework/repository/ChallengeRepository.scala @@ -266,6 +266,7 @@ object ChallengeRepository { get[Boolean]("challenges.is_archived") ~ get[Int]("challenges.review_setting") ~ get[Option[String]]("challenges.dataset_url") ~ + get[Boolean]("challenges.require_confirmation") ~ get[Option[JsValue]]("challenges.task_widget_layout") ~ get[Option[DateTime]]("challenges.system_archived_at") map { case id ~ name ~ created ~ modified ~ description ~ infoLink ~ ownerId ~ parentId ~ instruction ~ @@ -274,7 +275,7 @@ object ChallengeRepository { mediumPriorityRule ~ lowPriorityRule ~ defaultZoom ~ minZoom ~ maxZoom ~ defaultBasemap ~ defaultBasemapId ~ customBasemap ~ updateTasks ~ exportableProperties ~ osmIdProperty ~ taskBundleIdProperty ~ preferredTags ~ preferredReviewTags ~ limitTags ~ limitReviewTags ~ taskStyles ~ lastTaskRefresh ~ dataOriginDate ~ requiresLocal ~ location ~ bounding ~ - deleted ~ isGlobal ~ virtualParents ~ isArchived ~ reviewSetting ~ datasetUrl ~ taskWidgetLayout ~ systemArchivedAt => + deleted ~ isGlobal ~ virtualParents ~ isArchived ~ reviewSetting ~ datasetUrl ~ requireConfirmation ~ taskWidgetLayout ~ systemArchivedAt => val hpr = highPriorityRule match { case Some(c) if StringUtils.isEmpty(c) || StringUtils.equals(c, "{}") => None case r => r @@ -296,6 +297,7 @@ object ChallengeRepository { description, deleted, isGlobal, + requireConfirmation, infoLink, ChallengeGeneral( ownerId, diff --git a/app/org/maproulette/framework/repository/ProjectRepository.scala b/app/org/maproulette/framework/repository/ProjectRepository.scala index dfc88d8f..c47fb341 100644 --- a/app/org/maproulette/framework/repository/ProjectRepository.scala +++ b/app/org/maproulette/framework/repository/ProjectRepository.scala @@ -78,17 +78,18 @@ class ProjectRepository @Inject() (override val db: Database, grantService: Gran */ def create(project: Project)(implicit c: Option[Connection] = None): Project = { this.withMRTransaction { implicit c => - SQL("""INSERT INTO projects (name, owner_id, display_name, description, enabled, is_virtual, featured) - VALUES ({name}, {ownerId}, {displayName}, {description}, {enabled}, {virtual}, {featured}) + SQL("""INSERT INTO projects (name, owner_id, display_name, description, enabled, is_virtual, featured, require_confirmation) + VALUES ({name}, {ownerId}, {displayName}, {description}, {enabled}, {virtual}, {featured}, {requireConfirmation}) RETURNING *""") .on( - Symbol("name") -> project.name, - Symbol("ownerId") -> project.owner, - Symbol("displayName") -> project.displayName, - Symbol("description") -> project.description.getOrElse(""), - Symbol("enabled") -> project.enabled, - Symbol("virtual") -> project.isVirtual.getOrElse(false), - Symbol("featured") -> project.featured + Symbol("name") -> project.name, + Symbol("ownerId") -> project.owner, + Symbol("displayName") -> project.displayName, + Symbol("description") -> project.description.getOrElse(""), + Symbol("enabled") -> project.enabled, + Symbol("virtual") -> project.isVirtual.getOrElse(false), + Symbol("featured") -> project.featured, + Symbol("requireConfirmation") -> project.requireConfirmation ) .as(this.parser.*) .head @@ -112,20 +113,22 @@ class ProjectRepository @Inject() (override val db: Database, grantService: Gran enabled = {enabled}, is_virtual = {virtual}, featured = {featured}, - is_archived = {isArchived} + is_archived = {isArchived}, + require_confirmation = {requireConfirmation} WHERE id = {id} RETURNING * """) .on( - Symbol("name") -> project.name, - Symbol("ownerId") -> project.owner, - Symbol("displayName") -> project.displayName, - Symbol("description") -> project.description, - Symbol("enabled") -> project.enabled, - Symbol("virtual") -> project.isVirtual, - Symbol("featured") -> project.featured, - Symbol("isArchived") -> project.isArchived, - Symbol("id") -> project.id + Symbol("name") -> project.name, + Symbol("ownerId") -> project.owner, + Symbol("displayName") -> project.displayName, + Symbol("description") -> project.description, + Symbol("enabled") -> project.enabled, + Symbol("virtual") -> project.isVirtual, + Symbol("featured") -> project.featured, + Symbol("isArchived") -> project.isArchived, + Symbol("requireConfirmation") -> project.requireConfirmation, + Symbol("id") -> project.id ) .as(this.parser.*) .headOption @@ -400,8 +403,9 @@ object ProjectRepository extends Readers { get[Boolean]("projects.deleted") ~ get[Boolean]("projects.is_virtual") ~ get[Boolean]("projects.featured") ~ - get[Boolean]("projects.is_archived") map { - case id ~ ownerId ~ name ~ created ~ modified ~ description ~ enabled ~ displayName ~ deleted ~ isVirtual ~ featured ~ isArchived => + get[Boolean]("projects.is_archived") ~ + get[Boolean]("projects.require_confirmation") map { + case id ~ ownerId ~ name ~ created ~ modified ~ description ~ enabled ~ displayName ~ deleted ~ isVirtual ~ featured ~ isArchived ~ requireConfirmation => new Project( id, ownerId, @@ -415,7 +419,8 @@ object ProjectRepository extends Readers { deleted, Some(isVirtual), featured, - isArchived + isArchived, + requireConfirmation ) } } diff --git a/app/org/maproulette/framework/repository/UserRepository.scala b/app/org/maproulette/framework/repository/UserRepository.scala index ade689ba..75ac4691 100644 --- a/app/org/maproulette/framework/repository/UserRepository.scala +++ b/app/org/maproulette/framework/repository/UserRepository.scala @@ -109,7 +109,7 @@ class UserRepository @Inject() ( default_basemap = {defaultBasemap}, default_basemap_id = {defaultBasemapId}, locale = {locale}, email = {email}, email_opt_in = {emailOptIn}, leaderboard_opt_out = {leaderboardOptOut}, needs_review = {needsReview}, is_reviewer = {isReviewer}, theme = {theme}, allow_following = {allowFollowing}, - properties = {properties}, see_tag_fix_suggestions = {seeTagFixSuggestions} + properties = {properties}, see_tag_fix_suggestions = {seeTagFixSuggestions}, disable_task_confirm = {disableTaskConfirm} WHERE id = {id} RETURNING ${UserRepository.standardColumns}, (SELECT score FROM user_metrics um WHERE um.user_id = ${user.id}) as score, (SELECT achievements FROM user_metrics um WHERE um.user_id = ${user.id}) as achievements""" @@ -134,7 +134,8 @@ class UserRepository @Inject() ( Symbol("theme") -> user.settings.theme, Symbol("allowFollowing") -> user.settings.allowFollowing, Symbol("properties") -> user.properties, - Symbol("seeTagFixSuggestions") -> user.settings.seeTagFixSuggestions + Symbol("seeTagFixSuggestions") -> user.settings.seeTagFixSuggestions, + Symbol("disableTaskConfirm") -> user.settings.disableTaskConfirm ) .as(this.parser().*) .head @@ -514,12 +515,14 @@ object UserRepository { get[Option[Boolean]]("users.allow_following") ~ get[Option[Long]]("users.following_group") ~ get[Option[Long]]("users.followers_group") ~ - get[Option[Boolean]]("users.see_tag_fix_suggestions") map { + get[Option[Boolean]]("users.see_tag_fix_suggestions") ~ + get[Option[Boolean]]("users.disable_task_confirm") map { case id ~ osmId ~ created ~ modified ~ osmCreated ~ displayName ~ description ~ avatarURL ~ homeLocation ~ apiKey ~ oauthToken ~ defaultEditor ~ defaultBasemap ~ defaultBasemapId ~ customBasemapList ~ email ~ emailOptIn ~ leaderboardOptOut ~ needsReview ~ isReviewer ~ locale ~ theme ~ - properties ~ score ~ achievements ~ allowFollowing ~ followingGroupId ~ followersGroupId ~ seeTagFixSuggestions => + properties ~ score ~ achievements ~ allowFollowing ~ followingGroupId ~ followersGroupId ~ + seeTagFixSuggestions ~ disableTaskConfirm => val locationWKT = homeLocation match { case Some(wkt) => new WKTReader().read(wkt).asInstanceOf[Point] case None => new GeometryFactory().createPoint(new Coordinate(0, 0)) @@ -565,7 +568,8 @@ object UserRepository { allowFollowing, theme, customBasemaps, - seeTagFixSuggestions + seeTagFixSuggestions, + disableTaskConfirm ), properties, score, diff --git a/app/org/maproulette/framework/service/ProjectService.scala b/app/org/maproulette/framework/service/ProjectService.scala index 7ef33481..7d8a5b1e 100644 --- a/app/org/maproulette/framework/service/ProjectService.scala +++ b/app/org/maproulette/framework/service/ProjectService.scala @@ -304,6 +304,8 @@ class ProjectService @Inject() ( } val isVirtual = cachedItem.isVirtual // Don't allow updates to virtual status val isArchived = (updates \ "isArchived").asOpt[Boolean].getOrElse(cachedItem.isArchived) + val requireConfirmation = + (updates \ "requireConfirmation").asOpt[Boolean].getOrElse(cachedItem.requireConfirmation) this.repository.update( Project( @@ -315,7 +317,8 @@ class ProjectService @Inject() ( enabled = enabled, isVirtual = isVirtual, featured = featured, - isArchived = isArchived + isArchived = isArchived, + requireConfirmation = requireConfirmation ) ) }(id = id) diff --git a/app/org/maproulette/framework/service/UserService.scala b/app/org/maproulette/framework/service/UserService.scala index 1a16cdea..c5946eab 100644 --- a/app/org/maproulette/framework/service/UserService.scala +++ b/app/org/maproulette/framework/service/UserService.scala @@ -458,7 +458,10 @@ class UserService @Inject() ( .getOrElse(cachedItem.settings.allowFollowing.getOrElse(true)) val seeTagFixSuggestions = (value \ "settings" \ "seeTagFixSuggestions") .asOpt[Boolean] - .getOrElse(cachedItem.settings.seeTagFixSuggestions.getOrElse(true)) + .getOrElse(cachedItem.settings.seeTagFixSuggestions.getOrElse(false)) + val disableTaskConfirm = (value \ "settings" \ "disableTaskConfirm") + .asOpt[Boolean] + .getOrElse(cachedItem.settings.disableTaskConfirm.getOrElse(false)) val theme = (value \ "settings" \ "theme") .asOpt[Int] .getOrElse(cachedItem.settings.theme.getOrElse(-1)) @@ -502,7 +505,8 @@ class UserService @Inject() ( Some(allowFollowing), Some(theme), customBasemaps, - Some(seeTagFixSuggestions) + Some(seeTagFixSuggestions), + Some(disableTaskConfirm) ), properties = Some(properties) ), diff --git a/app/org/maproulette/models/dal/ChallengeDAL.scala b/app/org/maproulette/models/dal/ChallengeDAL.scala index 5df69718..fca41aa8 100644 --- a/app/org/maproulette/models/dal/ChallengeDAL.scala +++ b/app/org/maproulette/models/dal/ChallengeDAL.scala @@ -126,7 +126,8 @@ class ChallengeDAL @Inject() ( get[Option[String]]("challenges.dataset_url") ~ get[Option[JsValue]]("challenges.task_widget_layout") ~ get[Option[Int]]("challenges.completion_percentage") ~ - get[Option[Int]]("challenges.tasks_remaining") map { + get[Option[Int]]("challenges.tasks_remaining") ~ + get[Boolean]("challenges.require_confirmation") map { case id ~ name ~ created ~ modified ~ description ~ infoLink ~ ownerId ~ parentId ~ instruction ~ difficulty ~ blurb ~ enabled ~ featured ~ cooperativeType ~ popularity ~ checkin_comment ~ checkin_source ~ overpassql ~ remoteGeoJson ~ overpassTargetType ~ status ~ statusMessage ~ @@ -134,7 +135,8 @@ class ChallengeDAL @Inject() ( minZoom ~ maxZoom ~ defaultBasemap ~ defaultBasemapId ~ customBasemap ~ updateTasks ~ exportableProperties ~ osmIdProperty ~ taskBundleIdProperty ~ preferredTags ~ preferredReviewTags ~ limitTags ~ limitReviewTags ~ taskStyles ~ lastTaskRefresh ~ dataOriginDate ~ location ~ bounding ~ - requiresLocal ~ deleted ~ isGlobal ~ isArchived ~ reviewSetting ~ datasetUrl ~ taskWidgetLayout ~ completionPercentage ~ tasksRemaining => + requiresLocal ~ deleted ~ isGlobal ~ isArchived ~ reviewSetting ~ datasetUrl ~ taskWidgetLayout ~ + completionPercentage ~ tasksRemaining ~ requireConfirmation => val hpr = highPriorityRule match { case Some(c) if StringUtils.isEmpty(c) || StringUtils.equals(c, "{}") => None case r => r @@ -156,6 +158,7 @@ class ChallengeDAL @Inject() ( description, deleted, isGlobal, + requireConfirmation, infoLink, ChallengeGeneral( ownerId, @@ -268,7 +271,8 @@ class ChallengeDAL @Inject() ( get[Option[JsValue]]("challenges.task_widget_layout") ~ get[Option[DateTime]]("challenges.system_archived_at") ~ get[Option[Int]]("challenges.completion_percentage") ~ - get[Option[Int]]("challenges.tasks_remaining") map { + get[Option[Int]]("challenges.tasks_remaining") ~ + get[Boolean]("challenges.require_confirmation") map { case id ~ name ~ created ~ modified ~ description ~ infoLink ~ ownerId ~ parentId ~ instruction ~ difficulty ~ blurb ~ enabled ~ featured ~ cooperativeType ~ popularity ~ checkin_comment ~ checkin_source ~ overpassql ~ remoteGeoJson ~ overpassTargetType ~ @@ -277,7 +281,8 @@ class ChallengeDAL @Inject() ( customBasemap ~ updateTasks ~ exportableProperties ~ osmIdProperty ~ taskBundleIdProperty ~ preferredTags ~ preferredReviewTags ~ limitTags ~ limitReviewTags ~ taskStyles ~ lastTaskRefresh ~ dataOriginDate ~ location ~ bounding ~ requiresLocal ~ deleted ~ isGlobal ~ virtualParents ~ - presets ~ isArchived ~ reviewSetting ~ datasetUrl ~ taskWidgetLayout ~ systemArchivedAt ~ completionPercentage ~ tasksRemaining => + presets ~ isArchived ~ reviewSetting ~ datasetUrl ~ taskWidgetLayout ~ systemArchivedAt ~ completionPercentage ~ + tasksRemaining ~ requireConfirmation => val hpr = highPriorityRule match { case Some(c) if StringUtils.isEmpty(c) || StringUtils.equals(c, "{}") => None case r => r @@ -299,6 +304,7 @@ class ChallengeDAL @Inject() ( description, deleted, isGlobal, + requireConfirmation, infoLink, ChallengeGeneral( ownerId, @@ -338,7 +344,8 @@ class ChallengeDAL @Inject() ( taskWidgetLayout, datasetUrl, systemArchivedAt, - presets + presets, + requireConfirmation ), status, statusMessage, @@ -489,7 +496,7 @@ class ChallengeDAL @Inject() ( medium_priority_rule, low_priority_rule, default_zoom, min_zoom, max_zoom, default_basemap, default_basemap_id, custom_basemap, updatetasks, exportable_properties, osm_id_property, task_bundle_id_property, last_task_refresh, data_origin_date, preferred_tags, preferred_review_tags, - limit_tags, limit_review_tags, task_styles, requires_local, is_archived, review_setting, dataset_url, task_widget_layout) + limit_tags, limit_review_tags, task_styles, requires_local, is_archived, review_setting, dataset_url, require_confirmation, task_widget_layout) VALUES (${challenge.name}, ${challenge.general.owner}, ${challenge.general.parent}, ${challenge.general.difficulty}, ${challenge.description}, ${challenge.isGlobal}, ${challenge.infoLink}, ${challenge.general.blurb}, ${challenge.general.instruction}, ${challenge.general.enabled}, ${challenge.general.featured}, @@ -503,7 +510,7 @@ class ChallengeDAL @Inject() ( ${challenge.dataOriginDate.getOrElse(DateTime.now()).toString}::timestamptz, ${challenge.extra.preferredTags}, ${challenge.extra.preferredReviewTags}, ${challenge.extra.limitTags}, ${challenge.extra.limitReviewTags}, ${challenge.extra.taskStyles}, ${challenge.general.requiresLocal}, ${challenge.extra.isArchived}, - ${challenge.extra.reviewSetting}, ${challenge.extra.datasetUrl}, + ${challenge.extra.reviewSetting}, ${challenge.extra.datasetUrl}, ${challenge.extra.requireConfirmation}, ${asJson(challenge.extra.taskWidgetLayout.getOrElse(Json.parse("{}")))} ) ON CONFLICT(parent_id, LOWER(name)) DO NOTHING RETURNING #${this.retrieveColumns}""" .as(this.parser.*) @@ -696,6 +703,10 @@ class ChallengeDAL @Inject() ( .asOpt[String] .getOrElse(cachedItem.extra.datasetUrl) + val requireConfirmation = (updates \ "requireConfirmation") + .asOpt[Boolean] + .getOrElse(cachedItem.extra.requireConfirmation) + val taskWidgetLayout = (updates \ "taskWidgetLayout") .asOpt[JsValue] .getOrElse(cachedItem.extra.taskWidgetLayout.getOrElse(Json.parse("{}"))) @@ -709,7 +720,8 @@ class ChallengeDAL @Inject() ( description = $description, info_link = $infoLink, blurb = $blurb, instruction = $instruction, enabled = $enabled, featured = $featured, checkin_comment = $checkinComment, checkin_source = $checkinSource, overpass_ql = $overpassQL, remote_geo_json = $remoteGeoJson, overpass_target_type = $overpassTargetType, status = $status, status_message = $statusMessage, default_priority = $defaultPriority, - data_origin_date = ${dataOriginDate.toString()}::timestamptz, + data_origin_date = ${dataOriginDate + .toString()}::timestamptz, require_confirmation = $requireConfirmation, high_priority_rule = ${if (StringUtils.isEmpty(highPriorityRule)) { Option.empty[String] } else { diff --git a/app/org/maproulette/models/utils/ChallengeFormatters.scala b/app/org/maproulette/models/utils/ChallengeFormatters.scala index 27c59d3c..086157cd 100644 --- a/app/org/maproulette/models/utils/ChallengeFormatters.scala +++ b/app/org/maproulette/models/utils/ChallengeFormatters.scala @@ -56,6 +56,7 @@ trait ChallengeWrites extends DefaultWrites { (JsPath \ "description").writeNullable[String] and (JsPath \ "deleted").write[Boolean] and (JsPath \ "isGlobal").write[Boolean] and + (JsPath \ "requireConfirmation").write[Boolean] and (JsPath \ "infoLink").writeNullable[String] and JsPath.write[ChallengeGeneral] and JsPath.write[ChallengeCreation] and @@ -112,6 +113,7 @@ trait ChallengeReads extends DefaultReads { (JsPath \ "description").readNullable[String] and (JsPath \ "deleted").read[Boolean] and (JsPath \ "isGlobal").read[Boolean] and + (JsPath \ "requireConfirmation").read[Boolean] and (JsPath \ "infoLink").readNullable[String] and JsPath.read[ChallengeGeneral] and JsPath.read[ChallengeCreation] and diff --git a/app/org/maproulette/provider/KeepRightProvider.scala b/app/org/maproulette/provider/KeepRightProvider.scala index ea64a132..fa8a2f65 100644 --- a/app/org/maproulette/provider/KeepRightProvider.scala +++ b/app/org/maproulette/provider/KeepRightProvider.scala @@ -242,6 +242,7 @@ class KeepRightProvider @Inject() ( None, false, false, + false, None, ChallengeGeneral(User.superUser.id, rootProjectId, ""), ChallengeCreation(), diff --git a/conf/evolutions/default/99.sql b/conf/evolutions/default/99.sql new file mode 100644 index 00000000..71eeed9a --- /dev/null +++ b/conf/evolutions/default/99.sql @@ -0,0 +1,9 @@ +# --- !Ups +ALTER TABLE users ADD COLUMN disable_task_confirm BOOLEAN DEFAULT false;; +ALTER TABLE challenges ADD COLUMN require_confirmation BOOLEAN DEFAULT false;; +ALTER TABLE projects ADD COLUMN require_confirmation BOOLEAN DEFAULT false;; + +# --- !Downs +ALTER TABLE IF EXISTS users DROP COLUMN disable_task_confirm;; +ALTER TABLE IF EXISTS challenges DROP COLUMN require_confirmation;; +ALTER TABLE IF EXISTS projects DROP COLUMN require_confirmation;; diff --git a/docs/github_example.md b/docs/github_example.md index b524c74c..5f38e15c 100644 --- a/docs/github_example.md +++ b/docs/github_example.md @@ -47,7 +47,8 @@ RESPONSE { "groups": [], "enabled": true, "deleted": false, - "isGlobal": false + "isGlobal": false, + "requireConfirmation": false, } ``` ***NOTE:** The owner id will match the ID of the user used based on the APIKey.
diff --git a/test/org/maproulette/provider/ChallengeProviderSpec.scala b/test/org/maproulette/provider/ChallengeProviderSpec.scala index d317faeb..4a5288bc 100644 --- a/test/org/maproulette/provider/ChallengeProviderSpec.scala +++ b/test/org/maproulette/provider/ChallengeProviderSpec.scala @@ -17,6 +17,7 @@ class ChallengeProviderSpec extends PlaySpec with MockitoSugar { None, false, false, + false, None, ChallengeGeneral(101, 1, ""), ChallengeCreation(), @@ -32,6 +33,7 @@ class ChallengeProviderSpec extends PlaySpec with MockitoSugar { None, false, false, + false, None, ChallengeGeneral(101, 1, ""), ChallengeCreation(), diff --git a/test/org/maproulette/utils/TestSpec.scala b/test/org/maproulette/utils/TestSpec.scala index 7eb6da75..45c6bac2 100644 --- a/test/org/maproulette/utils/TestSpec.scala +++ b/test/org/maproulette/utils/TestSpec.scala @@ -52,6 +52,7 @@ trait TestSpec extends PlaySpec with MockitoSugar { None, false, false, + false, None, ChallengeGeneral(101, 1, ""), ChallengeCreation(),