Skip to content

Commit e4dec15

Browse files
committed
TD-3727: Prompting a password entry screen on file upload
1 parent af255b6 commit e4dec15

File tree

3 files changed

+120
-6
lines changed

3 files changed

+120
-6
lines changed

LearningHub.Nhs.WebUI/Controllers/Api/UserController.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,27 @@ public async Task<ActionResult> CheckUserRole()
9898
return this.Ok(isSystemAdmin);
9999
}
100100

101+
/// <summary>
102+
/// to check user password is correct.
103+
/// </summary>
104+
/// <param name="currentPassword">The currentPassword.</param>
105+
/// <returns>The <see cref="Task{ActionResult}"/>.</returns>
106+
[HttpGet]
107+
[Route("ConfirmPassword/{currentPassword}")]
108+
public async Task<ActionResult> ConfirmPassword(string currentPassword)
109+
{
110+
string passwordHash = this.userService.Base64MD5HashDigest(currentPassword);
111+
var userPersonalDetails = await this.userService.GetCurrentUserPersonalDetailsAsync();
112+
if (userPersonalDetails != null && userPersonalDetails.PasswordHash == passwordHash)
113+
{
114+
return this.Ok(true);
115+
}
116+
else
117+
{
118+
return this.Ok(false);
119+
}
120+
}
121+
101122
/// <summary>
102123
/// The GetCurrentUserPersonalDetails.
103124
/// </summary>

LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/Content.vue

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,50 @@
376376
</transition>
377377
</div>
378378

379+
<div v-if="passwordVerification">
380+
<transition name="modal">
381+
<div class="modal-mask">
382+
<div class="modal-wrapper">
383+
<div class="modal-dialog">
384+
<div class="modal-content">
385+
<div class="modal-header text-center">
386+
<h4 class="modal-title"><i class="warningTriangle fa-solid fa-triangle-exclamation"></i> Confirm the password</h4>
387+
</div>
388+
<div class="modal-body">
389+
<div class="model-body-container">
390+
<p>
391+
To continue with the upload, please verify your identity by entering your password.
392+
</p>
393+
</div>
394+
<div>
395+
<div class="form-group password-div-width" v-bind:class="{ 'input-validation-error': $v.currentPassword.$error}">
396+
<label for="confirmPassword" class="pt-10">Current password</label>
397+
<div class="error-text" v-if="$v.currentPassword.$invalid && $v.currentPassword.$dirty">
398+
<span class="text-danger">Enter a valid password.</span>
399+
</div>
400+
<input type="password" class="form-control" id="currentPassword" aria-describedby="currentPassword" autocomplete="off" maxlength="1000"
401+
v-model.trim="currentPassword"
402+
placeholder="Current password"
403+
@blur="$v.currentPassword.$touch()"
404+
v-bind:class="{ 'input-validation-error': $v.currentPassword.$error}">
405+
</div>
406+
407+
<div class="row" v-if="showError">
408+
<div class="form-group col-12 text-danger" v-html="errorMessage" />
409+
</div>
410+
</div>
411+
</div>
412+
<div class="modal-footer modal-footer--buttons">
413+
<button type="button" class="nhsuk-button nhsuk-button--secondary" @click="passwordVerification=false">Cancel</button>
414+
<button type="button" class="nhsuk-button" @click="submitPassword">Continue</button>
415+
</div>
416+
</div>
417+
</div>
418+
</div>
419+
</div>
420+
</transition>
421+
</div>
422+
379423
</div>
380424

