Skip to content

Commit

Permalink
add Retrieve a Users Locked Tasks endpoint (#1139)
Browse files Browse the repository at this point in the history
* add `Retrieve Users Locked Tasks` endpoint

* format and remove unused code

* fix imports

* include challenge id in object

* simplify parser and LockedTaskData object

* add more descriptions and simplify queries and parses

* fix descriptions

* fix file name
  • Loading branch information
CollinBeczak authored Aug 10, 2024
1 parent 5949dc0 commit 9dc82e6
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 3 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
28 changes: 28 additions & 0 deletions app/org/maproulette/framework/model/LockedTaskData.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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 play.api.libs.json.{Format, Json}
import play.api.libs.json.JodaWrites._
import play.api.libs.json.JodaReads._

/**
* Mapping of object structure for fetching task lock data
*/
case class LockedTaskData(
id: Long,
parent: Long,
parentName: String,
/**
* The time that the task was locked
*/
startedAt: DateTime
)

// 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,19 @@
package org.maproulette.framework.repository

import java.sql.Connection

import anorm.SQL
import anorm.SqlParser._
import org.joda.time.DateTime

import javax.inject.{Inject, Singleton}
import org.maproulette.framework.model.{Challenge, SavedChallenge, SavedTasks}
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 +151,41 @@ 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")
parent <- get[Long]("tasks.parent_id")
parentName <- get[String]("challenges.challenge_name")
lockedTime <- get[DateTime]("locked.locked_time")
} yield (LockedTaskData(id, parent, parentName, lockedTime))

val query = """
SELECT t.id, t.parent_id, l.locked_time, c.name AS challenge_name
FROM tasks t
INNER JOIN locked l ON t.id = l.item_id
INNER 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
30 changes: 30 additions & 0 deletions conf/v2_route/user.api
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,36 @@ 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.LockedTaskData'
# '401':
# description: The user is not authorized to make this request.
# '404':
# description: userId is not known.
# 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.
# required: false
# schema:
# type: integer
# default: 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 9dc82e6

Please sign in to comment.