Merge branch 'main' of https://github.com/frappe/community into main
This commit is contained in:
@@ -3,3 +3,5 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
__version__ = '0.0.1'
|
__version__ = '0.0.1'
|
||||||
|
|
||||||
|
# load the methods from the lms api
|
||||||
|
from .lms import api # noqa
|
||||||
|
|||||||
@@ -127,14 +127,9 @@ scheduler_events = {
|
|||||||
#
|
#
|
||||||
# auto_cancel_exempted_doctypes = ["Auto Repeat"]
|
# auto_cancel_exempted_doctypes = ["Auto Repeat"]
|
||||||
|
|
||||||
from .routing import install_regex_converter
|
|
||||||
install_regex_converter()
|
|
||||||
|
|
||||||
# Add all simple route rules here
|
# Add all simple route rules here
|
||||||
primary_rules = [
|
primary_rules = [
|
||||||
{"from_route": "/sketches", "to_route": "sketches"},
|
|
||||||
{"from_route": "/sketches/<sketch>", "to_route": "sketches/sketch"},
|
{"from_route": "/sketches/<sketch>", "to_route": "sketches/sketch"},
|
||||||
{"from_route": "/courses", "to_route": "courses"},
|
|
||||||
{"from_route": "/courses/<course>", "to_route": "courses/course"},
|
{"from_route": "/courses/<course>", "to_route": "courses/course"},
|
||||||
{"from_route": "/courses/<course>/<topic>", "to_route": "courses/topic"},
|
{"from_route": "/courses/<course>/<topic>", "to_route": "courses/topic"},
|
||||||
{"from_route": "/hackathons", "to_route": "hackathons"},
|
{"from_route": "/hackathons", "to_route": "hackathons"},
|
||||||
@@ -147,13 +142,18 @@ whitelist = [
|
|||||||
"/login",
|
"/login",
|
||||||
"/update-password",
|
"/update-password",
|
||||||
"/update-profile",
|
"/update-profile",
|
||||||
"/third-party-apps"
|
"/third-party-apps",
|
||||||
|
"/website_script.js",
|
||||||
|
"/courses",
|
||||||
|
"/sketches",
|
||||||
|
"/admin",
|
||||||
|
"/socket.io",
|
||||||
]
|
]
|
||||||
whitelist_rules = [{"from_route": p, "to_route": p[1:]} for p in whitelist]
|
whitelist_rules = [{"from_route": p, "to_route": p[1:]} for p in whitelist]
|
||||||
|
|
||||||
# regex rule to match all profiles
|
# regex rule to match all profiles
|
||||||
profile_rules = [
|
profile_rules = [
|
||||||
{"from_route": "/<regex('[a-z0-9-]{5,}'):username>", "to_route": "profiles/profile"},
|
{"from_route": "/<string(minlength=5):username>", "to_route": "profiles/profile"},
|
||||||
]
|
]
|
||||||
|
|
||||||
website_route_rules = primary_rules + whitelist_rules + profile_rules
|
website_route_rules = primary_rules + whitelist_rules + profile_rules
|
||||||
|
|||||||
23
community/lms/api.py
Normal file
23
community/lms/api.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
"""API methods for the LMS.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def autosave_section(section, code):
|
||||||
|
"""Saves the code edited in one of the sections.
|
||||||
|
"""
|
||||||
|
doc = frappe.get_doc(
|
||||||
|
doctype="Code Revision",
|
||||||
|
section=section,
|
||||||
|
code=code,
|
||||||
|
author=frappe.session.user)
|
||||||
|
doc.insert()
|
||||||
|
return {"name": doc.name}
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_section(name):
|
||||||
|
"""Saves the code edited in one of the sections.
|
||||||
|
"""
|
||||||
|
doc = frappe.get_doc("LMS Section", name)
|
||||||
|
return doc and doc.as_dict()
|
||||||
@@ -3,9 +3,27 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
# import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
class LMSSection(Document):
|
class LMSSection(Document):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<LMSSection {self.label!r}>"
|
return f"<LMSSection {self.label!r}>"
|
||||||
|
|
||||||
|
def get_latest_code_for_user(self):
|
||||||
|
"""Returns the latest code for the logged in user.
|
||||||
|
"""
|
||||||
|
if not frappe.session.user or frappe.session.user == "Guest":
|
||||||
|
return self.contents
|
||||||
|
result = frappe.get_all('Code Revision',
|
||||||
|
fields=["code"],
|
||||||
|
filters={
|
||||||
|
"author": frappe.session.user,
|
||||||
|
"section": self.name
|
||||||
|
},
|
||||||
|
order_by="creation desc",
|
||||||
|
page_length=1)
|
||||||
|
if result:
|
||||||
|
return result[0]['code']
|
||||||
|
else:
|
||||||
|
return self.contents
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
{% if s.type == "text" %}
|
{% if s.type == "text" %}
|
||||||
{{ render_section_text(s) }}
|
{{ render_section_text(s) }}
|
||||||
{% elif s.type == "example" or s.type == "code" %}
|
{% elif s.type == "example" or s.type == "code" %}
|
||||||
{{ LiveCodeEditor(s.name, s.contents) }}
|
{{ LiveCodeEditor(s.name, s.get_latest_code_for_user()) }}
|
||||||
{% else %}
|
{% else %}
|
||||||
<div>Unknown section type: {{s.type}}</div>
|
<div>Unknown section type: {{s.type}}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -63,11 +63,40 @@
|
|||||||
<script type="text/javascript" src="{{ livecode_url }}/static/livecode.js"></script>
|
<script type="text/javascript" src="{{ livecode_url }}/static/livecode.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function() {
|
$(function() {
|
||||||
|
var editorLookup = {};
|
||||||
|
|
||||||
$(".canvas-editor").each((i, e) => {
|
$(".canvas-editor").each((i, e) => {
|
||||||
|
var data = $(e).data();
|
||||||
var editor = new LiveCodeEditor(e, {
|
var editor = new LiveCodeEditor(e, {
|
||||||
runtime: "python-canvas",
|
runtime: "python-canvas",
|
||||||
base_url: "{{ livecode_url }}",
|
base_url: "{{ livecode_url }}",
|
||||||
codemirror: true
|
codemirror: true,
|
||||||
|
userdata: data,
|
||||||
|
autosave: function(editor, code) {
|
||||||
|
var data = editor.options.userdata;
|
||||||
|
var code = editor.codemirror.doc.getValue();
|
||||||
|
// console.log("autosaving...")
|
||||||
|
frappe.call("community.lms.api.autosave_section", {
|
||||||
|
section: data.section,
|
||||||
|
code: code
|
||||||
|
}).then((r) => {
|
||||||
|
// TODO: verify
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
editorLookup[data.section] = editor;
|
||||||
|
})
|
||||||
|
|
||||||
|
$(".canvas-editor .reset").each((i, e) => {
|
||||||
|
$(e).on("click", function(event) {
|
||||||
|
var data = $(this).parents(".canvas-editor").data();
|
||||||
|
var section = data.section;
|
||||||
|
frappe.call("community.lms.api.get_section", {
|
||||||
|
name: section
|
||||||
|
}).then(r => {
|
||||||
|
var editor = editorLookup[data.section];
|
||||||
|
editor.codemirror.doc.setValue(r.message.contents);
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -21,7 +21,8 @@
|
|||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro LiveCodeEditor(name, code) %}
|
{% macro LiveCodeEditor(name, code) %}
|
||||||
<div class="livecode-editor canvas-editor" id="editor-{{name}}">
|
<div class="livecode-editor canvas-editor" id="editor-{{name}}"
|
||||||
|
data-section="{{name}}">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
Reference in New Issue
Block a user