381425
<div v-if="!resourceLoading" class="limit-width px-xl-0 mx-xl-0 pb-5">
@@ -427,6 +471,7 @@
427471
import GenericFileUploader from './GenericFileUploader.vue';
428472
import { UploadResourceType, ResourceType, VersionStatus } from '../constants';
429473
import { resourceData } from '../data/resource';
474+
import { userData } from '../data/user';
430475
import { FileTypeModel } from "../models/contribute/fileTypeModel";
431476
import { FileUploadResult } from "../models/contribute/FileUploadResult";
432477
import { FlagModel } from '../models/flagModel';
@@ -490,6 +535,8 @@
490535
displayType: '' as string,
491536
commonContentKey: 0,
492537
avUnavailableMessage: false,
538+
passwordVerification: false,
539+
currentPassword: '',
493540
// Some of the Content components have local state
494541
// which isn't in the vuex store.
495542
// This means those fields are validated using an
@@ -573,7 +620,7 @@
573620
closeAfterSave(): boolean {
574621
return this.$store.state.closeAfterSave;
575622
},
576-
isFileAlreadyUploaded(): boolean {
623+
isFileAlreadyUploaded(): boolean {
577624
switch (this.selectedResourceType) {
578625
case this.resourceType.GENERICFILE:
579626
return this.$store.state.genericFileDetail.file.fileName !== '';
@@ -739,6 +786,12 @@
739786
this.processPublish();
740787
}
741788
},
789+
submitPassword() {
790+
this.$v.currentPassword.$touch();
791+
if (!this.$v.currentPassword.$invalid) {
792+
this.validatePassword();
793+
}
794+
},
742795
async processPublish() {
743796
this.showError = false;
744797
let publishSuccess = await resourceData.publishResource(this.resourceVersionId, this.publishNotes);
@@ -758,6 +811,18 @@
758811
this.errorMessage = "An error occurred whilst trying to publish the resource.";
759812
}
760813
},
814+
async validatePassword() {
815+
this.showError = false;
816+
let isValidUser = await userData.IsValidUser(this.currentPassword);
817+
if (isValidUser) {
818+
this.acceptUploadedFile();
819+
this.passwordVerification = false;
820+
}
821+
else {
822+
this.showError = true;
823+
this.errorMessage = "Enter a valid password.";
824+
}
825+
},
761826
deleteResource() {
762827
this.deleteWarning = true;
763828
this.showError = false;
@@ -822,6 +887,10 @@
822887
this.fileUploadRef.value = null;
823888
(this.$refs.fileUploader as any).uploadResourceFile(this.file);
824889
},
890+
confirmPassword() {
891+
this.currentPassword = '';
892+
this.passwordVerification = true;
893+
},
825894
async fileUploadComplete(uploadResult: FileUploadResult) {
826895
if (!uploadResult.invalid) {
827896
if (uploadResult.resourceType != ResourceType.SCORM) {
@@ -900,9 +969,11 @@
900969
this.fileErrorType = FileErrorTypeEnum.InvalidScormType;
901970
return;
902971
}
903-
this.acceptUploadedFile();
972+
this.confirmPassword();
973+
//this.acceptUploadedFile();
904974
} else {
905-
this.acceptUploadedFile();
975+
this.confirmPassword();
976+
//this.acceptUploadedFile();
906977
}
907978
}
908979
}
@@ -948,10 +1019,12 @@
9481019
this.fileTypeChangeWarning = true;
9491020
}
9501021
} else {
951-
this.acceptUploadedFile();
1022+
this.confirmPassword();
1023+
//this.acceptUploadedFile();
9521024
}
9531025
} else {
954-
this.acceptUploadedFile();
1026+
this.confirmPassword();
1027+
//this.acceptUploadedFile();
9551028
}
9561029
}
9571030
}
@@ -1062,6 +1135,9 @@
10621135
},
10631136
publishNotes: {
10641137
required
1138+
},
1139+
currentPassword: {
1140+
required
10651141
}
10661142
},
10671143
watch: {
@@ -1105,4 +1181,7 @@
11051181
max-height: 90vh;
11061182
overflow-y: auto;
11071183
}
1184+
.password-div-width{
1185+
max-width:70% !important;
1186+
}
11081187
</style>

LearningHub.Nhs.WebUI/Scripts/vuesrc/data/user.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,19 @@ const IsSystemAdmin = async function (): Promise<boolean[]> {
6666
});
6767
};
6868

69+
const IsValidUser = async function (currentPassword: string): Promise<boolean[]> {
70+
debugger;
71+
var IsValidUser = `/api/User/ConfirmPassword/${currentPassword}`;
72+
return await AxiosWrapper.axios.get<boolean[]>(IsValidUser)
73+
.then(response => {
74+
return response.data;
75+
})
76+
.catch(e => {
77+
console.log('IsValidUser:' + e);
78+
throw e;
79+
});
80+
};
81+
6982
const getCurrentUserBasicDetails = async function (): Promise<UserBasicModel> {
7083
return await AxiosWrapper.axios.get<UserBasicModel>('/api/User/GetCurrentUserBasicDetails')
7184
.then(response => {
@@ -173,5 +186,6 @@ export const userData = {
173186
keepUserSessionAlive,
174187
getkeepUserSessionAliveInterval,
175188
isGeneralUser,
176-
IsSystemAdmin
189+
IsSystemAdmin,
190+
IsValidUser
177191
}

0 commit comments

Comments
 (0)