nitc :: api_feedback
nitc :: StarRating
Star ratings allow users to rate mentities with a 5-stars system.nitc :: api_feedback $ Deserializer
Abstract deserialization servicenitc :: api_feedback $ MEntity
A named and possibly documented entity in the model.nitc :: api_feedback $ Deserializer
Abstract deserialization servicenitc :: api_feedback $ MEntity
A named and possibly documented entity in the model.nitc :: actors_injection_phase
Injects model for the classes annotated with "is actor" sonitc :: astbuilder
Instantiation and transformation of semantic nodes in the AST of expressions and statementsnitc :: commands_ini
FileServer
action, which is a standard and minimal file server
HttpRequest
class and services to create it
nitc :: i18n_phase
Basic support of internationalization through the generation of id-to-string tablesSerializable::inspect
to show more useful information
nitc :: modelbuilder
more_collections :: more_collections
Highly specific, but useful, collections-related classes.curl :: native_curl
Binding of C libCurl which allow us to interact with network.threaded
annotation
serialization :: serialization_core
Abstract services to serialize Nit objects to different formatsnitc :: serialization_model_phase
Phase generating methods (model-only) to serialize Nit objectsdeserialize_json
and JsonDeserializer
serialize_to_json
and JsonSerializer
nitc :: toolcontext
Common command-line tool infrastructure than handle options and error messagesnitc :: uml_module
Services for generation of a UML package diagram based on aModel
core :: union_find
union–find algorithm using an efficient disjoint-set data structure
# Feedback related features
module api_feedback
import api_base
import popcorn::pop_auth
redef class NitwebConfig
# MongoDB collection used to store stars.
var stars = new StarRatingRepo(db.collection("stars")) is lazy
end
redef class APIRouter
redef init do
super
use("/feedback/grades/most", new APIStarsMost(config))
use("/feedback/grades/best", new APIStarsBest(config))
use("/feedback/grades/worst", new APIStarsWorst(config))
use("/feedback/grades/users", new APIStarsUsers(config))
use("/feedback/user/stars", new APIUserStars(config))
use("/feedback/stars/:id", new APIStars(config))
use("/feedback/stars/:id/dimension/:dimension", new APIStarsDimension(config))
end
end
# Base handler for feedback features.
abstract class APIFeedBack
super APIHandler
# Get the user logged in or null if no session
fun get_session_user(req: HttpRequest): nullable User do
var session = req.session
if session == null then return null
return session.user
end
# Get the login of the session user or null if no session
fun get_session_login(req: HttpRequest): nullable String do
var user = get_session_user(req)
if user == null then return null
return user.login
end
end
# Most rated entities
class APIStarsMost
super APIFeedBack
redef fun get(req, res) do
res.api_json(req, new JsonArray.from(config.stars.most_rated))
end
end
# Best rated entities
class APIStarsBest
super APIFeedBack
redef fun get(req, res) do
res.api_json(req, new JsonArray.from(config.stars.best_rated))
end
end
# Best rated entities
class APIStarsWorst
super APIFeedBack
redef fun get(req, res) do
res.api_json(req, new JsonArray.from(config.stars.worst_rated))
end
end
# Best rated entities
class APIStarsUsers
super APIFeedBack
redef fun get(req, res) do
res.api_json(req, new JsonArray.from(config.stars.users_ratings))
end
end
# Stars attributed to mentities by user
class APIUserStars
super APIFeedBack
redef fun get(req, res) do
var user = get_session_user(req)
if user == null then return
res.api_json(req, new JsonArray.from(user.ratings(config)))
end
end
# Stars attributed to mentities
class APIStars
super APIFeedBack
redef fun get(req, res) do
var login = get_session_login(req)
var mentity = mentity_from_uri(req, res)
if mentity == null then return
res.api_json(req, mentity.ratings(config, login))
end
end
# Stars attributed to mentities by dimension
class APIStarsDimension
super APIFeedBack
redef fun get(req, res) do
var login = get_session_login(req)
var mentity = mentity_from_uri(req, res)
if mentity == null then return
var dimension = req.param("dimension")
if dimension == null then return
res.api_json(req, mentity.ratings_by_dimension(config, dimension, login))
end
redef fun post(req, res) do
var user = get_session_user(req)
var login = null
if user != null then login = user.login
var mentity = mentity_from_uri(req, res)
if mentity == null then return
var dimension = req.param("dimension")
if dimension == null then return
# Retrieve user previous rating
var previous = null
if user != null then
previous = user.find_previous_rating(config, mentity, dimension)
end
var obj = req.body.parse_json
if not obj isa JsonObject then
res.api_error(400, "Expected a JSON object")
return
end
var rating = obj["rating"]
if not rating isa Int then
res.api_error(400, "Expected a key `rating`")
return
end
if previous != null then
previous.rating = rating
previous.timestamp = get_time
config.stars.save previous
else
config.stars.save new StarRating(login, mentity.full_name, dimension, rating)
end
res.api_json(req, mentity.ratings_by_dimension(config, dimension, login))
end
end
# Star ratings allow users to rate mentities with a 5-stars system.
#
# Each rating can consider only one `dimension` of the mentity.
# Dimensions are arbitrary strings used to group ratings.
class StarRating
super RepoObject
serialize
# The user login that made that rating (or null if anon)
var user: nullable String
# Rated `MEntity::full_name`
var mentity: String
# The dimension rated (arbritrary key)
var dimension: nullable String
# The rating (traditionally a score between 0 and 5)
var rating: Int is writable
# Timestamp when this rating was created
var timestamp = 0 is writable
end
redef class User
# Find a previous rating of `self` for `mentity` and `dimension`
fun find_previous_rating(config: NitwebConfig, mentity: MEntity, dimension: nullable String): nullable StarRating do
var match = new MongoMatch
match.eq("mentity", mentity.full_name)
match.eq("dimension", dimension)
match.eq("user", login)
return config.stars.find(match)
end
# Find all ratings by `self`
fun ratings(config: NitwebConfig): Array[StarRating] do
return config.stars.find_all((new MongoMatch).eq("user", login))
end
end
redef class MEntity
# Get the ratings of a `dimension`
fun ratings_by_dimension(config: NitwebConfig, dimension: String, user: nullable String): JsonObject do
var match = (new MongoMatch).eq("mentity", full_name).eq("dimension", dimension)
var pipeline = new MongoPipeline
pipeline.match(match)
pipeline.group((new MongoGroup("mean_group")).avg("mean", "$rating"))
var res = config.stars.collection.aggregate(pipeline)
var obj = new JsonObject
obj["mean"] = if res.is_empty then 0.0 else res.first["mean"]
obj["ratings"] = new JsonArray.from(config.stars.find_all(match))
if user != null then
match["user"] = user
obj["user"] = config.stars.find(match)
end
return obj
end
# Get the ratings of a `mentity`
fun ratings(config: NitwebConfig, user: nullable String): JsonObject do
var match = new JsonObject
match["mentity"] = full_name
match["ratings"] = new JsonArray.from(config.stars.find_all(match))
match["feature"] = ratings_by_dimension(config, "feature", user)
match["doc"] = ratings_by_dimension(config, "doc", user)
match["examples"] = ratings_by_dimension(config, "examples", user)
match["code"] = ratings_by_dimension(config, "code", user)
return match
end
end
# StarRating Mongo Repository
class StarRatingRepo
super MongoRepository[StarRating]
# Find most rated mentities
fun most_rated: Array[JsonObject] do
var pipeline = new MongoPipeline
pipeline.group((new MongoGroup("$mentity")).sum("count", 1))
pipeline.sort((new MongoMatch).eq("count", -1))
pipeline.limit(10)
return collection.aggregate(pipeline)
end
# Find best rated mentities
fun best_rated: Array[JsonObject] do
var pipeline = new MongoPipeline
pipeline.group((new MongoGroup("$mentity")).avg("avg", "$rating"))
pipeline.sort((new MongoMatch).eq("avg", -1))
pipeline.limit(10)
return collection.aggregate(pipeline)
end
# Find worst rated mentities
fun worst_rated: Array[JsonObject] do
var pipeline = new MongoPipeline
pipeline.group((new MongoGroup("$mentity")).avg("avg", "$rating"))
pipeline.sort((new MongoMatch).eq("avg", 1))
pipeline.limit(10)
return collection.aggregate(pipeline)
end
# Find worst rated mentities
fun users_ratings: Array[JsonObject] do
var pipeline = new MongoPipeline
pipeline.group((new MongoGroup("$user")).sum("count", 1))
pipeline.sort((new MongoMatch).eq("count", -1))
pipeline.limit(10)
return collection.aggregate(pipeline)
end
end
src/doc/api/api_feedback.nit:15,1--287,3