diff --git a/lms/lms/doctype/lms_class/lms_class.py b/lms/lms/doctype/lms_class/lms_class.py index 2896ffd8..48e0e733 100644 --- a/lms/lms/doctype/lms_class/lms_class.py +++ b/lms/lms/doctype/lms_class/lms_class.py @@ -4,10 +4,10 @@ import frappe from frappe.model.document import Document from frappe import _ -from frappe.utils import cint +from frappe.utils import cint, format_date, format_datetime import requests -import urllib -from requests.auth import HTTPBasicAuth +import base64 +import json class LMSClass(Document): @@ -91,8 +91,40 @@ def update_course(class_name, course, value): @frappe.whitelist() -def create_live_class(class_name): - authenticate() +def create_live_class(class_name, title, duration, date, time, description=None): + date = format_date(date, "yyyy-mm-dd") + payload = { + "topic": title, + "start_time": format_datetime(f"{date} {time}", "yyyy-MM-ddTHH:mm:ssZ"), + "duration": duration, + "timezone": "IN", + "agenda": description, + "private_meeting": True, + } + headers = { + "Authorization": "Bearer " + authenticate(), + "content-type": "application/json", + } + response = requests.post( + "https://api.zoom.us/v2/users/me/meetings", headers=headers, data=json.dumps(payload) + ) + + if response.status_code == 201: + data = json.loads(response.text) + payload.update( + { + "doctype": "LMS Live Class", + "start_url": data.get("start_url"), + "join_url": data.get("join_url"), + "title": title, + "host": frappe.session.user, + "date": date, + "time": time, + } + ) + class_details = frappe.get_doc(payload) + class_details.save() + return class_details def authenticate(): @@ -100,10 +132,18 @@ def authenticate(): if not zoom.enable: frappe.throw(_("Please enable Zoom Settings to use this feature.")) - authenticate_url = "https://zoom.us/oauth/token?grant_type=client_credentials" - print(authenticate_url) - breakpoint - r = requests.get( - authenticate_url, auth=HTTPBasicAuth(zoom.client_id, zoom.client_secret) - ) - return r + authenticate_url = f"https://zoom.us/oauth/token?grant_type=account_credentials&account_id={zoom.account_id}" + + headers = { + "Authorization": "Basic " + + base64.b64encode( + bytes( + zoom.client_id + + ":" + + zoom.get_password(fieldname="client_secret", raise_exception=False), + encoding="utf8", + ) + ).decode() + } + response = requests.request("POST", authenticate_url, headers=headers) + return response.json()["access_token"] diff --git a/lms/lms/doctype/lms_live_class/__init__.py b/lms/lms/doctype/lms_live_class/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lms/lms/doctype/lms_live_class/lms_live_class.js b/lms/lms/doctype/lms_live_class/lms_live_class.js new file mode 100644 index 00000000..ebba6c7d --- /dev/null +++ b/lms/lms/doctype/lms_live_class/lms_live_class.js @@ -0,0 +1,8 @@ +// Copyright (c) 2023, Frappe and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("LMS Live Class", { +// refresh(frm) { + +// }, +// }); diff --git a/lms/lms/doctype/lms_live_class/lms_live_class.json b/lms/lms/doctype/lms_live_class/lms_live_class.json new file mode 100644 index 00000000..abecd7b0 --- /dev/null +++ b/lms/lms/doctype/lms_live_class/lms_live_class.json @@ -0,0 +1,156 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2023-03-02 10:59:01.741349", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "title", + "host", + "class", + "password", + "column_break_astv", + "description", + "section_break_glxh", + "date", + "timezone", + "column_break_spvt", + "start_time", + "duration", + "section_break_yrpq", + "start_url", + "column_break_yokr", + "join_url" + ], + "fields": [ + { + "fieldname": "title", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Title", + "reqd": 1 + }, + { + "fieldname": "description", + "fieldtype": "Text", + "label": "Description" + }, + { + "fieldname": "date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Date", + "reqd": 1 + }, + { + "fieldname": "start_time", + "fieldtype": "Time", + "label": "Start Time", + "reqd": 1 + }, + { + "fieldname": "duration", + "fieldtype": "Int", + "label": "Duration", + "reqd": 1 + }, + { + "fieldname": "timezone", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Timezone", + "reqd": 1 + }, + { + "fieldname": "class", + "fieldtype": "Link", + "label": "Class", + "options": "LMS Class" + }, + { + "fieldname": "host", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Host", + "options": "User", + "reqd": 1 + }, + { + "fieldname": "column_break_astv", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_glxh", + "fieldtype": "Section Break", + "label": "Date and Time" + }, + { + "fieldname": "column_break_spvt", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_yrpq", + "fieldtype": "Section Break" + }, + { + "fieldname": "start_url", + "fieldtype": "Small Text", + "label": "Start URL", + "read_only": 1 + }, + { + "fieldname": "column_break_yokr", + "fieldtype": "Column Break" + }, + { + "fieldname": "join_url", + "fieldtype": "Small Text", + "label": "Join URL", + "read_only": 1 + }, + { + "fieldname": "password", + "fieldtype": "Password", + "label": "Password" + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2023-03-02 17:47:07.807968", + "modified_by": "Administrator", + "module": "LMS", + "name": "LMS Live Class", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Moderator", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "track_changes": 1 +} \ No newline at end of file diff --git a/lms/lms/doctype/lms_live_class/lms_live_class.py b/lms/lms/doctype/lms_live_class/lms_live_class.py new file mode 100644 index 00000000..81de90d2 --- /dev/null +++ b/lms/lms/doctype/lms_live_class/lms_live_class.py @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Frappe and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class LMSLiveClass(Document): + pass diff --git a/lms/lms/doctype/lms_live_class/test_lms_live_class.py b/lms/lms/doctype/lms_live_class/test_lms_live_class.py new file mode 100644 index 00000000..b169369a --- /dev/null +++ b/lms/lms/doctype/lms_live_class/test_lms_live_class.py @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Frappe and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestLMSLiveClass(FrappeTestCase): + pass diff --git a/lms/lms/doctype/zoom_settings/zoom_settings.json b/lms/lms/doctype/zoom_settings/zoom_settings.json index df8f69b3..a20a6b5e 100644 --- a/lms/lms/doctype/zoom_settings/zoom_settings.json +++ b/lms/lms/doctype/zoom_settings/zoom_settings.json @@ -7,6 +7,7 @@ "field_order": [ "enable", "sb_00", + "account_id", "client_id", "client_secret" ], @@ -36,11 +37,16 @@ "fieldtype": "Password", "in_list_view": 1, "label": "Client Secret" + }, + { + "fieldname": "account_id", + "fieldtype": "Data", + "label": "Account ID" } ], "issingle": 1, "links": [], - "modified": "2023-02-27 14:30:28.696814", + "modified": "2023-03-01 17:15:59.722497", "modified_by": "Administrator", "module": "LMS", "name": "Zoom Settings", diff --git a/lms/public/css/style.css b/lms/public/css/style.css index 94a244cb..ede48338 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -1776,7 +1776,7 @@ li { } .modal-content { - font-size: var(--text-base) !important; + font-size: var(--text-sm) !important; } .modal-header, .modal-body { @@ -1790,11 +1790,14 @@ li { .modal-footer { padding: 0.75rem 1.5rem !important; border-top: none !important; - background-color: var(--gray-200) !important; + background-color: var(--gray-50) !important; + justify-content: flex-end !important; } .modal-header .modal-title { color: var(--gray-900); + line-height: 1.5rem; + margin-bottom: 0.5rem; } .frappe-chart .title { @@ -1977,3 +1980,7 @@ select { .common-page-style .tooltip-content { display: none; } + +.resize-none { + resize: none; +} diff --git a/lms/www/classes/class.html b/lms/www/classes/class.html index fb418d99..4d9788ea 100644 --- a/lms/www/classes/class.html +++ b/lms/www/classes/class.html @@ -191,9 +191,41 @@ {% macro LiveClassSection(class_info) %}
{% if is_moderator %} - + + + {% endif %}
{% endmacro %} + +{%- block script %} + {{ super() }} + {{ include_script('controls.bundle.js') }} +{% endblock %} diff --git a/lms/www/classes/class.js b/lms/www/classes/class.js index 9c13ad62..acf33173 100644 --- a/lms/www/classes/class.js +++ b/lms/www/classes/class.js @@ -11,8 +11,16 @@ frappe.ready(() => { update_course(e); }); + if ($("#live-class-form").length) { + make_live_class_form(); + } + + $("#open-class-modal").click((e) => { + e.preventDefault(); + $("#live-class-modal").modal("show"); + }); + $("#create-live-class").click((e) => { - console.log("call"); create_live_class(e); }); }); @@ -75,14 +83,77 @@ const update_course = (e) => { }; const create_live_class = (e) => { - console.log("call"); frappe.call({ method: "lms.lms.doctype.lms_class.lms_class.create_live_class", args: { class_name: $(".class-details").data("class"), + title: $("input[data-fieldname='meeting_title']").val(), + duration: $("input[data-fieldname='meeting_duration']").val(), + date: $("input[data-fieldname='meeting_date']").val(), + time: $("input[data-fieldname='meeting_time']").val(), + description: $( + "textarea[data-fieldname='meeting_description']" + ).val(), }, callback: (data) => { - console.log(data); + $("#live-class-modal").modal("hide"); }, }); }; + +const make_live_class_form = (e) => { + this.field_group = new frappe.ui.FieldGroup({ + fields: [ + { + fieldname: "meeting_title", + fieldtype: "Data", + options: "", + label: "Title", + reqd: 1, + }, + { + fieldname: "meeting_time", + fieldtype: "Datetime", + options: "", + label: "Date and Time", + reqd: 1, + }, + { + fieldname: "meeting_col", + fieldtype: "Column Break", + options: "", + }, + { + fieldname: "meeting_date", + fieldtype: "Date", + options: "", + label: "Date", + reqd: 1, + }, + { + fieldname: "meeting_duration", + fieldtype: "Int", + options: "", + label: "Duration (in Minutes)", + reqd: 1, + }, + { + fieldname: "meeting_sec", + fieldtype: "Section Break", + options: "", + }, + { + fieldname: "meeting_description", + fieldtype: "Small Text", + options: "", + max_height: 100, + min_lines: 5, + label: "Description", + }, + ], + body: $("#live-class-form").get(0), + }); + this.field_group.make(); + $("#live-class-form .form-section:last").removeClass("empty-section"); + $("#live-class-form .frappe-control").removeClass("hide-control"); +};