Compare commits

...

27 Commits

Author SHA1 Message Date
pateljannat
4c55f1f71c fix: exhibitor template 2021-08-19 12:16:05 +05:30
Summayya
eb58b1c149 fix: remove hover 2021-08-18 23:53:02 +05:30
Summayya
af9760f944 fix: remove div in schedule template 2021-08-18 19:49:12 +05:30
Summayya
21b2412362 fix: remove dummy data 2021-08-18 19:41:37 +05:30
Summayya
7e5e167eec fix: remove dummy data 2021-08-18 19:40:35 +05:30
Summayya
7c3189e273 fix:conflict 2021-08-18 11:41:09 +05:30
Summayya
ace74febc7 Template for Previous content 2021-08-18 11:37:04 +05:30
Summayya
8dbdabd52c Create web templates for event management 2021-08-17 22:31:15 +05:30
Jannat Patel
f0ee8d7b88 Merge pull request #173 from fossunited/sketch-redesign
fix: sketch cards
2021-08-16 13:47:05 +05:30
Jannat Patel
7e5203f058 Merge pull request #179 from fossunited/discussions
feat: Discussions
2021-08-16 13:45:00 +05:30
pateljannat
a3672e9d91 feat: discussions 2021-08-16 13:33:08 +05:30
pateljannat
7017382451 fix: removed sketch card 2021-08-11 11:40:57 +05:30
pateljannat
6c9d49bf8c discussion doctypes 2021-08-11 11:14:40 +05:30
pateljannat
2de058246b Merge branch 'main' of https://github.com/frappe/community into main 2021-08-11 10:46:11 +05:30
pateljannat
798ea30382 fix: chapter teaser jerk issue 2021-08-11 10:46:01 +05:30
pateljannat
3e2c6b3343 fix: sketch image call 2021-08-10 17:08:32 +05:30
pateljannat
5ea744de5c fix: removed unused file 2021-08-10 16:46:48 +05:30
pateljannat
aedb3d3d45 fix: sketch cards 2021-08-10 16:39:17 +05:30
Jannat Patel
83a2f42df9 Merge pull request #171 from fossunited/username-fixes
fix: username issues
2021-08-10 13:19:29 +05:30
pateljannat
66aace247c fix: conditions and tests 2021-08-10 10:28:59 +05:30
pateljannat
bc3db06960 fix: username issues 2021-08-09 16:54:02 +05:30
Jannat Patel
ddaa063587 Merge pull request #170 from fossunited/upcoming-course-notify
feat: notify me
2021-08-09 15:39:04 +05:30
pateljannat
f9b4fe468e fix: removed unused import 2021-08-09 13:27:09 +05:30
pateljannat
6cbca8d1bb feat: notify me 2021-08-09 13:13:48 +05:30
Jannat Patel
d5067a4bcd Merge pull request #169 from fossunited/username-validations
fix: Username validations
2021-08-06 15:05:36 +05:30
Jannat Patel
145b5efab0 Merge pull request #168 from fossunited/minor-issues
fix: quiz, course outline, and lesson indexing
2021-08-05 18:41:15 +05:30
pateljannat
4079ed97b9 fix: quiz, course outline, and lesson indexing 2021-08-05 18:26:41 +05:30
125 changed files with 2633 additions and 405 deletions

View File

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

View File

@@ -1,67 +1,53 @@
{ {
"actions": [], "actions": [],
"creation": "2021-03-19 12:19:32.355307", "creation": "2021-08-11 10:59:38.597046",
"doctype": "DocType", "doctype": "DocType",
"editable_grid": 1, "editable_grid": 1,
"engine": "InnoDB", "engine": "InnoDB",
"field_order": [ "field_order": [
"author", "thread",
"batch", "column_break_2",
"column_break_3", "parent_message",
"author_name", "section_break_4",
"pin",
"section_break_6",
"message" "message"
], ],
"fields": [ "fields": [
{
"fieldname": "batch",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Batch",
"options": "LMS Batch"
},
{
"fieldname": "author",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Author",
"options": "User"
},
{ {
"fieldname": "message", "fieldname": "message",
"fieldtype": "Markdown Editor", "fieldtype": "Long Text",
"in_list_view": 1, "in_list_view": 1,
"label": "Message" "label": "Message"
}, },
{ {
"default": "0", "fieldname": "thread",
"fieldname": "pin", "fieldtype": "Link",
"fieldtype": "Check", "in_list_view": 1,
"label": "Pin" "in_standard_filter": 1,
"label": "Thread",
"options": "Discussion Thread"
}, },
{ {
"fetch_from": "author.full_name", "fieldname": "column_break_2",
"fieldname": "author_name",
"fieldtype": "Data",
"label": "Author Name",
"read_only": 1
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break" "fieldtype": "Column Break"
}, },
{ {
"fieldname": "section_break_6", "fieldname": "parent_message",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Parent Message",
"options": "Discussion Message"
},
{
"fieldname": "section_break_4",
"fieldtype": "Section Break" "fieldtype": "Section Break"
} }
], ],
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"links": [], "links": [],
"modified": "2021-05-21 11:49:34.911479", "modified": "2021-08-12 15:59:04.811286",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "Community",
"name": "LMS Message", "name": "Discussion Message",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {
@@ -77,9 +63,7 @@
"write": 1 "write": 1
} }
], ],
"quick_entry": 1,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"title_field": "author",
"track_changes": 1 "track_changes": 1
} }

View File

@@ -0,0 +1,22 @@
# 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 Widget, Widgets
class DiscussionMessage(Document):
def after_insert(self):
data = {
"message": self,
"widgets": Widgets()
}
template = frappe.render_template("community/templates/message_card.html", data)
thread_info = frappe.db.get_value("Discussion Thread", self.thread, ["reference_doctype", "reference_docname"], as_dict=True)
frappe.publish_realtime(event="publish_message",
message = {
"thread": self.thread,
"template": template,
"thread_info": thread_info
},
after_commit=True)

View File

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

View File

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

View File

@@ -0,0 +1,57 @@
{
"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 Thread",
"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
}

View File

@@ -0,0 +1,48 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
import frappe
from frappe.model.document import Document
class DiscussionThread(Document):
pass
@frappe.whitelist()
def submit_discussion(doctype, docname, message, title=None, thread_name=None):
thread = []
filters = {}
if doctype and docname:
filters = {
"reference_doctype": doctype,
"reference_docname": docname
}
elif thread_name:
filters = {
"name": thread_name
}
if filters:
thread = frappe.get_all("Discussion Thread",filters)
if len(thread):
thread = thread[0]
save_message(message, thread)
else:
thread = frappe.get_doc({
"doctype": "Discussion Thread",
"title": title,
"reference_doctype": doctype,
"reference_docname": docname
})
thread.save(ignore_permissions=True)
save_message(message, thread)
return thread.name
def save_message(message, thread):
frappe.get_doc({
"doctype": "Discussion Message",
"message": message,
"thread": thread.name
}).save(ignore_permissions=True)

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
# import frappe
import unittest
class TestDiscussionThread(unittest.TestCase):
pass

