nitweb: introduce feedback API for star rating system
authorAlexandre Terrasa <alexandre@moz-code.org>
Thu, 30 Jun 2016 02:34:53 +0000 (22:34 -0400)
committerAlexandre Terrasa <alexandre@moz-code.org>
Thu, 30 Jun 2016 02:34:53 +0000 (22:34 -0400)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

src/nitweb.nit
src/web/api_feedback.nit [new file with mode: 0644]
src/web/web.nit

index 3897c5c..af58044 100644 (file)
@@ -60,6 +60,11 @@ private class NitwebPhase
                        catalog.package_page(mpackage)
                end
 
+               # Prepare mongo connection
+               var mongo = new MongoClient("mongodb://localhost:27017/")
+               var db = mongo.database("nitweb")
+               var collection = db.collection("stars")
+
                # Run the server
                var host = toolcontext.opt_host.value or else "localhost"
                var port = toolcontext.opt_port.value
@@ -67,7 +72,7 @@ private class NitwebPhase
                var app = new App
 
                app.use_before("/*", new RequestClock)
-               app.use("/api", new APIRouter(model, modelbuilder, mainmodule, catalog))
+               app.use("/api", new APIRouter(model, modelbuilder, mainmodule, catalog, collection))
                app.use("/*", new StaticHandler(toolcontext.share_dir / "nitweb", "index.html"))
                app.use_after("/*", new ConsoleLog)
 
@@ -91,6 +96,9 @@ class APIRouter
        # Catalog to pass to handlers.
        var catalog: Catalog
 
+       # Mongo collection used to store ratings.
+       var collection: MongoCollection
+
        init do
                use("/catalog", new APICatalogRouter(model, mainmodule, catalog))
                use("/list", new APIList(model, mainmodule))
@@ -101,6 +109,7 @@ class APIRouter
                use("/uml/:id", new APIEntityUML(model, mainmodule))
                use("/linearization/:id", new APIEntityLinearization(model, mainmodule))
                use("/defs/:id", new APIEntityDefs(model, mainmodule))
+               use("/feedback/", new APIFeedbackRouter(model, mainmodule, collection))
                use("/inheritance/:id", new APIEntityInheritance(model, mainmodule))
                use("/graph/", new APIGraphRouter(model, mainmodule))
                use("/docdown/", new APIDocdown(model, mainmodule, modelbuilder))
diff --git a/src/web/api_feedback.nit b/src/web/api_feedback.nit
new file mode 100644 (file)
index 0000000..61ba756
--- /dev/null
@@ -0,0 +1,150 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Feedback related features
+module api_feedback
+
+import web_base
+import mongodb
+
+# Group all api handlers in one router
+class APIFeedbackRouter
+       super Router
+
+       # Model to pass to handlers
+       var model: Model
+
+       # Mainmodule to pass to handlers
+       var mainmodule: MModule
+
+       # Mongo collection used to store ratings
+       var collection: MongoCollection
+
+       init do
+               use("/stars/:id", new APIStars(model, mainmodule, collection))
+       end
+end
+
+# Stars attributed to mentities
+class APIStars
+       super APIHandler
+
+       # Collection used to store ratings
+       var collection: MongoCollection
+
+       redef fun get(req, res) do
+               var mentity = mentity_from_uri(req, res)
+               if mentity == null then
+                       res.error 404
+                       return
+               end
+
+               res.json mentity_ratings(mentity)
+       end
+
+       redef fun post(req, res) do
+               var mentity = mentity_from_uri(req, res)
+               if mentity == null then
+                       res.error 404
+                       return
+               end
+               var obj = req.body.parse_json
+               if not obj isa JsonObject then
+                       res.error 400
+                       return
+               end
+               var rating = obj["rating"]
+               if not rating isa Int then
+                       res.error 400
+                       return
+               end
+
+               var val = new MEntityRating(mentity.full_name, rating, get_time)
+               collection.insert(val.json)
+
+               res.json mentity_ratings(mentity)
+       end
+
+       # Get the ratings of a `mentity`
+       fun mentity_ratings(mentity: MEntity): MEntityRatings do
+               var ratings = new MEntityRatings(mentity)
+
+               var req = new JsonObject
+               req["mentity"] = mentity.full_name
+               var rs = collection.find_all(req)
+               for r in rs do ratings.ratings.add new MEntityRating.from_json(r)
+               return ratings
+       end
+end
+
+# Ratings representation for a mentity
+class MEntityRatings
+       super Jsonable
+
+       # MEntity rated
+       var mentity: MEntity
+
+       # List of ratings
+       var ratings = new Array[MEntityRating]
+
+       # Mean of all ratings or 0
+       fun mean: Float do
+               if ratings.is_empty then return 0.0
+               var sum = 0.0
+               for r in ratings do sum += r.rating.to_f
+               var res = sum / ratings.length.to_f
+               return res
+       end
+
+       # Json representation of `self`
+       fun json: JsonObject do
+               var obj = new JsonObject
+               obj["mentity"] = mentity.full_name
+               obj["ratings"] = new JsonArray.from(ratings)
+               obj["mean"] = mean
+               return obj
+       end
+
+       redef fun to_json do return json.to_json
+end
+
+# Rating value of a MEntity
+class MEntityRating
+       super Jsonable
+
+       # MEntity this rating is about
+       var mentity: String
+
+       # Rating value (between 1 and 5)
+       var rating: Int
+
+       # Timestamp of this rating
+       var timestamp: Int
+
+       # Init this rating value from a JsonObject
+       init from_json(obj: JsonObject) do
+               init(obj["mentity"].as(String), obj["rating"].as(Int), obj["timestamp"].as(Int))
+       end
+
+       # Translate this rating value to a JsonObject
+       fun json: JsonObject do
+               var obj = new JsonObject
+               obj["mentity"] = mentity
+               obj["rating"] = rating
+               obj["timestamp"] = timestamp
+               return obj
+       end
+
+       redef fun to_json do return json.to_json
+end
index 4dd39b5..c6bb476 100644 (file)
@@ -19,3 +19,4 @@ import api_model
 import api_catalog
 import api_graph
 import api_docdown
+import api_feedback