diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Assessment/AssessmentBusiness.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Assessment/AssessmentBusiness.cs index 4b038b5c44..384e0ee809 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Assessment/AssessmentBusiness.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Assessment/AssessmentBusiness.cs @@ -847,5 +847,15 @@ public void SaveOtherRemarks(int assessmentId, string remark) dd.StringValue = remark; _context.SaveChanges(); } + + public void clearFirstTime(int userid, int assessment_id) + { + var us = _context.USERS.Where(x => x.UserId == userid).FirstOrDefault(); + if(us != null) + { + us.IsFirstLogin = false; + _context.SaveChanges(); + } + } } } \ No newline at end of file diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Model/CsetwebContext.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Model/CsetwebContext.cs index 576e9928d3..0c8bc6a780 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Model/CsetwebContext.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Model/CsetwebContext.cs @@ -2720,6 +2720,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) entity.ToTable(tb => tb.HasComment("A collection of USERS records")); entity.Property(e => e.IsActive).HasDefaultValueSql("((1))"); + entity.Property(e => e.IsFirstLogin).HasDefaultValueSql("((1))"); entity.Property(e => e.Lang).HasDefaultValueSql("('en')"); entity.Property(e => e.PasswordResetRequired).HasDefaultValueSql("((1))"); entity.Property(e => e.PreventEncrypt).HasDefaultValueSql("((1))"); diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Model/USERS.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Model/USERS.cs index fd24efd0c8..4ebcb13bcb 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Model/USERS.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Model/USERS.cs @@ -54,6 +54,9 @@ public partial class USERS [StringLength(10)] public string Lang { get; set; } + [Required] + public bool? IsFirstLogin { get; set; } + [InverseProperty("AssessmentCreator")] public virtual ICollection ASSESSMENTS { get; set; } = new List(); diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Model/usp_Assessments_Completion_For_UserResult.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Model/usp_Assessments_Completion_For_UserResult.cs index 5f303e545f..95c30a97c7 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Model/usp_Assessments_Completion_For_UserResult.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Model/usp_Assessments_Completion_For_UserResult.cs @@ -7,5 +7,6 @@ namespace CSETWebCore.DataLayer.Model { public partial class usp_Assessments_Completion_For_UserResult { + } } diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/efpt.config.json b/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/efpt.config.json index 21895d8369..a7f0ba07e7 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/efpt.config.json +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/efpt.config.json @@ -1409,6 +1409,7 @@ "UseLegacyPluralizer": false, "UseManyToManyEntity": true, "UseNoDefaultConstructor": false, + "UseNoNavigations": false, "UseNoObjectFilter": false, "UseNodaTime": false, "UseNullableReferences": false, diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Helpers/UserAuthentication.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.Helpers/UserAuthentication.cs index 93845c3f92..7ebde930d1 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Helpers/UserAuthentication.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Helpers/UserAuthentication.cs @@ -123,7 +123,8 @@ public LoginResponse Authenticate(Login login) ResetRequired = loginUser.PasswordResetRequired ?? true, ExportExtension = IOHelper.GetExportFileExtension(login.Scope), ImportExtensions = IOHelper.GetImportFileExtensions(login.Scope), - LinkerTime = new BuildNumberHelper().GetLinkerTime() + LinkerTime = new BuildNumberHelper().GetLinkerTime(), + IsFirstLogin = loginUser.IsFirstLogin??false }; @@ -245,7 +246,8 @@ public LoginResponse AuthenticateStandalone(Login login, ITokenManager tokenMana UserId = userIdSO, ExportExtension = IOHelper.GetExportFileExtension(login.Scope), ImportExtensions = IOHelper.GetImportFileExtensions(login.Scope), - LinkerTime = new BuildNumberHelper().GetLinkerTime() + LinkerTime = new BuildNumberHelper().GetLinkerTime(), + IsFirstLogin = user.IsFirstLogin??false }; diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Interfaces/Assessment/IAssessmentBusiness.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.Interfaces/Assessment/IAssessmentBusiness.cs index a76de3c68a..a8b9945349 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Interfaces/Assessment/IAssessmentBusiness.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Interfaces/Assessment/IAssessmentBusiness.cs @@ -36,5 +36,6 @@ public interface IAssessmentBusiness string GetOtherRemarks(int assessmentId); void SaveOtherRemarks(int assessmentId, string remark); + void clearFirstTime(int userid, int assessmentId); } } diff --git a/CSETWebApi/CSETWeb_Api/CSETWebCore.Model/Authentication/LoginResponse.cs b/CSETWebApi/CSETWeb_Api/CSETWebCore.Model/Authentication/LoginResponse.cs index ae50fab313..db3ace9aa5 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWebCore.Model/Authentication/LoginResponse.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWebCore.Model/Authentication/LoginResponse.cs @@ -20,5 +20,6 @@ public class LoginResponse public string ExportExtension { get; set; } public string ImportExtensions { get; set; } public string LinkerTime { get; set; } + public bool IsFirstLogin { get; set; } } } \ No newline at end of file diff --git a/CSETWebApi/CSETWeb_Api/CSETWeb_ApiCore/Controllers/AssessmentController.cs b/CSETWebApi/CSETWeb_Api/CSETWeb_ApiCore/Controllers/AssessmentController.cs index cc69722980..d8ce374f7b 100644 --- a/CSETWebApi/CSETWeb_Api/CSETWeb_ApiCore/Controllers/AssessmentController.cs +++ b/CSETWebApi/CSETWeb_Api/CSETWeb_ApiCore/Controllers/AssessmentController.cs @@ -443,5 +443,15 @@ public IActionResult UpdateSubmissionStatus() this._acsetAssessmentBusiness.UpdateIseSubmission(assessmentId); return Ok(); } + + [HttpGet] + [Route("api/clearFirstTime")] + public IActionResult clearFirstTime() + { + int assessmentId = _tokenManager.AssessmentForUser(); + int userid = _tokenManager.GetCurrentUserId()??0; + this._assessmentBusiness.clearFirstTime(userid,assessmentId); + return Ok(); + } } } diff --git a/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-convert-cf/assessment-convert-cf.component.html b/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-convert-cf/assessment-convert-cf.component.html index 8c8eaa7059..e1bc457505 100644 --- a/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-convert-cf/assessment-convert-cf.component.html +++ b/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-convert-cf/assessment-convert-cf.component.html @@ -1,8 +1,8 @@
- {{t('cyberFlorida.convert message')}} + {{t('cyberFlorida.upgrade message')}}
- +
diff --git a/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-convert-cf/assessment-convert-cf.component.ts b/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-convert-cf/assessment-convert-cf.component.ts index 444bf2774c..767a7e1bfb 100644 --- a/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-convert-cf/assessment-convert-cf.component.ts +++ b/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-convert-cf/assessment-convert-cf.component.ts @@ -47,9 +47,9 @@ export class AssessmentConvertCfComponent implements OnInit { * Reload the assessment. */ convert() { - const msg1 = this.tSvc.translate('cyberFlorida.convert confirm 1'); - const msg2 = this.tSvc.translate('cyberFlorida.convert confirm 2'); - const titleComplete = this.tSvc.translate('cyberFlorida.title convert complete'); + const msg1 = this.tSvc.translate('cyberFlorida.upgrade confirm 1'); + const msg2 = this.tSvc.translate('cyberFlorida.upgrade confirm 2'); + const titleComplete = this.tSvc.translate('cyberFlorida.title upgrade complete'); const dialogRef = this.dialog.open(ConfirmComponent); dialogRef.componentInstance.confirmMessage = msg1; diff --git a/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-detail-cf/assessment-detail-cf.component.ts b/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-detail-cf/assessment-detail-cf.component.ts index 070f916731..9245d03fbf 100644 --- a/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-detail-cf/assessment-detail-cf.component.ts +++ b/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-detail-cf/assessment-detail-cf.component.ts @@ -66,6 +66,7 @@ export class AssessmentDetailCfComponent implements OnInit { // a few things for a brand new assessment if (this.assessSvc.isBrandNew) { + this.assessSvc.clearFirstTime(); } this.assessSvc.isBrandNew = false; diff --git a/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-detail/assessment-detail.component.ts b/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-detail/assessment-detail.component.ts index eebf785053..af797d99a2 100644 --- a/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-detail/assessment-detail.component.ts +++ b/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-detail/assessment-detail.component.ts @@ -40,7 +40,9 @@ import { MatDialog, MatDialogRef } from '@angular/material/dialog'; }) export class AssessmentDetailComponent implements OnInit { - assessment: AssessmentDetail = {}; + assessment: AssessmentDetail = { + assessmentName:'' + }; dialogRefAwwa: MatDialogRef; isAwwa = false; diff --git a/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-info.component.html b/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-info.component.html index b6db9b1aef..87a8d99083 100644 --- a/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-info.component.html +++ b/CSETWebNg/src/app/assessment/prepare/assessment-info/assessment-info.component.html @@ -35,7 +35,7 @@

{{ t('demogr - + diff --git a/CSETWebNg/src/app/assessment/prepare/assessment-info/demographics-extended/demographics-extended.component.html b/CSETWebNg/src/app/assessment/prepare/assessment-info/demographics-extended/demographics-extended.component.html index d15d87a550..ad9d52da41 100644 --- a/CSETWebNg/src/app/assessment/prepare/assessment-info/demographics-extended/demographics-extended.component.html +++ b/CSETWebNg/src/app/assessment/prepare/assessment-info/demographics-extended/demographics-extended.component.html @@ -74,6 +74,7 @@

Infrastructure Taxonomy

Are you completing the full assessment (156 questions) as local government submitter in response to Florida House Bill 7055? + (Examples: Collier County Water Division, Broward County Aviation Department, City of Tampa Emergency Management, Bay County Supervisor of Elections)

{ this.demographicData = data; - // populate Subsector (industry) dropdown based on Sector this.getSubsectors(this.demographicData.sectorId, false); this.checkComplete(); diff --git a/CSETWebNg/src/app/assessment/results/reports/reports.component.html b/CSETWebNg/src/app/assessment/results/reports/reports.component.html index a83a586dc3..5ac5c01149 100644 --- a/CSETWebNg/src/app/assessment/results/reports/reports.component.html +++ b/CSETWebNg/src/app/assessment/results/reports/reports.component.html @@ -41,6 +41,7 @@

{{ 'titles.reports' | transloco }}

  • {{ field }}
  • +
    All demographics information on the Assessment Information page must be diff --git a/CSETWebNg/src/app/dialogs/edit-user/edit-user.component.ts b/CSETWebNg/src/app/dialogs/edit-user/edit-user.component.ts index 806aef3ff3..9a98855db1 100644 --- a/CSETWebNg/src/app/dialogs/edit-user/edit-user.component.ts +++ b/CSETWebNg/src/app/dialogs/edit-user/edit-user.component.ts @@ -88,7 +88,9 @@ export class EditUserComponent implements OnInit { save(form: NgForm) { if (this.model && form.valid) { this.auth.updateUser(this.model).subscribe( - () => { this.auth.setUserInfo(this.model) }, + () => { + this.auth.setUserInfo(this.model) + }, error => console.log('Error updating the user information' + error.message) ); this.dialog.close(this.model); diff --git a/CSETWebNg/src/app/initial/login-cf/login-cf.component.ts b/CSETWebNg/src/app/initial/login-cf/login-cf.component.ts index 0d4fd124c5..1c8da7bde1 100644 --- a/CSETWebNg/src/app/initial/login-cf/login-cf.component.ts +++ b/CSETWebNg/src/app/initial/login-cf/login-cf.component.ts @@ -105,7 +105,7 @@ export class LoginCfComponent implements OnInit { login() { this.loading = true; this.incorrect = false; - this.passwordExpired = false; + this.passwordExpired = false; this.authenticationService .login(this.model.email, this.model.password) diff --git a/CSETWebNg/src/app/models/user.model.ts b/CSETWebNg/src/app/models/user.model.ts index 19a997317b..4ea1a706f0 100644 --- a/CSETWebNg/src/app/models/user.model.ts +++ b/CSETWebNg/src/app/models/user.model.ts @@ -60,6 +60,7 @@ export interface CreateUser { appCode?: string; title?: string; phone?: string; + isFirstLogin?: boolean; } export interface PotentialQuestions { diff --git a/CSETWebNg/src/app/services/assessment.service.ts b/CSETWebNg/src/app/services/assessment.service.ts index 8a757a2889..09f86529f8 100644 --- a/CSETWebNg/src/app/services/assessment.service.ts +++ b/CSETWebNg/src/app/services/assessment.service.ts @@ -48,6 +48,7 @@ const headers = { @Injectable() export class AssessmentService { + userRoleId: number; roles: Role[]; @@ -119,6 +120,14 @@ export class AssessmentService { return this.http.get(this.apiUrl + 'contacts/allroles'); } + clearFirstTime() { + this.http.get(this.apiUrl + 'clearFirstTime').subscribe( + ()=>{ + console.log("first time assessment clearded"); + } + ); + } + /** * If a custom set name is found on the gallery item, include it in the query string. * Custom set gallery items are built on the fly and don't have a gallery ID. diff --git a/CSETWebNg/src/app/services/authentication.service.ts b/CSETWebNg/src/app/services/authentication.service.ts index 6bcfd38c1e..7b0e27003a 100644 --- a/CSETWebNg/src/app/services/authentication.service.ts +++ b/CSETWebNg/src/app/services/authentication.service.ts @@ -21,7 +21,7 @@ // SOFTWARE. // //////////////////////////////// -import { map } from 'rxjs/operators'; +import { first, map } from 'rxjs/operators'; import { timer, Observable } from 'rxjs'; import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; @@ -49,6 +49,7 @@ export interface LoginResponse { exportExtension: string; importExtensions: string; linkerTime: string; + isFirstLogin: boolean; } const headers = { @@ -58,6 +59,7 @@ const headers = { @Injectable() export class AuthenticationService { + isLocal: boolean; private initialized = false; private parser = new JwtParser(); @@ -115,7 +117,7 @@ export class AuthenticationService { this.isLocal = true; this.storeUserData(response); } - + // if there's a language for the user, set it if (!!response?.lang) { this.tSvc.setActiveLang(response.lang); @@ -156,7 +158,7 @@ export class AuthenticationService { localStorage.setItem('exportExtension', user.exportExtension); localStorage.setItem('importExtensions', user.importExtensions); localStorage.setItem('developer', String(false)); - + localStorage.setItem('isFirstLogin', String(user.isFirstLogin)) // schedule the first token refresh event this.scheduleTokenRefresh(this.http, user.token); } @@ -359,11 +361,22 @@ export class AuthenticationService { lastName() { return localStorage.getItem('lastName'); } + isFirstLogin():boolean{ + var tstring = localStorage.getItem('isFirstLogin'); + if(tstring){ + return Boolean(JSON.parse(tstring)); + } + return false; + } + setFirstLogin(firstLogin: boolean) { + localStorage.setItem('isFirstLogin', String(firstLogin)); + } setUserInfo(info: CreateUser) { localStorage.setItem('firstName', info.firstName); localStorage.setItem('lastName', info.lastName); localStorage.setItem('email', info.primaryEmail); + localStorage.setItem('isFirstLogin', String(info.isFirstLogin)); } /** diff --git a/CSETWebNg/src/app/services/demographic.service.ts b/CSETWebNg/src/app/services/demographic.service.ts index 5ebaf490e0..fc49c2cf66 100644 --- a/CSETWebNg/src/app/services/demographic.service.ts +++ b/CSETWebNg/src/app/services/demographic.service.ts @@ -73,6 +73,10 @@ export class DemographicService { */ updateDemographic(demographic: Demographic) { this.http.post(this.apiUrl, JSON.stringify(demographic), headers) - .subscribe(); + .subscribe(()=> { + if(this.configSvc.cisaAssessorWorkflow){ + + } + }); } } diff --git a/CSETWebNg/src/app/services/gallery.service.ts b/CSETWebNg/src/app/services/gallery.service.ts index 75e5db14fb..e68722dd1d 100644 --- a/CSETWebNg/src/app/services/gallery.service.ts +++ b/CSETWebNg/src/app/services/gallery.service.ts @@ -27,6 +27,7 @@ import { ConfigService } from './config.service'; import { SelectedTier } from '../models/frameworks.model'; import { AssessmentService } from './assessment.service'; import { NavigationService } from './navigation/navigation.service'; +import { AuthenticationService } from './authentication.service'; const headers = { headers: new HttpHeaders() @@ -45,7 +46,8 @@ export class GalleryService { private http: HttpClient, private configSvc: ConfigService, private assessSvc: AssessmentService, - private navSvc: NavigationService + private navSvc: NavigationService, + private authSvc: AuthenticationService ) { } @@ -72,9 +74,16 @@ export class GalleryService { this.testRow = this.rows[1]; ///NOTE THIS runs the default item if there is only one item automatically - if (this.rows.length == 1 && this.rows[0].galleryItems.length == 1) { - this.navSvc.beginNewAssessmentGallery(this.rows[0].galleryItems[0]); + if(this.configSvc.installationMode=="CF"){ + if(this.authSvc.isFirstLogin()){ + this.assessSvc.clearFirstTime(); + this.authSvc.setFirstLogin(false); + this.navSvc.beginNewAssessmentGallery(this.rows[0].galleryItems[0]); + } } + // if (this.rows.length == 1 && this.rows[0].galleryItems.length == 1) { + // this.navSvc.beginNewAssessmentGallery(this.rows[0].galleryItems[0]); + // } // create a plainText property for the elipsis display in case a description has HTML markup const dom = document.createElement("div"); @@ -87,7 +96,7 @@ export class GalleryService { } ); } - + /** * Posts the current selected tier to the server. */ diff --git a/CSETWebNg/src/assets/i18n/en.json b/CSETWebNg/src/assets/i18n/en.json index 69fd791a12..954af213ba 100644 --- a/CSETWebNg/src/assets/i18n/en.json +++ b/CSETWebNg/src/assets/i18n/en.json @@ -142,10 +142,11 @@ "statements": "Statements" }, "cyberFlorida": { - "convert message": "This assessment is using a subset of the Cybersecurity Framework v1.1 requirements and a subset of the Ransomware Readiness Assessment. To convert this assessment to include all questions, click the button below.", - "convert confirm 1": "Are you sure you want to convert this assessment? This is a one-way conversion; it cannot be undone.", - "convert confirm 2": "The assessment has been converted.", - "title convert complete": "Conversion Complete" + "upgrade message": "This assessment is using a subset of the Cybersecurity Framework v1.1 requirements and a subset of the Ransomware Readiness Assessment. To Participate in the full Cyber Florida Assessment Click the Upgrade button below.", + "upgrade confirm 1": "Are you sure you want to upgrade this assessment? This is a one-way conversion; it cannot be undone.", + "upgrade confirm 2": "The assessment has been upgradeed.", + "title upgrade complete":"Upgrade Complete", + "upgradeButton":"Upgrade to Full Assessment" }, "answer-options": { "button-labels": { @@ -420,6 +421,13 @@ "no compensating comment": "No compensating comment or explanation was provided.", "no compensating controls": "There are no compensating controls to display" } + }, + "cyberFlorida": { + "upgrade message": "This assessment is using a subset of the Cybersecurity Framework v1.1 requirements and a subset of the Ransomware Readiness Assessment. To Participate in the full Cyber Florida Assessment Click the Upgrade button below.", + "upgrade confirm 1": "Are you sure you want to upgrade this assessment? This is a one-way conversion; it cannot be undone.", + "upgrade confirm 2": "The assessment has been upgradeed.", + "title upgrade complete":"Upgrade Complete", + "upgradeButton":"Upgrade to Full Assessment" } }, "observation": { diff --git a/CSETWebNg/src/assets/settings/config.json b/CSETWebNg/src/assets/settings/config.json index cc2991730b..79cfce34d9 100644 --- a/CSETWebNg/src/assets/settings/config.json +++ b/CSETWebNg/src/assets/settings/config.json @@ -1,5 +1,5 @@ { - "NOTENODE": "Casing on config chain matters", + "NOTENODE": "Casing on config chain matters, the only item that should be chagned here is the current ConfigChain value. Once that is changed everything else should be set", "currentConfigChain": [ "CSET" ], diff --git a/Database Scripts/Database Maint Scripts/Assessment Clean-out.sql b/Database Scripts/Database Maint Scripts/Assessment Clean-out.sql index 672c2afe6a..4fd7ea36d6 100644 --- a/Database Scripts/Database Maint Scripts/Assessment Clean-out.sql +++ b/Database Scripts/Database Maint Scripts/Assessment Clean-out.sql @@ -4,7 +4,7 @@ delete from [DOCUMENT_FILE] delete from [ACCESS_KEY_ASSESSMENT] delete from [ACCESS_KEY] delete from [ASSESSMENTS] - +delete from FINANCIAL_DOMAIN_FILTERS_V2 DBCC CHECKIDENT ('[ASSESSMENTS]', RESEED, 0); GO