From eb0587f726669e905ab1c0c5c4160aeac6af1b0f Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Sat, 19 Apr 2025 12:37:24 +0530 Subject: [PATCH 1/4] feat: meta image and keywords from settings --- frontend/src/components/Modals/Settings.vue | 15 +++++++++++- frontend/src/components/SettingDetails.vue | 4 +++- frontend/src/components/SettingFields.vue | 17 ++++++++++---- .../doctype/lms_settings/lms_settings.json | 23 +++++++++++++++++-- lms/www/lms.py | 14 ++++++----- 5 files changed, 59 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/Modals/Settings.vue b/frontend/src/components/Modals/Settings.vue index 46c9d1e3..ab89d535 100644 --- a/frontend/src/components/Modals/Settings.vue +++ b/frontend/src/components/Modals/Settings.vue @@ -352,10 +352,23 @@ const tabsStructure = computed(() => { label: 'Meta Description', name: 'meta_description', type: 'textarea', - rows: 5, + rows: 4, description: "This description will be shown on lists and pages that don't have meta description", }, + { + label: 'Meta Keywords', + name: 'meta_keywords', + type: 'textarea', + rows: 4, + description: + 'Keywords for search engines to find your website. Separated by commas.', + }, + { + label: 'Meta Image', + name: 'meta_image', + type: 'Upload', + }, ], }, ], diff --git a/frontend/src/components/SettingDetails.vue b/frontend/src/components/SettingDetails.vue index 8f7a49e2..e4916e7b 100644 --- a/frontend/src/components/SettingDetails.vue +++ b/frontend/src/components/SettingDetails.vue @@ -51,7 +51,9 @@ const props = defineProps({ const update = () => { props.fields.forEach((f) => { - if (f.type != 'Column Break') { + if (f.type == 'Upload') { + props.data.doc[f.name] = f.value ? f.value.file_url : null + } else if (f.type != 'Column Break') { props.data.doc[f.name] = f.value } }) diff --git a/frontend/src/components/SettingFields.vue b/frontend/src/components/SettingFields.vue index b01ff093..df9bebbd 100644 --- a/frontend/src/components/SettingFields.vue +++ b/frontend/src/components/SettingFields.vue @@ -54,15 +54,24 @@
- +
- {{ data[field.name]?.file_name }} + {{ + data[field.name]?.file_name || + data[field.name].split('/').pop() + }} - + {{ getFileSize(data[field.name]?.file_size) }}
diff --git a/lms/lms/doctype/lms_settings/lms_settings.json b/lms/lms/doctype/lms_settings/lms_settings.json index 95b87930..772a6fbe 100644 --- a/lms/lms/doctype/lms_settings/lms_settings.json +++ b/lms/lms/doctype/lms_settings/lms_settings.json @@ -60,7 +60,10 @@ "column_break_uwsp", "payment_reminder_template", "seo_tab", - "meta_description" + "meta_description", + "meta_image", + "column_break_xijv", + "meta_keywords" ], "fields": [ { @@ -370,13 +373,29 @@ "fieldname": "meta_description", "fieldtype": "Small Text", "label": "Meta Description" + }, + { + "description": "This image will be shown on lists and pages that don't have an image by default", + "fieldname": "meta_image", + "fieldtype": "Attach Image", + "label": "Meta Image" + }, + { + "description": "Common keywords that will be used for all pages", + "fieldname": "meta_keywords", + "fieldtype": "Small Text", + "label": "Meta Keywords" + }, + { + "fieldname": "column_break_xijv", + "fieldtype": "Column Break" } ], "grid_page_length": 50, "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2025-04-17 21:58:30.365876", + "modified": "2025-04-19 12:19:24.037931", "modified_by": "sayali@frappe.io", "module": "LMS", "name": "LMS Settings", diff --git a/lms/www/lms.py b/lms/www/lms.py index 6e76c58b..a01e9371 100644 --- a/lms/www/lms.py +++ b/lms/www/lms.py @@ -14,25 +14,28 @@ def get_context(): or "/assets/lms/frontend/favicon.png" ) title = frappe.db.get_single_value("Website Settings", "app_name") or "Frappe Learning" - description = frappe.db.get_single_value("LMS Settings", "meta_description") + csrf_token = frappe.sessions.get_csrf_token() frappe.db.commit() context = frappe._dict() context.csrf_token = csrf_token - context.meta = get_meta(app_path, title, favicon, description) + context.meta = get_meta(app_path, title, favicon) capture("active_site", "lms") context.title = title context.favicon = favicon return context -def get_meta(app_path, title, favicon, description): +def get_meta(app_path, title, favicon): meta = frappe._dict() if app_path: meta = get_meta_from_document(app_path) route_meta = frappe.get_all("Website Meta Tag", {"parent": app_path}, ["key", "value"]) + description = frappe.db.get_single_value("LMS Settings", "meta_description") + image = frappe.db.get_single_value("LMS Settings", "meta_image") + keywords = frappe.db.get_single_value("LMS Settings", "meta_keywords") if len(route_meta) > 0: for row in route_meta: @@ -54,10 +57,9 @@ def get_meta(app_path, title, favicon, description): meta["description"] = description if not meta.get("image"): - meta["image"] = favicon + meta["image"] = image or favicon - if not meta.get("keywords"): - meta["keywords"] = "" + meta["keywords"] = f"{meta.get('keywords')}, {keywords}" if not meta: meta = { From f6008cf46a25c2c600c6120d0281b9cc6442cb1c Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Sat, 19 Apr 2025 12:46:31 +0530 Subject: [PATCH 2/4] fix: don't show course count on batch details if there are no courses --- frontend/src/components/BatchOverlay.vue | 5 ++++- frontend/src/pages/BatchDetail.vue | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/BatchOverlay.vue b/frontend/src/components/BatchOverlay.vue index cf684993..ef2723f9 100644 --- a/frontend/src/components/BatchOverlay.vue +++ b/frontend/src/components/BatchOverlay.vue @@ -24,7 +24,10 @@ > {{ formatNumberIntoCurrency(batch.data.amount, batch.data.currency) }}
-
+
{{ batch.data.courses.length }} {{ __('Courses') }}
diff --git a/frontend/src/pages/BatchDetail.vue b/frontend/src/pages/BatchDetail.vue index 4ccd4c33..8e68f1f9 100644 --- a/frontend/src/pages/BatchDetail.vue +++ b/frontend/src/pages/BatchDetail.vue @@ -14,13 +14,16 @@ {{ batch.data.description }}
-
+
{{ batch.data?.courses?.length }} {{ __('Courses') }}
- Date: Mon, 21 Apr 2025 10:33:24 +0530 Subject: [PATCH 3/4] test: attach course image if selector is hidden --- cypress/e2e/course_creation.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/e2e/course_creation.cy.js b/cypress/e2e/course_creation.cy.js index 7d20fdcb..d65b1d0f 100644 --- a/cypress/e2e/course_creation.cy.js +++ b/cypress/e2e/course_creation.cy.js @@ -19,7 +19,7 @@ describe("Course Creation", () => { ); cy.fixture("profile.png", "base64").then((fileContent) => { - cy.get('input[type="file"]').attachFile({ + cy.get('input[type="file"]').should("be.hidden").attachFile({ fileContent, fileName: "profile.png", mimeType: "image/png", From 9143cc39d9a43e71ede088546cdaf25371e29929 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 21 Apr 2025 10:53:22 +0530 Subject: [PATCH 4/4] test: find the course image label and attach course image to its sibling input --- cypress/e2e/course_creation.cy.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/cypress/e2e/course_creation.cy.js b/cypress/e2e/course_creation.cy.js index d65b1d0f..69c0f1ca 100644 --- a/cypress/e2e/course_creation.cy.js +++ b/cypress/e2e/course_creation.cy.js @@ -19,12 +19,23 @@ describe("Course Creation", () => { ); cy.fixture("profile.png", "base64").then((fileContent) => { - cy.get('input[type="file"]').should("be.hidden").attachFile({ + /* cy.get('input[type="file"]').should("be.hidden").attachFile({ fileContent, fileName: "profile.png", mimeType: "image/png", encoding: "base64", - }); + }); */ + + cy.get("div") + .contains("Course Image") + .siblings("div") + .children('input[type="file"]') + .attachFile({ + fileContent, + fileName: "profile.png", + mimeType: "image/png", + encoding: "base64", + }); }); cy.get("label")