Refactoring statistics api
This commit is contained in:
parent
8aa85d10ed
commit
ab4e560ba7
15
app.py
15
app.py
|
@ -2,23 +2,22 @@ from flask import Flask
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from apps.admin import admin as blueprint_admin
|
from apps import statistics_app
|
||||||
from apps.auth import auth as blueprint_auth
|
from apps import auth_app
|
||||||
|
from apps import admin_app
|
||||||
from apps.group_stat_api import group_stat_api as blueprint_stat_api
|
|
||||||
|
|
||||||
from config import secret_key
|
from config import secret_key
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = secret_key
|
app.secret_key = secret_key
|
||||||
|
|
||||||
app.register_blueprint(blueprint_auth)
|
app.register_blueprint(auth_app)
|
||||||
app.register_blueprint(blueprint_admin)
|
app.register_blueprint(admin_app)
|
||||||
app.register_blueprint(blueprint_stat_api)
|
app.register_blueprint(statistics_app)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from database import build_database
|
from database import build_database
|
||||||
build_database()
|
build_database()
|
||||||
logging.info("Build database models")
|
logging.info("Build database models")
|
||||||
|
|
||||||
app.run(host="0.0.0.0")
|
app.run(host="0.0.0.0")
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
from .admin import admin as admin_app
|
||||||
|
from .auth import auth as auth_app
|
||||||
|
from .group_statistics_api import statistics_api as statistics_app
|
|
@ -1,146 +0,0 @@
|
||||||
from flask import Blueprint
|
|
||||||
from flask import request, jsonify
|
|
||||||
|
|
||||||
from peewee import SQL, fn
|
|
||||||
from database import Message, Member
|
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
group_stat_api = Blueprint('group_stat_api', __name__)
|
|
||||||
|
|
||||||
|
|
||||||
@group_stat_api.route("/top_users", methods=["GET"])
|
|
||||||
def top_users():
|
|
||||||
number = request.args.get("number")
|
|
||||||
|
|
||||||
if not number: number = 3
|
|
||||||
|
|
||||||
number = int(number)
|
|
||||||
|
|
||||||
members = []
|
|
||||||
counts = []
|
|
||||||
|
|
||||||
query = (Member
|
|
||||||
.select(fn.count(Message.id).alias("count"), Member)
|
|
||||||
.join(Message)
|
|
||||||
.group_by(Member)
|
|
||||||
.order_by(SQL("count").desc())
|
|
||||||
)
|
|
||||||
|
|
||||||
for group in query:
|
|
||||||
members.append(group.first_name)
|
|
||||||
counts.append(group.count)
|
|
||||||
|
|
||||||
members.insert(0, "Others")
|
|
||||||
counts.insert(0, sum(counts[number:]))
|
|
||||||
|
|
||||||
return jsonify({
|
|
||||||
"members": members[:number + 1],
|
|
||||||
"counts": counts[:number + 1]
|
|
||||||
})
|
|
||||||
|
|
||||||
@group_stat_api.route("/chat_activity", methods=["GET"])
|
|
||||||
def chat_activity():
|
|
||||||
dates = []
|
|
||||||
counts = []
|
|
||||||
|
|
||||||
from_date = request.args.get("from_date")
|
|
||||||
to_date = request.args.get("to_date")
|
|
||||||
|
|
||||||
if not from_date or not to_date:
|
|
||||||
return jsonify({
|
|
||||||
"err": "from_date/to_date empty"
|
|
||||||
}),422
|
|
||||||
|
|
||||||
date_format = request.args.get("date_format")
|
|
||||||
date_format = date_format if date_format else "%Y-%m-%d"
|
|
||||||
|
|
||||||
group_by = request.args.get("group_by")
|
|
||||||
group_by = group_by if group_by else "day"
|
|
||||||
|
|
||||||
try:
|
|
||||||
from_date = datetime.strptime(from_date, date_format)
|
|
||||||
to_date = datetime.strptime(to_date, date_format)
|
|
||||||
except ValueError:
|
|
||||||
return jsonify({
|
|
||||||
"from_date": from_date,
|
|
||||||
"to_date": to_date,
|
|
||||||
"date_format": date_format,
|
|
||||||
"err":"can't format datatime obj"
|
|
||||||
}),422
|
|
||||||
|
|
||||||
if not group_by in ["day","week","month","year"]:
|
|
||||||
return jsonify({
|
|
||||||
"err":"invalid group_by"
|
|
||||||
}),422
|
|
||||||
|
|
||||||
query = (Message
|
|
||||||
.select(fn.date_trunc(group_by, Message.timestamp).alias('range'), fn.count(Message.id).alias('count'))
|
|
||||||
.where((Message.timestamp >= from_date) & (Message.timestamp <= to_date))
|
|
||||||
.group_by(fn.date_trunc(group_by, Message.timestamp))
|
|
||||||
.order_by(SQL("range"))
|
|
||||||
)
|
|
||||||
|
|
||||||
for row in query:
|
|
||||||
dates.append(row.range.strftime(date_format))
|
|
||||||
counts.append(row.count)
|
|
||||||
|
|
||||||
return jsonify({
|
|
||||||
"date": dates,
|
|
||||||
"counts": counts
|
|
||||||
})
|
|
||||||
|
|
||||||
@group_stat_api.route("/user_activity", methods=["GET"])
|
|
||||||
def user_activity():
|
|
||||||
dates = []
|
|
||||||
counts = []
|
|
||||||
|
|
||||||
user_id = request.args.get("user_id")
|
|
||||||
user = Member.get_or_none(Member.user_id == user_id)
|
|
||||||
|
|
||||||
if not user:
|
|
||||||
return jsonify({
|
|
||||||
"err":"invalid user_id"
|
|
||||||
}),422
|
|
||||||
|
|
||||||
from_date = request.args.get("from_date")
|
|
||||||
to_date = request.args.get("to_date")
|
|
||||||
|
|
||||||
if not from_date or not to_date:
|
|
||||||
return jsonify({
|
|
||||||
"err": "from_date/to_date empty"
|
|
||||||
}),422
|
|
||||||
|
|
||||||
group_by = request.args.get("group_by")
|
|
||||||
group_by = group_by if group_by else "day"
|
|
||||||
|
|
||||||
date_format = request.args.get("date_format")
|
|
||||||
date_format = date_format if date_format else "%Y-%m-%d"
|
|
||||||
|
|
||||||
try:
|
|
||||||
from_date = datetime.strptime(from_date,date_format)
|
|
||||||
to_date = datetime.strptime(to_date, date_format)
|
|
||||||
except ValueError:
|
|
||||||
return jsonify({
|
|
||||||
"from_date": from_date,
|
|
||||||
"to_date": to_date,
|
|
||||||
"date_format": date_format,
|
|
||||||
"err":"can't format datatime obj"
|
|
||||||
}),422
|
|
||||||
|
|
||||||
query = (Message
|
|
||||||
.select( fn.date_trunc(group_by, Message.timestamp).alias("range"), fn.count(Message.id).alias("count") )
|
|
||||||
.where((Message.user == user) & (Message.timestamp >= from_date) & (Message.timestamp <= to_date))
|
|
||||||
.group_by(fn.date_trunc(group_by, Message.timestamp))
|
|
||||||
.order_by(SQL("range"))
|
|
||||||
)
|
|
||||||
|
|
||||||
for row in query:
|
|
||||||
dates.append(row.range.strftime(date_format))
|
|
||||||
counts.append(row.count)
|
|
||||||
|
|
||||||
return jsonify({
|
|
||||||
"date": dates,
|
|
||||||
"counts": counts
|
|
||||||
})
|
|
||||||
|
|
|
@ -0,0 +1,157 @@
|
||||||
|
from flask import Blueprint
|
||||||
|
from flask import request, jsonify
|
||||||
|
|
||||||
|
from peewee import SQL, fn
|
||||||
|
from database import Message, Member
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
statistics_api = Blueprint('statistics_api', __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@statistics_api.route("/top-users", methods=["GET"])
|
||||||
|
def top_users():
|
||||||
|
"""
|
||||||
|
/top_users - top users for activity
|
||||||
|
:param number - number top users
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = []
|
||||||
|
|
||||||
|
number = int(request.args.get("number"))
|
||||||
|
|
||||||
|
if not number:
|
||||||
|
number = 3
|
||||||
|
|
||||||
|
query = (Member
|
||||||
|
.select(fn.count(Message.id).alias("count"), Member)
|
||||||
|
.join(Message)
|
||||||
|
.group_by(Member)
|
||||||
|
.order_by(SQL("count").desc())
|
||||||
|
)
|
||||||
|
|
||||||
|
for group in query:
|
||||||
|
data.append({
|
||||||
|
"user": group.first_name,
|
||||||
|
"count": group.count,
|
||||||
|
})
|
||||||
|
|
||||||
|
data.insert(0, {
|
||||||
|
"user": "Others",
|
||||||
|
"count": sum(item["count"] for i, item in enumerate(data) if i >= number),
|
||||||
|
})
|
||||||
|
|
||||||
|
return jsonify(data[:number + 1])
|
||||||
|
|
||||||
|
|
||||||
|
@statistics_api.route("/last-chat-activity", methods=["GET"])
|
||||||
|
def last_chat_activity():
|
||||||
|
"""
|
||||||
|
/last-chat-activity - last chat activity selected range
|
||||||
|
:param startDate: datetime at which start(optional)
|
||||||
|
:param endDate: datetime at which end
|
||||||
|
:param groupBy: year, month, day, hour
|
||||||
|
:param formatDatetime: format string datetime object(default: %Y-%m-%d)
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = []
|
||||||
|
|
||||||
|
start_date = request.args.get("startDate")
|
||||||
|
end_date = request.args.get("endDate")
|
||||||
|
|
||||||
|
if not start_date or not end_date:
|
||||||
|
return jsonify({
|
||||||
|
"err": "startDate/endDate must be defined"
|
||||||
|
}), 422
|
||||||
|
|
||||||
|
date_format = request.args.get("formatDatetime")
|
||||||
|
if not date_format:
|
||||||
|
date_format = "%Y-%m-%d"
|
||||||
|
|
||||||
|
groupby_keys = ["year", "month", "week", "day"]
|
||||||
|
group_by = request.args.get("groupBy")
|
||||||
|
if not group_by or not (group_by in groupby_keys):
|
||||||
|
return jsonify({
|
||||||
|
"err": "invalid groupBy parametr(year, month, day, hour)"
|
||||||
|
}), 422
|
||||||
|
|
||||||
|
try:
|
||||||
|
start_date = datetime.strptime(start_date, date_format)
|
||||||
|
end_date = datetime.strptime(end_date, date_format)
|
||||||
|
except ValueError:
|
||||||
|
return jsonify({
|
||||||
|
"err": "Can't unparse startDate/endDate"
|
||||||
|
}), 422
|
||||||
|
|
||||||
|
query = (Message
|
||||||
|
.select(fn.date_trunc(group_by, Message.timestamp).alias('range'), fn.count(Message.id).alias('count'))
|
||||||
|
.where((Message.timestamp >= start_date) & (Message.timestamp <= end_date))
|
||||||
|
.group_by(fn.date_trunc(group_by, Message.timestamp))
|
||||||
|
.order_by(SQL("range"))
|
||||||
|
)
|
||||||
|
|
||||||
|
for record in query:
|
||||||
|
data.append({
|
||||||
|
"datetime": record.range.strftime(date_format),
|
||||||
|
"count": record.count,
|
||||||
|
})
|
||||||
|
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
|
||||||
|
@statistics_api.route("/last-user-activity", methods=["GET"])
|
||||||
|
def last_user_activity():
|
||||||
|
"""
|
||||||
|
/last-user-activity - user activity selected range
|
||||||
|
:param user_id: user id
|
||||||
|
:param startDate: datetime at which start(optional)
|
||||||
|
:param endDate: datetime at which end
|
||||||
|
:param groupBy: year, month, day, hour
|
||||||
|
:param formatDatetime: format string datetime object(default: %Y-%m-%d)
|
||||||
|
"""
|
||||||
|
data = []
|
||||||
|
|
||||||
|
user_id = request.args.get("user_id")
|
||||||
|
user = Member.get_or_none(Member.user_id == user_id)
|
||||||
|
|
||||||
|
start_date = request.args.get("startDate")
|
||||||
|
end_date = request.args.get("endDate")
|
||||||
|
|
||||||
|
if not start_date or not end_date:
|
||||||
|
return jsonify({
|
||||||
|
"err": "startDate/endDate must be defined"
|
||||||
|
}), 422
|
||||||
|
|
||||||
|
date_format = request.args.get("formatDatetime")
|
||||||
|
if not date_format:
|
||||||
|
date_format = "%Y-%m-%d"
|
||||||
|
|
||||||
|
groupby_keys = ["year", "month", "week", "day"]
|
||||||
|
group_by = request.args.get("groupBy")
|
||||||
|
if not group_by or not (group_by in groupby_keys):
|
||||||
|
return jsonify({
|
||||||
|
"err": "invalid groupBy parametr(year, month, day, hour)"
|
||||||
|
}), 422
|
||||||
|
|
||||||
|
try:
|
||||||
|
start_date = datetime.strptime(start_date, date_format)
|
||||||
|
end_date = datetime.strptime(end_date, date_format)
|
||||||
|
except ValueError:
|
||||||
|
return jsonify({
|
||||||
|
"err": "Can't unparse start_date and end_date"
|
||||||
|
}), 422
|
||||||
|
|
||||||
|
query = (Message
|
||||||
|
.select(fn.date_trunc(group_by, Message.timestamp).alias("range"), fn.count(Message.id).alias("count"))
|
||||||
|
.where((Message.user == user) & (Message.timestamp >= start_date) & (Message.timestamp <= end_date))
|
||||||
|
.group_by(fn.date_trunc(group_by, Message.timestamp))
|
||||||
|
.order_by(SQL("range"))
|
||||||
|
)
|
||||||
|
|
||||||
|
for record in query:
|
||||||
|
data.append({
|
||||||
|
"datetime": record.range.strftime(date_format),
|
||||||
|
"count": record.count,
|
||||||
|
})
|
||||||
|
|
||||||
|
return jsonify(data)
|
|
@ -1,51 +1,51 @@
|
||||||
fetch("/top_users?number=5")
|
fetch("/top-users?number=5")
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error: ${response.status}`);
|
throw new Error(`HTTP error: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.json();
|
return response.json();
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
const ctx = document.getElementById('top-users');
|
const ctx = document.getElementById('top-users');
|
||||||
|
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'doughnut',
|
||||||
|
data: {
|
||||||
|
labels: data.map(data => data.user),
|
||||||
|
datasets: [{
|
||||||
|
data: data.map(data => data.count)
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
|
||||||
new Chart(ctx, {
|
plugins: [ChartDataLabels],
|
||||||
type: 'doughnut',
|
options: {
|
||||||
data: {
|
maintainAspectRatio: false,
|
||||||
labels: data["members"],
|
plugins :{
|
||||||
datasets: [{
|
legend: false,
|
||||||
data: data["counts"]
|
|
||||||
}]
|
datalabels: {
|
||||||
|
color: '#f4f6fc',
|
||||||
|
formatter: function(value, context) {
|
||||||
|
return context.chart.data.labels[context.dataIndex];
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
plugins: [ChartDataLabels],
|
tooltip: {
|
||||||
options: {
|
callbacks: {
|
||||||
maintainAspectRatio: false,
|
label: (context) => {
|
||||||
plugins :{
|
let sum = 0;
|
||||||
legend: false,
|
let value = context.parsed;
|
||||||
|
let dataArray = context.dataset.data;
|
||||||
datalabels: {
|
dataArray.map(data => {
|
||||||
color: '#f4f6fc',
|
sum += data;
|
||||||
formatter: function(value, context) {
|
});
|
||||||
return context.chart.data.labels[context.dataIndex];
|
let percentage = Math.round(value*100 / sum);
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
tooltip: {
|
return `${percentage}%`
|
||||||
callbacks: {
|
|
||||||
label: (context) => {
|
|
||||||
let sum = 0;
|
|
||||||
let value = context.parsed;
|
|
||||||
let dataArray = context.dataset.data;
|
|
||||||
dataArray.map(data => {
|
|
||||||
sum += data;
|
|
||||||
});
|
|
||||||
let percentage = Math.round(value*100 / sum);
|
|
||||||
|
|
||||||
return `${percentage}%`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue