from datetime import date
from flask import (
Blueprint, render_template, request, abort, redirect, url_for, flash
)
from flask_login import login_required, current_user
from app.models import db, Intern, Attendance, User
from app.services.statistics import intern_stats, monthly_calendar
from app.utils import parse_period
interns_bp = Blueprint("interns", __name__, url_prefix="/interns")
def _can_access(intern: Intern) -> bool:
return current_user.is_admin or intern.mentor_id == current_user.id
@interns_bp.route("/")
@login_required
def list_interns():
mentor_id = request.args.get("mentor_id", type=int)
q = Intern.query
if current_user.is_admin:
if mentor_id:
q = q.filter_by(mentor_id=mentor_id)
else:
q = q.filter_by(mentor_id=current_user.id)
interns = q.order_by(Intern.full_name).all()
mentors = User.query.filter_by(role="mentor").order_by(User.full_name).all() \
if current_user.is_admin else []
return render_template(
"interns/list.html",
interns=interns, mentors=mentors,
selected_mentor=mentor_id,
)
@interns_bp.route("/<int:intern_id>")
@login_required
def detail(intern_id: int):
intern = Intern.query.get_or_404(intern_id)
if not _can_access(intern):
abort(403)
today = date.today()
year = request.args.get("year", today.year, type=int)
month = request.args.get("month", today.month, type=int)
if month < 1:
month, year = 12, year - 1
elif month > 12:
month, year = 1, year + 1
weeks = monthly_calendar(year, month)
records = Attendance.query.filter_by(intern_id=intern_id).all()
att_map = {
r.date.day: r
for r in records
if r.date.year == year and r.date.month == month
}
date_from, date_to = parse_period(default_days=30)
stats_period = intern_stats(intern_id, date_from, date_to)
stats_all = intern_stats(intern_id)
prev_year, prev_month = (year, month - 1) if month > 1 else (year - 1, 12)
next_year, next_month = (year, month + 1) if month < 12 else (year + 1, 1)
return render_template(
"interns/detail.html",
intern=intern,
weeks=weeks, year=year, month=month,
att_map=att_map,
stats_period=stats_period,
stats_all=stats_all,
today=today,
date_from=date_from, date_to=date_to,
prev_year=prev_year, prev_month=prev_month,
next_year=next_year, next_month=next_month,
)
@interns_bp.route("/create", methods=["POST"])
@login_required
def create():
if not current_user.is_admin:
abort(403)
# Базовая форма (используется из админского интерфейса)
full_name = request.form.get("full_name", "").strip()
mentor_id = request.form.get("mentor_id", type=int)
if not full_name or not mentor_id:
flash("Заполните ФИО и наставника", "danger")
return redirect(url_for("interns.list_interns"))
intern = Intern(
full_name=full_name,
direction=request.form.get("direction", "").strip() or None,
email=request.form.get("email", "").strip() or None,
phone=request.form.get("phone", "").strip() or None,
mentor_id=mentor_id,
)
db.session.add(intern)
db.session.commit()
flash("Стажёр добавлен", "success")
return redirect(url_for("interns.detail", intern_id=intern.id))