176 lines
5.2 KiB
Python
176 lines
5.2 KiB
Python
"""Custom page renderers for LMS app.
|
|
|
|
Handles rendering of profile pages.
|
|
"""
|
|
import re
|
|
import os
|
|
import mimetypes
|
|
import frappe
|
|
from frappe.website.page_renderers.base_renderer import BaseRenderer
|
|
from frappe.website.page_renderers.document_page import DocumentPage
|
|
from frappe.website.page_renderers.list_page import ListPage
|
|
from frappe.website.page_renderers.not_found_page import NotFoundPage
|
|
from frappe.website.page_renderers.print_page import PrintPage
|
|
from frappe.website.page_renderers.redirect_page import RedirectPage
|
|
from frappe.website.page_renderers.static_page import StaticPage
|
|
from frappe.website.page_renderers.template_page import TemplatePage
|
|
from frappe.website.page_renderers.web_form import WebFormPage
|
|
from werkzeug.wrappers import Response
|
|
from werkzeug.wsgi import wrap_file
|
|
|
|
|
|
def get_profile_url(username):
|
|
"""Returns the profile URL given username.
|
|
|
|
The default URL prefix for profiles is /users, but tha can be customized.
|
|
|
|
This functions looks at the current value from the config and generates
|
|
the URL for the profile.
|
|
"""
|
|
return get_profile_url_prefix() + username
|
|
|
|
|
|
def get_profile_url_prefix():
|
|
hooks = frappe.get_hooks("profile_url_prefix") or ["/users/"]
|
|
return hooks[-1]
|
|
|
|
|
|
RE_INVALID_USERNAME = re.compile("[@!#$%^&*()<>?/\\|}{~:-]")
|
|
|
|
|
|
class ProfileRedirectPage(BaseRenderer):
|
|
"""Renderer to redirect /profile_/foo to <profile_prefix>/foo.
|
|
|
|
This is useful to redirect to profile pages from javascript as there is no
|
|
easy to find the profile prefix.
|
|
"""
|
|
|
|
def can_render(self):
|
|
return self.path.startswith("profile_/")
|
|
|
|
def render(self):
|
|
username = self.path[len("profile_/") :]
|
|
frappe.flags.redirect_location = get_profile_url_prefix() + username
|
|
return RedirectPage(self.path).render()
|
|
|
|
|
|
class ProfilePage(BaseRenderer):
|
|
def __init__(self, path, http_status_code):
|
|
super().__init__(path, http_status_code)
|
|
self.renderer = None
|
|
|
|
def can_render(self):
|
|
"""if "." in self.path:
|
|
return False"""
|
|
|
|
# has prefix and path starts with prefix?
|
|
prefix = get_profile_url_prefix().lstrip("/")
|
|
if prefix and not self.path.startswith(prefix):
|
|
return False
|
|
|
|
# not a userpage?
|
|
username = self.get_username()
|
|
""" if RE_INVALID_USERNAME.search(username):
|
|
return False """
|
|
# if there is prefix then we can allow all usernames
|
|
if prefix:
|
|
return True
|
|
|
|
# if we are having top-level usernames, then give preference to
|
|
# the existing website_route_rules, web pages, web forms etc.
|
|
|
|
# Don't handle any of the exsiting website_route_rules
|
|
routes = [rule["to_route"] for rule in frappe.get_hooks("website_route_rules")]
|
|
if self.path in routes:
|
|
return False
|
|
|
|
# if any of the existing renders can render, let them do
|
|
renderers = [StaticPage, WebFormPage, DocumentPage, TemplatePage, ListPage, PrintPage]
|
|
for renderer in renderers:
|
|
renderer_instance = renderer(self.path, 200)
|
|
if renderer_instance.can_render():
|
|
self.renderer = renderer_instance
|
|
return True
|
|
|
|
return True
|
|
|
|
def get_username(self):
|
|
prefix = get_profile_url_prefix().lstrip("/")
|
|
return self.path[len(prefix) :]
|
|
|
|
def render(self):
|
|
if self.renderer:
|
|
return self.renderer.render()
|
|
else:
|
|
username = self.get_username()
|
|
return render_portal_page("profiles/profile", username=username)
|
|
|
|
|
|
def render_portal_page(path, **kwargs):
|
|
frappe.form_dict.update(kwargs)
|
|
page = TemplatePage(path)
|
|
return page.render()
|
|
|
|
|
|
class CoursePage(BaseRenderer):
|
|
def __init__(self, path, http_status_code):
|
|
super().__init__(path, http_status_code)
|
|
self.renderer = None
|
|
|
|
def can_render(self):
|
|
return self.path.startswith("course")
|
|
|
|
def render(self):
|
|
if "learn" in self.path:
|
|
prefix = self.path.split("/learn")[0]
|
|
course_name = prefix.split("/")[1]
|
|
lesson_index = self.path.split("/learn/")[1]
|
|
chapter_number = lesson_index.split(".")[0]
|
|
lesson_number = lesson_index.split(".")[1]
|
|
|
|
frappe.flags.redirect_location = (
|
|
f"/lms/courses/{course_name}/learn/{chapter_number}-{lesson_number}"
|
|
)
|
|
return RedirectPage(self.path).render()
|
|
|
|
elif len(self.path.split("/")) > 1:
|
|
course_name = self.path.split("/")[1]
|
|
frappe.flags.redirect_location = f"/lms/courses/{course_name}"
|
|
return RedirectPage(self.path).render()
|
|
|
|
else:
|
|
frappe.flags.redirect_location = "/lms/courses"
|
|
return RedirectPage(self.path).render()
|
|
|
|
|
|
class SCORMRenderer(BaseRenderer):
|
|
def can_render(self):
|
|
return "scorm/" in self.path
|
|
|
|
def render(self):
|
|
path = os.path.join(frappe.local.site_path, "public", self.path.lstrip("/"))
|
|
|
|
extension = os.path.splitext(path)[1]
|
|
if not extension:
|
|
path = f"{path}.html"
|
|
|
|
# check if path exists and is actually a file and not a folder
|
|
if os.path.exists(path) and os.path.isfile(path):
|
|
f = open(path, "rb")
|
|
response = Response(
|
|
wrap_file(frappe.local.request.environ, f), direct_passthrough=True
|
|
)
|
|
response.mimetype = mimetypes.guess_type(path)[0]
|
|
return response
|
|
else:
|
|
path = path.replace(".html", "")
|
|
if os.path.exists(path) and os.path.isdir(path):
|
|
index_path = os.path.join(path, "index.html")
|
|
if os.path.exists(index_path):
|
|
f = open(index_path, "rb")
|
|
response = Response(
|
|
wrap_file(frappe.local.request.environ, f), direct_passthrough=True
|
|
)
|
|
response.mimetype = mimetypes.guess_type(index_path)[0]
|
|
return response
|