fix: video watch time permission and other issues
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
v-model="show"
|
||||
:options="{
|
||||
size: '4xl',
|
||||
title: __('Video Statistics for {0}').format(lessonTitle),
|
||||
title: __('Video Statistics'),
|
||||
}"
|
||||
>
|
||||
<template #body-content>
|
||||
@@ -21,17 +21,22 @@
|
||||
class="mt-2 mr-5 w-[25%]"
|
||||
/> -->
|
||||
</div>
|
||||
<div v-if="currentTab" class="mt-4">
|
||||
<div
|
||||
v-if="currentTab"
|
||||
:class="{
|
||||
'mt-5': tabs.length > 1,
|
||||
}"
|
||||
>
|
||||
<div class="grid grid-cols-[55%,40%] gap-5">
|
||||
<div
|
||||
class="space-y-5 border rounded-md p-2 pt-4 h-[70vh] overflow-y-auto"
|
||||
class="space-y-5 border rounded-md p-2 pt-4 max-h-[70vh] overflow-y-auto"
|
||||
>
|
||||
<div class="grid grid-cols-[70%,30%] text-sm text-ink-gray-5">
|
||||
<div class="px-4">
|
||||
{{ __('Member') }}
|
||||
</div>
|
||||
<div class="text-center">
|
||||
{{ __('Watch Time') }}
|
||||
{{ __('Watch Time (mins)') }}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -68,15 +73,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-5">
|
||||
<NumberChart
|
||||
class="border rounded-md"
|
||||
:config="{
|
||||
title: __('Average Watch Time'),
|
||||
value: averageWatchTime,
|
||||
}"
|
||||
<NumberChartGraph
|
||||
:title="__('Average Watch Time (mins)')"
|
||||
:value="averageWatchTime"
|
||||
/>
|
||||
<div v-if="isPlyrSource">
|
||||
<div class="video-player" :src="currentTab"></div>
|
||||
<div
|
||||
class="video-player"
|
||||
:data-plyr-provider="provider"
|
||||
:src="currentTab"
|
||||
></div>
|
||||
</div>
|
||||
<VideoBlock v-else :file="currentTab" />
|
||||
</div>
|
||||
@@ -101,6 +107,7 @@ import {
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { enablePlyr, formatTimestamp } from '@/utils'
|
||||
import VideoBlock from '@/components/VideoBlock.vue'
|
||||
import NumberChartGraph from '@/components/NumberChartGraph.vue'
|
||||
|
||||
const show = defineModel<boolean | undefined>()
|
||||
const currentTab = ref<string>('')
|
||||
@@ -171,7 +178,7 @@ watch(show, () => {
|
||||
|
||||
const statisticsData = computed(() => {
|
||||
const grouped = <Record<string, any[]>>{}
|
||||
statistics.data.forEach((item: { source: string }) => {
|
||||
statistics.data?.forEach((item: { source: string }) => {
|
||||
if (!grouped[item.source]) {
|
||||
grouped[item.source] = []
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</template>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Button v-if="canSeeStats()" @click="showVideoStats()">
|
||||
<Button v-if="isAdmin" @click="showVideoStats()">
|
||||
<template #icon>
|
||||
<TrendingUp class="size-4 stroke-1.5" />
|
||||
</template>
|
||||
@@ -326,7 +326,7 @@
|
||||
@updateNotes="updateNotes"
|
||||
/>
|
||||
<VideoStatistics
|
||||
v-if="showStatsDialog"
|
||||
v-if="isAdmin"
|
||||
v-model="showStatsDialog"
|
||||
:lessonName="lesson.data?.name"
|
||||
:lessonTitle="lesson.data?.title"
|
||||
@@ -524,7 +524,14 @@ const renderEditor = (holder, content) => {
|
||||
|
||||
const markProgress = () => {
|
||||
if (user.data && lesson.data && !lesson.data.progress) {
|
||||
progress.submit()
|
||||
progress.submit(
|
||||
{},
|
||||
{
|
||||
onError(err) {
|
||||
console.error(err)
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,7 +612,6 @@ watch(
|
||||
plyrSources.value = []
|
||||
await nextTick()
|
||||
resetLessonState(newChapterNumber, newLessonNumber)
|
||||
startTimer()
|
||||
updateNotes()
|
||||
checkIfDiscussionsAllowed()
|
||||
checkQuiz()
|
||||
@@ -652,7 +658,7 @@ const getVideoDetails = () => {
|
||||
|
||||
const getPlyrSourceDetails = () => {
|
||||
let details = []
|
||||
plyrSources.value.forEach((source) => {
|
||||
plyrSources.value.forEach(async (source) => {
|
||||
if (source.currentTime == source.duration) markProgress()
|
||||
let src = cleanYouTubeUrl(source.source)
|
||||
details.push({
|
||||
@@ -674,6 +680,7 @@ watch(
|
||||
() => lesson.data,
|
||||
async (data) => {
|
||||
setupLesson(data)
|
||||
startTimer()
|
||||
getPlyrSource()
|
||||
updateNotes()
|
||||
if (data.icon == 'icon-youtube') clearInterval(timerInterval)
|
||||
@@ -769,17 +776,19 @@ const checkIfDiscussionsAllowed = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const isAdmin = computed(() => {
|
||||
let isInstructor = lesson.data?.instructors?.includes(user.data?.name)
|
||||
return user.data?.is_moderator || isInstructor
|
||||
})
|
||||
|
||||
const allowEdit = () => {
|
||||
if (window.read_only_mode) return false
|
||||
if (user.data?.is_moderator) return true
|
||||
if (lesson.data?.instructors?.includes(user.data?.name)) return true
|
||||
if (isAdmin.value) return true
|
||||
return false
|
||||
}
|
||||
|
||||
const allowInstructorContent = () => {
|
||||
if (user.data?.is_moderator) return true
|
||||
if (lesson.data?.instructors?.includes(user.data?.name)) return true
|
||||
return false
|
||||
return isAdmin.value
|
||||
}
|
||||
|
||||
const enrollment = createResource({
|
||||
@@ -819,11 +828,6 @@ const toggleInlineMenu = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const canSeeStats = () => {
|
||||
if (user.data?.is_moderator || user.data?.is_instructor) return true
|
||||
return false
|
||||
}
|
||||
|
||||
const showVideoStats = () => {
|
||||
showStatsDialog.value = true
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ from frappe.utils import ceil
|
||||
|
||||
|
||||
class LMSEnrollment(Document):
|
||||
def validate(self):
|
||||
def before_insert(self):
|
||||
self.validate_duplicate_enrollment()
|
||||
self.validate_course_enrollment_eligibility()
|
||||
self.validate_owner()
|
||||
@@ -27,6 +27,7 @@ class LMSEnrollment(Document):
|
||||
{
|
||||
"course": self.course,
|
||||
"member": self.member,
|
||||
"name": ["!=", self.name],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -113,11 +113,12 @@
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"grid_page_length": 50,
|
||||
"in_create": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2024-10-07 16:52:04.162521",
|
||||
"modified_by": "Administrator",
|
||||
"modified": "2026-02-19 16:31:23.401819",
|
||||
"modified_by": "sayali@frappe.io",
|
||||
"module": "LMS",
|
||||
"name": "LMS Quiz Submission",
|
||||
"owner": "Administrator",
|
||||
@@ -133,21 +134,12 @@
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "LMS Student",
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "member_name",
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
"grid_page_length": 50,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2025-07-30 14:38:52.555010",
|
||||
"modified": "2026-02-20 12:02:29.458645",
|
||||
"modified_by": "sayali@frappe.io",
|
||||
"module": "LMS",
|
||||
"name": "LMS Video Watch Duration",
|
||||
@@ -120,17 +120,6 @@
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "LMS Student",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
@@ -154,6 +143,18 @@
|
||||
"role": "Course Creator",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"if_owner": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "LMS Student",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
Reference in New Issue
Block a user