You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
6.2 KiB
230 lines
6.2 KiB
import json
|
|
|
|
from flask import Flask, request, Response
|
|
from pymongo import MongoClient
|
|
from flasgger import Swagger
|
|
|
|
|
|
app = Flask(__name__)
|
|
swagger = Swagger(app)
|
|
baesian = MongoClient("mongodb", 27017).demo.baesian
|
|
|
|
|
|
@app.route("/item/<int:itemid>", methods=["POST"])
|
|
def upsert_item(itemid):
|
|
"""Create item
|
|
---
|
|
parameters:
|
|
- name: itemid
|
|
in: path
|
|
type: string
|
|
required: true
|
|
- name: name
|
|
in: formData
|
|
type: string
|
|
required: false
|
|
responses:
|
|
200:
|
|
description: Item added
|
|
"""
|
|
request_params = request.form
|
|
if "name" not in request_params:
|
|
return Response(
|
|
"Name not present in parameters!", status=404, mimetype="application/json"
|
|
)
|
|
baesian.update_one(
|
|
{"_id": itemid},
|
|
{"$set": {"name": request_params["name"], "nr_votes": 0}},
|
|
upsert=True,
|
|
)
|
|
|
|
return Response(
|
|
json.dumps({"_id": itemid, "name": request_params["name"]}),
|
|
status=200,
|
|
mimetype="application/json",
|
|
)
|
|
|
|
|
|
@app.route("/item/vote/<int:itemid>", methods=["PUT"])
|
|
def add_vote(itemid):
|
|
"""Vote an item
|
|
---
|
|
parameters:
|
|
- name: itemid
|
|
in: path
|
|
type: string
|
|
required: true
|
|
- name: mark
|
|
in: formData
|
|
type: integer
|
|
required: false
|
|
- name: userid
|
|
in: formData
|
|
type: integer
|
|
required: false
|
|
responses:
|
|
200:
|
|
description: Update succeded
|
|
"""
|
|
request_params = request.form
|
|
if "mark" not in request_params or "userid" not in request_params:
|
|
return Response(
|
|
"Mark and userid must be present in form data!",
|
|
status=404,
|
|
mimetype="application/json",
|
|
)
|
|
mark = int(request_params["mark"])
|
|
if mark not in range(0, 10):
|
|
return Response(
|
|
"Mark must be in range (0, 10) !", status=500, mimetype="application/json"
|
|
)
|
|
userid = int(request_params["userid"])
|
|
update_items_data = {
|
|
"$push": {"marks": {"userid": userid, "mark": mark}},
|
|
"$inc": {"nr_votes": 1, "sum_votes": mark},
|
|
}
|
|
baesian.update_one({"_id": itemid}, update_items_data)
|
|
return Response("", status=200, mimetype="application/json")
|
|
|
|
|
|
@app.route("/item/<int:itemid>", methods=["GET"])
|
|
def get_item(itemid):
|
|
"""Item details
|
|
---
|
|
parameters:
|
|
- name: itemid
|
|
in: path
|
|
type: string
|
|
required: true
|
|
definitions:
|
|
Item:
|
|
type: object
|
|
properties:
|
|
_id:
|
|
type: integer
|
|
name:
|
|
type: string
|
|
marks:
|
|
type: array
|
|
items:
|
|
type: integer
|
|
sum_votes:
|
|
type: integer
|
|
nr_votes:
|
|
type: integer
|
|
baesian_average:
|
|
type: float
|
|
responses:
|
|
200:
|
|
description: Item model
|
|
schema:
|
|
$ref: '#/definitions/Item'
|
|
404:
|
|
description: Item not found
|
|
"""
|
|
item_data = baesian.find_one({"_id": itemid})
|
|
if None == item_data:
|
|
return Response("", status=404, mimetype="application/json")
|
|
if "marks" not in item_data:
|
|
item_data["nr_votes"] = 0
|
|
item_data["sum_votes"] = 0
|
|
item_data["baesian_average"] = 0
|
|
return Response(json.dumps(item_data), status=200, mimetype="application/json")
|
|
|
|
average_nr_votes_pipeline = [
|
|
{"$group": {"_id": "avg_nr_votes", "avg_nr_votes": {"$avg": "$nr_votes"}}},
|
|
]
|
|
average_nr_votes = list(baesian.aggregate(average_nr_votes_pipeline))[0][
|
|
"avg_nr_votes"
|
|
]
|
|
average_rating = [
|
|
{
|
|
"$group": {
|
|
"_id": "avg",
|
|
"avg": {"$sum": "$sum_votes"},
|
|
"count": {"$sum": "$nr_votes"},
|
|
}
|
|
},
|
|
{"$project": {"result": {"$divide": ["$avg", "$count"]}}},
|
|
]
|
|
average_rating = list(baesian.aggregate(average_rating))[0]["result"]
|
|
item_nr_votes = item_data["nr_votes"]
|
|
item_average_rating = item_data["sum_votes"] / item_data["nr_votes"]
|
|
baesian_average = round(
|
|
((average_nr_votes * average_rating) + (item_nr_votes * item_average_rating))
|
|
/ (average_nr_votes + item_nr_votes),
|
|
3,
|
|
)
|
|
item_data["baesian_average"] = baesian_average
|
|
return Response(json.dumps(item_data), status=200, mimetype="application/json")
|
|
|
|
|
|
@app.route("/items", methods=["GET"])
|
|
def get_items():
|
|
"""All items with pagination without averages
|
|
---
|
|
parameters:
|
|
- name: limit
|
|
in: query
|
|
type: integer
|
|
required: false
|
|
- name: offset
|
|
in: query
|
|
type: integer
|
|
required: false
|
|
definitions:
|
|
Items:
|
|
type: array
|
|
items:
|
|
properties:
|
|
_id:
|
|
type: integer
|
|
name:
|
|
type: string
|
|
marks:
|
|
type: array
|
|
items:
|
|
type: integer
|
|
responses:
|
|
200:
|
|
description: List of items
|
|
schema:
|
|
$ref: '#/definitions/Items'
|
|
"""
|
|
request_args = request.args
|
|
limit = int(request_args.get("limit")) if "limit" in request_args else 10
|
|
offset = int(request_args.get("offset")) if "offset" in request_args else 0
|
|
item_list = baesian.find().limit(limit).skip(offset)
|
|
if None == baesian:
|
|
return Response(json.dumps([]), status=200, mimetype="application/json")
|
|
extracted = [
|
|
{
|
|
"_id": d["_id"],
|
|
"name": d["name"],
|
|
"marks": d["marks"] if "marks" in d else [],
|
|
}
|
|
for d in item_list
|
|
]
|
|
return Response(json.dumps(extracted), status=200, mimetype="application/json")
|
|
|
|
|
|
@app.route("/item/<int:itemid>", methods=["DELETE"])
|
|
def delete_item(itemid):
|
|
"""Delete operation for a item
|
|
---
|
|
parameters:
|
|
- name: itemid
|
|
in: path
|
|
type: string
|
|
required: true
|
|
responses:
|
|
200:
|
|
description: Item deleted
|
|
"""
|
|
baesian.delete_one({"_id": itemid})
|
|
return Response("", status=200, mimetype="application/json")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# starts the app in debug mode, bind on all ip's and on port 5000
|
|
app.run(debug=True, host="0.0.0.0", port=5000)
|
|
|