Author: rhirsch
Date: Mon Nov 2 09:57:20 2009
New Revision: 831838
URL: http://svn.apache.org/viewvc?rev=831838&view=rev
Log:
[ESME-14] Make current API more REST-like
Patch from Ethan Jewett applied
Modified:
incubator/esme/trunk/server/src/main/scala/org/apache/esme/api/API2.scala
Modified:
incubator/esme/trunk/server/src/main/scala/org/apache/esme/api/API2.scala
URL:
http://svn.apache.org/viewvc/incubator/esme/trunk/server/src/main/scala/org/apache/esme/api/API2.scala?rev=831838&r1=831837&r2=831838&view=diff
==============================================================================
--- incubator/esme/trunk/server/src/main/scala/org/apache/esme/api/API2.scala
(original)
+++ incubator/esme/trunk/server/src/main/scala/org/apache/esme/api/API2.scala
Mon Nov 2 09:57:20 2009
@@ -50,174 +50,65 @@
val logger: Logger = Logger.getLogger("org.apache.esme.api")
def dispatch: LiftRules.DispatchPF = {
- case Req("api2" :: "session" :: Nil, _, GetRequest) => status
- case Req("api2" :: "session" :: Nil, _, PostRequest) => login
- case Req("api2" :: "session" :: Nil, _, DeleteRequest) => logout
+ case Req("api2" :: "session" :: Nil, _, GetRequest) => status // No params
+ case Req("api2" :: "session" :: Nil, _, PostRequest) => login // token
+ case Req("api2" :: "session" :: Nil, _, DeleteRequest) => logout // No
params
- case Req("api2" :: "users" :: Nil, _, GetRequest) => allUsers _
+ case Req("api2" :: "users" :: Nil, _, GetRequest) => allUsers _ // No
params
+// Add a method to get detail for a specific user
- case Req("api2" :: "user" :: "messages" :: Nil, _, GetRequest) => getMsgs
- case Req("api2" :: "user" :: "messages" :: Nil, _, PostRequest) => () =>
sendMsg(User.currentUser.map(_.id.is), S)
-
- case Req("api2" :: "user" :: "followees" :: Nil, _, GetRequest) =>
following(calcUser)
- case Req("api2" :: "user" :: "followees" :: Nil, _, PostRequest) =>
performFollow(S.param("user"))
- case Req("api2" :: "user" :: "followees" :: userId :: Nil, _,
DeleteRequest) => performUnfollow(Box(List(userId)))
-
- case Req("api2" :: "user" :: "followers" :: Nil, _, GetRequest) =>
followers(calcUser)
-
- case Req("api2" :: "user" :: "tracks" :: Nil, _, GetRequest) => getTracking
- case Req("api2" :: "user" :: "tracks" :: Nil, _, PostRequest) =>
addTracking
- case Req("api2" :: "user" :: "tracks" :: trackId :: Nil, _, DeleteRequest)
=> () => removeTracking(Box(List(trackId)))
-
- case Req("api2" :: "user" :: "actions" :: Nil, _, GetRequest) =>
getActions _
- case Req("api2" :: "user" :: "actions" :: Nil, _, PostRequest) =>
addAction _
- case Req("api2" :: "user" :: "actions" :: actionId :: Nil, _, PutRequest)
=> () => enableAction(Box(List(actionId)))
- case Req("api2" :: "user" :: "actions" :: actionId :: Nil, _,
DeleteRequest) => () => deleteAction(Box(List(actionId)))
+ case Req("api2" :: "user" :: "messages" :: Nil, _, GetRequest) =>
allUserMsgs // tag (opt)
+// Possibly deprecate and move to api2/messages or api2/pools/poolName/messages
+ case Req("api2" :: "user" :: "messages" :: Nil, _, PostRequest) => () =>
addMsg // message,
+// via (opt), pool (opt), realm (opt), metadata (opt), tags (opt), replyto
(opt)
+
+ case Req("api2" :: "user" :: "followees" :: Nil, _, GetRequest) =>
allFollowees // No params
+ case Req("api2" :: "user" :: "followees" :: Nil, _, PostRequest) =>
addFollowee // userId
+ case Req("api2" :: "user" :: "followees" :: userId :: Nil, _,
DeleteRequest)
+ => removeFollow(Box(List(userId))) // No params
+
+ case Req("api2" :: "user" :: "followers" :: Nil, _, GetRequest) =>
allFollowers // No params
+
+ case Req("api2" :: "user" :: "tracks" :: Nil, _, GetRequest) =>
allTracking // No params
+ case Req("api2" :: "user" :: "tracks" :: Nil, _, PostRequest) =>
addTracking // track (regex)
+// Add a method to get detail for a specific track (or messages for the track?)
+ case Req("api2" :: "user" :: "tracks" :: trackId :: Nil, _, DeleteRequest)
=> ()
+ => removeTracking(Box(List(trackId))) // No params
+
+ case Req("api2" :: "user" :: "actions" :: Nil, _, GetRequest) =>
allActions // No params
+ case Req("api2" :: "user" :: "actions" :: Nil, _, PostRequest) =>
addAction // name, test, action
+// Add a method to get detail of a specific action
+ case Req("api2" :: "user" :: "actions" :: actionId :: Nil, _, PutRequest)
=> ()
+ => changeAction(Box(List(actionId))) // enabled
(boolean)
+ case Req("api2" :: "user" :: "actions" :: actionId :: Nil, _,
DeleteRequest) => ()
+ => removeAction(Box(List(actionId))) // No params
- case Req("api2" :: "pools" :: Nil, _, GetRequest) => getPools
- case Req("api2" :: "pools" :: poolName :: Nil, _, PostRequest) => () =>
addPool(poolName)
- case Req("api2" :: "pools" :: poolId :: "users" :: userId :: Nil, _,
PostRequest) => ()
- => addUserToPool(Box(List(userId)), Box(List(poolId)))
-
+ case Req("api2" :: "pools" :: Nil, _, GetRequest) => allPools // No params
+ case Req("api2" :: "pools" :: Nil, _, PostRequest) => () => addPool //
poolName
+// Add a method to delete pool
+// Add a method to get the detail for a pool
+// Add a method to get the list of users in a pool
+ case Req("api2" :: "pools" :: poolId :: "users" :: Nil, _, PostRequest) =>
()
+ => addUserToPool(Box(List(poolId))) // realm, userId,
permission
+// Add a method to delete a user from a pool
+// Add a method to get the messages from a pool
+// Add a method to post a new message to a pool
+
+// Add a method to get list of conversations
case Req("api2" :: "conversations" :: conversationId :: Nil, _,
GetRequest) => ()
- => getConversation(Box(List(conversationId)))
+ => getConversation(Box(List(conversationId))) // No
params
+// Add a method to post a message to a conversation??
-// Do we need this?
- case Req("api2" :: "wait_for_msgs" :: Nil, _, GetRequest) => waitForMsgs
- }
-
- def findAction(actionId: Box[String]): Box[Action] =
- for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in");
- id <- actionId ?~ S.?("base_rest_api_err_missing_param", "id");
- action <- Action.find(By(Action.user, user),
- By(Action.id, id.toLong),
- By(Action.removed, false))) yield action
-
- def addAction(): LiftResponse = {
- val ret: Box[NodeSeq] =
- for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in");
- name <- S.param("name") ?~ S.?("base_rest_api_err_missing_param",
"name");
- test <- S.param("test") ?~ S.?("base_rest_api_err_missing_param",
"test");
- action <- S.param("action") ?~ S.?("base_rest_api_err_missing_param",
"action");
- val a = Action.create.user(user).name(name);
- a2 <- a.setTest(test);
- a3 <- a.setAction(action)) yield a3.saveMe.toXml
-
- ret
- }
-
- def getActions(): LiftResponse = {
- val ret: Box[NodeSeq] =
- for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in"))
- yield user.performing.flatMap(_.toXml)
-
- ret
- }
-
- def enableAction(actionId: Box[String]): LiftResponse = {
- val ret: Box[Boolean] =
- for (action <- findAction(actionId);
- enabled <- S.param("enabled").map(toBoolean) ?~
S.?("base_rest_api_err_missing_param", "enable"))
- yield action.disabled(!enabled).save
-
- ret
- }
-
- def deleteAction(actionId: Box[String]): LiftResponse = {
- val ret: Box[Boolean] =
- for (action <- findAction(actionId))
- yield action.removed(true).save
-
- ret
- }
-
- private def calcUser: Box[User] =
- S.param("user").flatMap(User.findFromWeb) or
- User.currentUser
-
- def getTracking(): LiftResponse = {
- val ret: Box[NodeSeq] =
- for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in"))
- yield Tracking.findAll(By(Tracking.user, user)).flatMap(_.toXml)
- ret
- }
-
- def getConversation(conversationId: Box[String]): LiftResponse = {
- val ret: Box[NodeSeq] =
- for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in");
- id <- conversationId.map(toLong) ?~
S.?("base_rest_api_err_missing_param", "id")
- ) yield <conversation id={id.toString}>{
- Message.findAndPrime(By(Message.conversation, id),
- OrderBy(Message.id, Ascending)).map(_.toXml)
- }</conversation>
-
- ret
- }
-
- def removeTracking(trackId: Box[String]): LiftResponse = {
- val ret: Box[Boolean] =
- for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in");
- id <- trackId ?~ S.?("base_rest_api_err_missing_param", "id");
- track <- Tracking.find(By(Tracking.id, id.toLong),
- By(Tracking.user, user)) ?~ "Couldn't find
tracking item"
- ) yield track.removed(true).save
-
- ret
- }
-
- def addTracking(): LiftResponse = {
- val ret: Box[Boolean] =
- for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in");
- toTrack <- (S.param("track") ?~
S.?("base_rest_api_err_missing_param", "track")) if toTrack.trim.length > 0)
- yield
- Tracking.create.user(user).regex(toTrack).save
-
- ret
+// Do we need this? - specifically, can we merge it with the
/api2/user/messages
+// resource with a different match?
+// case Req("api2" :: "wait_for_msgs" :: Nil, _, GetRequest) => waitForMsgs
}
def status(): LiftResponse =
{
val ret: Box[NodeSeq] = User.currentUser.map(_.toXml)
ret
- }
-
- def allUsers(): LiftResponse =
- for (user <- User.findAll) yield user.toXml
-
-
- def following(muser: Box[User])(): LiftResponse = {
- val r: Box[NodeSeq] = for (user <- muser) yield
- user.following().map(_.toXml)
-
- r
- }
-
- def followers(muser: Box[User])(): LiftResponse = {
- val r: Box[NodeSeq] = for (user <- muser) yield
- user.followers().map(_.toXml)
-
- r
- }
-
- def performFollow(userName: Box[String])(): LiftResponse = {
- val r: Box[Boolean] =
- for (user <- User.currentUser;
- userName <- userName;
- other <- User.findFromWeb(userName)
- ) yield user.follow(other)
-
- r
- }
-
- def performUnfollow(userName: Box[String])(): LiftResponse = {
- val r: Box[Boolean] =
- for (user <- User.currentUser;
- userName <- userName;
- other <- User.findFromWeb(userName)
- ) yield user.unfollow(other)
-
- r
- }
+ }
def login(): LiftResponse = {
val res: Box[Boolean] = if (User.loggedIn_?) Empty else
@@ -234,81 +125,175 @@
}
res
- }
+ }
def logout(): LiftResponse = {
User.logUserOut()
true
- }
+ }
- def waitForMsgs(): LiftResponse = {
- val future = new LAFuture[List[(Message, MailboxReason)]]()
-
- def waitForAnswer: Box[List[(Message, MailboxReason)]] =
- future.get(6L * 60L * 1000L)
- var r: Box[NodeSeq] =
- for (act <- restActor.is ?~ "No REST actor";
- val ignore = act ! ListenFor(future, 5 minutes);
- answer <- waitForAnswer ?~ "Didn't get an answer")
- yield answer.flatMap{ case (msg, reason) => msg.toXml % reason.attr}
+ def allUsers(): LiftResponse =
+ for (user <- User.findAll) yield user.toXml
+
+ def allUserMsgs(): LiftResponse = {
+ val t: Box[NodeSeq] =
+ for (tagName <- S.param("tag");
+ tag <- Tag.find(By(Tag.name, tagName)))
+ yield tag.findMessages.map(_.toXml)
+
+ val r: Box[NodeSeq] =
+ t or (for (user <- calcUser ?~ S.?("base_rest_api_err_param_not_found",
"User");
+ val lst = Mailbox.mostRecentMessagesFor(user.id, 40))
+ yield lst.flatMap{ case (msg, why, _) => msg.toXml % why.attr})
r
- }
+ }
- def sendMsgWithToken(req: Req): Box[LiftResponse] = {
- for (token <- req.param("token");
- auth <- AuthToken.find(By(AuthToken.uniqueId, token));
- userId <- auth.user.can;
- ret <- sendMsg(Full(userId), req)) yield ret
- }
-
- def sendMsg(theUser: Box[Long], params: HasParams): LiftResponse = {
+ def addMsg(): LiftResponse = {
val r: Box[Boolean] =
- for (user <- theUser ?~ S.?("base_rest_api_err_param_not_found", "User");
- msg <- params.param("message") ?~
S.?("base_rest_api_err_missing_param", "message"))
+ for (user <- calcUser.map(_.id.is) ?~
S.?("base_rest_api_err_param_not_found", "User");
+ msg <- S.param("message") ?~ S.?("base_rest_api_err_missing_param",
"message"))
yield {
- val from: String = params.param("via") openOr "api"
- val pool = for (poolName <- params.param("pool");
+ val from: String = S.param("via") openOr "api"
+ val pool = for (poolName <- S.param("pool");
p <- AccessPool.findPool(poolName,
- params.param("realm") openOr AccessPool.Native)
+ S.param("realm") openOr AccessPool.Native)
) yield p.id.is
- val xml: Box[Elem] = params.param("metadata").flatMap(md =>
+ val xml: Box[Elem] = S.param("metadata").flatMap(md =>
tryo(XML.loadString(md)))
Distributor !
Distributor.UserCreatedMessage(user, msg,
- Tag.split(params.param("tags")
+ Tag.split(S.param("tags")
openOr ""),
millis,
xml,
from,
- params.param("replyto").map(toLong),
+ S.param("replyto").map(toLong),
pool)
true
}
r
+ }
+
+
+ def allFollowees(): LiftResponse = {
+ val r: Box[NodeSeq] = for (user <- calcUser) yield
+ user.following().map(_.toXml)
+
+ r
+ }
+
+ def addFollowee(): LiftResponse = {
+ val r: Box[Boolean] =
+ for (user <- User.currentUser;
+ userName <- S.param("userId");
+ other <- User.findFromWeb(userName)
+ ) yield user.follow(other)
+
+ r
+ }
+
+
+ def removeFollow(userName: Box[String])(): LiftResponse = {
+ val r: Box[Boolean] =
+ for (user <- User.currentUser;
+ userName <- userName;
+ other <- User.findFromWeb(userName)
+ ) yield user.unfollow(other)
+
+ r
}
- def getMsgs(): LiftResponse = {
- val t: Box[NodeSeq] =
- for (tagName <- S.param("tag");
- tag <- Tag.find(By(Tag.name, tagName)))
- yield tag.findMessages.map(_.toXml)
-
- val r: Box[NodeSeq] =
- t or (for (user <- calcUser ?~ S.?("base_rest_api_err_param_not_found",
"User");
- val lst = Mailbox.mostRecentMessagesFor(user.id, 40))
- yield lst.flatMap{ case (msg, why, _) => msg.toXml % why.attr})
+ def allFollowers(): LiftResponse = {
+ val r: Box[NodeSeq] = for (user <- calcUser) yield
+ user.followers().map(_.toXml)
r
+ }
+
+ def allTracking(): LiftResponse = {
+ val ret: Box[NodeSeq] =
+ for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in"))
+ yield Tracking.findAll(By(Tracking.user, user)).flatMap(_.toXml)
+ ret
+ }
+
+ def addTracking(): LiftResponse = {
+ val ret: Box[Boolean] =
+ for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in");
+ toTrack <- (S.param("track") ?~
S.?("base_rest_api_err_missing_param", "track")) if toTrack.trim.length > 0)
+ yield
+ Tracking.create.user(user).regex(toTrack).save
+
+ ret
+ }
+
+ def removeTracking(trackId: Box[String]): LiftResponse = {
+ val ret: Box[Boolean] =
+ for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in");
+ id <- trackId ?~ S.?("base_rest_api_err_missing_param", "id");
+ track <- Tracking.find(By(Tracking.id, id.toLong),
+ By(Tracking.user, user)) ?~ "Couldn't find
tracking item"
+ ) yield track.removed(true).save
+
+ ret
+ }
+
+ def allActions(): LiftResponse = {
+ val ret: Box[NodeSeq] =
+ for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in"))
+ yield user.performing.flatMap(_.toXml)
+
+ ret
+ }
+
+ def addAction(): LiftResponse = {
+ val ret: Box[NodeSeq] =
+ for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in");
+ name <- S.param("name") ?~ S.?("base_rest_api_err_missing_param",
"name");
+ test <- S.param("test") ?~ S.?("base_rest_api_err_missing_param",
"test");
+ action <- S.param("action") ?~ S.?("base_rest_api_err_missing_param",
"action");
+ val a = Action.create.user(user).name(name);
+ a2 <- a.setTest(test);
+ a3 <- a.setAction(action)) yield a3.saveMe.toXml
+
+ ret
+ }
+
+ def changeAction(actionId: Box[String]): LiftResponse = {
+ val ret: Box[Boolean] =
+ for (action <- findAction(actionId);
+ enabled <- S.param("enabled").map(toBoolean) ?~
S.?("base_rest_api_err_missing_param", "enable"))
+ yield action.disabled(!enabled).save
+
+ ret
}
- def addPool(poolName: String): LiftResponse = {
+ def removeAction(actionId: Box[String]): LiftResponse = {
+ val ret: Box[Boolean] =
+ for (action <- findAction(actionId))
+ yield action.removed(true).save
+
+ ret
+ }
+
+ def allPools(): LiftResponse = {
+ val ret: Box[NodeSeq] =
+ for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in"))
+ yield AccessPool.findAll(In(AccessPool.id, Privilege.pool,
By(Privilege.user, user)),
+ OrderBy(AccessPool.id, Descending),
+ MaxRows(20)).
+ flatMap(_.toXml)
+ ret
+ }
+
+ def addPool(): LiftResponse = {
val r: Box[Boolean] =
for (user <- User.currentUser;
- pool <- AccessPool.create.realm(AccessPool.Native).setName(poolName);
+ pool <-
AccessPool.create.realm(AccessPool.Native).setName(S.param("poolName").openOr(""));
privilegeSaved = Privilege.create.pool(pool.saveMe).user(user).
permission(Permission.Admin).save
) yield {
@@ -317,15 +302,15 @@
}
r
- }
-
- def addUserToPool(userId: Box[String], poolId: Box[String]): LiftResponse = {
+ }
+
+ def addUserToPool(poolId: Box[String]): LiftResponse = {
val r: Box[Boolean] =
for (adminUser <- User.currentUser;
poolName <- poolId ?~ S.?("base_rest_api_err_missing_param", "pool");
realm <- (S.param("realm") or Full(AccessPool.Native));
pool <- AccessPool.findPool(poolName, realm) ?~
S.?("base_rest_api_err_param_not_found", "Pool");
- userName <- userId ?~ S.?("base_rest_api_err_missing_param", "user");
+ userName <- S.param("userId") ?~
S.?("base_rest_api_err_missing_param", "user");
user <- User.findFromWeb(userName) ?~
S.?("base_rest_api_err_param_not_found", "User");
permissionName <- (S.param("permission") or Full("Write"));
permission <- Box(Permission.valueOf(permissionName)) ?~
S.?("base_rest_api_err_param_not_found", "Permission")
@@ -340,18 +325,49 @@
} else false // "User has no permission to administer pool"
r
- }
-
- def getPools(): LiftResponse = {
+ }
+
+ def getConversation(conversationId: Box[String]): LiftResponse = {
val ret: Box[NodeSeq] =
- for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in"))
- yield AccessPool.findAll(In(AccessPool.id, Privilege.pool,
By(Privilege.user, user)),
- OrderBy(AccessPool.id, Descending),
- MaxRows(20)).
- flatMap(_.toXml)
+ for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in");
+ id <- conversationId.map(toLong) ?~
S.?("base_rest_api_err_missing_param", "id")
+ ) yield <conversation id={id.toString}>{
+ Message.findAndPrime(By(Message.conversation, id),
+ OrderBy(Message.id, Ascending)).map(_.toXml)
+ }</conversation>
+
ret
}
+ private def findAction(actionId: Box[String]): Box[Action] =
+ for (user <- User.currentUser ?~ S.?("base_rest_api_err_not_logged_in");
+ id <- actionId ?~ S.?("base_rest_api_err_missing_param", "id");
+ action <- Action.find(By(Action.user, user),
+ By(Action.id, id.toLong),
+ By(Action.removed, false))) yield action
+
+
+ private def calcUser: Box[User] =
+ S.param("user").flatMap(User.findFromWeb) or
+ User.currentUser
+
+
+
+ def waitForMsgs(): LiftResponse = {
+ val future = new LAFuture[List[(Message, MailboxReason)]]()
+
+ def waitForAnswer: Box[List[(Message, MailboxReason)]] =
+ future.get(6L * 60L * 1000L)
+
+ var r: Box[NodeSeq] =
+ for (act <- restActor.is ?~ "No REST actor";
+ val ignore = act ! ListenFor(future, 5 minutes);
+ answer <- waitForAnswer ?~ "Didn't get an answer")
+ yield answer.flatMap{ case (msg, reason) => msg.toXml % reason.attr}
+
+ r
+ }
+
def createTag(in: NodeSeq) = <esme_api>{in}</esme_api>
@@ -413,4 +429,10 @@
private case class ListenFor(who: LAFuture[List[(Message, MailboxReason)]],
howLong: TimeSpan)
private case object ReleaseListener
-}
+}
+
+// TODO:
+// 1. Get rid of calcUser and replace with User.currentUser ?~
S.?("base_rest_api_err_not_logged_in")
+// 2. Fix errors so that they properly indicate a missing parameter or 404
+// 3. Change changeAction so that if the "enabled" parameter doesn't show up
it will simply use
+// the current value for the action, not throw an error.