Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/cts2 #37

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions VueApp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions VueApp/src/CTS/components/AssessmentBubble.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,11 @@
setBubbleAttrs()
</script>
<template>
<q-icon :name="bubbleIcon" size="sm" :class="'assessmentIcon ' + bubbleClass" :title="props?.text" @click="clickBubble"></q-icon>
</template>
<q-icon :name="bubbleIcon" size="sm" :class="'assessmentIcon cursor-pointer ' + bubbleClass" @click="clickBubble">
<q-tooltip style="white-space:pre-wrap;" class="text-body2">
<strong>Click to open details</strong>
<br />
{{ props.text }}
</q-tooltip>
</q-icon>
</template>
6 changes: 6 additions & 0 deletions VueApp/src/CTS/pages/AssessmentEpa.vue
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@
studentEpa.value.levelId = ""
studentEpa.value.comment = ""
success.value = true

//set back to false so the next submission clears student and level
setTimeout(() => {
clearStudent.value = false
clearLevel.value = false
}, 500)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions VueApp/src/CTS/pages/AssessmentList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@
<template v-slot:body-cell-action="props">
<q-td :props="props">
<router-link :props="props"
v-if="props.row.editable"
:to="{name: 'AssessmentEpaEdit', query: {assessmentId: props.row.encounterId}}"
v-slot:default="props">
<q-btn color="primary" square flat icon="edit" title="Edit EPA" />
Expand Down
30 changes: 20 additions & 10 deletions VueApp/src/CTS/pages/MyAssessments.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
}

function getText(date: Date, enteredBy: string, levelName: string, comment: string | null, serviceName: string | null) {
return formatDate(date.toString()) + ' ' + enteredBy + ' ' + '\n' + serviceName + '\n' + levelName + '\n ' + (comment != null ? comment : "")
return levelName + '\n' + (comment != null ? comment : "") + "\n" + formatDate(date.toString()) + ' ' + enteredBy + ' ' + '\n' + serviceName + '\n'
}

