Merge branch 'main' of https://github.com/frappe/community into community-member-to-user-refactor

This commit is contained in:
pateljannat
2021-05-21 13:27:22 +05:30
36 changed files with 285 additions and 393 deletions

View File

@@ -24,6 +24,8 @@ class Exercise(Document):
},
order_by="creation desc",
page_length=1)
print("get_user_submission", result)
if result:
return result[0]
@@ -41,6 +43,8 @@ class Exercise(Document):
course = frappe.get_doc("LMS Course", self.course)
batch = course.get_student_batch(user)
image = livecode_to_svg(None, code)
doc = frappe.get_doc(
doctype="Exercise Submission",
exercise=self.name,
@@ -48,7 +52,8 @@ class Exercise(Document):
course=self.course,
lesson=self.lesson,
batch=batch and batch.name,
image=image,
solution=code)
doc.insert()
doc.insert(ignore_permissions=True)
return doc

View File

@@ -10,7 +10,8 @@
"exercise_title",
"course",
"batch",
"lesson"
"lesson",
"image"
],
"fields": [
{
@@ -54,11 +55,17 @@
"fieldtype": "Link",
"label": "Lesson",
"options": "Lesson"
},
{
"fieldname": "image",
"fieldtype": "Code",
"label": "Image",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-05-20 13:30:16.349278",
"modified": "2021-05-21 11:28:45.833018",
"modified_by": "Administrator",
"module": "LMS",
"name": "Exercise Submission",

View File

@@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from ..lms_topic.section_parser import SectionParser
from ...section_parser import SectionParser
class Lesson(Document):
def before_save(self):

View File

@@ -37,13 +37,37 @@ class LMSBatch(Document):
member_names = [m['member'] for m in memberships]
return find_all("User", name=["IN", member_names])
def is_member(self, email):
def is_member(self, email, member_type=None):
"""Checks if a person is part of a batch.
If member_type is specified, checks if the person is a Student/Mentor.
"""
member = find("Community Member", email=email)
return member and frappe.db.exists(
if not member:
return
filters = {
"batch": self.name,
"member": member.name
}
if member_type:
filters['member_type'] = member_type
return frappe.db.exists("LMS Batch Membership", filters)
def get_students(self):
"""Returns (email, full_name, username) of all the students of this batch as a list of dict.
"""
memberships = frappe.get_all(
"LMS Batch Membership",
{"batch": self.name, "member": member.name})
{"batch": self.name, "member_type": "Student"},
["member"])
member_names = [m['member'] for m in memberships]
members = frappe.get_all(
"Community Member",
{"name": ["IN", member_names]},
["email", "full_name", "username"])
return members
@frappe.whitelist()
def get_messages(batch):

View File

@@ -35,17 +35,6 @@ class LMSCourse(Document):
def __repr__(self):
return f"<Course#{self.name}>"
def get_topic(self, slug):
"""Returns the topic with given slug in this course as a Document.
"""
result = frappe.get_all(
"LMS Topic",
filters={"course": self.name, "slug": slug})
if result:
row = result[0]
return frappe.get_doc('LMS Topic', row['name'])
def has_mentor(self, email):
"""Checks if this course has a mentor with given email.
"""

View File

@@ -1,8 +0,0 @@
// Copyright (c) 2021, FOSS United and contributors
// For license information, please see license.txt
frappe.ui.form.on('LMS Topic', {
// refresh: function(frm) {
// }
});

View File

@@ -1,89 +0,0 @@
{
"actions": [],
"allow_guest_to_view": 1,
"creation": "2021-03-02 07:20:41.686573",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"course",
"title",
"slug",
"preview",
"description",
"order",
"sections"
],
"fields": [
{
"fieldname": "title",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Title",
"reqd": 1
},
{
"fieldname": "description",
"fieldtype": "Markdown Editor",
"label": "Description"
},
{
"fieldname": "course",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Course",
"options": "LMS Course",
"reqd": 1
},
{
"fieldname": "order",
"fieldtype": "Int",
"label": "Order"
},
{
"fieldname": "preview",
"fieldtype": "Markdown Editor",
"label": "Preview"
},
{
"fieldname": "sections",
"fieldtype": "Table",
"label": "Sections",
"options": "LMS Section"
},
{
"description": "The slug of the topic. Autogenerated from the title if not specified.",
"fieldname": "slug",
"fieldtype": "Data",
"label": "Slug"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-04-06 14:12:48.514062",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Topic",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"search_fields": "title",
"sort_field": "creation",
"sort_order": "ASC",
"title_field": "title",
"track_changes": 1,
"track_seen": 1,
"track_views": 1
}

View File

@@ -1,43 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from .section_parser import SectionParser
from ...utils import slugify
class LMSTopic(Document):
def before_save(self):
course = self.get_course()
if not self.slug:
self.slug = self.generate_slug(title=self.title)
sections = SectionParser().parse(self.description or "")
self.sections = [self.make_lms_section(i, s) for i, s in enumerate(sections)]
def get_course(self):
return frappe.get_doc("LMS Course", self.course)
def generate_slug(self, title):
result = frappe.get_all(
'LMS Topic',
filters={'course': self.course},
fields=['slug'])
slugs = set([row['slug'] for row in result])
return slugify(title, used_slugs=slugs)
def get_sections(self):
return sorted(self.sections, key=lambda s: s.index)
def make_lms_section(self, index, section):
s = frappe.new_doc('LMS Section', parent_doc=self, parentfield='sections')
s.type = section.type
s.label = section.label
s.contents = section.contents
s.index = index
return s

View File

@@ -1,84 +0,0 @@
"""Utility to split the text in the topic into multiple sections.
{{ section(type="example", id="foo") }}
circle(100, 100, 50)
{{ end }}
"""
from __future__ import annotations
from dataclasses import dataclass
import re
from typing import List, Tuple, Dict, Iterator
RE_SECTION = re.compile(r"^\{\{\s(\w+)\s*(?:\((.*)\))?\s*\}\}\s*")
class SectionParser:
def parse(self, text: str) -> Iterator[Section]:
"""Parses given text into sections and return an iterator over sections.
"""
lines = text.splitlines()
marked_lines = self.parse_lines(lines)
return self.group_sections(marked_lines)
def parse_lines(self, lines: List[str]) -> List[Tuple[str, str, str]]:
for line in lines:
m = RE_SECTION.match(line)
if m:
yield m.group(1), self.parse_attrs(m.group(2)), None
else:
yield None, None, line
def parse_attrs(self, attrs_str: str) -> Dict[str, str]:
# XXX-Anand: Hack
code = "dict({})".format(attrs_str or "")
return eval(code)
def group_sections(self, marked_lines) -> Iterator[Section]:
index = 0
def make_section(type='text', id=None, label=None, **attrs):
nonlocal index
index += 1
id = id or f"section-{index}"
label = label or id
return Section(
type=type,
id=id,
label=label,
attrs=attrs)
section = make_section("text")
for mark, attrs, line in marked_lines:
if not mark:
section.append(line)
continue
yield section
if mark == 'end':
section = make_section(type='text')
else:
section = make_section(**attrs)
yield section
@dataclass
class Section:
"""One section of the Topic.
"""
type: str
id: str
label: str
contents: str = ""
attrs: dict = None
def append(self, line):
if not line.endswith("\n"):
line = line + "\n"
self.contents += line
def __repr__(self):
attrs = dict(type=self.type, id=self.id, label=self.label, **self.attrs)
attrs_str = ", ".join(f'{k}="{v}"' for k, v in attrs.items())
return f'<Section({attrs_str})>'

View File

@@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
from __future__ import unicode_literals
# import frappe
import unittest
class TestLMSTopic(unittest.TestCase):
pass