Merge pull request #379 from pateljannat/notifications

This commit is contained in:
Jannat Patel
2022-09-27 18:22:40 +05:30
committed by GitHub
12 changed files with 147 additions and 41 deletions

View File

@@ -85,8 +85,8 @@ web_include_js = ["website.bundle.js", "controls.bundle.js"]
# Override standard doctype classes
override_doctype_class = {
"User": "lms.overrides.user.CustomUser",
"Web Template": "lms.overrides.web_template.CustomWebTemplate"
"User": "lms.overrides.user.CustomUser",
"Web Template": "lms.overrides.web_template.CustomWebTemplate"
}
# Document Events
@@ -94,7 +94,9 @@ override_doctype_class = {
# Hook on document methods and events
doc_events = {
"Discussion Reply": {
"after_insert": "lms.lms.utils.create_notification_log"
}
}
# 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
import string
from frappe import _
from frappe.desk.doctype.notification_log.notification_log import make_notification_logs
RE_SLUG_NOTALLOWED = re.compile("[^a-z0-9]+")
@@ -469,3 +470,35 @@ def validate_image(path):
file.save(ignore_permissions=True)
return file.file_url
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

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

View File

@@ -2,17 +2,17 @@
{% set progress = frappe.utils.cint(membership.progress) %}
<div class="common-card-style course-card" data-course="{{ course.name }}">
<div class="course-image {% if not course.image %}default-image{% endif %}" {% if course.image %}
style="background-image: url( {{ course.image | urlencode }} );" {% endif %}>
<div class="course-tags">
{% for tag in get_tags(course.name) %}
<div class="course-card-pills">{{ tag }}</div>
{% endfor %}
<div class="course-image {% if not course.image %}default-image{% endif %}"
{% if course.image %} style="background-image: url( {{ course.image | urlencode }} );" {% endif %}>
<div class="course-tags">
{% for tag in get_tags(course.name) %}
<div class="course-card-pills">{{ tag }}</div>
{% endfor %}
</div>
{% if not course.image %}
<div class="default-image-text">{{ course.title[0] }}</div>
{% endif %}
</div>
{% if not course.image %}
<div class="default-image-text">{{ course.title[0] }}</div>
{% endif %}
</div>
<div class="course-card-content">
<div class="course-card-meta">

View File

@@ -8,7 +8,7 @@
{{ _("Write a review") }}
</span>
{% 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" %}
<div class="btn btn-secondary btn-sm join-batch pull-right" data-course="{{ course.name | urlencode }}"> {{ _("Start Learning") }} </div>
{% endif %}

View File

@@ -1399,15 +1399,17 @@ pre {
}
.lms-nav .nav-link {
color: var(--text-muted);
padding: var(--padding-md) 0;
padding: var(--padding-sm) 0;
margin: 0 var(--margin-md);
font-size: var(--text-base);
color: var(--text-muted);
}
.lms-nav .nav-link.active {
font-weight: 600;
border-bottom: 1px solid var(--primary);
color: var(--text-color);
font-weight: 500;
border-bottom: 1px solid var(--primary-color);
color: var(--primary-color);
}
@media (min-width: 500px) {
@@ -1416,10 +1418,6 @@ pre {
}
}
.lms-nav .nav-link:hover {
color: inherit;
}
.dashboard-button {
position: relative;
top: -50px;
@@ -1708,3 +1706,23 @@ li {
width: 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 -->
{% 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 %}
</div>

View File

@@ -13,7 +13,7 @@ def get_context(context):
context.chapter = frappe.db.get_value("Chapter Reference", {
"idx": chapter_index,
"parent": context.course.name
}, "chapter")
}, "chapter")
if not chapter_index or not lesson_index:
if context.batch:

View File

@@ -347,7 +347,7 @@
{% endif %}
{% 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 %}
{% endmacro %}

View File

@@ -17,14 +17,14 @@
<ul class="nav lms-nav" id="courses-tab">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#courses-enrolled">
{{ _("Courses Enrolled") }}
{{ _("Enrolled") }}
</a>
</li>
{% if show_creators_section %}
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#courses-created">
{{ _("Courses Created") }}
{{ _("Created") }}
</a>
</li>
{% endif %}
@@ -32,10 +32,14 @@
{% if show_review_section %}
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#courses-under-review">
{{ _("Courses Under Review") }}
{{ _("Under Review") }}
</a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#notifications">{{ _("Notifications") }}
</a>
</li>
</ul>
<div class="border-bottom mb-4"></div>
@@ -57,6 +61,10 @@
</div>
{% endif %}
<div class="tab-pane" id="notifications" role="tabpanel" aria-labelledby="notifications">
{% include "lms/templates/notifications.html" %}
</div>
</div>
</div>
</div>

View File

@@ -1,5 +1,6 @@
import frappe
from lms.lms.utils import has_course_instructor_role, has_course_moderator_role
from datetime import datetime
from lms.lms.utils import has_course_instructor_role, has_course_moderator_role, get_lesson_index
def get_context(context):
@@ -7,3 +8,17 @@ def get_context(context):
portal_course_creation = frappe.db.get_single_value("LMS Settings", "portal_course_creation")
context.show_creators_section = portal_course_creation == "Anyone" or has_course_instructor_role()
context.show_review_section = has_course_moderator_role()
context.notifications = 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