function toggleExpandAll() {
Expand All @@ -100,34 +100,43 @@
</script>
<template>
<div v-if="loaded">
<h2>Assessments for <span v-if="showPersonName && person != null">{{ person.firstName }} {{ person.lastName }}</span></h2>
<h2>
<span v-if="showPersonName && person != null">Assessments for {{ person.firstName }} {{ person.lastName }}</span>
<span v-else>My Assessments</span>
</h2>

<q-dialog v-model="showAssessmentDetail">
<q-card style="width:700px; max-width: 80vw;">
<q-card-section>
<div class="text-h6">Assessment Details</div>
<div class="row">
<div class="col-12">
<AssessmentBubble class="q-mr-md" :maxValue="5" :value=epaAssessment.levelValue></AssessmentBubble>
<strong>EPA:</strong> {{ epaAssessment.epaName }}
</div>
</div>
<div class="row">
<div class="col-12">
<strong>Rating:</strong>
<AssessmentBubble class="q-ml-sm" :maxValue="5" :value=epaAssessment.levelValue></AssessmentBubble>
{{ epaAssessment.levelName }}
</div>
</div>
<div class="row q-mt-xs">
<div class="col-12">
Entered
{{ formatDate(epaAssessment.encounterDate.toString()) }}
by
{{ epaAssessment.enteredByName }}
<strong>Comment:</strong> {{ epaAssessment.comment }}
</div>
</div>
<div class="row q-mt-xs">
<div class="col-12">
{{ epaAssessment.serviceName }}
<strong>Entered:</strong>
{{ formatDate(epaAssessment.encounterDate.toString()) }}
by
{{ epaAssessment.enteredByName }}
</div>
</div>
<div class="row q-mt-xs">
<div class="col-12">
{{ epaAssessment.comment }}
<strong>Service:</strong> {{ epaAssessment.serviceName }}
</div>
</div>
</q-card-section>
Expand All @@ -152,7 +161,8 @@
v-for="a in getAssessmentsForEpa(epa.epaId)" :type="bubbleType"></AssessmentBubble>
</div>
<div class="col-1">
<q-btn dense :icon="showDetails[index] ? 'expand_less' : 'expand_more'" @click="showDetails[index] = !showDetails[index]"></q-btn>
<q-btn dense :icon="showDetails[index] ? 'expand_less' : 'expand_more'" @click="showDetails[index] = !showDetails[index]"
v-if="getAssessmentsForEpa(epa.epaId).length > 0"></q-btn>
</div>
<q-slide-transition>
<div class="col-12 q-mb-md" v-if="showDetails[index]" :key="'epadetails' + index">
Expand Down
2 changes: 1 addition & 1 deletion VueApp/src/CTS/router/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const routes = [
{
path: '/CTS/MyAssessments',
name: 'MyAssessments',
meta: { layout: ViperLayout, permissions: ["SVMSecure.CTS.Students"] },
meta: { layout: ViperLayout, permissions: ["SVMSecure.CTS.Students","SVMSecure.CTS.Manage","SVMSecure.CTS.ViewAllStudentAssessments"] },
component: () => import('@/CTS/pages/MyAssessments.vue'),
},
/* Assessments */
Expand Down
10 changes: 6 additions & 4 deletions test/CTS/AssessmentAccessTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,18 @@ public void CheckAssessmentModificationAccess()
var csCtsSec = SetupUsers.GetCtsSecurityService(rapsContext.Object, context.Object, SetupUsers.UserType.CSTeam);

//act
var facCanEditOwnAssessment = facCtsSec.CanEditStudentAssessment(SetupUsers.facultyUser.AaudUserId);
var facCanEditOtherAssessment = facCtsSec.CanEditStudentAssessment(SetupUsers.otherFacultyUser.AaudUserId);
var manCanEditOtherAssessment = managerCtsSec.CanEditStudentAssessment(SetupUsers.facultyUser.AaudUserId);
var csCanEditOtherAssessment = csCtsSec.CanEditStudentAssessment(SetupUsers.facultyUser.AaudUserId);
var facCanEditOwnAssessment = facCtsSec.CanEditStudentAssessment(SetupUsers.facultyUser.AaudUserId, DateTime.Now);
var facCanEditOtherAssessment = facCtsSec.CanEditStudentAssessment(SetupUsers.otherFacultyUser.AaudUserId, DateTime.Now);
var manCanEditOtherAssessment = managerCtsSec.CanEditStudentAssessment(SetupUsers.facultyUser.AaudUserId, DateTime.Now);
var csCanEditOtherAssessment = csCtsSec.CanEditStudentAssessment(SetupUsers.facultyUser.AaudUserId, DateTime.Now);
var canEditWhenDeadlinePassed = facCtsSec.CanEditStudentAssessment(SetupUsers.facultyUser.AaudUserId, DateTime.Now.AddHours(-49));

//assert
Assert.True(facCanEditOwnAssessment, "Faculty cannot edit own assessment.");
Assert.True(manCanEditOtherAssessment, "Manager cannot edit assessment.");
Assert.False(facCanEditOtherAssessment, "Faculty can edit another faculty's assessment.");
Assert.False(csCanEditOtherAssessment, "CS Team can edit faculty's assessment.");
Assert.False(canEditWhenDeadlinePassed, "Faculty can edit when deadline for editing is passed.");
}
}
}
3 changes: 3 additions & 0 deletions test/CTS/SetupAssessments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ internal class SetupAssessments
{
EncounterId = 1,
EnteredBy = SetupUsers.facultyUser.AaudUserId,
EnteredOn = DateTime.Now,
StudentUserId = SetupUsers.studentUser1.AaudUserId,
EncounterType = (int)EncounterCreationService.EncounterType.Epa,
Student = new Models.VIPER.Person()
Expand All @@ -34,6 +35,7 @@ internal class SetupAssessments
{
EncounterId = 2,
EnteredBy = SetupUsers.facultyUser.AaudUserId,
EnteredOn = DateTime.Now,
StudentUserId = SetupUsers.studentUser1.AaudUserId,
EncounterType = (int)EncounterCreationService.EncounterType.Epa,
Student = new Models.VIPER.Person()
Expand All @@ -48,6 +50,7 @@ internal class SetupAssessments
{
EncounterId = 3,
EnteredBy = SetupUsers.otherFacultyUser.AaudUserId,
EnteredOn = DateTime.Now,
StudentUserId = SetupUsers.studentUser2.AaudUserId,
EncounterType = (int)EncounterCreationService.EncounterType.Epa,
Student = new Models.VIPER.Person()
Expand Down
10 changes: 5 additions & 5 deletions web/Areas/CTS/Controllers/AssessmentController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public AssessmentController(VIPERContext _context, RAPSContext rapsContext, CtsS
/// <param name="dateTo"></param>
/// <returns></returns>
[HttpGet]
[Permission(Allow = "SVMSecure.CTS.Manage,SVMSecure.CTS.StudentAssessments,SVMSecure.CTS.AssessClinical")]
[Permission(Allow = "SVMSecure.CTS.Manage,SVMSecure.CTS.StudentAssessments,SVMSecure.CTS.AssessClinical,SVMSecure.CTS.MyAssessments")]
[ApiPagination(DefaultPerPage = 100, MaxPerPage = 100)]
public async Task<ActionResult<List<StudentAssessment>>> GetAssessments(int? type, int? studentUserId, int? enteredById, int? serviceId,
int? epaId, DateOnly? dateFrom, DateOnly? dateTo, ApiPagination? pagination,
Expand Down Expand Up @@ -142,7 +142,7 @@ public async Task<ActionResult<List<StudentAssessment>>> GetAssessments(int? typ
foreach (var a in assessmentsList)
{
var sa = CreateStudentAssessment(a);
sa.Editable = ctsSecurityService.CanEditStudentAssessment(sa.EnteredBy);
sa.Editable = ctsSecurityService.CanEditStudentAssessment(sa.EnteredBy, sa.EnteredOn);
studentAssessments.Add(sa);
}

Expand Down Expand Up @@ -200,7 +200,7 @@ public async Task<ActionResult<List<Assessor>>> GetAssessors(int? type, int? ser
/// <param name="encounterId"></param>
/// <returns></returns>
[HttpGet("{encounterId}")]
[Permission(Allow = "SVMSecure.CTS.Manage,SVMSecure.CTS.StudentAssessments,SVMSecure.CTS.AssessClinical")]
[Permission(Allow = "SVMSecure.CTS.Manage,SVMSecure.CTS.StudentAssessments,SVMSecure.CTS.AssessClinical,SVMSecure.CTS.MyAssessments")]
public async Task<ActionResult<StudentAssessment>> GetStudentAssessment(int encounterId)
{
var encounter = await context.Encounters
Expand All @@ -220,7 +220,7 @@ public async Task<ActionResult<StudentAssessment>> GetStudentAssessment(int enco
return (ActionResult<StudentAssessment>)ForbidApi();
}
var sa = CreateStudentAssessment(encounter);
sa.Editable = ctsSecurityService.CanEditStudentAssessment(sa.EnteredBy);
sa.Editable = ctsSecurityService.CanEditStudentAssessment(sa.EnteredBy, sa.EnteredOn);
return sa;
}

Expand Down Expand Up @@ -336,7 +336,7 @@ public async Task<ActionResult<CreateUpdateStudentEpa>> UpdateStudentEpa(int enc
return NotFound();
}
//check the logged in user can edit
if (!ctsSecurityService.CanEditStudentAssessment(encounter.EnteredBy))
if (!ctsSecurityService.CanEditStudentAssessment(encounter.EnteredBy, encounter.EnteredOn))
{
return ForbidApi();
}
Expand Down
2 changes: 1 addition & 1 deletion web/Areas/CTS/Services/CtsNavMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public NavMenu Nav()
//Assessments of the logged in user
if (userHelper.HasPermission(_rapsContext, userHelper.GetCurrentUser(), "SVMSecure.CTS.Students"))
{
//nav.Add(new NavMenuItem() { MenuItemText = "My Assessments", MenuItemURL = "MyAssessments" });
nav.Add(new NavMenuItem() { MenuItemText = "My Assessments", MenuItemURL = "MyAssessments" });
}

if (userHelper.HasPermission(_rapsContext, userHelper.GetCurrentUser(), "SVMSecure.CTS.Manage"))
Expand Down
11 changes: 9 additions & 2 deletions web/Areas/CTS/Services/CtsSecurityService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class CtsSecurityService
private const string AssessmentsViewPermission = "SVMSecure.CTS.ViewAllStudentAssessments";
private const string AssessClinicalPermission = "SVMSecure.CTS.AssessClinical";

private const int MinutesToEditEPA = 48 * 60; //submitter can edit EPAs for 48 hours


public CtsSecurityService(RAPSContext rapsContext, VIPERContext viperContext, IUserHelper? userHelper = null)
{
Expand Down Expand Up @@ -62,10 +64,15 @@ public bool CheckStudentAssessmentViewAccess(int? studentId = null, int? entered
return false;
}

public bool CanEditStudentAssessment(int enteredBy)
public bool CanEditStudentAssessment(int enteredBy, DateTime enteredDate)
{
DateTime editCutoff = enteredDate.AddMinutes(MinutesToEditEPA);
return userHelper.HasPermission(rapsContext, userHelper.GetCurrentUser(), ManagerPermission)
|| (userHelper.HasPermission(rapsContext, userHelper.GetCurrentUser(), AssessClinicalPermission) && enteredBy == userHelper.GetCurrentUser()?.AaudUserId);
|| (
userHelper.HasPermission(rapsContext, userHelper.GetCurrentUser(), AssessClinicalPermission)
&& enteredBy == userHelper.GetCurrentUser()?.AaudUserId
&& DateTime.Compare(DateTime.Now, editCutoff) < 1
);
}
}
}
Loading