Compare commits
91 Commits
profile-ur
...
rename-app
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5af07086b | ||
|
|
4d534db63f | ||
|
|
aec69e96cb | ||
|
|
6172b09aa3 | ||
|
|
98c386729c | ||
|
|
91ebcd8253 | ||
|
|
3a51299e8d | ||
|
|
eaa8876f4e | ||
|
|
7d80178b48 | ||
|
|
8090f2f397 | ||
|
|
bf986e26bc | ||
|
|
c95d957d2c | ||
|
|
b1aaddae59 | ||
|
|
8fe9bad2bb | ||
|
|
23dab6312d | ||
|
|
c91b1a7a23 | ||
|
|
d07dbcc50a | ||
|
|
49771a627d | ||
|
|
25ec4ae7c6 | ||
|
|
13022e0bcc | ||
|
|
cdc4b6992d | ||
|
|
f178f3806d | ||
|
|
d84f621813 | ||
|
|
7ba2ac1efd | ||
|
|
658a9e6172 | ||
|
|
0b44e78cc2 | ||
|
|
1c5766d022 | ||
|
|
3bff000cc9 | ||
|
|
30a8750f16 | ||
|
|
f3ad3f6d18 | ||
|
|
65a7dde47b | ||
|
|
38ebab59c7 | ||
|
|
b7f79b4832 | ||
|
|
876a2f562f | ||
|
|
5f4fc2fb59 | ||
|
|
44e8efd39b | ||
|
|
51c625da4d | ||
|
|
a795cd23a8 | ||
|
|
ebc3cf1cbf | ||
|
|
c717b3ba9d | ||
|
|
0ed3c87f79 | ||
|
|
9499700988 | ||
|
|
8366721643 | ||
|
|
66afd0fcdd | ||
|
|
a105a1d3b4 | ||
|
|
5488947922 | ||
|
|
aa466f9fb7 | ||
|
|
b3840e056f | ||
|
|
ddffc8372b | ||
|
|
dc877a9c09 | ||
|
|
04d2384283 | ||
|
|
50938afe77 | ||
|
|
ea6bd1f598 | ||
|
|
fb0f9885c1 | ||
|
|
4248a3af07 | ||
|
|
a3dc2402f7 | ||
|
|
153b439510 | ||
|
|
06b925435d | ||
|
|
93c2c3cc45 | ||
|
|
04a3d58028 | ||
|
|
8551cfa32e | ||
|
|
b19c7f2fac | ||
|
|
d135338088 | ||
|
|
b8fae5cd28 | ||
|
|
29fe75d807 | ||
|
|
1dbbf7c769 | ||
|
|
3be20b5658 | ||
|
|
73b6ddf365 | ||
|
|
64048a8a18 | ||
|
|
e245af57a8 | ||
|
|
0ab708396a | ||
|
|
29855a0cbc | ||
|
|
ff6457171f | ||
|
|
9fd59b5d38 | ||
|
|
c750c62993 | ||
|
|
a0d90ab16b | ||
|
|
af15d978c6 | ||
|
|
f4271e7c0e | ||
|
|
0440e1062d | ||
|
|
2bc30d696a | ||
|
|
6dcd210031 | ||
|
|
c78c4c92b7 | ||
|
|
6a2c749a86 | ||
|
|
56d738474a | ||
|
|
7721f31342 | ||
|
|
90e268ff2f | ||
|
|
69bdb75625 | ||
|
|
b9736cc6d6 | ||
|
|
3a2ebd42a7 | ||
|
|
e0b25c1e6e | ||
|
|
13b968e18c |
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -53,19 +53,19 @@ jobs:
|
||||
then
|
||||
(cd && tar xzf ~/bench-cache/bench.tgz)
|
||||
else
|
||||
bench init ~/frappe-bench --skip-redis-config-generation
|
||||
bench init ~/frappe-bench --skip-redis-config-generation --skip-assets --python "$(which python)"
|
||||
mkdir -p ~/bench-cache
|
||||
(cd && tar czf ~/bench-cache/bench.tgz frappe-bench)
|
||||
fi
|
||||
- name: add community app to bench
|
||||
- name: add school app to bench
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: bench get-app community $GITHUB_WORKSPACE
|
||||
run: bench get-app school $GITHUB_WORKSPACE
|
||||
- name: create bench site
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: bench new-site --mariadb-root-password root --admin-password admin frappe.local
|
||||
- name: install community app
|
||||
- name: install school app
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: bench --verbose --site frappe.local install-app community
|
||||
run: bench --verbose --site frappe.local install-app school
|
||||
- name: allow tests
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: bench --site frappe.local set-config allow_tests true
|
||||
@@ -74,5 +74,5 @@ jobs:
|
||||
run: bench --site frappe.local build
|
||||
- name: run tests
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: bench --site frappe.local run-tests --app community
|
||||
run: bench --site frappe.local run-tests --app school
|
||||
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,8 +3,8 @@
|
||||
*.egg-info
|
||||
*.swp
|
||||
tags
|
||||
community/docs/current
|
||||
community/public/dist
|
||||
school/docs/current
|
||||
school/public/dist
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
24
MANIFEST.in
24
MANIFEST.in
@@ -4,15 +4,15 @@ include *.json
|
||||
include *.md
|
||||
include *.py
|
||||
include *.txt
|
||||
recursive-include community *.css
|
||||
recursive-include community *.csv
|
||||
recursive-include community *.html
|
||||
recursive-include community *.ico
|
||||
recursive-include community *.js
|
||||
recursive-include community *.json
|
||||
recursive-include community *.md
|
||||
recursive-include community *.png
|
||||
recursive-include community *.py
|
||||
recursive-include community *.svg
|
||||
recursive-include community *.txt
|
||||
recursive-exclude community *.pyc
|
||||
recursive-include school *.css
|
||||
recursive-include school *.csv
|
||||
recursive-include school *.html
|
||||
recursive-include school *.ico
|
||||
recursive-include school *.js
|
||||
recursive-include school *.json
|
||||
recursive-include school *.md
|
||||
recursive-include school *.png
|
||||
recursive-include school *.py
|
||||
recursive-include school *.svg
|
||||
recursive-include school *.txt
|
||||
recursive-exclude school *.pyc
|
||||
20
README.md
20
README.md
@@ -1,4 +1,4 @@
|
||||
## Community
|
||||
## School
|
||||
|
||||
This app helps people organize and manage their own communities.
|
||||
|
||||
@@ -7,16 +7,16 @@ The App has following components:
|
||||
1. Hackathons
|
||||
1. LMS
|
||||
|
||||
Community is built on the [Frappe Framework](https://github.com/frappe/frappe), a full-stack web app framework built with Python & JavaScript.
|
||||
School is built on the [Frappe Framework](https://github.com/frappe/frappe), a full-stack web app framework built with Python & JavaScript.
|
||||
|
||||
## Development Setup
|
||||
|
||||
**Step 1:** Clone the repo
|
||||
|
||||
```
|
||||
$ git clone https://github.com/fossunited/community.git
|
||||
$ git clone https://github.com/frappe/school.git
|
||||
|
||||
$ cd community
|
||||
$ cd school
|
||||
```
|
||||
|
||||
**Step 2:** Run docker-compose
|
||||
@@ -59,15 +59,15 @@ To setup the repository locally follow the steps mentioned below:
|
||||
|
||||
1. Install bench and setup a frappe-bench directory by following the [Installation Steps](https://frappeframework.com/docs/user/en/installation).
|
||||
1. Start the server by running bench start.
|
||||
1. In a separate terminal window, create a new site by running bench new-site community.test.
|
||||
1. Run bench get-app https://github.com/fossunited/community.
|
||||
1. Run bench --site community.test install-app community.
|
||||
1. Map your site to localhost with the command ```bench --site community.test add-to-hosts```
|
||||
1. Now open the URL http://community.test:8000/ in your browser, you should see the app running.
|
||||
1. In a separate terminal window, create a new site by running bench new-site school.test.
|
||||
1. Run bench get-app https://github.com/frappe/school.
|
||||
1. Run bench --site school.test install-app school.
|
||||
1. Map your site to localhost with the command ```bench --site school.test add-to-hosts```
|
||||
1. Now open the URL http://school.test:8000/ in your browser, you should see the app running.
|
||||
|
||||
### Contribution Guidelines (for The Hard Way)
|
||||
|
||||
1. Go to the apps/community directory of your installation and execute git pull --unshallow to ensure that you have the full git repository. Also fork the fossunited/community repository on GitHub.
|
||||
1. Go to the apps/school directory of your installation and execute git pull --unshallow to ensure that you have the full git repository. Also fork the frappe/school repository on GitHub.
|
||||
1. Check out a working branch in git (e.g. git checkout -b my-new-branch).
|
||||
1. Make your proposed changes to the source
|
||||
1. Run your local version (e.g. bench start in your bench installation). Make sure that your changes work the way you want them to.
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Discussion Reply', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
@@ -1,51 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2021-08-11 10:59:38.597046",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"topic",
|
||||
"reply"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "reply",
|
||||
"fieldtype": "Long Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Reply"
|
||||
},
|
||||
{
|
||||
"fieldname": "topic",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Topic",
|
||||
"options": "Discussion Topic"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-08-27 15:06:51.362714",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Community",
|
||||
"name": "Discussion Reply",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
from community.widgets import Widgets
|
||||
|
||||
class DiscussionReply(Document):
|
||||
def after_insert(self):
|
||||
data = {
|
||||
"reply": self,
|
||||
"topic": {
|
||||
"name": self.topic
|
||||
},
|
||||
"widgets": Widgets()
|
||||
}
|
||||
template = frappe.render_template("community/templates/discussions/reply_card.html", data)
|
||||
topic_info = frappe.get_all("Discussion Topic", {"name": self.topic}, ["reference_doctype", "reference_docname", "name", "title", "owner", "creation"])
|
||||
sidebar = frappe.render_template("community/templates/discussions/sidebar.html", { "topic": topic_info[0], "widgets": Widgets() })
|
||||
new_topic_template = frappe.render_template("community/templates/discussions/reply_section.html", { "topics": topic_info, "widgets": Widgets() })
|
||||
|
||||
frappe.publish_realtime(event="publish_message",
|
||||
message = {
|
||||
"template": template,
|
||||
"topic_info": topic_info[0],
|
||||
"sidebar": sidebar,
|
||||
"new_topic_template": new_topic_template
|
||||
},
|
||||
after_commit=True)
|
||||
@@ -1,8 +0,0 @@
|
||||
// Copyright (c) 2021, FOSS United and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Discussion Topic', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
});
|
||||
@@ -1,57 +0,0 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2021-08-11 10:55:29.341674",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"title",
|
||||
"reference_doctype",
|
||||
"reference_docname"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "title",
|
||||
"fieldtype": "Data",
|
||||
"label": "Title"
|
||||
},
|
||||
{
|
||||
"fieldname": "reference_doctype",
|
||||
"fieldtype": "Link",
|
||||
"label": "Reference Doctype",
|
||||
"options": "DocType"
|
||||
},
|
||||
{
|
||||
"fieldname": "reference_docname",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"label": "Reference Docname",
|
||||
"options": "reference_doctype"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-08-11 12:29:43.564123",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Community",
|
||||
"name": "Discussion 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": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "title",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
# Copyright (c) 2021, FOSS United and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
class DiscussionTopic(Document):
|
||||
pass
|
||||
|
||||
@frappe.whitelist()
|
||||
def submit_discussion(doctype, docname, reply, title, topic_name=None):
|
||||
if topic_name:
|
||||
save_message(reply, topic_name)
|
||||
return topic_name
|
||||
|
||||
topic = frappe.get_doc({
|
||||
"doctype": "Discussion Topic",
|
||||
"title": title,
|
||||
"reference_doctype": doctype,
|
||||
"reference_docname": docname
|
||||
})
|
||||
topic.save(ignore_permissions=True)
|
||||
save_message(reply, topic.name)
|
||||
return topic.name
|
||||
|
||||
def save_message(reply, topic):
|
||||
frappe.get_doc({
|
||||
"doctype": "Discussion Reply",
|
||||
"reply": reply,
|
||||
"topic": topic
|
||||
}).save(ignore_permissions=True)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_docname(route):
|
||||
return frappe.db.get_value("Web Page", {"route": route}, ["name"])
|
||||
@@ -1,2 +0,0 @@
|
||||
{% set docname = frappe.db.get_value("Web Page", {"route": ""}, ["name"])%}
|
||||
{{ widgets.DiscussionMessage(doctype="Web Page", docname=docname) }}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"__islocal": true,
|
||||
"__unsaved": 1,
|
||||
"creation": "2021-08-30 12:42:31.550200",
|
||||
"docstatus": 0,
|
||||
"doctype": "Web Template",
|
||||
"fields": [],
|
||||
"idx": 0,
|
||||
"modified": "2021-08-30 12:42:31.550200",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Community",
|
||||
"name": "Discussions",
|
||||
"owner": "Administrator",
|
||||
"standard": 1,
|
||||
"template": "",
|
||||
"type": "Section"
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<form class="discussion-form">
|
||||
|
||||
<div class="form-group">
|
||||
<div class="control-input-wrapper">
|
||||
<div class="control-input">
|
||||
<input type="text" autocomplete="off" class="input-with-feedback form-control topic-title" data-fieldtype="Data"
|
||||
data-fieldname="feedback_comments" placeholder="Title" spellcheck="false"></input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="control-input-wrapper">
|
||||
<div class="control-input">
|
||||
<textarea type="text" autocomplete="off" class="input-with-feedback form-control comment-field"
|
||||
data-fieldtype="Text" data-fieldname="feedback_comments" placeholder="Enter a comment..."
|
||||
spellcheck="false"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="comment-footer">
|
||||
<div class="button is-default pull-right mb-5 submit-discussion" data-doctype="{{ doctype | urlencode }}"
|
||||
data-docname="{{ docname | urlencode }}">
|
||||
Post</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
@@ -1,54 +0,0 @@
|
||||
{% set topics = frappe.get_all("Discussion Topic",
|
||||
{"reference_doctype": doctype, "reference_docname": docname}, ["name", "title", "owner", "creation"]) %}
|
||||
|
||||
{% include "community/templates/discussions/topic_modal.html" %}
|
||||
|
||||
<div class="discussions-parent">
|
||||
<div class="discussions-header">
|
||||
<span class="course-home-headings">{{_('Discussions')}}</span>
|
||||
{% if topics %}
|
||||
{% include "community/templates/discussions/button.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if topics %}
|
||||
<div class="common-card-style thread-card course-content-parent" data-doctype="{{ doctype }}"
|
||||
data-docname="{{ docname }}">
|
||||
|
||||
<div class="discussions-sidebar">
|
||||
{% include "community/templates/discussions/search.html" %}
|
||||
{% for topic in topics %}
|
||||
{% set replies = frappe.get_all("Discussion Reply", {"topic": topic.name})%}
|
||||
{% include "community/templates/discussions/sidebar.html" %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="mr-2" id="discussion-group">
|
||||
{% include "community/templates/discussions/reply_section.html" %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
|
||||
<div id="no-discussions" class="common-card-style thread-card">
|
||||
<div class="no-discussions">
|
||||
<div class="font-weight-bold">No Discussions</div>
|
||||
<div class="muted-text mt-3 mb-3">There are no discussions for this {{ doctype | lower }}, why don't you start
|
||||
one! </div>
|
||||
{% if frappe.session.user == "Guest" %}
|
||||
<div class="button is-primary mt-3" id="login-from-discussion">Log In</div>
|
||||
{% elif not condition %}
|
||||
<div class="button is-primary mt-3" id="login-from-discussion" data-redirect="{{ redirect_to }}">
|
||||
{{ button_name }}
|
||||
</div>
|
||||
{% else %}
|
||||
{% include "community/templates/discussions/button.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% block script %}
|
||||
<script>{% include "community/templates/discussions/discussions.js" %}</script>
|
||||
{% endblock %}
|
||||
@@ -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 TestChapter(unittest.TestCase):
|
||||
pass
|
||||
@@ -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 TestLesson(unittest.TestCase):
|
||||
pass
|
||||
@@ -1,4 +0,0 @@
|
||||
<div class="p-5 batch-header">
|
||||
<h3>{{batch_name}}</h3>
|
||||
<div class="text-muted">{{member_count}} members</div>
|
||||
</div>
|
||||
@@ -1,21 +0,0 @@
|
||||
<div class="breadcrumb">
|
||||
|
||||
|
||||
{% if course %}
|
||||
<a class="dark-links" href="/courses">All Courses</a>
|
||||
<img class="ml-1 mr-1" src="/assets/community/icons/chevron-right.svg">
|
||||
{% if lesson %}
|
||||
<a class="dark-links" href="/courses/{{ course.name }}">{{ course.title }}</a>
|
||||
<img class="ml-1 mr-1" src="/assets/community/icons/chevron-right.svg">
|
||||
<span class="muted-text"> {{ lesson.title }}</span>
|
||||
{% else %}
|
||||
<span class="muted-text">{{ course.title }}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if thread %}
|
||||
<a class="dark-links" href="/discussions">Discussions</a>
|
||||
<img class="ml-1 mr-1" src="/assets/community/icons/chevron-right.svg">
|
||||
<span class="muted-text">{{ thread.title }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -1,90 +0,0 @@
|
||||
<div class="common-card-style course-card">
|
||||
<div class="course-image {% if not course.image %}default-image{% endif %}"
|
||||
{% if course.image %} style="background-image: url( {{ course.image }} );" {% endif %}>
|
||||
<div class="course-tags">
|
||||
{% for tag in course.get_tags() %}
|
||||
<div class="course-card-pills">{{ tag }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if not course.image %}
|
||||
<div class="default-image-text">{{ course.title[0] }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="course-card-content">
|
||||
<div class="course-card-meta muted-text">
|
||||
{% if course.get_chapters() | length %}
|
||||
<span>
|
||||
{{ course.get_chapters() | length }} Chapters
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if course.get_chapters() | length and course.get_upcoming_batches() | length %}
|
||||
<span class="font-weight-bold ml-3 mr-3"> . </span>
|
||||
{% endif %}
|
||||
{% if course.get_upcoming_batches() | length %}
|
||||
<span class="">
|
||||
{{ course.get_upcoming_batches() | length }} Open Batches
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="course-card-title">{{ course.title }}</div>
|
||||
<div class="card-divider"></div>
|
||||
<div class="course-card-meta-2">
|
||||
{{ widgets.Avatar(member=course.get_instructor(), avatar_class="avatar-small") }}
|
||||
<span class="course-instructor">
|
||||
{{ course.get_instructor().full_name }}
|
||||
</span>
|
||||
<span class="course-student-count">
|
||||
{% if course.get_students() | length %}
|
||||
<span class="mr-4">
|
||||
<img class="icon-background" src="/assets/community/icons/user.svg" />
|
||||
{{ course.get_students() | length }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% set avg_rating = course.get_average_rating() %}
|
||||
{% if avg_rating %}
|
||||
<span>
|
||||
<img class="icon-background" src="/assets/community/icons/rating.svg" />
|
||||
{{ avg_rating }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
{% set membership = course.get_membership(frappe.session.user) %}
|
||||
|
||||
{% set lesson_index = course.get_lesson_index(membership.current_lesson) if membership and
|
||||
membership.current_lesson
|
||||
else '1.1' %}
|
||||
|
||||
{% set query_parameter = "?batch=" + membership.batch if membership and membership.batch else "" %}
|
||||
|
||||
{% if course.upcoming %}
|
||||
<div class="view-course-link is-secondary border">
|
||||
Upcoming Course <img class="ml-3" src="/assets/community/icons/black-arrow.svg" />
|
||||
</div>
|
||||
<a class="stretched-link" href="/courses/{{ course.name }}"></a>
|
||||
|
||||
{% elif membership %}
|
||||
<div class="view-course-link is-primary">
|
||||
Continue Course <img class="ml-3" src="/assets/community/icons/white-arrow.svg" />
|
||||
</div>
|
||||
<a class="stretched-link" href="{{ course.get_learn_url(lesson_index) }}{{ query_parameter }}"></a>
|
||||
|
||||
{% else %}
|
||||
<div class="view-course-link is-default">
|
||||
View Course <img class="ml-3" src="/assets/community/icons/black-arrow.svg" />
|
||||
</div>
|
||||
<a class="stretched-link" href="/courses/{{ course.name }}"></a>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
frappe.ready(() => {
|
||||
$(".course-card-title").each((i, element) => {
|
||||
var title = $(element).text();
|
||||
var length = $(window).width() <= 375 ? 60 : 65;
|
||||
var suffix = title.length > length ? "..." : "";
|
||||
$(element).text(title.substring(0, length) + suffix);
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@@ -1,6 +0,0 @@
|
||||
<div class="instructor">
|
||||
{{ widgets.Avatar(member=instructor, avatar_class="avatar-medium") }}
|
||||
<a class="ml-1 instructor-title" href="{{get_profile_url(instructor.username)}}">{{ instructor.full_name }}</a>
|
||||
<div class="instructor-subtitle">Course Creator</div>
|
||||
<!-- <div class="instructor-subtitle">Created {{instructor.get_course_count()}} courses</div> -->
|
||||
</div>
|
||||
@@ -1,37 +0,0 @@
|
||||
<div class="common-card-style">
|
||||
<div class="certificate-content">
|
||||
<div class="certificate-heading">
|
||||
Certificate of Completion
|
||||
</div>
|
||||
<div class="certificate-para">
|
||||
This is to certify that <span class="font-weight-bold">{{ student.full_name }}</span> has successfully completed
|
||||
<span class="font-weight-bold">{{ course.title }}</span> online course on
|
||||
<span class="font-weight-bold">{{ frappe.utils.format_date(certificate.issue_date, "medium") }}</span>
|
||||
</div>
|
||||
<div class="certificate-footer">
|
||||
{% if instructor %}
|
||||
<div>
|
||||
<span>
|
||||
Instructor:
|
||||
</span>
|
||||
<span class="font-weight-bold">
|
||||
{{ instructor.full_name }}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if certificate.expiry_date %}
|
||||
<div>
|
||||
<span>
|
||||
Expiry Date:
|
||||
</span>
|
||||
<span class="font-weight-bold">
|
||||
{{ frappe.utils.format_date(certificate.expiry_date, "medium") }}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<img src="{{ logo }}" class="certificate-logo">
|
||||
</div>
|
||||
<div class="certificate-ribbon"></div>
|
||||
</div>
|
||||
<script src="/assets/community/js/html2canvas.js"></script>
|
||||
@@ -1,7 +0,0 @@
|
||||
{% if frappe.session.user != "Guest" and
|
||||
(condition is not defined or (condition is defined and condition )) %}
|
||||
<span class="button is-secondary reply">
|
||||
New Discussion
|
||||
<img src="/assets/community/icons/small-add-black.svg">
|
||||
</span>
|
||||
{% endif %}
|
||||
@@ -1,198 +0,0 @@
|
||||
frappe.ready(() => {
|
||||
setup_socket_io();
|
||||
|
||||
set_docname_if_missing();
|
||||
|
||||
expand_first_discussion();
|
||||
|
||||
$(".search-field").keyup((e) => {
|
||||
search_topic(e);
|
||||
});
|
||||
|
||||
$(".reply").click((e) => {
|
||||
show_new_topic_modal(e);
|
||||
});
|
||||
|
||||
$("#login-from-discussion").click((e) => {
|
||||
login_from_discussion(e);
|
||||
});
|
||||
|
||||
$(".sidebar-topic").click((e) => {
|
||||
if ($(e.currentTarget).attr("aria-expanded") == "true") {
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("click", ".submit-discussion", (e) => {
|
||||
submit_discussion(e);
|
||||
});
|
||||
})
|
||||
|
||||
var show_new_topic_modal = (e) => {
|
||||
e.preventDefault();
|
||||
$("#discussion-modal").modal("show");
|
||||
var topic = $(e.currentTarget).attr("data-topic");
|
||||
$(".modal-headings").text(topic ? "Reply" : "Start a Discussion");
|
||||
topic ? $(".topic-title").addClass("hide") : $(".topic-title").removeClass("hide");
|
||||
$("#submit-discussion").attr("data-topic", topic ? topic : "");
|
||||
}
|
||||
|
||||
var setup_socket_io = () => {
|
||||
const assets = [
|
||||
"/assets/frappe/js/lib/socket.io.min.js",
|
||||
"/assets/frappe/js/frappe/socketio_client.js",
|
||||
]
|
||||
|
||||
frappe.require(assets, () => {
|
||||
if (window.dev_server) {
|
||||
frappe.boot.socketio_port = "9000";
|
||||
}
|
||||
frappe.socketio.init(9000);
|
||||
frappe.socketio.socket.on("publish_message", (data) => {
|
||||
publish_message(data);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
var publish_message = (data) => {
|
||||
post_message_cleanup();
|
||||
|
||||
if ($(`.discussion-on-page[data-topic=${data.topic_info.name}]`).length) {
|
||||
if ($(`.discussion-on-page[data-topic=${data.topic_info.name}] .card-divider-dark`).length) {
|
||||
$(data.template).insertAfter(`.discussion-on-page[data-topic=${data.topic_info.name}] .card-divider-dark`);
|
||||
}
|
||||
else {
|
||||
|
||||
$('<div class="card-divider-dark mb-10"></div>' + data.template).insertAfter(`.discussion-on-page[data-topic=${data.topic_info.name}] .discussion-form`);
|
||||
}
|
||||
}
|
||||
else if ((decodeURIComponent($(".discussions-parent .course-content-parent").attr("data-doctype")) == data.topic_info.reference_doctype
|
||||
&& decodeURIComponent($(".discussions-parent .course-content-parent").attr("data-docname")) == data.topic_info.reference_docname)) {
|
||||
$(data.sidebar).insertAfter(`.discussions-sidebar .form-group`);
|
||||
$(`#discussion-group`).prepend(data.new_topic_template);
|
||||
|
||||
if (data.topic_info.owner == frappe.session.user) {
|
||||
$(".discussion-on-page").collapse();
|
||||
$(".sidebar-topic").first().click();
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
update_reply_count(data.topic_info.name);
|
||||
}
|
||||
|
||||
var post_message_cleanup = () => {
|
||||
$(".comment-field").val("");
|
||||
$("#discussion-modal").modal("hide");
|
||||
$("#no-discussions").addClass("hide");
|
||||
}
|
||||
|
||||
var update_reply_count = (topic) => {
|
||||
var reply_count = $(`[data-target='#t${topic}']`).find(".reply-count").text();
|
||||
reply_count = parseInt(reply_count) + 1;
|
||||
$(`[data-target='#t${topic}']`).find(".reply-count").text(reply_count);
|
||||
}
|
||||
|
||||
var set_docname_if_missing = () => {
|
||||
if ($("[data-docname='None']").length) {
|
||||
frappe.call({
|
||||
method: "community.community.doctype.discussion_topic.discussion_topic.get_docname",
|
||||
args: {
|
||||
"route": window.location.href.split("/").slice(-1)[0]
|
||||
},
|
||||
callback: (data) => {
|
||||
$("[data-docname='None']").attr("data-docname", data.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var expand_first_discussion = () => {
|
||||
$($(".discussions-parent .collapse")[0]).addClass("show");
|
||||
$($(".discussions-sidebar [data-toggle='collapse']")[0]).attr("aria-expanded", true);
|
||||
}
|
||||
|
||||
var search_topic = (e) => {
|
||||
var input = $(e.currentTarget).val();
|
||||
|
||||
var topics = $(".discussions-parent .discussion-topic-title");
|
||||
if (input.length < 3 || input.trim() == "") {
|
||||
topics.closest(".sidebar-parent").removeClass("hide");
|
||||
return
|
||||
}
|
||||
|
||||
topics.each((i, elem) => {
|
||||
var topic_id = $(elem).parent().attr("data-target");
|
||||
|
||||
/* Check match in replies */
|
||||
var match_in_reply = false;
|
||||
var replies = $(`${topic_id}`);
|
||||
for (var reply of replies.find(".reply-text")) {
|
||||
if (has_common_substring($(reply).text(), input)) {
|
||||
match_in_reply = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Match found in title or replies, then show */
|
||||
if (has_common_substring($(elem).text(), input) || match_in_reply) {
|
||||
$(elem).closest(".sidebar-parent").removeClass("hide")
|
||||
}
|
||||
else {
|
||||
$(elem).closest(".sidebar-parent").addClass("hide");
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
var has_common_substring = (str1, str2) => {
|
||||
var str1_arr = str1.toLowerCase().split(" ");
|
||||
var str2_arr = str2.toLowerCase().split(" ");
|
||||
|
||||
var substring_found = false;
|
||||
for (var first_word of str1_arr) {
|
||||
for (var second_word of str2_arr) {
|
||||
if (first_word.indexOf(second_word) > -1) {
|
||||
substring_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return substring_found;
|
||||
}
|
||||
|
||||
var submit_discussion = (e) => {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
var title = $(".topic-title:visible").length ? $(".topic-title:visible").val().trim() : "";
|
||||
var reply = $(".comment-field:visible").val().trim();
|
||||
|
||||
if (reply) {
|
||||
var doctype = $(e.currentTarget).attr("data-doctype");
|
||||
doctype = doctype ? decodeURIComponent(doctype) : doctype;
|
||||
|
||||
var docname = $(e.currentTarget).attr("data-docname");
|
||||
docname = docname ? decodeURIComponent(docname) : docname;
|
||||
|
||||
frappe.call({
|
||||
method: "community.community.doctype.discussion_topic.discussion_topic.submit_discussion",
|
||||
args: {
|
||||
"doctype": doctype ? doctype : "",
|
||||
"docname": docname ? docname : "",
|
||||
"reply": reply,
|
||||
"title": title,
|
||||
"topic_name": $(e.currentTarget).closest(".discussion-on-page").attr("data-topic")
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var login_from_discussion = (e) => {
|
||||
var redirect = $(e.currentTarget).attr("data-redirect") || window.location.href;
|
||||
window.location.href = `/login?redirect-to=${redirect}`;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<div class="reply-card">
|
||||
{% set member = frappe.get_doc("User", reply.owner) %}
|
||||
<div class="d-flex align-items-center muted-text">
|
||||
{% set member = frappe.get_doc("User", reply.owner) %}
|
||||
{{ widgets.Avatar(member=member, avatar_class="avatar-small")}}
|
||||
<a class="button-links ml-2" href="{{ get_profile_url(member.username) }}">
|
||||
{{ member.full_name }}
|
||||
</a>
|
||||
<div class="ml-2 frappe-timestamp" data-timestamp="{{ reply.creation }}"> just now </div>
|
||||
</div>
|
||||
<div class="card-divider mt-3"></div>
|
||||
<div class="reply-text">{{ reply.reply }}</div>
|
||||
</div>
|
||||
@@ -1,41 +0,0 @@
|
||||
{% for topic in topics %}
|
||||
{% set replies = frappe.get_all("Discussion Reply", {"topic": topic.name},
|
||||
["reply", "owner", "creation"], order_by="creation desc")%}
|
||||
|
||||
<!-- Hack to reorganize the replies array. So even though we want reverse cronology, the first reply should appear first. -->
|
||||
{% if replies.insert(0, replies.pop()) %}{% endif %}
|
||||
|
||||
{% if replies %}
|
||||
<div class="collapse discussion-on-page" id="t{{ topic.name }}" data-topic="{{ topic.name }}"
|
||||
data-parent="#discussion-group">
|
||||
<div class="course-home-headings p-0">{{ topic.title }}</div>
|
||||
{% for reply in replies %}
|
||||
|
||||
{% if loop.index == 2 %}
|
||||
<div class="card-divider-dark mb-10"></div>
|
||||
{% endif %}
|
||||
|
||||
{% include "community/templates/discussions/reply_card.html" %}
|
||||
|
||||
{% if loop.index == 1 %}
|
||||
|
||||
{% if frappe.session.user == "Guest" or (condition is defined and not condition) %}
|
||||
<div class="d-flex flex-column align-items-center muted-text">
|
||||
Want to join the discussion?
|
||||
{% if frappe.session.user == "Guest" %}
|
||||
<div class="button is-primary mt-3 mb-3" id="login-from-discussion">Log In</div>
|
||||
{% elif not condition %}
|
||||
<div class="button is-primary mt-3 mb-3" id="login-from-discussion" data-redirect="{{ redirect_to }}">{{ button_name }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
{{ widgets.CommentBox(doctype=doctype, docname=docname) }}
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
@@ -1,9 +0,0 @@
|
||||
<div class="form-group">
|
||||
<div class="control-input-wrapper">
|
||||
<div class="control-input">
|
||||
<textarea type="text" autocomplete="off" class="input-with-feedback form-control search-field"
|
||||
data-fieldtype="Text" data-fieldname="feedback_comments" placeholder="Search Topics"
|
||||
spellcheck="false"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,20 +0,0 @@
|
||||
<div class="sidebar-parent">
|
||||
<div class="sidebar-topic" data-target="#t{{ topic.name }}" data-toggle="collapse" aria-expanded="false">
|
||||
<div class="discussion-topic-title">{{ topic.title }}</div>
|
||||
<div class="mt-2 mb-3">
|
||||
{% set creator = frappe.get_doc("User", topic.owner) %}
|
||||
{{ widgets.Avatar(member=creator, avatar_class="avatar-small") }}
|
||||
<span class="course-instructor">
|
||||
{{ creator.full_name }}
|
||||
</span>
|
||||
<span class="muted-text pull-right">
|
||||
<span class="mr-2">
|
||||
<img src="/assets/community/icons/message.svg">
|
||||
<span class="reply-count">{{ replies | length }}</span>
|
||||
</span>
|
||||
<span> {{ frappe.utils.format_date(topic.creation, "dd MMM YYYY") }} </span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-divider"></div>
|
||||
</div>
|
||||
@@ -1,15 +0,0 @@
|
||||
<div class="modal fade discussion-modal" id="discussion-modal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<div class="course-home-headings modal-headings">Start a Discussion</div>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{{ widgets.CommentBox(doctype=doctype, docname=docname) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,13 +0,0 @@
|
||||
<div class="discussion {% if message.is_author %} is-author {% endif %}">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="font-weight-bold">
|
||||
{{ message.author_name }}
|
||||
</div>
|
||||
<div class="text-muted">
|
||||
{{ message.message_time }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5">
|
||||
{{ message.message }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,22 +0,0 @@
|
||||
{% extends "templates/base.html" %}
|
||||
{% from "www/hackathons/macros/card.html" import null_card %}
|
||||
{% block title %}{{ 'Courses' }}{% endblock %}
|
||||
{% block head_include %}
|
||||
<style>
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="common-page-style">
|
||||
<div class="container">
|
||||
<div class="courses-header">
|
||||
{{ 'All Courses' }}
|
||||
</div>
|
||||
<div class="cards-parent">
|
||||
{% for course in courses %}
|
||||
{{ widgets.CourseCard(course=course) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,18 +0,0 @@
|
||||
import frappe
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
context.courses = get_courses()
|
||||
context.metatags = {
|
||||
"title": "All Courses",
|
||||
"image": frappe.db.get_single_value("Website Settings", "banner_image"),
|
||||
"description": "This page lists all the courses published on our website",
|
||||
"keywords": "All Courses, Courses, Learn"
|
||||
}
|
||||
|
||||
def get_courses():
|
||||
course_names = frappe.get_all("LMS Course", filters={"is_published": True}, pluck="name")
|
||||
courses = []
|
||||
for course in course_names:
|
||||
courses.append(frappe.get_doc("LMS Course", course))
|
||||
return courses
|
||||
@@ -17,9 +17,9 @@ services:
|
||||
bench:
|
||||
image: anandology/frappe-bench
|
||||
volumes:
|
||||
- .:/home/bench/frappe-bench/apps/community
|
||||
- .:/home/bench/frappe-bench/apps/school
|
||||
environment:
|
||||
- FRAPPE_APPS=community
|
||||
- FRAPPE_APPS=school
|
||||
- FRAPPE_ALLOW_TESTS=true
|
||||
- FRAPPE_SITE_NAME=frappe.localhost
|
||||
depends_on:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user