Return-Path: Delivered-To: apmail-incubator-esme-commits-archive@minotaur.apache.org Received: (qmail 63346 invoked from network); 2 Nov 2009 09:57:44 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 2 Nov 2009 09:57:44 -0000 Received: (qmail 20137 invoked by uid 500); 2 Nov 2009 09:57:44 -0000 Delivered-To: apmail-incubator-esme-commits-archive@incubator.apache.org Received: (qmail 20111 invoked by uid 500); 2 Nov 2009 09:57:44 -0000 Mailing-List: contact esme-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: esme-dev@incubator.apache.org Delivered-To: mailing list esme-commits@incubator.apache.org Received: (qmail 20097 invoked by uid 99); 2 Nov 2009 09:57:44 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 02 Nov 2009 09:57:44 +0000 X-ASF-Spam-Status: No, hits=-2.6 required=5.0 tests=AWL,BAYES_00 X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 02 Nov 2009 09:57:41 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id D008E23888DA; Mon, 2 Nov 2009 09:57:20 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r831838 - /incubator/esme/trunk/server/src/main/scala/org/apache/esme/api/API2.scala Date: Mon, 02 Nov 2009 09:57:20 -0000 To: esme-commits@incubator.apache.org From: rhirsch@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20091102095720.D008E23888DA@eris.apache.org> 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 { - Message.findAndPrime(By(Message.conversation, id), - OrderBy(Message.id, Ascending)).map(_.toXml) - } - - 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 { + Message.findAndPrime(By(Message.conversation, id), + OrderBy(Message.id, Ascending)).map(_.toXml) + } + 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) = {in} @@ -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.