Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Retrieve a Users Locked Tasks endpoint #1139

Merged
merged 8 commits into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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':
CollinBeczak marked this conversation as resolved.
Show resolved Hide resolved
# 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.
CollinBeczak marked this conversation as resolved.
Show resolved Hide resolved
# 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