View File

@@ -0,0 +1,70 @@
<div class="discussions">
<form class="discussion-form {% if doctype or thread %} discussion-on-page {% endif %}" id="discussion-form">
<div class="form-group" {% if title or thread %} style="display: none;" {% endif %}>
<div class="control-input-wrapper">
<div class="control-input">
<input type="text" autocomplete="off" class="input-with-feedback form-control thread-title"
data-fieldtype="Data" data-fieldname="feedback_comments" placeholder="Title" spellcheck="false" {% if title
%} value="{{ title }}" {% endif %}></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-secondary pull-right" id="submit-discussion"
{% if doctype %} data-doctype="{{ doctype | urlencode}}" {% endif %}
{% if docname %} data-docname="{{ docname | urlencode}}" {% endif %}
{% if thread %} data-thread="{{ thread }}" {% endif %}>
Post</div>
</div>
</form>
</div>
<script>
frappe.ready(() => {
$("#submit-discussion").click((e) => {
submit_discussion(e);
})
})
var submit_discussion = (e) => {
var message = $(".comment-field").val().trim();
if (message) {
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_thread.discussion_thread.submit_discussion",
args: {
"doctype": doctype ? doctype : "",
"docname": docname ? docname : "",
"message": $(".comment-field").val(),
"title": $(".thread-title").val(),
"thread_name": $(e.currentTarget).attr("data-thread")
},
callback: (data) => {
if (! $(".discussion-on-page").length) {
$("#discussion-modal").modal("hide");
window.location.href = `/discussions/${data.message}`;
}
}
})
}
}
</script>

View File

@@ -0,0 +1,80 @@
{% if doctype and docname and not thread %}
{% set thread_info = frappe.get_all("Discussion Thread", {"reference_doctype": doctype, "reference_docname": docname},
["name"]) %}
{% if thread_info | length %}
{% set thread = thread_info[0].name %}
{% endif %}
{% endif %}
{% if thread %}
{% set messages = frappe.get_all("Discussion Message", {"thread": thread}, ["name", "message", "owner", "creation"],
order_by="creation") %}
{% endif %}
{% if doctype %}
<div class="course-home-headings mt-5"> Discussions </div>
{% endif %}
<div class="messages mt-5">
{% for message in messages %}
{% include "community/templates/message_card.html" %}
{% endfor %}
</div>
{% if frappe.session.user == "Guest" or (condition is defined and not condition) %}
<div class="d-flex flex-column align-items-center font-weight-bold">
Want to join the discussion?
{% if frappe.session.user == "Guest" %}
<div class="button is-primary" id="login-from-discussion">Log In</div>
{% elif not condition %}
<div class="button is-primary" id="login-from-discussion" data-redirect="{{ redirect_to }}">{{ button_name }}</div>
{% endif %}
</div>
{% else %}
{{ widgets.DiscussionComment(doctype=doctype, docname=docname, title=title, thread=thread ) }}
{% endif %}
<script>
frappe.ready(() => {
setup_socket_io();
$("#login-from-discussion").click((e) => {
login_from_discussion(e);
})
})
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);
var target = $("#submit-discussion");
frappe.socketio.socket.on("publish_message", (data) => {
if (target.attr("data-thread") == data.thread
|| (decodeURIComponent(target.attr("data-doctype")) == data.thread_info.reference_doctype
&& decodeURIComponent(target.attr("data-docname")) == data.thread_info.reference_docname)) {
$(".comment-field").val("");
$(".messages").append(data.template);
}
})
})
}
var login_from_discussion = (e) => {
var redirect = $(e.currentTarget).attr("data-redirect") || window.location.href;
window.location.href = `/login?redirect-to=${redirect}`;
}
</script>

View File

View File

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

View File

