diff --git a/main.py b/main.py new file mode 100644 index 0000000..2274f58 --- /dev/null +++ b/main.py @@ -0,0 +1,61 @@ +import io +from flask import Flask +from flask import render_template +from flask import Response +from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas +from services import get_cv, get_count_by_year, create_random_figure, get_top_edu_by_job + +app = Flask(__name__) + + +@app.route("/") +def cv_index(): + cvs = get_cv() + res = ("\n".join((f"

{i + 1})

", + f"

Желаемая зарплата: {cv['salary']}.

", + f"

Образование: {cv['educationType']}.

")) for i, cv in enumerate(cvs)) + return "".join(res) + + +@app.route("/dashboard") +def dashboard(): + return render_template('d3.html', cvs=get_cv()) + + +@app.route("/years") +def years(): + cvs = get_count_by_year() + data = [cv["count"] for cv in cvs] + labels = [cv["year"] for cv in cvs] + return render_template('d4.html', cvs=cvs, data=data, labels=labels) + + +@app.route("/edu/managers") +def edu_managers(): + cvs = get_top_edu_by_job(("manager", "менедж")) + data = [cv["count"] for cv in cvs] + labels = [cv["qualification"] for cv in cvs] + return render_template('d5.html', cvs=cvs, data=data, labels=labels, ql="менеджеров") + + +@app.route("/edu/engineer") +def edu_engineers(): + cvs = get_top_edu_by_job(("engineer", "инжене")) + data = [cv["count"] for cv in cvs] + labels = [cv["qualification"] for cv in cvs] + return render_template('d5.html', cvs=cvs, data=data, labels=labels, ql="инженеров") + + +@app.route('/plot.png') +def plot_png(): + output = io.BytesIO() + FigureCanvas(create_random_figure()).print_png(output) + return Response(output.getvalue(), mimetype='image/png') + + +def main() -> None: + app.run() + + +if __name__ == "__main__": + main() diff --git a/services.py b/services.py new file mode 100644 index 0000000..b7fdef3 --- /dev/null +++ b/services.py @@ -0,0 +1,60 @@ +import sqlite3 +import random +from matplotlib.figure import Figure + +DB_NAME = 'works.sqlite' + + +def _ignore_case_collation(value1_, value2_): + value1_, value2_ = str(value1_), str(value2_) + if value1_.lower() == value2_.lower(): + return 0 + elif value1_.lower() < value2_.lower(): + return -1 + else: + return 1 + + +def get_connection(): + con = sqlite3.connect(DB_NAME) + con.row_factory = lambda cursor, row: {col[0]: row[idx] for idx, col in enumerate(cursor.description)} + # Изначально sqlite работает только с ASCII символами. + con.create_collation("BINARY", _ignore_case_collation) + con.create_collation("NOCASE", _ignore_case_collation) + con.create_function("LOWER", 1, lambda value_: str(value_).lower()) + con.create_function("UPPER", 1, lambda value_: str(value_).upper()) + + return con + + +def get_cv(): + query = "SELECT * FROM works LIMIT 20" + with get_connection() as con: + return list(con.execute(query)) + + +def get_count_by_year(): + query = ("SELECT COUNT(*) as 'count', strftime('%Y', dateModify) as 'year' " + "FROM works WHERE year IS NOT NULL GROUP BY year") + with get_connection() as con: + return list(con.execute(query)) + + +def get_top_edu_by_job(job_titles: tuple[str, str], count: int = 15): + query = (f"SELECT LOWER(qualification) as 'qualification', count(*) as 'count' FROM works " + f"WHERE qualification IS NOT NULL AND " + f"(LOWER(jobTitle) like '%{job_titles[0]}%' OR LOWER(jobTitle) like '%{job_titles[1]}%')" + f"GROUP BY LOWER(qualification) " + f"ORDER BY count DESC LIMIT {count}") + with get_connection() as con: + return list(con.execute(query)) + + +def create_random_figure(): + fig = Figure() + axis = fig.add_subplot(1, 1, 1) + xs = range(100) + ys = [random.randint(1, 50) for _ in xs] + axis.plot(xs, ys) + + return fig diff --git a/templates/d4.html b/templates/d4.html new file mode 100644 index 0000000..a3ab6a3 --- /dev/null +++ b/templates/d4.html @@ -0,0 +1,226 @@ + + + + + + + + + Dashboard Template · Bootstrap v5.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

Dashboard

+
+
+ + +
+ +
+
+ + + +

Количество резюме по годам

+
+ + + + + + + + + + {% for cv in cvs %} + + + + + + {% endfor %} + +
#ГодКоличество
{{ loop.index }}{{ cv.year }}{{ cv.count }}
+
+
+
+
+ + + + + + + + diff --git a/templates/d5.html b/templates/d5.html new file mode 100644 index 0000000..a7356a6 --- /dev/null +++ b/templates/d5.html @@ -0,0 +1,239 @@ + + + + + + + + + Dashboard Template · Bootstrap v5.1 + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+

Dashboard

+
+
+ + +
+ +
+
+ + + +

Топ {{ cvs|length }} образований у {{ ql }}

+
+ + + + + + + + + + {% for cv in cvs %} + + + + + + {% endfor %} + +
#ОбразованиеКоличество
{{ loop.index }}{{ cv.qualification }}{{ cv.count }}
+
+
+
+
+ + + + + + + + + diff --git a/works.sqlite b/works.sqlite new file mode 100644 index 0000000..ba5b917 Binary files /dev/null and b/works.sqlite differ