Merge branch 'develop' of https://github.com/frappe/lms into issues-172
This commit is contained in:
@@ -216,7 +216,7 @@ const video_link = computed(() => {
|
|||||||
|
|
||||||
function enrollStudent() {
|
function enrollStudent() {
|
||||||
if (!user.data) {
|
if (!user.data) {
|
||||||
toast.success(__('You need to login first to enroll for this course'))
|
toast.warning(__('You need to login first to enroll for this course'))
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.href = `/login?redirect-to=${window.location.pathname}`
|
window.location.href = `/login?redirect-to=${window.location.pathname}`
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|||||||
@@ -107,7 +107,11 @@
|
|||||||
v-model:reloadLiveClasses="liveClasses"
|
v-model:reloadLiveClasses="liveClasses"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<LiveClassAttendance v-model="showAttendance" :live_class="attendanceFor" />
|
<LiveClassAttendance
|
||||||
|
v-if="showAttendance"
|
||||||
|
v-model="showAttendance"
|
||||||
|
:live_class="attendanceFor"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { createListResource, Button, Tooltip } from 'frappe-ui'
|
import { createListResource, Button, Tooltip } from 'frappe-ui'
|
||||||
|
|||||||
@@ -22,7 +22,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip :text="__('Course')">
|
<Tooltip :text="__('Course')">
|
||||||
<div class="flex items-center space-x-2 w-fit">
|
<div
|
||||||
|
class="flex space-x-2 w-fit cursor-pointer"
|
||||||
|
@click="openLink('course', event.course)"
|
||||||
|
>
|
||||||
<BookOpen class="h-4 w-4 stroke-1.5" />
|
<BookOpen class="h-4 w-4 stroke-1.5" />
|
||||||
<span>
|
<span>
|
||||||
{{ event.course_title }}
|
{{ event.course_title }}
|
||||||
@@ -30,7 +33,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip v-if="event.batch_title" :text="__('Batch')">
|
<Tooltip v-if="event.batch_title" :text="__('Batch')">
|
||||||
<div class="flex items-center space-x-2 w-fit">
|
<div
|
||||||
|
class="flex space-x-2 w-fit cursor-pointer"
|
||||||
|
@click="openLink('batch', event.batch_name)"
|
||||||
|
>
|
||||||
<Users class="h-4 w-4 stroke-1.5" />
|
<Users class="h-4 w-4 stroke-1.5" />
|
||||||
<span>
|
<span>
|
||||||
{{ event.batch_title }}
|
{{ event.batch_title }}
|
||||||
@@ -334,7 +340,7 @@ const certificateDetails = createResource({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError(err) {
|
onError(err) {
|
||||||
certificate.template = defaultTemplate.data.value
|
certificate.template = defaultTemplate.data?.value
|
||||||
},
|
},
|
||||||
auto: false,
|
auto: false,
|
||||||
})
|
})
|
||||||
@@ -377,6 +383,16 @@ const openCertificate = (certificate) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const openLink = (type, name) => {
|
||||||
|
let url = ''
|
||||||
|
if (type === 'course') {
|
||||||
|
url = `/lms/courses/${name}`
|
||||||
|
} else if (type === 'batch') {
|
||||||
|
url = `/lms/batches/${name}#students`
|
||||||
|
}
|
||||||
|
window.open(url, '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
const statusOptions = computed(() => {
|
const statusOptions = computed(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ const evaluationCourses = computed(() => {
|
|||||||
|
|
||||||
const canScheduleEvals = computed(() => {
|
const canScheduleEvals = computed(() => {
|
||||||
return (
|
return (
|
||||||
upcoming_evals.data?.length != evaluationCourses.length &&
|
upcoming_evals.data?.length != evaluationCourses.value?.length &&
|
||||||
!props.forHome &&
|
!props.forHome &&
|
||||||
!endDateHasPassed.value
|
!endDateHasPassed.value
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -130,7 +130,6 @@
|
|||||||
import {
|
import {
|
||||||
Breadcrumbs,
|
Breadcrumbs,
|
||||||
Button,
|
Button,
|
||||||
call,
|
|
||||||
createListResource,
|
createListResource,
|
||||||
Dropdown,
|
Dropdown,
|
||||||
FormControl,
|
FormControl,
|
||||||
@@ -185,24 +184,27 @@ const batches = createListResource({
|
|||||||
cache: ['batches', user.data?.name],
|
cache: ['batches', user.data?.name],
|
||||||
pageLength: pageLength.value,
|
pageLength: pageLength.value,
|
||||||
start: start.value,
|
start: start.value,
|
||||||
onSuccess(data) {
|
|
||||||
let allCategories = data.map((batch) => batch.category)
|
|
||||||
allCategories = allCategories.filter(
|
|
||||||
(category, index) => allCategories.indexOf(category) === index && category
|
|
||||||
)
|
|
||||||
if (categories.value.length <= allCategories.length) {
|
|
||||||
updateCategories(data)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const setCategories = (data) => {
|
||||||
|
let allCategories = data.map((batch) => batch.category)
|
||||||
|
allCategories = allCategories.filter(
|
||||||
|
(category, index) => allCategories.indexOf(category) === index && category
|
||||||
|
)
|
||||||
|
if (categories.value.length <= allCategories.length) {
|
||||||
|
updateCategories(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const updateBatches = () => {
|
const updateBatches = () => {
|
||||||
updateFilters()
|
updateFilters()
|
||||||
batches.update({
|
batches.update({
|
||||||
filters: filters.value,
|
filters: filters.value,
|
||||||
orderBy: orderBy.value,
|
orderBy: orderBy.value,
|
||||||
})
|
})
|
||||||
batches.reload()
|
batches.reload().then((data) => {
|
||||||
|
setCategories(data)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateFilters = () => {
|
const updateFilters = () => {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
class="sticky flex items-center justify-between top-0 z-10 border-b bg-surface-white px-3 py-2.5 sm:px-5"
|
class="sticky flex items-center justify-between top-0 z-10 border-b bg-surface-white px-3 py-2.5 sm:px-5"
|
||||||
>
|
>
|
||||||
<Breadcrumbs :items="breadcrumbs" />
|
<Breadcrumbs :items="breadcrumbs" />
|
||||||
<router-link :to="{ name: 'Batches', query: { certification: true } }">
|
<router-link :to="{ name: 'Courses', query: { certification: true } }">
|
||||||
<Button>
|
<Button>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<GraduationCap class="h-4 w-4 stroke-1.5" />
|
<GraduationCap class="h-4 w-4 stroke-1.5" />
|
||||||
|
|||||||
@@ -168,9 +168,6 @@ const courses = createListResource({
|
|||||||
cache: ['courses', user.data?.name],
|
cache: ['courses', user.data?.name],
|
||||||
pageLength: pageLength.value,
|
pageLength: pageLength.value,
|
||||||
start: start.value,
|
start: start.value,
|
||||||
onSuccess(data) {
|
|
||||||
setCategories(data)
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const setCategories = (data) => {
|
const setCategories = (data) => {
|
||||||
@@ -205,7 +202,7 @@ const identifyUserPersona = async () => {
|
|||||||
|
|
||||||
const getCourseCount = () => {
|
const getCourseCount = () => {
|
||||||
if (!user.data) return
|
if (!user.data) return
|
||||||
|
if (!user.data.is_moderator) return
|
||||||
call('frappe.client.get_count', {
|
call('frappe.client.get_count', {
|
||||||
doctype: 'LMS Course',
|
doctype: 'LMS Course',
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
@@ -219,7 +216,9 @@ const updateCourses = () => {
|
|||||||
courses.update({
|
courses.update({
|
||||||
filters: filters.value,
|
filters: filters.value,
|
||||||
})
|
})
|
||||||
courses.reload()
|
courses.reload().then((data) => {
|
||||||
|
setCategories(data)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateFilters = () => {
|
const updateFilters = () => {
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
<Uploader
|
<Uploader
|
||||||
v-model="job.company_logo"
|
v-model="job.company_logo"
|
||||||
:label="__('Company Logo')"
|
:label="__('Company Logo')"
|
||||||
:required="false"
|
:required="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
class="flex space-x-2 px-2 py-4"
|
class="flex space-x-2 px-2 py-4"
|
||||||
:class="{
|
:class="{
|
||||||
'cursor-pointer': log.link,
|
'cursor-pointer': log.link,
|
||||||
'items-center': !showDetails(log) && !isMention(log),
|
'items-center': !showDetails(log) && !isMentionOrComment(log),
|
||||||
}"
|
}"
|
||||||
@click="navigateToPage(log)"
|
@click="navigateToPage(log)"
|
||||||
>
|
>
|
||||||
@@ -56,9 +56,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="isMention(log)"
|
v-if="isMentionOrComment(log)"
|
||||||
v-html="log.email_content"
|
v-html="log.email_content"
|
||||||
class="bg-surface-gray-2 rounded-md px-3 py-2"
|
class="bg-surface-gray-2 rounded-md px-3 py-2 line-clamp-3 overflow-hidden"
|
||||||
></div>
|
></div>
|
||||||
<div
|
<div
|
||||||
v-else-if="showDetails(log)"
|
v-else-if="showDetails(log)"
|
||||||
@@ -260,7 +260,7 @@ const navigateToPage = (log) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isMention = (log) => {
|
const isMentionOrComment = (log) => {
|
||||||
if (log.type == 'Mention') {
|
if (log.type == 'Mention') {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,5 +21,5 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [require('@tailwindcss/line-clamp')],
|
||||||
}
|
}
|
||||||
|
|||||||
57
lms/auth.py
Normal file
57
lms/auth.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
ALLOWED_PATHS = [
|
||||||
|
"/api/method/ping",
|
||||||
|
"/api/method/login",
|
||||||
|
"/api/method/logout",
|
||||||
|
"/api/method/frappe.core.doctype.communication.email.mark_email_as_seen",
|
||||||
|
"/api/method/frappe.realtime.get_user_info",
|
||||||
|
"/api/method/frappe.realtime.can_subscribe_doc",
|
||||||
|
"/api/method/frappe.realtime.can_subscribe_doctype",
|
||||||
|
"/api/method/frappe.realtime.has_permission",
|
||||||
|
"/api/method/frappe.integrations.oauth2.authorize",
|
||||||
|
"/api/method/frappe.integrations.oauth2.approve",
|
||||||
|
"/api/method/frappe.integrations.oauth2.get_token",
|
||||||
|
"/api/method/frappe.integrations.oauth2.openid_profile",
|
||||||
|
"/api/method/frappe.website.doctype.web_page_view.web_page_view.make_view_log",
|
||||||
|
"/api/method/upload_file",
|
||||||
|
"/api/method/frappe.search.web_search",
|
||||||
|
"/api/method/frappe.email.queue.unsubscribe",
|
||||||
|
"/api/method/frappe.website.doctype.web_form.web_form.accept",
|
||||||
|
"/api/method/frappe.core.doctype.user.user.test_password_strength",
|
||||||
|
"/api/method/frappe.core.doctype.user.user.update_password",
|
||||||
|
"/api/method/frappe.utils.telemetry.pulse.client.is_enabled",
|
||||||
|
"/api/method/frappe.client.get_value",
|
||||||
|
"/api/method/frappe.client.get_count",
|
||||||
|
"/api/method/frappe.client.get",
|
||||||
|
"/api/method/frappe.client.insert",
|
||||||
|
"/api/method/frappe.client.set_value",
|
||||||
|
"/api/method/frappe.client.delete",
|
||||||
|
"/api/method/frappe.client.get_list",
|
||||||
|
"/api/method/frappe.client.rename_doc",
|
||||||
|
"/api/method/frappe.onboarding.get_onboarding_status",
|
||||||
|
"/api/method/frappe.utils.print_format.download_pdf",
|
||||||
|
"/api/method/frappe.desk.search.search_link",
|
||||||
|
"/api/method/frappe.core.doctype.communication.email.make",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def authenticate():
|
||||||
|
if frappe.form_dict.cmd:
|
||||||
|
path = f"/api/method/{frappe.form_dict.cmd}"
|
||||||
|
else:
|
||||||
|
path = frappe.request.path
|
||||||
|
|
||||||
|
user_type = frappe.db.get_value("User", frappe.session.user, "user_type")
|
||||||
|
if user_type == "System User":
|
||||||
|
return
|
||||||
|
|
||||||
|
if not path.startswith("/api/"):
|
||||||
|
return
|
||||||
|
print("path", path)
|
||||||
|
if path.startswith("/lms") or path.startswith("/api/method/lms."):
|
||||||
|
return
|
||||||
|
|
||||||
|
if path in ALLOWED_PATHS:
|
||||||
|
return
|
||||||
|
frappe.throw(f"Access not allowed for this URL: {path}", frappe.PermissionError)
|
||||||
@@ -262,3 +262,4 @@ add_to_apps_screen = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
sqlite_search = ["lms.sqlite.LearningSearch"]
|
sqlite_search = ["lms.sqlite.LearningSearch"]
|
||||||
|
auth_hooks = ["lms.auth.authenticate"]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
from frappe.tests import UnitTestCase
|
from frappe.tests import UnitTestCase
|
||||||
from frappe.utils import add_days, format_time, getdate
|
from frappe.utils import add_days, format_time, getdate
|
||||||
|
|
||||||
from lms.lms.doctype.course_evaluator.course_evaluator import get_schedule
|
from lms.lms.doctype.course_evaluator.course_evaluator import get_schedule, get_schedule_range_end_date
|
||||||
from lms.lms.test_utils import TestUtils
|
from lms.lms.test_utils import TestUtils
|
||||||
|
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ class TestCourseEvaluator(UnitTestCase):
|
|||||||
def test_schedule_dates(self):
|
def test_schedule_dates(self):
|
||||||
schedule = get_schedule(self.batch.courses[0].course, self.batch.name)
|
schedule = get_schedule(self.batch.courses[0].course, self.batch.name)
|
||||||
first_date = self.calculated_first_date_of_schedule()
|
first_date = self.calculated_first_date_of_schedule()
|
||||||
last_date = self.calculated_last_date_of_schedule(first_date)
|
last_date = self.calculated_last_date_of_schedule()
|
||||||
self.assertEqual(getdate(schedule[0].get("date")), first_date)
|
self.assertEqual(getdate(schedule[0].get("date")), first_date)
|
||||||
self.assertEqual(getdate(schedule[-1].get("date")), last_date)
|
self.assertEqual(getdate(schedule[-1].get("date")), last_date)
|
||||||
|
|
||||||
@@ -51,17 +51,10 @@ class TestCourseEvaluator(UnitTestCase):
|
|||||||
first_date = add_days(today, offset_wednesday)
|
first_date = add_days(today, offset_wednesday)
|
||||||
return first_date
|
return first_date
|
||||||
|
|
||||||
def calculated_last_date_of_schedule(self, first_date):
|
def calculated_last_date_of_schedule(self):
|
||||||
last_day = add_days(getdate(), 56)
|
last_day = getdate(get_schedule_range_end_date(getdate(), self.batch.name))
|
||||||
offset_monday = (0 - last_day.weekday() + 7) % 7 # 0 for Monday
|
while last_day.weekday() not in (0, 2):
|
||||||
offset_wednesday = (2 - last_day.weekday() + 7) % 7 # 2 for Wednesday
|
last_day = add_days(last_day, -1)
|
||||||
|
|
||||||
if offset_monday < offset_wednesday and offset_monday <= 4:
|
|
||||||
last_day = add_days(last_day, offset_monday)
|
|
||||||
elif offset_wednesday <= 4:
|
|
||||||
last_day = add_days(last_day, offset_wednesday)
|
|
||||||
else:
|
|
||||||
last_day = add_days(last_day, min(offset_monday, offset_wednesday) + 7)
|
|
||||||
|
|
||||||
return last_day
|
return last_day
|
||||||
|
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ def get_batch_details_for_notification(topic):
|
|||||||
users = []
|
users = []
|
||||||
batch_title = frappe.db.get_value("LMS Batch", topic.reference_docname, "title")
|
batch_title = frappe.db.get_value("LMS Batch", topic.reference_docname, "title")
|
||||||
subject = _("New comment in batch {0}").format(batch_title)
|
subject = _("New comment in batch {0}").format(batch_title)
|
||||||
link = f"/lms/batches/{topic.reference_docname}"
|
link = f"/lms/batches/{topic.reference_docname}#discussions"
|
||||||
instructors = frappe.db.get_all(
|
instructors = frappe.db.get_all(
|
||||||
"Course Instructor",
|
"Course Instructor",
|
||||||
{"parenttype": "LMS Batch", "parent": topic.reference_docname},
|
{"parenttype": "LMS Batch", "parent": topic.reference_docname},
|
||||||
@@ -590,32 +590,24 @@ def get_chart_date_range(from_date, to_date):
|
|||||||
|
|
||||||
def get_chart_filters(doctype, chart, datefield, from_date, to_date):
|
def get_chart_filters(doctype, chart, datefield, from_date, to_date):
|
||||||
version = get_frappe_version()
|
version = get_frappe_version()
|
||||||
if version.startswith("16."):
|
if version.startswith("15.") or version.startswith("14."):
|
||||||
filters = [([chart.document_type, "docstatus", "<", 2])]
|
|
||||||
filters = filters + json.loads(chart.filters_json)
|
|
||||||
filters.append([doctype, datefield, ">=", from_date])
|
|
||||||
filters.append([doctype, datefield, "<=", to_date])
|
|
||||||
else:
|
|
||||||
filters = [([chart.document_type, "docstatus", "<", 2, False])]
|
filters = [([chart.document_type, "docstatus", "<", 2, False])]
|
||||||
filters = filters + json.loads(chart.filters_json)
|
filters = filters + json.loads(chart.filters_json)
|
||||||
filters.append([doctype, datefield, ">=", from_date, False])
|
filters.append([doctype, datefield, ">=", from_date, False])
|
||||||
filters.append([doctype, datefield, "<=", to_date, False])
|
filters.append([doctype, datefield, "<=", to_date, False])
|
||||||
|
else:
|
||||||
|
filters = [([chart.document_type, "docstatus", "<", 2])]
|
||||||
|
filters = filters + json.loads(chart.filters_json)
|
||||||
|
filters.append([doctype, datefield, ">=", from_date])
|
||||||
|
filters.append([doctype, datefield, "<=", to_date])
|
||||||
|
|
||||||
return filters
|
return filters
|
||||||
|
|
||||||
|
|
||||||
def get_chart_details(doctype, datefield, value_field, chart, from_date, to_date):
|
def get_chart_details(doctype, datefield, value_field, chart, from_date, to_date):
|
||||||
filters = get_chart_filters(doctype, chart, datefield, from_date, to_date)
|
filters = get_chart_filters(doctype, chart, datefield, from_date, to_date)
|
||||||
version = get_frappe_version()
|
version = get_frappe_version()
|
||||||
if version.startswith("16."):
|
if version.startswith("15.") or version.startswith("14."):
|
||||||
return frappe.db.get_all(
|
|
||||||
doctype,
|
|
||||||
fields=[datefield, {"SUM": value_field}, {"COUNT": "*"}],
|
|
||||||
filters=filters,
|
|
||||||
group_by=datefield,
|
|
||||||
order_by=datefield,
|
|
||||||
as_list=True,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return frappe.db.get_all(
|
return frappe.db.get_all(
|
||||||
doctype,
|
doctype,
|
||||||
fields=[f"{datefield} as _unit", f"SUM({value_field})", "COUNT(*)"],
|
fields=[f"{datefield} as _unit", f"SUM({value_field})", "COUNT(*)"],
|
||||||
@@ -624,6 +616,15 @@ def get_chart_details(doctype, datefield, value_field, chart, from_date, to_date
|
|||||||
order_by="_unit asc",
|
order_by="_unit asc",
|
||||||
as_list=True,
|
as_list=True,
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
return frappe.db.get_all(
|
||||||
|
doctype,
|
||||||
|
fields=[datefield, {"SUM": value_field}, {"COUNT": "*"}],
|
||||||
|
filters=filters,
|
||||||
|
group_by=datefield,
|
||||||
|
order_by=datefield,
|
||||||
|
as_list=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist(allow_guest=True)
|
@frappe.whitelist(allow_guest=True)
|
||||||
|
|||||||
36
lms/test_auth.py
Normal file
36
lms/test_auth.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import frappe
|
||||||
|
from frappe.tests import UnitTestCase
|
||||||
|
from frappe.tests.test_api import FrappeAPITestCase
|
||||||
|
|
||||||
|
from lms.auth import authenticate
|
||||||
|
from lms.lms.test_utils import TestUtils
|
||||||
|
|
||||||
|
|
||||||
|
class TestAuth(FrappeAPITestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.normal_user = TestUtils.create_user(
|
||||||
|
self, "normal-user@example.com", "Normal", "User", ["LMS Student"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_allowed_path(self):
|
||||||
|
site_url = frappe.utils.get_site_url(frappe.local.site)
|
||||||
|
headers = {"Authorization": "Bearer set_test_example_user"}
|
||||||
|
url = site_url + "/api/method/lms.lms.utils.get_courses"
|
||||||
|
response = self.get(
|
||||||
|
url,
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
self.assertNotEqual(response.json.get("exc_type"), "PermissionError")
|
||||||
|
|
||||||
|
def test_not_allowed_path(self):
|
||||||
|
site_url = frappe.utils.get_site_url(frappe.local.site)
|
||||||
|
headers = {"Authorization": "Bearer set_test_example_user"}
|
||||||
|
url = site_url + "/api/method/frappe.auth.get_logged_user"
|
||||||
|
response = self.get(
|
||||||
|
url,
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
self.assertEqual(response.json.get("exc_type"), "PermissionError")
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
frappe.delete_doc("User", self.normal_user.name)
|
||||||
Reference in New Issue
Block a user