@@ -0,0 +1,77 @@
{
"actions": [],
"creation": "2021-08-11 10:07:53.262504",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"attendee_info_section",
"name1",
"email",
"phone_number",
"occupation",
"company",
"what_are_you_hoping_to_learn"
],
"fields": [
{
"fieldname": "attendee_info_section",
"fieldtype": "Section Break",
"label": "Attendee Info"
},
{
"fieldname": "name1",
"fieldtype": "Data",
"label": "Name"
},
{
"fieldname": "email",
"fieldtype": "Data",
"label": "Email"
},
{
"fieldname": "phone_number",
"fieldtype": "Data",
"label": "Phone Number"
},
{
"fieldname": "occupation",
"fieldtype": "Data",
"label": "Occupation"
},
{
"fieldname": "company",
"fieldtype": "Data",
"label": "Company"
},
{
"fieldname": "what_are_you_hoping_to_learn",
"fieldtype": "Text",
"label": "What are you hoping to learn"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-08-11 10:07:53.262504",
"modified_by": "Administrator",
"module": "Event Management",
"name": "Attendee Registration",
"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
}

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class AttendeeRegistration(Document):
pass

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
# import frappe
import unittest
class TestAttendeeRegistration(unittest.TestCase):
pass

View File

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

View File

@@ -0,0 +1,68 @@
{
"actions": [],
"autoname": "field:event_name",
"creation": "2021-08-11 10:05:41.072432",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"event_name",
"start_date",
"end_date",
"event_description"
],
"fields": [
{
"fieldname": "event_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Event Name",
"reqd": 1,
"unique": 1
},
{
"fieldname": "start_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Start Date",
"reqd": 1
},
{
"fieldname": "end_date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "End Date",
"reqd": 1
},
{
"fieldname": "event_description",
"fieldtype": "Markdown Editor",
"in_list_view": 1,
"label": "Event Description"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-08-18 23:51:30.432691",
"modified_by": "Administrator",
"module": "Event Management",
"name": "Event Details",
"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
}

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class EventDetails(Document):
pass

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
# import frappe
import unittest
class TestEventDetails(unittest.TestCase):
pass

View File

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

View File

@@ -0,0 +1,55 @@
{
"actions": [],
"creation": "2021-08-11 11:17:28.452289",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"event",
"ticket",
"attendee"
],
"fields": [
{
"fieldname": "ticket",
"fieldtype": "Data",
"label": "Ticket"
},
{
"fieldname": "attendee",
"fieldtype": "Link",
"label": "attendee",
"options": "Attendee Registration"
},
{
"fieldname": "event",
"fieldtype": "Link",
"label": "Event",
"options": "Event Details"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-08-18 09:51:14.654098",
"modified_by": "Administrator",
"module": "Event Management",
"name": "Event Ticket",
"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
}

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class EventTicket(Document):
pass

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
# import frappe
import unittest
class TestEventTicket(unittest.TestCase):
pass

View File

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

View File

@@ -0,0 +1,54 @@
{
"actions": [],
"autoname": "Exhibitor-Regis-.####.",
"creation": "2021-08-16 16:26:46.189119",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"full_name",
"company",
"logo"
],
"fields": [
{
"fieldname": "full_name",
"fieldtype": "Data",
"label": "Full Name"
},
{
"fieldname": "company",
"fieldtype": "Data",
"label": "Company "
},
{
"fieldname": "logo",
"fieldtype": "Attach Image",
"label": "Logo"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-08-18 20:08:31.591935",
"modified_by": "Administrator",
"module": "Event Management",
"name": "Exhibitor Registration",
"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
}

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class ExhibitorRegistration(Document):
pass

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
# import frappe
import unittest
class TestExhibitorRegistration(unittest.TestCase):
pass

View File

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

View File

@@ -0,0 +1,65 @@
{
"actions": [],
"autoname": "field:full_name",
"creation": "2021-08-11 10:51:47.234690",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"event",
"full_name",
"user_image",
"title"
],
"fields": [
{
"fieldname": "event",
"fieldtype": "Link",
"label": "Event",
"options": "Event Details"
},
{
"fieldname": "title",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Title"
},
{
"fieldname": "full_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Full Name",
"reqd": 1,
"unique": 1
},
{
"fieldname": "user_image",
"fieldtype": "Attach Image",
"label": "Image"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-08-11 23:54:17.790263",
"modified_by": "Administrator",
"module": "Event Management",
"name": "Host",
"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
}

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class Host(Document):
pass

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
# import frappe
import unittest
class TestHost(unittest.TestCase):
pass

View File

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

View File

@@ -0,0 +1,67 @@
{
"actions": [],
"autoname": "format:PRE-VID-BY-{name_of_the_speaker}-{####}",
"creation": "2021-08-18 08:42:58.711932",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"event",
"title",
"name_of_the_speaker",
"url",
"thumbnail"
],
"fields": [
{
"fieldname": "title",
"fieldtype": "Data",
"label": "Title"
},
{
"fieldname": "name_of_the_speaker",
"fieldtype": "Data",
"label": "Name of the Speaker"
},
{
"fieldname": "url",
"fieldtype": "Data",
"label": "Video Embed Link"
},
{
"fieldname": "thumbnail",
"fieldtype": "Data",
"label": "Preview Image (Link)"
},
{
"fieldname": "event",
"fieldtype": "Link",
"label": "Event",
"options": "Event Details"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-08-18 09:37:03.278439",
"modified_by": "Administrator",
"module": "Event Management",
"name": "Previous Content",
"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
}

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PreviousContent(Document):
pass

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
# import frappe
import unittest
class TestPreviousContent(unittest.TestCase):
pass

View File

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

View File

@@ -0,0 +1,63 @@
{
"actions": [],
"autoname": "Schedule-.####",
"creation": "2021-08-11 10:50:23.522178",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"event",
"speaker",
"slot"
],
"fields": [
{
"fieldname": "speaker",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Speaker",
"options": "Speaker Registration",
"reqd": 1
},
{
"fieldname": "slot",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Slot",
"options": "Slot",
"reqd": 1
},
{
"fieldname": "event",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Event",
"options": "Event Details",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-08-18 09:46:18.694910",
"modified_by": "Administrator",
"module": "Event Management",
"name": "Schedule",
"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
}

View File

@@ -0,0 +1,18 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
import frappe
from frappe.model.document import Document
class Schedule(Document):
def before_save(self):
exists = frappe.db.exists(
"Schedule",
{
"Event": self.event,
"slot": self.slot
},
)
if exists:
frappe.throw("Slot already Assigned")

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
# import frappe
import unittest
class TestSchedule(unittest.TestCase):
pass

View File

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

View File

@@ -0,0 +1,69 @@
{
"actions": [],
"autoname": "format:SLOT-{date}-{start_time}",
"creation": "2021-08-11 11:19:50.276917",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"event",
"date",
"start_time",
"end_time"
],
"fields": [
{
"fieldname": "event",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Event",
"options": "Event Details",
"reqd": 1
},
{
"fieldname": "date",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Date",
"reqd": 1
},
{
"fieldname": "start_time",
"fieldtype": "Time",
"in_list_view": 1,
"label": "Start Time",
"reqd": 1
},
{
"fieldname": "end_time",
"fieldtype": "Time",
"in_list_view": 1,
"label": "End Time",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-08-18 23:51:47.850435",
"modified_by": "Administrator",
"module": "Event Management",
"name": "Slot",
"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
}

View File

@@ -0,0 +1,14 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
import frappe
from frappe.model.document import Document
from frappe.utils import getdate
class Slot(Document):
def before_save(self):
event = frappe.get_doc("Event Details", self.event)
if getdate(self.date) < event.start_date or getdate(self.date) > event.end_date:
frappe.throw("Slot should be in Event's span")

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
# import frappe
import unittest
class TestSlot(unittest.TestCase):
pass

View File

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

View File

@@ -0,0 +1,149 @@
{
"actions": [],
"autoname": "SPEAKER-REGIS.####.",
"creation": "2021-08-11 10:37:32.124651",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"speaker_info_section",
"full_name",
"email",
"phone_number",
"job_title",
"company",
"column_break_8",
"picture",
"bio",
"talk_info_section",
"topic",
"title",
"column_break_13",
"about",
"attachment",
"status"
],
"fields": [
{
"fieldname": "speaker_info_section",
"fieldtype": "Section Break",
"label": "Speaker Info"
},
{
"fieldname": "email",
"fieldtype": "Data",
"label": "Email",
"reqd": 1,
"unique": 1
},
{
"fieldname": "phone_number",
"fieldtype": "Data",
"label": "Phone Number",
"unique": 1
},
{
"fieldname": "job_title",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Job Title",
"reqd": 1
},
{
"fieldname": "company",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Company",
"reqd": 1
},
{
"fieldname": "picture",
"fieldtype": "Attach Image",
"label": "Profile Image",
"reqd": 1
},
{
"fieldname": "bio",
"fieldtype": "Text",
"label": "Bio"
},
{
"fieldname": "talk_info_section",
"fieldtype": "Section Break",
"label": "Talk Info"
},
{
"fieldname": "topic",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Topic",
"options": "Delivery\nCloud\nCustomer Success\nMarketing\nDevelopment\nHR\nCustomer Stories",
"reqd": 1
},
{
"fieldname": "title",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Title",
"reqd": 1
},
{
"fieldname": "about",
"fieldtype": "Text",
"label": "About",
"reqd": 1
},
{
"fieldname": "attachment",
"fieldtype": "Attach",
"label": "Attachment"
},
{
"fieldname": "column_break_8",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_13",
"fieldtype": "Column Break"
},
{
"default": "Applied",
"fieldname": "status",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Status",
"options": "Applied\nPending\nApproved\nRejected"
},
{
"fieldname": "full_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Full Name",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-08-18 09:48:19.602309",
"modified_by": "Administrator",
"module": "Event Management",
"name": "Speaker Registration",
"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
}

View File

@@ -0,0 +1,10 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
import frappe
from frappe.model.document import Document
class SpeakerRegistration(Document):
def on_update(self):
pass

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
# import frappe
import unittest
class TestSpeakerRegistration(unittest.TestCase):
pass

View File

@@ -0,0 +1,3 @@
frappe.ready(function() {
// bind events here
})

View File

@@ -0,0 +1,122 @@
{
"accept_payment": 0,
"allow_comments": 0,
"allow_delete": 0,
"allow_edit": 0,
"allow_incomplete": 0,
"allow_multiple": 0,
"allow_print": 0,
"amount": 0.0,
"amount_based_on_field": 0,
"apply_document_permissions": 0,
"button_label": "Register",
"creation": "2021-08-11 10:08:24.418743",
"doc_type": "Attendee Registration",
"docstatus": 0,
"doctype": "Web Form",
"idx": 0,
"is_standard": 1,
"login_required": 1,
"max_attachment_size": 0,
"modified": "2021-08-18 11:35:06.067390",
"modified_by": "Administrator",
"module": "Event Management",
"name": "attendee-registration",
"owner": "Administrator",
"payment_button_label": "Buy Now",
"published": 1,
"route": "event/conference2021/attendee-registration",
"route_to_success_link": 0,
"show_attachments": 0,
"show_in_grid": 0,
"show_sidebar": 0,
"sidebar_items": [],
"success_url": "/event/conference20221",
"title": "Attendee Registration",
"web_form_fields": [
{
"allow_read_on_all_link_options": 0,
"fieldname": "attendee_info_section",
"fieldtype": "Section Break",
"hidden": 0,
"label": "Attendee Info",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "name1",
"fieldtype": "Data",
"hidden": 0,
"label": "Name",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "email",
"fieldtype": "Data",
"hidden": 0,
"label": "Email",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "phone_number",
"fieldtype": "Data",
"hidden": 0,
"label": "Phone Number",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "occupation",
"fieldtype": "Data",
"hidden": 0,
"label": "Occupation",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "company",
"fieldtype": "Data",
"hidden": 0,
"label": "Company",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "what_are_you_hoping_to_learn",
"fieldtype": "Text",
"hidden": 0,
"label": "What are you hoping to learn",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
}
]
}

View File

@@ -0,0 +1,5 @@
import frappe
def get_context(context):
# do your magic here
pass

View File

@@ -0,0 +1,3 @@
frappe.ready(function() {
// bind events here
})

View File

@@ -0,0 +1,74 @@
{
"accept_payment": 0,
"allow_comments": 0,
"allow_delete": 0,
"allow_edit": 0,
"allow_incomplete": 0,
"allow_multiple": 0,
"allow_print": 0,
"amount": 0.0,
"amount_based_on_field": 0,
"apply_document_permissions": 0,
"button_label": "Save",
"creation": "2021-08-16 16:27:06.566564",
"doc_type": "Exhibitor Registration",
"docstatus": 0,
"doctype": "Web Form",
"idx": 0,
"is_standard": 1,
"login_required": 1,
"max_attachment_size": 0,
"modified": "2021-08-17 11:51:02.929819",
"modified_by": "Administrator",
"module": "Event Management",
"name": "exhibitor-registration",
"owner": "Administrator",
"payment_button_label": "Buy Now",
"published": 1,
"route": "event/conference2021/exhibitor-registration",
"route_to_success_link": 0,
"show_attachments": 0,
"show_in_grid": 0,
"show_sidebar": 0,
"sidebar_items": [],
"success_url": "/exhibitor-registration",
"title": "Exhibitor Registration",
"web_form_fields": [
{
"allow_read_on_all_link_options": 0,
"fieldname": "full_name",
"fieldtype": "Data",
"hidden": 0,
"label": "Full Name",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "company",
"fieldtype": "Data",
"hidden": 0,
"label": "Company ",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "logo",
"fieldtype": "Attach Image",
"hidden": 0,
"label": "Logo",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
}
]
}

View File

@@ -0,0 +1,5 @@
import frappe
def get_context(context):
# do your magic here
pass

View File

@@ -0,0 +1,3 @@
frappe.ready(function() {
// bind events here
})

View File

@@ -0,0 +1,218 @@
{
"accept_payment": 0,
"allow_comments": 0,
"allow_delete": 0,
"allow_edit": 0,
"allow_incomplete": 0,
"allow_multiple": 0,
"allow_print": 0,
"amount": 0.0,
"amount_based_on_field": 0,
"apply_document_permissions": 0,
"button_label": "Submit",
"creation": "2021-08-11 20:52:20.308925",
"doc_type": "Speaker Registration",
"docstatus": 0,
"doctype": "Web Form",
"idx": 0,
"introduction_text": "<div class=\"ql-editor read-mode\"><p><br></p></div>",
"is_standard": 1,
"login_required": 1,
"max_attachment_size": 0,
"modified": "2021-08-18 20:00:46.756407",
"modified_by": "Administrator",
"module": "Event Management",
"name": "speaker-registration",
"owner": "Administrator",
"payment_button_label": "Buy Now",
"published": 1,
"route": "event/conference2021/speaker-registration",
"route_to_success_link": 1,
"show_attachments": 0,
"show_in_grid": 0,
"show_sidebar": 0,
"sidebar_items": [],
"success_url": "/event/conference2021/about",
"title": "Speaker Registration",
"web_form_fields": [
{
"allow_read_on_all_link_options": 0,
"fieldname": "speaker_info_section",
"fieldtype": "Section Break",
"hidden": 0,
"label": "Speaker Info",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "full_name",
"fieldtype": "Data",
"hidden": 0,
"label": "Full Name",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "email",
"fieldtype": "Data",
"hidden": 0,
"label": "Email",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "phone_number",
"fieldtype": "Data",
"hidden": 0,
"label": "Phone Number",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "job_title",
"fieldtype": "Data",
"hidden": 0,
"label": "Job Title",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "company",
"fieldtype": "Data",
"hidden": 0,
"label": "Company",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "column_break_8",
"fieldtype": "Column Break",
"hidden": 0,
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "picture",
"fieldtype": "Attach Image",
"hidden": 0,
"label": "Picture",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "bio",
"fieldtype": "Text",
"hidden": 0,
"label": "Bio",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "talk_info_section",
"fieldtype": "Section Break",
"hidden": 0,
"label": "Talk Info",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "topic",
"fieldtype": "Select",
"hidden": 0,
"label": "Topic",
"max_length": 0,
"max_value": 0,
"options": "Delivery\nCloud\nCustomer Success\nMarketing\nDevelopment\nHR\nCustomer Stories",
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "title",
"fieldtype": "Data",
"hidden": 0,
"label": "Title",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "column_break_13",
"fieldtype": "Column Break",
"hidden": 0,
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "about",
"fieldtype": "Data",
"hidden": 0,
"label": "About",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 1,
"show_in_filter": 0
},
{
"allow_read_on_all_link_options": 0,
"fieldname": "attachment",
"fieldtype": "Attach",
"hidden": 0,
"label": "Attachment",
"max_length": 0,
"max_value": 0,
"read_only": 0,
"reqd": 0,
"show_in_filter": 0
}
]
}

View File

@@ -0,0 +1,5 @@
import frappe
def get_context(context):
# do your magic here
pass

View File

@@ -0,0 +1,20 @@
<div class="section-with-cards">
<div class="courses-header">
<span>{{ title }}</span>
{% set cta_link = "/exhibitor-registration" if frappe.session.user != "Guest" else
"/login?redirect_to=exhibitor-registration" %}
<a href={{cta_link}} class="button is-primary pull-right">Become an Exhibitor</a>
</div>
<div class="speaker-cards-parent">
{% for exhibitor in exhibitor_details %}
{% set exhibitor_doc = frappe.db.get_value("Exhibitor Registration", exhibitor.exhibitor, ["logo", "company"],
as_dict=True) %}
<div class="common-card-style flex-column exhibitor-card">
<span>
<img class="standard-image company-logo" src="{{exhibitor_doc.logo}}" />
</span>
<div class="font-weight-bold mt-5">{{exhibitor_doc.company}}</div>
</div>
{% endfor %}
</div>
</div>

View File

@@ -0,0 +1,49 @@
{
"__unsaved": 1,
"creation": "2021-08-13 15:05:41.606772",
"docstatus": 0,
"doctype": "Web Template",
"fields": [
{
"fieldname": "title",
"fieldtype": "Data",
"label": "Title",
"reqd": 0
},
{
"fieldname": "subtitle",
"fieldtype": "Data",
"label": "Subtitle",
"reqd": 0
},
{
"fieldname": "event",
"fieldtype": "Link",
"label": "Event",
"options": "Event Details",
"reqd": 0
},
{
"fieldname": "exhibitor_details",
"fieldtype": "Table Break",
"label": "Exhibitor Details",
"reqd": 0
},
{
"fieldname": "exhibitor",
"fieldtype": "Link",
"label": "Exhibitor",
"options": "Exhibitor Registration",
"reqd": 0
}
],
"idx": 1,
"modified": "2021-08-19 10:57:20.815230",
"modified_by": "Administrator",
"module": "Event Management",
"name": "Exhibitor Section",
"owner": "Administrator",
"standard": 1,
"template": "",
"type": "Section"
}

View File

@@ -0,0 +1,38 @@
<div class="section-with-cards">
<div class="course-home-headings">{{title}}</div>
<div class="speaker-cards-parent">
{% for video in talk_details %}
{% set video_details = frappe.get_doc('Previous Content', video.previous_content, filters={
'event': event
}) %}
<div class="common-card-style talk-card">
<div class="course-image" style="background-image: url({{video_details.thumbnail}})">
<div class="course-tags"></div>
</div>
<div class="course-card-content">
<div class="course-card-meta muted-text">
<span> ERPNext </span>
</div>
<div class="course-card-title">{{video_details.title}}</div>
<div class="card-divider"></div>
<div class="course-card-meta-2">
<a class="button-links" href="/rushabh">
<span class="avatar avatar-small" title="Rushabh Mehta">
<img class="avatar-frame standard-image" style="object-fit: cover"
src="{{video_details.thumbnail}}"
title={{video_details.name_of_the_speaker}} />
</span>
</a>
<span class="course-instructor"> {{video_details.name_of_the_speaker}} </span>
<span class="small-title company-name"></span>
</div>
<div class="view-talk-link">
Vew Talk
<img class="ml-3" src="/assets/community/icons/black-arrow.svg" />
</div>
<a class="stretched-link" href="{{video_details.url}}"></a>
</div>
</div>
{% endfor %}
</div>
</div>

View File

@@ -0,0 +1,52 @@
{
"__unsaved": 1,
"creation": "2021-08-13 11:34:07.611034",
"docstatus": 0,
"doctype": "Web Template",
"fields": [
{
"fieldname": "title",
"fieldtype": "Data",
"label": "Title",
"reqd": 1
},
{
"fieldname": "subtitle",
"fieldtype": "Data",
"label": "Subtitle",
"reqd": 0
},
{
"__unsaved": 1,
"fieldname": "event",
"fieldtype": "Link",
"label": "Event",
"options": "Event Details",
"reqd": 1
},
{
"fieldname": "talk_details",
"fieldtype": "Table Break",
"label": "Talk Details",
"reqd": 0
},
{
"__islocal": 1,
"__unsaved": 1,
"fieldname": "previous_content",
"fieldtype": "Link",
"label": "Previous Content",
"options": "Previous Content",
"reqd": 0
}
],
"idx": 1,
"modified": "2021-08-18 10:03:50.193908",
"modified_by": "Administrator",
"module": "Event Management",
"name": "Previous Talk",
"owner": "Administrator",
"standard": 1,
"template": "",
"type": "Section"
}

View File

@@ -0,0 +1,78 @@
{% set schedule_docs = frappe.get_all("Schedule", fields =["speaker", "slot"], filters={
'event': event
},) %}
{% set slot_data = {} %}
{% for schedule in schedule_docs %}
{% set speaker = frappe.get_doc("Speaker Registration", schedule.speaker) %}
{% set slot = frappe.get_doc("Slot", schedule.slot) %}
{% set slot_data = slot_data.setdefault(slot.date, []).append({
"slot": slot.name|string,
"start_time": slot.start_time,
"end_time": slot.end_time,
"speaker": speaker.name,
"picture": speaker.picture,
"about": speaker.about,
"title": speaker.title,
"full_name": speaker.full_name,
"email": speaker.email
}) %}
{% endfor %}
<div class="courses-header">{{title}}</div>
<div class="common-page-style">
<div class="container">
<div class="course-content-parent">
<div class="course-details-outline">
<div class="course-home-outline">
<div class="coure-outline">
<div>
{% for day in slot_data %}
<div class="small-title chapter-title" data-target="#apps-sites-and-bench"
data-toggle="collapse" aria-expanded="false">
<img class="chapter-icon" src="/assets/community/icons/chevron-right.svg" />
{{day}}
</div>
<div class="card-divider"></div>
</div>
{% endfor %}
</div>
</div>
<div>
{% for day in slot_data %}
{% set outer_loop = loop %}
<div class="course-details-outline">
<div class="course-home-headings">{{day}}</div>
<div class="coure-outline">
{% for slot in slot_data[day] %}
<div class="schedule-container">
<div class="schedule-inner-container">
<span class="info-speaker-avatar">
<span class="info-avatar avatar avatar-small">
<img class="avatar-frame standard-image" src="{{slot.picture}}" />
</span>
<h6 class="info-speaker">{{slot.full_name}}</h6>
</span>
<div class="schedule-title">{{slot.title}}</div>
<div class="schedule-slot">
{{ frappe.format(slot.start_time, {'fieldtype': 'Time'})}} - {{
frappe.format(slot.end_time, {'fieldtype': 'Time'}) }}
</div>
<div class="chapter-title small-title" data-toggle="collapse" data-target="#slot-{{loop.index}}-{{outer_loop.index}}" aria-expanded="false" aria-controls="collapseExample">
<img class="chapter-icon" src="/assets/community/icons/chevron-right.svg">
</div>
</div>
<div class="collapse" id="slot-{{loop.index}}-{{outer_loop.index}}">
<p class="schedule-info">{{slot.about}}</p>
</div>
<div class="card-divider"></div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,37 @@
{
"__unsaved": 1,
"creation": "2021-08-17 16:43:49.506200",
"docstatus": 0,
"doctype": "Web Template",
"fields": [
{
"fieldname": "title",
"fieldtype": "Data",
"label": "Title",
"reqd": 1
},
{
"fieldname": "subtitle",
"fieldtype": "Data",
"label": "Subtitle",
"reqd": 0
},
{
"__unsaved": 1,
"fieldname": "event",
"fieldtype": "Link",
"label": "Event",
"options": "Event Details",
"reqd": 1
}
],
"idx": 0,
"modified": "2021-08-18 10:13:49.300196",
"modified_by": "Administrator",
"module": "Event Management",
"name": "Schedule Section",
"owner": "Administrator",
"standard": 1,
"template": "",
"type": "Section"
}

View File

@@ -0,0 +1,23 @@
<div class="section-with-cards">
<h1 class="course-home-headings">{{section_title}}</h1>
<div class="speaker-cards-parent">
{% for speaker in speaker_details %}
{% set speaker_doc = frappe.get_doc("Speaker Registration", speaker.speaker) %}
<div class="common-card-style member-card">
<span class="avatar avatar-large">
<img class="avatar-frame" src="{{speaker_doc.picture}}" />
</span>
<div class="small-title talk-title mt-5">
{{ speaker_doc.full_name }}
</div>
<div class="small-title mt-5 bb">{{speaker_doc.job_title}}</div>
<div class="small-title company-name">{{speaker_doc.company}}</div>
</div>
{% endfor %}
</div>
{%- if cta_link -%}
<div class="event-btn"><a href={{cta_link}} class="btn btn-primary ">Become a Speaker</a></div>
{%- endif -%}
</div>

View File

@@ -0,0 +1,56 @@
{
"__unsaved": 1,
"creation": "2021-08-12 21:15:14.492000",
"docstatus": 0,
"doctype": "Web Template",
"fields": [
{
"fieldname": "section_title",
"fieldtype": "Data",
"label": "Section Title",
"reqd": 1
},
{
"fieldname": "subtitle",
"fieldtype": "Data",
"label": "Subtitle",
"reqd": 0
},
{
"__unsaved": 1,
"fieldname": "event_",
"fieldtype": "Link",
"label": "Event ",
"options": "Event Details",
"reqd": 0
},
{
"fieldname": "cta_link",
"fieldtype": "Data",
"label": "CTA Link",
"reqd": 0
},
{
"fieldname": "speaker_details",
"fieldtype": "Table Break",
"label": "Speaker Details",
"reqd": 0
},
{
"fieldname": "speaker",
"fieldtype": "Link",
"label": "Speaker",
"options": "Speaker Registration",
"reqd": 0
}
],
"idx": 1,
"modified": "2021-08-18 10:06:03.032441",
"modified_by": "Administrator",
"module": "Event Management",
"name": "Speaker Section",
"owner": "Administrator",
"standard": 1,
"template": "",
"type": "Section"
}

View File

@@ -145,7 +145,8 @@ primary_rules = [
{"from_route": "/courses/<course>/discuss", "to_route": "batch/discuss"}, {"from_route": "/courses/<course>/discuss", "to_route": "batch/discuss"},
{"from_route": "/courses/<course>/about", "to_route": "batch/about"}, {"from_route": "/courses/<course>/about", "to_route": "batch/about"},
{"from_route": "/courses/<course>/progress", "to_route": "batch/progress"}, {"from_route": "/courses/<course>/progress", "to_route": "batch/progress"},
{"from_route": "/courses/<course>/join", "to_route": "batch/join"} {"from_route": "/courses/<course>/join", "to_route": "batch/join"},
{"from_route": "/discussions/<discussion>", "to_route": "discussions/discussion"}
] ]
# Any frappe default URL is blocked by profile-rules, add it here to unblock it # Any frappe default URL is blocked by profile-rules, add it here to unblock it
@@ -167,7 +168,13 @@ whitelist = [
"/new-sign-up", "/new-sign-up",
"/message", "/message",
"/about", "/about",
"/edit-profile" "/edit-profile",
"/attendee-registration",
"/speaker-registration",
"/event",
"/hello",
"/exhibitor-registration",
"/discussions"
] ]
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]

View File

@@ -13,6 +13,38 @@ from ...utils import slugify
class LMSCourse(Document): class LMSCourse(Document):
def on_update(self):
if not self.upcoming and self.has_value_changed("upcoming"):
self.send_email_to_interested_users()
def send_email_to_interested_users(self):
interested_users = frappe.get_all("LMS Course Interest",
{
"course": self.name
},
["name", "user"])
subject = self.title + " is available!"
args = {
"title": self.title,
"course_link": "/courses/{0}".format(self.name),
"app_name": frappe.db.get_single_value("System Settings", "app_name"),
"site_url": frappe.utils.get_url()
}
for user in interested_users:
args["first_name"] = frappe.db.get_value("User", user.user, "first_name")
email_args = frappe._dict(
recipients = user.user,
sender = frappe.db.get_single_value("LMS Settings", "email_sender"),
subject = subject,
header = [subject, "green"],
template = "lms_course_interest",
args = args,
now = True
)
frappe.enqueue(method=frappe.sendmail, queue='short', timeout=300, is_async=True, **email_args)
frappe.db.set_value("LMS Course Interest", user.name, "email_sent", True)
@staticmethod @staticmethod
def find(name): def find(name):
"""Returns the course with specified name. """Returns the course with specified name.
@@ -194,7 +226,13 @@ class LMSCourse(Document):
"""Returns the {chapter_index}.{lesson_index} for the lesson. """Returns the {chapter_index}.{lesson_index} for the lesson.
""" """
lesson = frappe.db.get_value("Lessons", {"lesson": lesson_name}, ["idx", "parent"], as_dict=True) lesson = frappe.db.get_value("Lessons", {"lesson": lesson_name}, ["idx", "parent"], as_dict=True)
if not lesson:
return None
chapter = frappe.db.get_value("Chapters", {"chapter": lesson.parent}, ["idx"], as_dict=True) chapter = frappe.db.get_value("Chapters", {"chapter": lesson.parent}, ["idx"], as_dict=True)
if not chapter:
return None
return f"{chapter.idx}.{lesson.idx}" return f"{chapter.idx}.{lesson.idx}"
def reindex_exercises(self): def reindex_exercises(self):

View File

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

View File

@@ -0,0 +1,61 @@
{
"actions": [],
"creation": "2021-08-06 17:37:20.184849",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"course",
"user",
"email_sent"
],
"fields": [
{
"fieldname": "course",
"fieldtype": "Link",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Course",
"options": "LMS Course"
},
{
"fieldname": "user",
"fieldtype": "Link",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "User",
"options": "User"
},
{
"default": "0",
"fieldname": "email_sent",
"fieldtype": "Check",
"label": "Email Sent",
"options": "email_sent"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-08-06 18:06:21.370741",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Course Interest",
"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
}

View File

@@ -0,0 +1,17 @@
# Copyright (c) 2021, FOSS United and contributors
# For license information, please see license.txt
import frappe
from frappe.model.document import Document
class LMSCourseInterest(Document):
pass
@frappe.whitelist()
def capture_interest(course):
frappe.get_doc({
"doctype": "LMS Course Interest",
"course": course,
"user": frappe.session.user
}).save(ignore_permissions=True)
return "OK"

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2021, FOSS United and Contributors
# See license.txt
# import frappe
import unittest
class TestLMSCourseInterest(unittest.TestCase):
pass

View File

@@ -1,110 +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 frappe import _
from frappe.utils import add_days, nowdate
class LMSMessage(Document):
def after_insert(self):
self.publish_message()
#Todo: Adding email preference field for users
#self.send_email()
def publish_message(self):
template = self.get_message_template()
message = frappe._dict({
"author_name": self.author_name,
"message_time": frappe.utils.format_datetime(self.creation, "dd-mm-yyyy HH:mm"),
"message": frappe.utils.md_to_html(self.message)
})
js = """
$(".msger-input").val("");
var template = `{0}`;
var message = {1};
var session_user = ("{2}" == frappe.session.user) ? true : false;
message.author_name = session_user ? "You" : message.author_name
message.is_author = session_user;
template = frappe.render_template(template, {{
"message": message
}})
$(".messages").append(template);
var message_element = document.getElementsByClassName("messages")[0]
message_element.scrollTo(0, message_element.scrollHeight);
""".format(template, message, self.owner)
frappe.publish_realtime(event="eval_js", message=js, after_commit=True)
def get_message_template(self):
return """
<li class="{% if message.is_author %} ours {% endif %}">
<div class="d-flex justify-content-between">
<div class="font-weight-bold">
{{ message.author_name }}
</div>
<small class="">
{{ message.message_time }}
</small>
</div>
<div class="message-para">
{{ message.message }}
</div>
</li>
"""
def send_email(self):
membership = frappe.get_all("LMS Batch Membership", {"batch": self.batch}, ["member"])
for entry in membership:
member = frappe.get_doc("User", entry.member)
if member.name != self.author:
#Todo: wrap sendmail in frappe.enqueue, else messages takes long to display.
frappe.sendmail(
recipients = member.email,
subject = _("New Message on ") + self.batch,
header = _("New Message on ") + self.batch,
template = "lms_message",
args = {
"author": self.author,
"message": frappe.utils.md_to_html(self.message),
"creation": frappe.utils.format_datetime(self.creation, "medium"),
"course": frappe.db.get_value("LMS Batch", self.batch, ["course"])
}
)
def send_daily_digest():
#Todo: Optimize this
emails = frappe._dict()
messages = frappe.get_all("LMS Message", {"creation": [">=", add_days(nowdate(), -1)]}, ["message", "batch", "author", "creation"])
for message in messages:
membership = frappe.get_all("LMS Batch Membership", {"batch": message.batch}, ["member"])
for entry in membership:
member = frappe.db.get_value("User", entry.member, ["name", "email"], as_dict=1)
if member.name != message.author:
if member.name in emails.keys():
emails[member.name]["messages"].append(message)
else:
emails[member.name] = frappe._dict({
"email": member.email,
"messages": [message]
})
for email in emails:
group_by_batch = frappe._dict()
for message in emails[email]["messages"]:
if message.batch in group_by_batch.keys():
group_by_batch[message.batch].append(message)
else:
group_by_batch[message.batch] = [message]
frappe.sendmail(
recipients = frappe.db.get_value("User", email, "email"),
subject = _("Message Digest"),
header = _("Message Digest"),
template = "lms_daily_digest",
args = {
"batches": group_by_batch
},
delayed = False
)

View File

@@ -1,8 +1,9 @@
<div class="breadcrumb"> <div class="breadcrumb">
<a class="dark-links" href="/courses">All Courses</a>
<img class="ml-1 mr-1" src="/assets/community/icons/chevron-right.svg">
{% if course %} {% 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 %} {% if lesson %}
<a class="dark-links" href="/courses/{{ course.name }}">{{ course.title }}</a> <a class="dark-links" href="/courses/{{ course.name }}">{{ course.title }}</a>
<img class="ml-1 mr-1" src="/assets/community/icons/chevron-right.svg"> <img class="ml-1 mr-1" src="/assets/community/icons/chevron-right.svg">
@@ -12,8 +13,9 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if member_name %} {% if thread %}
<span class="muted-text">{{ member_name }}</span> <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 %} {% endif %}
</div> </div>

View File

@@ -1,6 +1,6 @@
<div> <div>
<div class="small-title chapter-title" data-target="#{{ course.get_slugified_chapter_title(chapter.title) }}" <div class="chapter-title small-title" data-target="#{{ course.get_slugified_chapter_title(chapter.title) }}"
data-toggle="collapse" aria-expanded="false"> data-toggle="collapse" aria-expanded="false">
<img class="chapter-icon" src="/assets/community/icons/chevron-right.svg"> <img class="chapter-icon" src="/assets/community/icons/chevron-right.svg">
{{ index }}. {{ chapter.title }} {{ index }}. {{ chapter.title }}
@@ -27,7 +27,7 @@
{{ lesson.title }} {{ lesson.title }}
{% if membership %} {% if membership %}
<img class="lesson-progress-tick {{ course.get_progress(lesson.name) != 'Complete' and 'hide' }}" <img class="ml-1 lesson-progress-tick {{ course.get_progress(lesson.name) != 'Complete' and 'hide' }}"
src="/assets/community/icons/check.svg"> src="/assets/community/icons/check.svg">
{% endif %} {% endif %}

View File

@@ -58,7 +58,7 @@
{% set query_parameter = "?batch=" + membership.batch if membership and membership.batch else "" %} {% set query_parameter = "?batch=" + membership.batch if membership and membership.batch else "" %}
{% if course.upcoming %} {% if course.upcoming %}
<div class="view-course-link is-default"> <div class="view-course-link is-secondary border">
Upcoming Course <img class="ml-3" src="/assets/community/icons/black-arrow.svg" /> Upcoming Course <img class="ml-3" src="/assets/community/icons/black-arrow.svg" />
</div> </div>
<a class="stretched-link" href="/courses/{{ course.name }}"></a> <a class="stretched-link" href="/courses/{{ course.name }}"></a>

View File

@@ -1,16 +0,0 @@
<div class="sketch-teaser">
<div class="sketch-image">
<a href="/sketches/{{sketch.sketch_id}}">
{{ sketch.to_svg() }}
</a>
</div>
<div class="sketch-footer">
<div class="sketch-title">
<a href="sketches/{{sketch.sketch_id}}">{{sketch.title}}</a>
</div>
<div class="sketch-author">
{% set owner = sketch.get_owner() %}
by <a href="/{{owner.username}}">{{owner.full_name}}</a>
</div>
</div>
</div>

View File

@@ -2,3 +2,4 @@ Community
Hackathon Hackathon
LMS LMS
Conference Conference
Event Management

View File

@@ -34,14 +34,22 @@ class TestCustomUser(unittest.TestCase):
}).insert() }).insert()
self.assertEqual(new_user.username[:8], "username") self.assertEqual(new_user.username[:8], "username")
def test_with_hyphen_at_end(self): def test_with_underscore_at_end(self):
new_user = frappe.get_doc({ new_user = frappe.get_doc({
"doctype": "User", "doctype": "User",
"email": "test_with_hyphen_at_end@example.com", "email": "test_with_underscore_at_end@example.com",
"first_name": "Username---" "first_name": "Username___"
}).insert() }).insert()
length = len(new_user.username) self.assertNotEqual(new_user.username[-1], "_")
self.assertNotEqual(new_user.username[length-1], "-")
def test_with_short_first_name(self):
new_user = frappe.get_doc({
"doctype": "User",
"email": "test_with_short_first_name@example.com",
"first_name": "USN"
}).insert()
self.assertGreaterEqual(len(new_user.username), 4)
@classmethod @classmethod
def tearDownClass(cls) -> None: def tearDownClass(cls) -> None:
@@ -49,6 +57,7 @@ class TestCustomUser(unittest.TestCase):
"test_with_basic_username@example.com", "test_with_basic_username@example.com",
"test-without-username@example.com", "test-without-username@example.com",
"test_with_illegal_characters@example.com", "test_with_illegal_characters@example.com",
"test_with_hyphen_at_end@example.com" "test_with_underscore_at_end@example.com",
"test_with_short_first_name@example.com"
] ]
frappe.db.delete("User", {"name": ["in", users]}) frappe.db.delete("User", {"name": ["in", users]})

