Skip to content

Commit

Permalink
add Retrieve Users Locked Tasks endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
CollinBeczak committed Jul 27, 2024
1 parent 5949dc0 commit 87cca3a
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 9 deletions.
10 changes: 10 additions & 0 deletions app/org/maproulette/framework/controller/UserController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,16 @@ class UserController @Inject() (
}
}

def getLockedTasks(
userId: Long,
limit: Long
): Action[AnyContent] = Action.async { implicit request =>
this.sessionManager.authenticatedRequest { implicit user =>
val tasks = this.serviceManager.user.getLockedTasks(userId, user, limit)
Ok(Json.toJson(tasks))
}
}

def saveTask(userId: Long, taskId: Long): Action[AnyContent] = Action.async { implicit request =>
this.sessionManager.authenticatedRequest { implicit user =>
this.serviceManager.user.saveTask(userId, taskId, user)
Expand Down
41 changes: 41 additions & 0 deletions app/org/maproulette/framework/model/LockedTask.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2020 MapRoulette contributors (see CONTRIBUTORS.md).
* Licensed under the Apache License, Version 2.0 (see LICENSE).
*/
package org.maproulette.framework.model

import org.joda.time.DateTime
import org.maproulette.cache.CacheObject
import org.maproulette.framework.psql.CommonField
import play.api.libs.json.{Json, Format}
import play.api.libs.json.JodaWrites._
import play.api.libs.json.JodaReads._

// Define the LockedTask case class
case class LockedTask(
override val id: Long,
challengeName: Option[String],
startedAt: DateTime
) extends CacheObject[Long] {
// Implement the abstract member 'name'
override def name: String = "LockedTask"
}

/**
* Mapping between Task and Challenge and Lock
*/
case class LockedTaskData(
id: Long,
challengeName: Option[String],
startedAt: DateTime
)

object LockedTask extends CommonField {
// Use Json.format to automatically derive both Reads and Writes
implicit val lockedTaskFormat: Format[LockedTask] = Json.format[LockedTask]
}

// Define implicit Formats for LockedTaskData
object LockedTaskData {
implicit val lockedTaskDataFormat: Format[LockedTaskData] = Json.format[LockedTaskData]
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,14 @@
package org.maproulette.framework.repository

import java.sql.Connection
import anorm.{SQL, SqlParser}
import anorm.SqlParser._
import org.joda.time.DateTime

import anorm.SQL
import javax.inject.{Inject, Singleton}
import org.maproulette.framework.model.{Challenge, SavedChallenge, SavedTasks}
import org.maproulette.framework.psql.filter.{
BaseParameter,
FilterParameter,
Operator,
SubQueryFilter
}
import org.maproulette.framework.model.{Challenge, LockedTaskData, SavedChallenge, SavedTasks, Task}
import org.maproulette.framework.psql.filter.{BaseParameter, FilterParameter, Operator, SubQueryFilter}
import org.maproulette.framework.psql._
import org.maproulette.framework.model.Task
import org.maproulette.models.dal.{ChallengeDAL, TaskDAL}
import play.api.db.Database

Expand Down Expand Up @@ -150,6 +146,40 @@ class UserSavedObjectsRepository @Inject() (
}
}

/**
* Retrieves a list of locked tasks for a specific user.
*
* @param userId The ID of the user for whom you are requesting the saved challenges.
* @param limit The maximum number of tasks to return.
* @param c An optional existing connection.
* @return A list tasks the user has locked, each item containing the task ID, its locked time, and the challenge name.
*/
def getLockedTasks(
userId: Long,
limit: Long
)(implicit c: Option[Connection] = None): List[LockedTaskData] = {
this.withMRTransaction { implicit c =>
val parser = for {
id <- get[Long]("id")
challengeName <- get[Option[String]]("challenges.challenge_name")
lockedTime <- get[DateTime]("locked.locked_time")
} yield (LockedTaskData(id, challengeName, lockedTime))

val query = """
SELECT t.id, l.locked_time, c.name AS challenge_name
FROM tasks t
INNER JOIN locked l ON t.id = l.item_id
LEFT JOIN challenges c ON t.parent_id = c.id
WHERE l.user_id = {userId}
LIMIT {limit}
"""

SQL(query)
.on("userId" -> userId, "limit" -> limit)
.as(parser.*)
}
}

/**
* Saves the task for the user, will validate that the task actually exists first based on the
* provided id
Expand Down
17 changes: 17 additions & 0 deletions app/org/maproulette/framework/service/UserService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,23 @@ class UserService @Inject() (
this.savedObjectsRepository.getSavedTasks(userId, challengeIds, paging)
}

/**
* Retrieve all the tasks that have been locked by the provided user
*
* @param userId The id of the user
* @param user The user making the actual request
* @param limit
* @return A list of Tasks that have been locked by the user
*/
def getLockedTasks(
userId: Long,
user: User,
limit: Long
): List[LockedTaskData] = {
this.permission.hasReadAccess(UserType(), user)(userId)
this.savedObjectsRepository.getLockedTasks(userId, limit)
}

/**
* Saves the task for the user, will validate that the task actually exists first based on the
* provided id
Expand Down
24 changes: 24 additions & 0 deletions conf/v2_route/user.api
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,30 @@ DELETE /user/:userId/unsave/:challengeId @org.maproulette.framework.c
GET /user/:userId/savedTasks @org.maproulette.framework.controller.UserController.getSavedTasks(userId:Long, challengeIds:String ?= "", limit:Int ?= 10, page:Int ?= 0)
###
# tags: [ User ]
# summary: Retrieves Users Locked Tasks
# description: Retrieves a list of all the tasks the user with the matching id has locked
# responses:
# '200':
# description: The retrieved Tasks
# content:
# application/json:
# schema:
# type: array
# items:
# $ref: '#/components/schemas/org.maproulette.framework.model.Task'
# '401':
# description: The user is not authorized to make this request
# parameters:
# - name: userId
# in: path
# description: The id of the user to retrieve the locked tasks for
# - name: limit
# in: query
# description: Limit the number of results returned in the response. Default value is 50.
###
GET /user/:userId/lockedTasks @org.maproulette.framework.controller.UserController.getLockedTasks(userId:Long, limit:Int ?= 50)
###
# tags: [ User ]
# summary: Saves a Task for a User
# description: Saves a Task to a user account
# responses:
Expand Down

0 comments on commit 87cca3a

Please sign in to comment.