From e7ccf0a711d0e0ab5e6b28b7a1e4e0510b6b9543 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Wed, 14 Jan 2026 17:54:23 +0530 Subject: [PATCH] fix: sanitize image filename before saving for course and jobs --- frontend/src/components/Controls/Uploader.vue | 2 +- frontend/src/pages/BatchForm.vue | 17 ++-- frontend/src/pages/CourseForm.vue | 98 +++---------------- frontend/src/pages/JobForm.vue | 79 ++------------- 4 files changed, 33 insertions(+), 163 deletions(-) diff --git a/frontend/src/components/Controls/Uploader.vue b/frontend/src/components/Controls/Uploader.vue index 73643892..8c83ff4c 100644 --- a/frontend/src/components/Controls/Uploader.vue +++ b/frontend/src/components/Controls/Uploader.vue @@ -70,7 +70,7 @@ const props = withDefaults( modelValue: string label?: string description?: string - type: 'image' | 'video' + type?: 'image' | 'video' required?: boolean }>(), { diff --git a/frontend/src/pages/BatchForm.vue b/frontend/src/pages/BatchForm.vue index e88b1aa6..1a694f3a 100644 --- a/frontend/src/pages/BatchForm.vue +++ b/frontend/src/pages/BatchForm.vue @@ -281,22 +281,13 @@ import { import { Breadcrumbs, FormControl, - FileUploader, Button, TextEditor, createResource, usePageMeta, toast, call, - Toast, } from 'frappe-ui' -import { useRouter } from 'vue-router' -import { Image, Trash2 } from 'lucide-vue-next' -import { capture } from '@/telemetry' -import { useOnboarding } from 'frappe-ui/frappe' -import { sessionStore } from '../stores/session' -import MultiSelect from '@/components/Controls/MultiSelect.vue' -import Link from '@/components/Controls/Link.vue' import { escapeHTML, getMetaInfo, @@ -304,7 +295,14 @@ import { sanitizeHTML, updateMetaInfo, } from '@/utils' +import { useRouter } from 'vue-router' +import { Trash2 } from 'lucide-vue-next' +import { capture } from '@/telemetry' +import { useOnboarding } from 'frappe-ui/frappe' +import { sessionStore } from '../stores/session' import Uploader from '@/components/Controls/Uploader.vue' +import MultiSelect from '@/components/Controls/MultiSelect.vue' +import Link from '@/components/Controls/Link.vue' const router = useRouter() const user = inject('$user') @@ -466,6 +464,7 @@ const validateFields = () => { !['description', 'batch_details'].includes(key) && typeof batch[key] === 'string' ) { + console.log(key) batch[key] = escapeHTML(batch[key]) } }) diff --git a/frontend/src/pages/CourseForm.vue b/frontend/src/pages/CourseForm.vue index 5a412e1c..339d35d3 100644 --- a/frontend/src/pages/CourseForm.vue +++ b/frontend/src/pages/CourseForm.vue @@ -75,58 +75,11 @@
-
-
- {{ __('Course Image') }} -
- - - -
-
- -
- -
- {{ - __('Appears on the course card in the course list') - }} -
-
-
-
-
+ ({ instructor: instructor, })), @@ -471,7 +423,7 @@ const courseEditResource = createResource({ doctype: 'LMS Course', name: values.course, fieldname: { - image: course.course_image?.file_url || '', + image: course.image, instructors: instructors.value.map((instructor) => ({ instructor: instructor, })), @@ -521,24 +473,10 @@ const courseResource = createResource({ course[key] = course[key] ? true : false } - if (data.image) imageResource.reload({ image: data.image }) check_permission() }, }) -const imageResource = createResource({ - url: 'lms.lms.api.get_file_info', - makeParams(values) { - return { - file_url: values.image, - } - }, - auto: false, - onSuccess(data) { - course.course_image = data - }, -}) - const validateFields = () => { course.description = sanitizeHTML(course.description) @@ -655,14 +593,6 @@ const removeTag = (tag) => { newTag.value = '' } -const saveImage = (file) => { - course.course_image = file -} - -const removeImage = () => { - course.course_image = null -} - const check_permission = () => { let user_is_instructor = false if (user.data?.is_moderator) return diff --git a/frontend/src/pages/JobForm.vue b/frontend/src/pages/JobForm.vue index c81d5c62..3b850371 100644 --- a/frontend/src/pages/JobForm.vue +++ b/frontend/src/pages/JobForm.vue @@ -83,47 +83,11 @@ class="mb-4" :required="true" /> - - - - -
-
-
- -
-
- - {{ job.image.file_name }} - - - {{ getFileSize(job.image.file_size) }} - -
- -
-
+
@@ -150,15 +114,14 @@ import { createResource, Button, TextEditor, - FileUploader, usePageMeta, toast, } from 'frappe-ui' import { computed, onMounted, reactive, inject } from 'vue' -import { FileText, X } from 'lucide-vue-next' import { sessionStore } from '@/stores/session' import { useRouter } from 'vue-router' -import { escapeHTML, getFileSize, sanitizeHTML, validateFile } from '@/utils' +import { escapeHTML, sanitizeHTML } from '@/utils' +import Uploader from '@/components/Controls/Uploader.vue' const user = inject('$user') const router = useRouter() @@ -177,7 +140,7 @@ const newJob = createResource({ return { doc: { doctype: 'Job Opportunity', - company_logo: job.image?.file_url, + company_logo: job.company_logo, ...job, }, } @@ -191,7 +154,7 @@ const updateJob = createResource({ doctype: 'Job Opportunity', name: props.jobName, fieldname: { - company_logo: job.image.file_url, + company_logo: job.company_logo, ...job, }, } @@ -215,20 +178,6 @@ const jobDetail = createResource({ Object.keys(data).forEach((key) => { if (Object.hasOwn(job, key)) job[key] = data[key] }) - if (data.company_logo) imageResource.reload({ image: data.company_logo }) - }, -}) - -const imageResource = createResource({ - url: 'lms.lms.api.get_file_info', - makeParams(values) { - return { - file_url: values.image, - } - }, - auto: false, - onSuccess(data) { - job.image = data }, }) @@ -241,7 +190,7 @@ const job = reactive({ status: 'Open', company_name: '', company_website: '', - image: null, + company_logo: null, description: '', company_email_address: '', }) @@ -322,14 +271,6 @@ const validateJobFields = () => { }) } -const saveImage = (file) => { - job.image = file -} - -const removeImage = () => { - job.image = null -} - const jobTypes = computed(() => { return [ { label: 'Full Time', value: 'Full Time' },