feat: show notifications from logs

This commit is contained in:
Jannat Patel
2022-09-27 18:13:46 +05:30
parent a6156ec863
commit a291d73828
11 changed files with 129 additions and 47 deletions

View File

@@ -94,7 +94,9 @@ override_doctype_class = {
# Hook on document methods and events # Hook on document methods and events
doc_events = { doc_events = {
"Discussion Reply": {
"after_insert": "lms.lms.utils.create_notification_log"
}
} }
# Scheduled Tasks # Scheduled Tasks

View File

@@ -4,6 +4,7 @@ from frappe.utils import flt, cint, cstr, getdate, add_months, fmt_money
from lms.lms.md import markdown_to_html, find_macros from lms.lms.md import markdown_to_html, find_macros
import string import string
from frappe import _ from frappe import _
from frappe.desk.doctype.notification_log.notification_log import make_notification_logs
RE_SLUG_NOTALLOWED = re.compile("[^a-z0-9]+") RE_SLUG_NOTALLOWED = re.compile("[^a-z0-9]+")
@@ -469,3 +470,35 @@ def validate_image(path):
file.save(ignore_permissions=True) file.save(ignore_permissions=True)
return file.file_url return file.file_url
return path return path
def create_notification_log(doc, method):
topic = frappe.db.get_value("Discussion Topic", doc.topic,
["reference_doctype", "reference_docname", "owner", "title"], as_dict=1)
if topic.reference_doctype != "Course Lesson":
return
course = frappe.db.get_value("Course Lesson", topic.reference_docname, "course")
instructors = frappe.db.get_all("Course Instructor", { "parent": course }, pluck="instructor")
notification = frappe._dict({
"subject": _("New reply on the topic {0}").format(topic.title),
"email_content": doc.reply,
"document_type": topic.reference_doctype,
"document_name": topic.reference_docname,
"for_user": topic.owner,
"from_user": doc.owner,
"type": "Alert"
})
users = []
if doc.owner != topic.owner:
users.append(topic.owner)
if doc.owner not in instructors:
users += instructors
make_notification_logs(notification, users)

View File

@@ -2,8 +2,8 @@
<span class="avatar {{ avatar_class }}" title="{{ member.full_name }}"> <span class="avatar {{ avatar_class }}" title="{{ member.full_name }}">
<a class="button-links" href="{{ get_profile_url(member.username) }}"> <a class="button-links" href="{{ get_profile_url(member.username) }}">
{% if member.user_image %} {% if member.user_image %}
<img class="avatar-frame standard-image" style="object-fit: cover;" src="{{ member.user_image }}" title="{{ member.full_name }}"> <img class="avatar-frame standard-image" style="object-fit: cover;" src="{{ member.user_image }}"
</img> title="{{ member.full_name }}">
{% else %} {% else %}
<span class="avatar-frame standard-image" title="{{ member.full_name }}" <span class="avatar-frame standard-image" title="{{ member.full_name }}"
style="background-color: var({{color[0]}}); color: var({{color[1]}});"> style="background-color: var({{color[0]}}); color: var({{color[1]}});">

View File

@@ -8,7 +8,7 @@
{{ _("Write a review") }} {{ _("Write a review") }}
</span> </span>
{% elif not is_instructor(course.name) and frappe.session.user == "Guest" %} {% elif not is_instructor(course.name) and frappe.session.user == "Guest" %}
<a class="btn btn-secondary btn-s pull-rightm" href="/login?redirect-to=/courses/{{ course.name }}"> {{ _("Login") }} </a> <a class="btn btn-secondary btn-sm pull-right" href="/login?redirect-to=/courses/{{ course.name }}"> {{ _("Login") }} </a>
{% elif not is_instructor(course.name) and not membership and course.status == "Approved" %} {% elif not is_instructor(course.name) and not membership and course.status == "Approved" %}
<div class="btn btn-secondary btn-sm join-batch pull-right" data-course="{{ course.name | urlencode }}"> {{ _("Start Learning") }} </div> <div class="btn btn-secondary btn-sm join-batch pull-right" data-course="{{ course.name | urlencode }}"> {{ _("Start Learning") }} </div>
{% endif %} {% endif %}

View File

@@ -1399,15 +1399,17 @@ pre {
} }
.lms-nav .nav-link { .lms-nav .nav-link {
color: var(--text-muted); padding: var(--padding-sm) 0;
padding: var(--padding-md) 0;
margin: 0 var(--margin-md); margin: 0 var(--margin-md);
font-size: var(--text-base);
color: var(--text-muted);
} }
.lms-nav .nav-link.active { .lms-nav .nav-link.active {
font-weight: 600; font-weight: 500;
border-bottom: 1px solid var(--primary); border-bottom: 1px solid var(--primary-color);
color: var(--text-color); color: var(--primary-color);
} }
@media (min-width: 500px) { @media (min-width: 500px) {
@@ -1416,10 +1418,6 @@ pre {
} }
} }
.lms-nav .nav-link:hover {
color: inherit;
}
.dashboard-button { .dashboard-button {
position: relative; position: relative;
top: -50px; top: -50px;
@@ -1708,3 +1706,23 @@ li {
width: 2.75rem; width: 2.75rem;
height: 2.75rem; height: 2.75rem;
} }
.modal .comment-field {
height: 150px !important;
resize: auto !important;
}
.notification-card {
display: flex;
align-items: center;
margin-bottom: 1.5rem;
position: relative;
}
.notification-card:last-child {
margin-bottom: 0;
}
.timestamp {
font-size: var(--text-xs);
}

View File

@@ -0,0 +1,30 @@
{% if notifications | length %}
<div class="common-card-style column-card">
{% for notification in notifications %}
<div class="notification-card">
<div>
{% set member = frappe.db.get_value("User", notification.from_user,
["username", "full_name", "user_image"], as_dict=1) %}
{{ widgets.Avatar(member=member, avatar_class="avatar-medium") }}
</div>
<div class="ml-2">
<div class="medium">
{{ notification.subject }} {{ frappe.utils.pretty_date(notification.creation) }}
</div>
<!-- <div class="timestamp"> {{ frappe.utils.pretty_date(notification.creation) }} </div> -->
</div>
<a class="stretched-link" href="{{ notification.url }}"></a>
</div>
{% endfor %}
</div>
{% else %}
<div class="empty-state">
<img class="icon icon-xl" src="/assets/lms/icons/comment.svg">
<div class="empty-state-text">
<div class="empty-state-heading">{{ _("No Notifications") }}</div>
<div class="course-meta">{{ _("You don't have any notifications.") }}</div>
</div>
</div>
{% endif %}

View File

@@ -74,7 +74,7 @@
<!-- Edit Button --> <!-- Edit Button -->
{% if (is_instructor or has_course_moderator_role()) and not lesson.edit_mode %} {% if (is_instructor or has_course_moderator_role()) and not lesson.edit_mode %}
<button class="button is-default button-links ml-auto btn-edit"> {{ _("Edit") }} </button> <button class="button is-default button-links ml-2 btn-edit"> {{ _("Edit") }} </button>
{% endif %} {% endif %}
</div> </div>

View File

@@ -347,7 +347,7 @@
{% endif %} {% endif %}
{% if is_instructor(course.name) or has_course_moderator_role() %} {% if is_instructor(course.name) or has_course_moderator_role() %}
<a class="btn btn-secondary wide-button" href="/courses/{{ course.name }}?edit=1"> {{ _("Edit Course") }} </a> <a class="btn btn-secondary wide-button mt-3" href="/courses/{{ course.name }}?edit=1"> {{ _("Edit Course") }} </a>
{% endif %} {% endif %}
{% endmacro %} {% endmacro %}

View File

@@ -17,14 +17,14 @@
<ul class="nav lms-nav" id="courses-tab"> <ul class="nav lms-nav" id="courses-tab">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#courses-enrolled"> <a class="nav-link active" data-toggle="tab" href="#courses-enrolled">
{{ _("Courses Enrolled") }} {{ _("Enrolled") }}
</a> </a>
</li> </li>
{% if show_creators_section %} {% if show_creators_section %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#courses-created"> <a class="nav-link" data-toggle="tab" href="#courses-created">
{{ _("Courses Created") }} {{ _("Created") }}
</a> </a>
</li> </li>
{% endif %} {% endif %}
@@ -32,7 +32,7 @@
{% if show_review_section %} {% if show_review_section %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#courses-under-review"> <a class="nav-link" data-toggle="tab" href="#courses-under-review">
{{ _("Courses Under Review") }} {{ _("Under Review") }}
</a> </a>
</li> </li>
{% endif %} {% endif %}
@@ -61,20 +61,8 @@
</div> </div>
{% endif %} {% endif %}
<div class="tab-pane fade" id="notifications" role="tabpanel" aria-labelledby="notifications"> <div class="tab-pane" id="notifications" role="tabpanel" aria-labelledby="notifications">
{% if notifications | length %} {% include "lms/templates/notifications.html" %}
{% for notification in notifications %}
{{ notification }}
{% endfor %}
{% else %}
<div class="empty-state">
<img class="icon icon-xl" src="/assets/lms/icons/comment.svg">
<div class="empty-state-text">
<div class="empty-state-heading">{{ _("No Notifications") }}</div>
<div class="course-meta">{{ _("You don't have any notifications.") }}</div>
</div>
</div>
{% endif %}
</div> </div>
</div> </div>

View File

@@ -1,6 +1,6 @@
import frappe import frappe
from datetime import datetime from datetime import datetime
from lms.lms.utils import has_course_instructor_role, has_course_moderator_role from lms.lms.utils import has_course_instructor_role, has_course_moderator_role, get_lesson_index
def get_context(context): def get_context(context):
@@ -12,6 +12,19 @@ def get_context(context):
def get_notifications(): def get_notifications():
notifications = frappe.get_all("Notification Log", {
"document_type": "Course Lesson",
"for_user": frappe.session.user
}, ["subject", "creation", "from_user", "document_name"])
for notification in notifications:
course = frappe.db.get_value("Course Lesson", notification.document_name, "course")
notification.url = "/courses/{0}/learn/{1}".format(course, get_lesson_index(notification.document_name))
return notifications
def get_notifications_old():
notifications = [] notifications = []
notifications += get_notifications_from_lessons_created() notifications += get_notifications_from_lessons_created()
@@ -19,7 +32,6 @@ def get_notifications():
notifications += get_notifications_from_topics_created() notifications += get_notifications_from_topics_created()
if len(notifications): if len(notifications):
print(notifications)
notifications = sorted(notifications, key=lambda t: datetime.strptime(frappe.utils.format_datetime(t.creation, "dd-mm-yyyy HH:mm:ss"),"%d/%m/%Y %H:%M:%S")) notifications = sorted(notifications, key=lambda t: datetime.strptime(frappe.utils.format_datetime(t.creation, "dd-mm-yyyy HH:mm:ss"),"%d/%m/%Y %H:%M:%S"))
return notifications return notifications
@@ -57,7 +69,6 @@ def get_notifications_from_replies(topics):
"topic": topic.name "topic": topic.name
}, ["reply", "owner", "creation"]) }, ["reply", "owner", "creation"])
for reply in replies: for reply in replies:
notification = frappe._dict() notification = frappe._dict()
notification["message"] = reply.reply notification["message"] = reply.reply