feat: batch folders, redirects, members page
This commit is contained in:
@@ -137,7 +137,12 @@ primary_rules = [
|
||||
{"from_route": "/hackathons/<hackathon>", "to_route": "hackathons/hackathon"},
|
||||
{"from_route": "/hackathons/<hackathon>/<project>", "to_route": "hackathons/project"},
|
||||
{"from_route": "/dashboard", "to_route": ""},
|
||||
{"from_route": "/add-a-new-batch", "to_route": "add-a-new-batch"}
|
||||
{"from_route": "/add-a-new-batch", "to_route": "add-a-new-batch"},
|
||||
{"from_route": "/courses/<course>/<batch>/learn", "to_route": "courses/learn"},
|
||||
{"from_route": "/courses/<course>/<batch>/schedule", "to_route": "courses/schedule"},
|
||||
{"from_route": "/courses/<course>/<batch>/members", "to_route": "courses/members"},
|
||||
{"from_route": "/courses/<course>/<batch>/discuss", "to_route": "courses/discuss"},
|
||||
{"from_route": "/courses/<course>/<batch>/about", "to_route": "courses/about"}
|
||||
]
|
||||
|
||||
# Any frappe default URL is blocked by profile-rules, add it here to unblock it
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"fieldname": "batch",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Batch",
|
||||
"options": "LMS Batch"
|
||||
},
|
||||
@@ -24,6 +25,7 @@
|
||||
"fieldname": "member",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Member",
|
||||
"options": "Community Member"
|
||||
},
|
||||
@@ -38,6 +40,7 @@
|
||||
"fieldname": "role",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Role",
|
||||
"options": "\nMember\nAdmin"
|
||||
},
|
||||
@@ -56,7 +59,7 @@
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-04-16 09:57:52.926943",
|
||||
"modified": "2021-04-22 15:30:00.069946",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "LMS Batch Membership",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@import url("https://cdn.jsdelivr.net/npm/bootstrap-icons@1.4.1/font/bootstrap-icons.css");
|
||||
@import url("https://use.fontawesome.com/releases/v5.13.0/css/all.css");
|
||||
|
||||
:root {
|
||||
--c1: #fefae0;
|
||||
@@ -61,6 +62,19 @@ body {
|
||||
color: var(--c2);
|
||||
}
|
||||
|
||||
.sidebar-batch {
|
||||
background: var(--sidebar-bg);
|
||||
color: var(--text-color);
|
||||
position: fixed;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sidebar-batch a {
|
||||
padding: 16px 8px 8px 16px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.instructor {
|
||||
padding: 10px;
|
||||
}
|
||||
@@ -193,3 +207,29 @@ nav.navbar {
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.dashboard__profile {
|
||||
width: 150px;
|
||||
height: 155px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.dashboard__profileSmall {
|
||||
width: 59px;
|
||||
height: 57px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.dashboard__abbr {
|
||||
font-size: 50px;
|
||||
width: 155px;
|
||||
height: 155px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.dashboard__abbrSmall {
|
||||
font-size: 20px;
|
||||
width: 59px;
|
||||
height: 57px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
13
community/www/courses/about/index.html
Normal file
13
community/www/courses/about/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% from "www/macros/sidebar.html" import Sidebar %}
|
||||
{% block title %}About{% endblock %}
|
||||
{% block head_include %}
|
||||
<meta name="description" content="Courses" />
|
||||
<meta name="keywords" content="" />
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{{ Sidebar(course, batch_code) }}
|
||||
<div class="container">
|
||||
</div>
|
||||
{% endblock %}
|
||||
8
community/www/courses/about/index.py
Normal file
8
community/www/courses/about/index.py
Normal file
@@ -0,0 +1,8 @@
|
||||
import frappe
|
||||
from community.www.courses.utils import redirect_if_not_a_member
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
context.course = frappe.form_dict["course"]
|
||||
context.batch_code = frappe.form_dict["batch"]
|
||||
redirect_if_not_a_member(context.course, context.batch_code)
|
||||
@@ -110,7 +110,7 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<a class="btn btn-primary add-batch margin-bottom" href="/add-a-new-batch?new=1&course={{course.name}}" data-course="{{course.name | urlencode}}">Add a new batch</a>
|
||||
<a class="btn btn-primary add-batch margin-bottom" href="/add-a-new-batch?new=1&course={{course.name}}">Add a new batch</a>
|
||||
{% else %}
|
||||
<div class="mentor_message">
|
||||
<p> You are a mentor for this course. </p>
|
||||
|
||||
@@ -12,11 +12,14 @@ def get_context(context):
|
||||
|
||||
context.course = get_course(course_id)
|
||||
context.batches = get_course_batches(context.course.name)
|
||||
context.is_mentor = is_mentor(context.course.name)
|
||||
context.memberships = get_membership(context.batches)
|
||||
context.upcoming_batches = [] if len(context.memberships) else get_upcoming_batches(context.course.name)
|
||||
if len(context.memberships) and not context.is_mentor:
|
||||
frappe.local.flags.redirect_location = "/courses/" + course_id + "/" + context.memberships[0].code + "/learn"
|
||||
raise frappe.Redirect
|
||||
context.upcoming_batches = get_upcoming_batches(context.course.name)
|
||||
context.instructor = get_instructor(context.course.owner)
|
||||
context.mentors = get_mentors(context.course.name)
|
||||
context.is_mentor = is_mentor(context.course.name)
|
||||
|
||||
if context.is_mentor:
|
||||
context.mentor_batches = get_mentor_batches(context.memberships) # Your Bacthes for mentor
|
||||
@@ -48,19 +51,13 @@ def get_batch_mentors(batches):
|
||||
batch.mentors.append(member)
|
||||
return batches
|
||||
|
||||
def get_discussions(batches):
|
||||
messages = []
|
||||
memberships = get_membership(batches)
|
||||
if len(memberships):
|
||||
messages = get_messages(memberships[0].batch)
|
||||
return messages, memberships
|
||||
|
||||
def get_membership(batches):
|
||||
memberships = []
|
||||
member = frappe.db.get_value("Community Member", {"email": frappe.session.user}, "name")
|
||||
for batch in batches:
|
||||
membership = frappe.db.get_value("LMS Batch Membership", {"member": member, "batch": batch.name}, ["batch", "member", "member_type"], as_dict=1)
|
||||
if membership:
|
||||
membership.code = batch.code
|
||||
memberships.append(membership)
|
||||
return memberships
|
||||
|
||||
@@ -84,7 +81,7 @@ def get_mentors(course):
|
||||
return course_mentors
|
||||
|
||||
def get_course_batches(course):
|
||||
return frappe.get_all("LMS Batch", {"course": course}, ["name"])
|
||||
return frappe.get_all("LMS Batch", {"course": course}, ["name", "code"])
|
||||
|
||||
def get_mentor_batches(memberships):
|
||||
mentor_batches = []
|
||||
|
||||
13
community/www/courses/discuss/index.html
Normal file
13
community/www/courses/discuss/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% from "www/macros/sidebar.html" import Sidebar %}
|
||||
{% block title %}Discuss{% endblock %}
|
||||
{% block head_include %}
|
||||
<meta name="description" content="Courses" />
|
||||
<meta name="keywords" content="" />
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{{ Sidebar(course, batch_code) }}
|
||||
<div class="container">
|
||||
</div>
|
||||
{% endblock %}
|
||||
8
community/www/courses/discuss/index.py
Normal file
8
community/www/courses/discuss/index.py
Normal file
@@ -0,0 +1,8 @@
|
||||
import frappe
|
||||
from community.www.courses.utils import redirect_if_not_a_member
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
context.course = frappe.form_dict["course"]
|
||||
context.batch_code = frappe.form_dict["batch"]
|
||||
redirect_if_not_a_member(context.course, context.batch_code)
|
||||
13
community/www/courses/learn/index.html
Normal file
13
community/www/courses/learn/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% from "www/macros/sidebar.html" import Sidebar %}
|
||||
{% block title %}Learn{% endblock %}
|
||||
{% block head_include %}
|
||||
<meta name="description" content="Courses" />
|
||||
<meta name="keywords" content="" />
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{{ Sidebar(course, batch_code) }}
|
||||
<div class="container">
|
||||
</div>
|
||||
{% endblock %}
|
||||
3
community/www/courses/learn/index.js
Normal file
3
community/www/courses/learn/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
frappe.ready(() => {
|
||||
|
||||
})
|
||||
10
community/www/courses/learn/index.py
Normal file
10
community/www/courses/learn/index.py
Normal file
@@ -0,0 +1,10 @@
|
||||
import frappe
|
||||
from community.www.courses.utils import redirect_if_not_a_member
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
context.course = frappe.form_dict["course"]
|
||||
context.batch_code = frappe.form_dict["batch"]
|
||||
redirect_if_not_a_member(context.course, context.batch_code)
|
||||
|
||||
print(context)
|
||||
35
community/www/courses/members/index.html
Normal file
35
community/www/courses/members/index.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% from "www/macros/sidebar.html" import Sidebar %}
|
||||
{% from "www/macros/profile.html" import Profile %}
|
||||
{% block title %}Members{% endblock %}
|
||||
{% block head_include %}
|
||||
<meta name="description" content="Courses" />
|
||||
<meta name="keywords" content="" />
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{{ Sidebar(course, batch_code) }}
|
||||
<div class="container">
|
||||
<div class="border p-3">
|
||||
<h3>{{course.name}}</h3>
|
||||
<div class="text-muted">{{member_count}} members</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-5">
|
||||
{% for member in members %}
|
||||
<div class="d-flex align-items-center">
|
||||
<div>
|
||||
{{ Profile(member.photo, member.full_name, member.abbr, "small") }}
|
||||
</div>
|
||||
<div class="mr-5">
|
||||
{{member.full_name}}
|
||||
</div>
|
||||
{% if member.is_mentor %}
|
||||
<div class="badge badge-success">Mentor</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<hr>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
23
community/www/courses/members/index.py
Normal file
23
community/www/courses/members/index.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import frappe
|
||||
from community.www.courses.utils import redirect_if_not_a_member, get_batch, get_member_with_name, get_course
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
context.course_slug = frappe.form_dict["course"]
|
||||
context.course = get_course(context.course_slug)
|
||||
context.batch_code = frappe.form_dict["batch"]
|
||||
redirect_if_not_a_member(context.course_slug, context.batch_code)
|
||||
context.batch = get_batch(context.batch_code)
|
||||
context.members = get_members(context.batch)
|
||||
context.member_count = len(context.members)
|
||||
|
||||
def get_members(batch):
|
||||
members = []
|
||||
memberships = frappe.get_all("LMS Batch Membership", {"batch": batch}, ["member", "member_type"])
|
||||
|
||||
for membership in memberships:
|
||||
member = get_member_with_name(membership.member)
|
||||
if membership.member_type == "Mentor":
|
||||
member.is_mentor = True
|
||||
members.append(member)
|
||||
return members
|
||||
13
community/www/courses/schedule/index.html
Normal file
13
community/www/courses/schedule/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% from "www/macros/sidebar.html" import Sidebar %}
|
||||
{% block title %}Schedule{% endblock %}
|
||||
{% block head_include %}
|
||||
<meta name="description" content="Courses" />
|
||||
<meta name="keywords" content="" />
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{{ Sidebar(course, batch_code) }}
|
||||
<div class="container">
|
||||
</div>
|
||||
{% endblock %}
|
||||
8
community/www/courses/schedule/index.py
Normal file
8
community/www/courses/schedule/index.py
Normal file
@@ -0,0 +1,8 @@
|
||||
import frappe
|
||||
from community.www.courses.utils import redirect_if_not_a_member
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
context.course = frappe.form_dict["course"]
|
||||
context.batch_code = frappe.form_dict["batch"]
|
||||
redirect_if_not_a_member(context.course, context.batch_code)
|
||||
36
community/www/courses/utils.py
Normal file
36
community/www/courses/utils.py
Normal file
@@ -0,0 +1,36 @@
|
||||
import frappe
|
||||
|
||||
def get_member_with_email():
|
||||
try:
|
||||
return frappe.db.get_value("Community Member", {"email": frappe.session.user}, "name")
|
||||
except frappe.DoesNotExistError:
|
||||
return
|
||||
|
||||
def get_member_with_name(name):
|
||||
try:
|
||||
return frappe.get_doc("Community Member", name)
|
||||
except frappe.DoesNotExistError:
|
||||
return
|
||||
|
||||
def get_batch(code):
|
||||
try:
|
||||
return frappe.db.get_value("LMS Batch", {"code": code}, "name")
|
||||
except frappe.DoesNotExistError:
|
||||
return
|
||||
|
||||
def is_member_of_batch(batch_code):
|
||||
membership = frappe.get_all("LMS Batch Membership", {"batch": get_batch(batch_code), "member": get_member_with_email()})
|
||||
if len(membership):
|
||||
return True
|
||||
return False
|
||||
|
||||
def redirect_if_not_a_member(course,batch_code):
|
||||
if not is_member_of_batch(batch_code):
|
||||
frappe.local.flags.redirect_location = "/courses/" + course
|
||||
raise frappe.Redirect
|
||||
|
||||
def get_course(slug):
|
||||
try:
|
||||
return frappe.db.get_value("LMS Course", {"slug": slug}, "name", as_dict=True)
|
||||
except frappe.DoesNotExistError:
|
||||
return
|
||||
@@ -1,5 +1,5 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% from "www/macros/profile.html" import profile %}
|
||||
{% from "www/macros/profile.html" import Profile %}
|
||||
{% block title %}{{ _("Community") }}{% endblock %}
|
||||
{% block head_include %}
|
||||
<meta name="description" content="{{ 'Community' }}" />
|
||||
@@ -91,7 +91,7 @@
|
||||
<section>
|
||||
<div class="dashboard__parent">
|
||||
<div>
|
||||
{{ profile(member.photo, member.full_name, member.abbr, "large")}}
|
||||
{{ Profile(member.photo, member.full_name, member.abbr, "large")}}
|
||||
</div>
|
||||
<div class="dashboard__details">
|
||||
<div class="dashboard__name">
|
||||
@@ -125,7 +125,7 @@
|
||||
</div>
|
||||
<div class="d-flex align-items-center w-100">
|
||||
<div>
|
||||
{{ profile(message.profile, message.full_name, message.abbr, "small")}}
|
||||
{{ Profile(message.profile, message.full_name, message.abbr, "small")}}
|
||||
</div>
|
||||
<div class="ml-5 mt-5">{{ frappe.utils.md_to_html(message.message) }}</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
{% macro profile(photo, full_name, abbr, icon) %}
|
||||
{% macro Profile(photo, full_name, abbr, icon) %}
|
||||
{% if photo %}
|
||||
<img class="avatar rounded-circle img-fluid mr-5{% if icon == 'large' %} avatar-xl {% else %} avatar-large {% endif %}"
|
||||
<img class="avatar rounded-circle img-fluid mr-5{% if icon == 'large' %} dashboard__profile {% else %} dashboard__profileSmall {% endif %}"
|
||||
src="{{ photo }}" alt="{{ full_name }}">
|
||||
{% else %}
|
||||
<div class="col-sm-2">
|
||||
<div class="standard-image {% if icon == 'large' %} dashboard__abbr {% else %} dashboard__abbrSmall {% endif %}">
|
||||
{{ abbr }}
|
||||
</div>
|
||||
<div class="standard-image mr-5 {% if icon == 'large' %} dashboard__abbr {% else %} dashboard__abbrSmall {% endif %}">
|
||||
{{ abbr }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
12
community/www/macros/sidebar.html
Normal file
12
community/www/macros/sidebar.html
Normal file
@@ -0,0 +1,12 @@
|
||||
{% macro Sidebar(course, batch_code) %}
|
||||
<div class="sidebar-batch">
|
||||
<a href=""><i class="fas fa-bars fa-lg"></i></a>
|
||||
<br>
|
||||
<a href="/courses/{{course}}/{{batch_code}}/learn"><i class="fas fa-book fa-lg"></i></a>
|
||||
<a href="/courses/{{course}}/{{batch_code}}/schedule"><i class="fas fa-calendar-alt fa-lg"></i></a>
|
||||
<a href="/courses/{{course}}/{{batch_code}}/members"><i class="fas fa-users fa-lg"></i></a>
|
||||
<a href="/courses/{{course}}/{{batch_code}}/discuss"><i class="fas fa-comments fa-lg"></i></a>
|
||||
<a href="/courses/{{course}}/{{batch_code}}/about"><i class="fas fa-info-circle fa-lg"></i></a>
|
||||
<!-- <a href="#contact"><i class="fas fa-home fa-lg"></i></a> -->
|
||||
</div>
|
||||
{% endmacro %}
|
||||
@@ -1,5 +1,5 @@
|
||||
{% extends "templates/web.html" %}
|
||||
{% from "www/macros/profile.html" import profile %}
|
||||
{% from "www/macros/profile.html" import Profile %}
|
||||
{% block head_include %}
|
||||
<meta name="description" content="{{ 'Community' }}" />
|
||||
<meta name="keywords" content="An app that supports Communities." />
|
||||
@@ -89,7 +89,7 @@
|
||||
<section>
|
||||
<div class="dashboard__parent">
|
||||
<div>
|
||||
{{ profile(member.photo, member.full_name, member.abbr, "large")}}
|
||||
{{ Profile(member.photo, member.full_name, member.abbr, "large")}}
|
||||
</div>
|
||||
<div class="dashboard__details">
|
||||
<div class="dashboard__name">
|
||||
|
||||
Reference in New Issue
Block a user