04/07 updated timezone, report via email, etc

This commit is contained in:
2026-04-07 11:24:08 -04:00
parent 56c65bfe4c
commit fed51f8c28
14 changed files with 1022 additions and 29 deletions
+79 -2
View File
@@ -9,7 +9,8 @@ from werkzeug.utils import secure_filename
from app import db
from app.models import (Ticket, Comment, Attachment, Notification,
TicketStatus, TicketPriority, TicketCategory,
User, UserRole, KnowledgeBase, TicketLink, CannedResponse)
User, UserRole, KnowledgeBase, TicketLink, CannedResponse,
KBFeedback)
from app.services.notification_service import (
notify_new_ticket, notify_status_change,
notify_comment_added, notify_assignment,
@@ -674,7 +675,19 @@ def kb_article(article_id):
db.session.commit()
# Re-fetch so the template receives the post-increment value.
db.session.refresh(article)
return render_template('tickets/kb_article.html', article=article)
# Load the current user's vote (if any) so the feedback widget shows state
user_feedback = KBFeedback.query.filter_by(
article_id=article.id, user_id=current_user.id
).first()
# Aggregate counts for the widget
helpful_count = KBFeedback.query.filter_by(article_id=article.id, is_helpful=True).count()
not_helpful_count = KBFeedback.query.filter_by(article_id=article.id, is_helpful=False).count()
return render_template('tickets/kb_article.html',
article=article,
user_feedback=user_feedback,
helpful_count=helpful_count,
not_helpful_count=not_helpful_count,
)
# ─── Ticket Link / Unlink ────────────────────────────────────────────────────
@@ -840,6 +853,70 @@ def get_canned_responses():
]})
# ─── KB Article Feedback ─────────────────────────────────────────────────────
@tickets_bp.route('/kb/<int:article_id>/feedback', methods=['POST'])
@login_required
def kb_feedback(article_id):
"""Record or update a thumbs-up / thumbs-down vote for a KB article.
One vote per user per article — subsequent submissions update the existing
row. Submitting the same vote a second time toggles it off (removes it),
giving users an undo path.
"""
article = db.session.get(KnowledgeBase, article_id) or abort(404)
value = request.form.get('helpful') # '1' = helpful, '0' = not helpful
if value not in ('0', '1'):
abort(400)
is_helpful = value == '1'
existing = KBFeedback.query.filter_by(
article_id=article.id, user_id=current_user.id
).first()
if existing:
if existing.is_helpful == is_helpful:
# Same vote again → toggle off (remove)
db.session.delete(existing)
log_action(current_user.id, 'kb_feedback_remove', 'knowledge_base',
article.id, f'was_helpful={is_helpful}')
logger.info(f'[KB FEEDBACK REMOVE] article_id={article.id} '
f'user_id={current_user.id} was_helpful={is_helpful}')
else:
# Changed vote → update
existing.is_helpful = is_helpful
log_action(current_user.id, 'kb_feedback_update', 'knowledge_base',
article.id, f'is_helpful={is_helpful}')
logger.info(f'[KB FEEDBACK UPDATE] article_id={article.id} '
f'user_id={current_user.id} is_helpful={is_helpful}')
else:
fb = KBFeedback(
article_id = article.id,
user_id = current_user.id,
is_helpful = is_helpful,
)
db.session.add(fb)
log_action(current_user.id, 'kb_feedback_create', 'knowledge_base',
article.id, f'is_helpful={is_helpful}')
logger.info(f'[KB FEEDBACK CREATE] article_id={article.id} '
f'user_id={current_user.id} is_helpful={is_helpful}')
db.session.commit()
# Return JSON so the widget can update without a full reload
helpful_count = KBFeedback.query.filter_by(article_id=article.id, is_helpful=True).count()
not_helpful_count = KBFeedback.query.filter_by(article_id=article.id, is_helpful=False).count()
from flask import jsonify
return jsonify({
'ok' : True,
'helpful_count' : helpful_count,
'not_helpful_count': not_helpful_count,
'user_vote' : None if (existing and existing.is_helpful == is_helpful)
else ('helpful' if is_helpful else 'not_helpful'),
})
# ─── Helpers ─────────────────────────────────────────────────────────────────
def _sla_due_date(priority: str) -> 'datetime':