diff --git a/community/hooks.py b/community/hooks.py index abaedcb0..90ad31b8 100644 --- a/community/hooks.py +++ b/community/hooks.py @@ -150,6 +150,7 @@ primary_rules = [ # Any frappe default URL is blocked by profile-rules, add it here to unblock it whitelist = [ + "/home", "/login", "/update-password", "/update-profile", diff --git a/community/lms/doctype/lms_course/lms_course.py b/community/lms/doctype/lms_course/lms_course.py index 49404f08..8d6de54e 100644 --- a/community/lms/doctype/lms_course/lms_course.py +++ b/community/lms/doctype/lms_course/lms_course.py @@ -88,3 +88,15 @@ class LMSCourse(Document): member.batch_count = len(frappe.get_all("LMS Batch Membership", {"member": member.name, "member_type": "Mentor"})) course_mentors.append(member) return course_mentors + + def get_instructor(self): + return frappe.get_doc("User", self.owner) + + @staticmethod + def find_all(): + """Returns all published courses. + """ + rows = frappe.db.get_all("LMS Course", + filters={"is_published": True}, + fields='*') + return [frappe.get_doc(dict(row, doctype='LMS Course')) for row in rows] diff --git a/community/lms/doctype/lms_course/test_lms_course.py b/community/lms/doctype/lms_course/test_lms_course.py index 2f50829b..a54ab337 100644 --- a/community/lms/doctype/lms_course/test_lms_course.py +++ b/community/lms/doctype/lms_course/test_lms_course.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe +from .lms_course import LMSCourse import unittest class TestLMSCourse(unittest.TestCase): @@ -26,6 +27,23 @@ class TestLMSCourse(unittest.TestCase): assert course.slug == "test-course" assert course.get_mentors() == [] + def test_find_all(self): + courses = LMSCourse.find_all() + assert courses == [] + + # new couse, but not published + course = self.new_course("Test Course") + assert courses == [] + + # publish the course + course.is_published = True + course.save() + + # now we should find one course + courses = LMSCourse.find_all() + assert [c.slug for c in courses] == [course.slug] + + # disabled this test as it is failing def _test_add_mentors(self): course = self.new_course("Test Course") assert course.get_mentors() == [] @@ -47,4 +65,4 @@ def new_user(name, email): email=email, first_name=name)) doc.insert() - return doc \ No newline at end of file + return doc diff --git a/community/lms/doctype/lms_sketch/lms_sketch.py b/community/lms/doctype/lms_sketch/lms_sketch.py index 2f0120fe..e26ff490 100644 --- a/community/lms/doctype/lms_sketch/lms_sketch.py +++ b/community/lms/doctype/lms_sketch/lms_sketch.py @@ -10,9 +10,6 @@ from frappe.model.document import Document from . import livecode class LMSSketch(Document): - def get_owner_name(self): - return get_userinfo(self.owner)['full_name'] - @property def sketch_id(self): """Returns the numeric part of the name. @@ -21,6 +18,14 @@ class LMSSketch(Document): """ return self.name.replace("SKETCH-", "") + def get_owner(self): + """Returns the owner of this sketch as a document. + """ + return frappe.get_doc("User", self.owner) + + def get_owner_name(self): + return self.get_owner().full_name + def get_livecode_url(self): doc = frappe.get_cached_doc("LMS Settings") return doc.livecode_url @@ -46,6 +51,18 @@ class LMSSketch(Document): cache.set(key, value) return value + @staticmethod + def get_recent_sketches(limit=100): + """Returns the recent sketches. + """ + sketches = frappe.get_all( + "LMS Sketch", + fields='*', + order_by='modified desc', + page_length=limit + ) + return [frappe.get_doc(doctype='LMS Sketch', **doc) for doc in sketches] + def __repr__(self): return f"" @@ -76,36 +93,3 @@ def save_sketch(name, title, code): "status": status, "name": doc.name, } - -def get_recent_sketches(): - """Returns the recent sketches. - - The return value will be a list of dicts with each entry containing - the following fields: - - name - - title - - owner - - owner_name - - modified - """ - sketches = frappe.get_all( - "LMS Sketch", - fields='*', - order_by='modified desc', - page_length=100 - ) - for s in sketches: - s['owner_name'] = get_userinfo(s['owner'])['full_name'] - return [frappe.get_doc(doctype='LMS Sketch', **doc) for doc in sketches] - -def get_userinfo(email): - """Returns the username and fullname of a user. - - Please note that the email could be "Administrator" or "Guest" - as a special case to denote the system admin and guest user respectively. - """ - user = frappe.get_doc("User", email) - return { - "full_name": user.full_name, - "username": user.username - } diff --git a/community/lms/models.py b/community/lms/models.py new file mode 100644 index 00000000..00c910c3 --- /dev/null +++ b/community/lms/models.py @@ -0,0 +1,5 @@ +"""Handy module to make access to all doctypes from a single place. +""" +from .doctype.lms_course.lms_course import LMSCourse as Course +from .doctype.lms_sketch.lms_sketch import LMSSketch as Sketch + diff --git a/community/lms/widgets/CourseTeaser.html b/community/lms/widgets/CourseTeaser.html new file mode 100644 index 00000000..290a8aed --- /dev/null +++ b/community/lms/widgets/CourseTeaser.html @@ -0,0 +1,13 @@ +
+
+

{{ course.title }}

+
+ {{ course.short_introduction or "" }} +
+
+ +
diff --git a/community/lms/widgets/SketchTeaser.html b/community/lms/widgets/SketchTeaser.html new file mode 100644 index 00000000..6c8ec431 --- /dev/null +++ b/community/lms/widgets/SketchTeaser.html @@ -0,0 +1,15 @@ +
+ + +
diff --git a/community/public/css/style.css b/community/public/css/style.css index bf157299..850f7038 100644 --- a/community/public/css/style.css +++ b/community/public/css/style.css @@ -25,12 +25,14 @@ --cta-color: var(--c4); --send-message: var(--c7); --received-message: var(--c8); + + --primary-color: #08B74F; } body { padding: 0px; margin: 0px; - background: var(--bg); + background: white; } .course-header { @@ -200,10 +202,6 @@ img.profile-photo { /* override style of base */ -nav.navbar { - background: var(--c1) !important; -} - .message { border: 1px dashed var(--text-color); padding: 20px; @@ -291,4 +289,71 @@ nav.navbar { .message-section { margin-left: 5%; display: inline-block; -} \ No newline at end of file +} + +.sketch-teaser { + background: white; + border-radius: 10px; + border: 1px solid #ddd; + width: 220px; +} + +.sketch-teaser svg { + width: 200px; + height: 200px; +} + +.sketch-image { + padding: 10px; +} + +.sketch-footer { + padding: 10px; + background: #eee; + border-radius: 0px 0px 10px 10px; +} + +.course-teaser { + background: white; + border-radius: 10px; + border: 1px solid #ddd; + color: #444; +} + +.course-teaser h3, .course-teaser h4 { + color: black; + font-weight: bold;; +} + +.course-teaser .course-body, .course-teaser .course-footer { + padding: 20px; +} + +.course-body { + min-height: 8em; +} + +.course-footer { + border-top: 1px solid #ddd; +} + +.course-teaser a, .course-teaser a:hover { + color: inherit; + text-decoration: none; +} + +section { + padding: 60px 0px; +} + +section h2 { + margin-bottom: 40px; +} + +section.lightgray { + background: #f8f8f8; +} + +#hero .jumbotron { + background: inherit; +} diff --git a/community/www/home/index.html b/community/www/home/index.html new file mode 100644 index 00000000..c087d76e --- /dev/null +++ b/community/www/home/index.html @@ -0,0 +1,51 @@ +{% extends "templates/base.html" %} + +{% block content %} + {{ HeroSection() }} + {{ ExploreCourses(courses) }} + {{ RecentSketches(recent_sketches) }} +{% endblock %} + +{% macro HeroSection() %} +
+
+
+

Guided online courses, with a mentor at your back.

+

Hands-on online courses designed by experts, delivered by passionate mentors.

+

+ Request Invite +

+
+
+
+{% endmacro %} + +{% macro ExploreCourses(courses) %} +
+
+

Explore Courses

+
+ {% for course in courses %} +
+ {{ widgets.CourseTeaser(course=course) }} +
+ {% endfor %} +
+
+
+{% endmacro %} + +{% macro RecentSketches(sketches) %} +
+
+

Recent Sketches

+
+ {% for sketch in sketches %} +
+ {{ widgets.SketchTeaser(sketch=sketch) }} +
+ {% endfor %} +
+
+
+{% endmacro %} diff --git a/community/www/home/index.py b/community/www/home/index.py new file mode 100644 index 00000000..34f55b61 --- /dev/null +++ b/community/www/home/index.py @@ -0,0 +1,7 @@ +import frappe +from community.lms.models import Course, Sketch + +def get_context(context): + context.no_cache = 1 + context.courses = Course.find_all() + context.recent_sketches = Sketch.get_recent_sketches(limit=8) diff --git a/community/www/sketches/index.html b/community/www/sketches/index.html index dd1a61de..71ad9996 100644 --- a/community/www/sketches/index.html +++ b/community/www/sketches/index.html @@ -16,37 +16,13 @@ Create a New Sketch
-
- {% for sketch in sketches %} -
-
- - - {% endfor %} + {% endfor %}
{% endblock %} - -{% block style %} - {{super()}} - -{% endblock %} diff --git a/community/www/sketches/index.py b/community/www/sketches/index.py index 3ab688e1..88bcd47e 100644 --- a/community/www/sketches/index.py +++ b/community/www/sketches/index.py @@ -1,7 +1,7 @@ import frappe -from ...lms.doctype.lms_sketch.lms_sketch import get_recent_sketches +from community.lms.models import Sketch def get_context(context): context.no_cache = 1 - context.sketches = get_recent_sketches() + context.sketches = Sketch.get_recent_sketches()