Add statistics page & statistics api
This commit is contained in:
parent
98922ce312
commit
96da02d311
3
app.py
3
app.py
|
@ -5,6 +5,8 @@ import logging
|
||||||
from apps.admin import admin as blueprint_admin
|
from apps.admin import admin as blueprint_admin
|
||||||
from apps.auth import auth as blueprint_auth
|
from apps.auth import auth as blueprint_auth
|
||||||
|
|
||||||
|
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__)
|
||||||
|
@ -12,6 +14,7 @@ app.secret_key = secret_key
|
||||||
|
|
||||||
app.register_blueprint(blueprint_auth)
|
app.register_blueprint(blueprint_auth)
|
||||||
app.register_blueprint(blueprint_admin)
|
app.register_blueprint(blueprint_admin)
|
||||||
|
app.register_blueprint(blueprint_stat_api)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from database import build_database
|
from database import build_database
|
||||||
|
|
|
@ -11,6 +11,10 @@ def admin_page():
|
||||||
return render_template("index.html", username=session["username"])
|
return render_template("index.html", username=session["username"])
|
||||||
return redirect(url_for("auth.login_page"))
|
return redirect(url_for("auth.login_page"))
|
||||||
|
|
||||||
|
@admin.route("/stat")
|
||||||
|
def chart():
|
||||||
|
return render_template("statistics.html")
|
||||||
|
|
||||||
@admin.route("/members")
|
@admin.route("/members")
|
||||||
def table_of_members():
|
def table_of_members():
|
||||||
return render_template("members.html", members=Member.select())
|
return render_template("members.html", members=Member.select())
|
||||||
|
|
|
@ -20,7 +20,7 @@ def login_page():
|
||||||
session["username"] = username
|
session["username"] = username
|
||||||
return redirect(url_for("admin.admin_page"))
|
return redirect(url_for("admin.admin_page"))
|
||||||
|
|
||||||
flash("password/username not valid")
|
flash("wrong nickname/password!")
|
||||||
return redirect(url_for("auth.login_page"))
|
return redirect(url_for("auth.login_page"))
|
||||||
|
|
||||||
@auth.route("/logout")
|
@auth.route("/logout")
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
from flask import Blueprint, jsonify
|
||||||
|
|
||||||
|
group_stat_api = Blueprint('group_stat_api', __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@group_stat_api.route("/top3_users",methods=["POST"])
|
||||||
|
def top_users():
|
||||||
|
# TODO: database
|
||||||
|
return jsonify({
|
||||||
|
"members": ["Mr.D", "𝙲𝚊𝚝𝚒𝚘𝚗", "Тёма","Others"],
|
||||||
|
"counts":[4026,3024,2024,4096]
|
||||||
|
})
|
35
database.py
35
database.py
|
@ -1,7 +1,8 @@
|
||||||
from peewee import Model,CharField
|
from peewee import Model, CharField, BigIntegerField, DateField, TimestampField
|
||||||
|
|
||||||
from playhouse.db_url import connect
|
from playhouse.db_url import connect
|
||||||
|
|
||||||
|
from datetime import date, datetime
|
||||||
|
|
||||||
from config import db_url
|
from config import db_url
|
||||||
db = connect(db_url)
|
db = connect(db_url)
|
||||||
|
|
||||||
|
@ -13,16 +14,30 @@ class WebUser(Model):
|
||||||
db_table = "webusers"
|
db_table = "webusers"
|
||||||
database = db
|
database = db
|
||||||
|
|
||||||
@staticmethod
|
class Member(Model):
|
||||||
def userExists(username) -> bool:
|
user_id = BigIntegerField()
|
||||||
"""Check if the username exists in a database."""
|
first_name = CharField()
|
||||||
query = WebUser.select().where(WebUser.username == username)
|
username = CharField(null=True)
|
||||||
|
|
||||||
if (query):
|
role = CharField(default="member")
|
||||||
if (query.exists()):
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
warns = BigIntegerField(default=0)
|
||||||
|
|
||||||
|
joined = DateField(default=date.today())
|
||||||
|
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "members"
|
||||||
|
database = db
|
||||||
|
|
||||||
|
class Message(Model):
|
||||||
|
user_id = BigIntegerField()
|
||||||
|
timestamp = TimestampField(default=datetime.now())
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "messages"
|
||||||
|
database = db
|
||||||
|
|
||||||
def build_database():
|
def build_database():
|
||||||
|
# db.create_tables([Message])
|
||||||
db.create_tables([WebUser])
|
db.create_tables([WebUser])
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
#top-users {
|
||||||
|
width: 500px;
|
||||||
|
height: 500px;
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
const options = {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {'Content-Type': 'application/json'}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch("/top3_users", options)
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
}).then((data) => {
|
||||||
|
const ctx = document.getElementById('top-users');
|
||||||
|
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'pie',
|
||||||
|
data: {
|
||||||
|
labels: data["members"],
|
||||||
|
datasets: [{
|
||||||
|
data: data["counts"]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [ChartDataLabels],
|
||||||
|
options: {
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
plugins :{
|
||||||
|
legend: false,
|
||||||
|
|
||||||
|
datalabels: {
|
||||||
|
color: '#f4f6fc',
|
||||||
|
formatter: function(value, context) {
|
||||||
|
return context.chart.data.labels[context.dataIndex];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
tooltip: {
|
||||||
|
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}%`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
|
@ -0,0 +1,22 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Statistics</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="../static/css/statistics.css">
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.2.0/chartjs-plugin-datalabels.min.js" integrity="sha512-JPcRR8yFa8mmCsfrw4TNte1ZvF1e3+1SdGMslZvmrzDYxS69J7J49vkFL8u6u8PlPJK+H3voElBtUCzaXj+6ig==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<canvas id="top-users"></canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="../static/js/top-users.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue