diff --git a/app/__init__.py b/app/__init__.py index eb152cb..99e90a9 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -37,6 +37,7 @@ def register_blueprints(app): from app.routes.file_format import file_format_bp # new + from app.routes.activity_routes import activity_bp from app.routes.engineering import engi_bp app.register_blueprint(auth_bp) @@ -49,8 +50,9 @@ def register_blueprints(app): app.register_blueprint(file_format_bp) # new + app.register_blueprint(activity_bp) app.register_blueprint(engi_bp) - + def register_error_handlers(app): diff --git a/app/routes/activity_routes.py b/app/routes/activity_routes.py new file mode 100644 index 0000000..afd1906 --- /dev/null +++ b/app/routes/activity_routes.py @@ -0,0 +1,59 @@ +from flask import Blueprint, render_template, request, send_file, abort +import os + +from app.utils.helpers import login_required +from app.utils.file_utils import get_logs_folder , ALLOWED_LOG_FILE +from app.services.activity_service import ActivityService + +activity_bp = Blueprint("activity", __name__, url_prefix="/activity") + +# call activity_log page +@activity_bp.route("/") +@login_required +def activity(): + file_name = request.args.get("file", "app.log") + search = request.args.get("search", "") + level = request.args.get("level", "").upper() + user = request.args.get("user", "") + from_date = request.args.get("from_date", "") + to_date = request.args.get("to_date", "") + + logs = ActivityService.read_logs( + file_name=file_name, + search=search, + level=level, + user=user, + from_date=from_date, + to_date=to_date + ) + + return render_template( + "activity/activity_log.html", + logs=logs, + file_name=file_name, + search=search, + level=level, + user=user, + from_date=from_date, + to_date=to_date + ) + +# Download activity_log files +@activity_bp.route("/logs") +@login_required +def download_log(): + + filename = request.args.get("file", "app.log") + if filename not in ALLOWED_LOG_FILE: + abort(400, "Invalid log file.") + + file_path = os.path.join(get_logs_folder(), filename) + if not os.path.isfile(file_path): + abort(404, "Log file not found.") + + return send_file( + file_path, + as_attachment=True, + download_name=filename, + mimetype="text/plain" + ) \ No newline at end of file diff --git a/app/services/activity_service.py b/app/services/activity_service.py new file mode 100644 index 0000000..a44bb4f --- /dev/null +++ b/app/services/activity_service.py @@ -0,0 +1,56 @@ +import re +from pathlib import Path + +# Activity log Service +class ActivityService: + + @staticmethod + def read_logs(file_name="", search="", level="", user="", from_date="", to_date=""): + + file = Path("logs") / file_name + + if not file.exists(): + return [] + + logs = [] + + with open(file, "r", encoding="utf-8") as f: + + for line in reversed(f.readlines()): + # Example: + # 2026-08-01 10:15:55 | INFO | admin | Dashboard | Dashboard Opened + parts = [x.strip() for x in line.split("|")] + + if len(parts) < 5: + continue + + record = { + "date": parts[0], + "level": parts[1], + "user": parts[2], + "module": parts[3], + "message": "|".join(parts[4:]) + } + + # Search Filter + if search and search.lower() not in line.lower(): + continue + + # Level Filter + if level and record["level"] != level: + continue + + # User Filter + if user and user.lower() not in record["user"].lower(): + continue + + # Date Filter + if from_date and record["date"][:10] < from_date: + continue + + if to_date and record["date"][:10] > to_date: + continue + + logs.append(record) + + return logs \ No newline at end of file diff --git a/app/templates/activity/activity_log.html b/app/templates/activity/activity_log.html new file mode 100644 index 0000000..14451c4 --- /dev/null +++ b/app/templates/activity/activity_log.html @@ -0,0 +1,208 @@ +{% extends "base.html" %} +{% block content %} + +
| Sr No | +Date & Time | +User | +Level | +Module | +Activity | +
|---|---|---|---|---|---|
| {{ loop.index }} | +{{ log.date }} | +{{ log.user }} | ++ {% if log.level=="INFO" %} + INFO + {% elif log.level=="WARNING" %} + WARNING + {% else %} + ERROR + {% endif %} + | + +{{ log.module }} | +{{ log.message }} | +