View File

@@ -13,38 +13,45 @@ class CustomUser(User):
self.validate_username_characters() self.validate_username_characters()
def validate_username_characters(self): def validate_username_characters(self):
if len(self.username):
underscore_condition = self.username[0] == "_" or self.username[-1] == "_"
else:
underscore_condition = ''
if self.is_new(): if self.is_new():
if not self.username:
self.username = self.get_username_from_first_name()
if self.username.find(" "): if self.username.find(" "):
self.username.replace(" ", "") self.username.replace(" ", "")
if not re.match("^[A-Za-z0-9_]*$", self.username): if not re.match("^[A-Za-z0-9_]*$", self.username) or underscore_condition:
self.username = self.remove_illegal_characters() self.username = self.remove_illegal_characters()
if not self.username: if len(self.username) < 4:
self.username = self.get_username_from_first_name() self.username = self.email.replace("@", "").replace(".", "")
if self.username_exists(): while self.username_exists():
self.username = self.remove_illegal_characters() + str(random.randint(0, 99)) self.username = self.remove_illegal_characters() + str(random.randint(0, 99))
else: else:
if not re.match("^[A-Za-z0-9_-]*$", self.username): if not self.username:
frappe.throw(_("Username can only contain alphabets, numbers, hyphen and underscore.")) frappe.throw(_("Username already exists."))
if self.username[0] == "-" or self.username[len(self.username) - 1] == "-": if not re.match("^[A-Za-z0-9_]*$", self.username):
frappe.throw(_("First and Last character of username cannot be Hyphen(-).")) frappe.throw(_("Username can only contain alphabets, numbers and unedrscore."))
if underscore_condition:
frappe.throw(_("First and Last character of username cannot be Underscore(_)."))
if len(self.username) < 4:
frappe.throw(_("Username cannot be less than 4 characters"))
def get_username_from_first_name(self): def get_username_from_first_name(self):
return frappe.scrub(self.first_name) + str(random.randint(0, 99)) return frappe.scrub(self.first_name) + str(random.randint(0, 99))
def remove_illegal_characters(self): def remove_illegal_characters(self):
username = ''.join([c for c in self.username if c.isalnum() or c in ['-', '_']]) return re.sub("[^\w]+", "", self.username).strip("_")
while username[0] == "-" or username[len(username) - 1] == "-":
if username[0] == "-":
username = username[1:]
if username[len(username) - 1]:
username = username[:1]
return username
def get_authored_courses(self) -> int: def get_authored_courses(self) -> int:
"""Returns the number of courses authored by this user. """Returns the number of courses authored by this user.

Some files were not shown because too many files have changed in this diff Show More