Compare commits
	
		
			5 Commits
		
	
	
		
			mrb
			...
			538b1f817e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 538b1f817e | |||
| 89790f4fc1 | |||
| 9b7e3ef897 | |||
| ba8d92ea01 | |||
| 603052d7e5 | 
| @ -1,74 +0,0 @@ | |||||||
| # EditorConfig is awesome:http://EditorConfig.org |  | ||||||
|  |  | ||||||
| # top-most EditorConfig file |  | ||||||
| root = true |  | ||||||
|  |  | ||||||
| [*] |  | ||||||
| # Don't use tabs for indentation. |  | ||||||
| # (Please don't specify an indent_size here; that has too many unintended consequences.) |  | ||||||
| indent_style = space |  | ||||||
|  |  | ||||||
| charset = utf-8 |  | ||||||
|  |  | ||||||
| # Where supported, trim trailing whitespace on all lines. |  | ||||||
| trim_trailing_whitespace = true |  | ||||||
|  |  | ||||||
| # Where supported (e.g. in VS Code but not VS), add a final newline to files. |  | ||||||
| insert_final_newline = true |  | ||||||
|  |  | ||||||
| # Code files |  | ||||||
| [*.{cs,csx,vb,vbx}] |  | ||||||
| indent_size = 4 |  | ||||||
| dotnet_sort_system_directives_first = true:warning |  | ||||||
|  |  | ||||||
| # Xml project files |  | ||||||
| [*.{*proj,vcxproj.filters,projitems}] |  | ||||||
| indent_size = 2 |  | ||||||
|  |  | ||||||
| # Xml config files |  | ||||||
| [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct,tasks,xml,yml}] |  | ||||||
| indent_size = 2 |  | ||||||
|  |  | ||||||
| # JSON files |  | ||||||
| [*.json] |  | ||||||
| indent_size = 2 |  | ||||||
|  |  | ||||||
| # PowerShell |  | ||||||
| [*.{ps1,psm1}] |  | ||||||
| indent_size = 4 |  | ||||||
|  |  | ||||||
| # Shell |  | ||||||
| [*.sh] |  | ||||||
| indent_size = 4 |  | ||||||
| end_of_line = lf |  | ||||||
|  |  | ||||||
| # Dotnet code style settings: |  | ||||||
| [*.cs] |  | ||||||
| # Sort using and Import directives with System.* appearing first |  | ||||||
| dotnet_sort_system_directives_first = true |  | ||||||
|  |  | ||||||
| # Don't use this. qualifier |  | ||||||
| dotnet_style_qualification_for_field = false:suggestion |  | ||||||
| dotnet_style_qualification_for_property = false:suggestion |  | ||||||
|  |  | ||||||
| # use int x = .. over Int32 |  | ||||||
| dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion |  | ||||||
|  |  | ||||||
| # use int.MaxValue over Int32.MaxValue |  | ||||||
| dotnet_style_predefined_type_for_member_access = true:suggestion |  | ||||||
|  |  | ||||||
| # Require var all the time. |  | ||||||
| csharp_style_var_for_built_in_types = false:suggestion |  | ||||||
| csharp_style_var_when_type_is_apparent = false:suggestion |  | ||||||
| csharp_style_var_elsewhere = false:suggestion |  | ||||||
|  |  | ||||||
| # Disallow throw expressions. |  | ||||||
| csharp_style_throw_expression = false:suggestion |  | ||||||
|  |  | ||||||
| # Newline settings |  | ||||||
| csharp_new_line_before_open_brace = all |  | ||||||
| csharp_new_line_before_else = true |  | ||||||
| csharp_new_line_before_catch = true |  | ||||||
| csharp_new_line_before_finally = true |  | ||||||
| csharp_new_line_before_members_in_object_initializers = true |  | ||||||
| csharp_new_line_before_members_in_anonymous_types = true |  | ||||||
|  | |||||||
							
								
								
									
										20
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -337,3 +337,23 @@ ASALocalRun/ | |||||||
| !.vscode/tasks.json | !.vscode/tasks.json | ||||||
| !.vscode/launch.json | !.vscode/launch.json | ||||||
| !.vscode/extensions.json | !.vscode/extensions.json | ||||||
|  |  | ||||||
|  | .env | ||||||
|  |  | ||||||
|  | /Fab2ApprovalMKLink/App_Start | ||||||
|  | /Fab2ApprovalMKLink/Controllers | ||||||
|  | /Fab2ApprovalMKLink/DMO | ||||||
|  | /Fab2ApprovalMKLink/Jobs | ||||||
|  | /Fab2ApprovalMKLink/JobSchedules | ||||||
|  | /Fab2ApprovalMKLink/Misc | ||||||
|  | /Fab2ApprovalMKLink/Models | ||||||
|  | /Fab2ApprovalMKLink/PdfGenerator | ||||||
|  | /Fab2ApprovalMKLink/Utilities | ||||||
|  | /Fab2ApprovalMKLink/ViewModels | ||||||
|  |  | ||||||
|  | /Fab2ApprovalMKLink/.vscode/.UserSecrets | ||||||
|  | /Fab2ApprovalSystem/.vscode/.UserSecrets | ||||||
|  | /Fab2ApprovalTests/.vscode/.UserSecrets | ||||||
|  | /MesaFabApproval.API/.vscode/.UserSecrets | ||||||
|  | /MesaFabApproval.Client/.vscode/.UserSecrets | ||||||
|  | /MesaFabApproval.Shared/.vscode/.UserSecrets | ||||||
							
								
								
									
										41
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | { | ||||||
|  |     // Use IntelliSense to learn about possible attributes. | ||||||
|  |     // Hover to view descriptions of existing attributes. | ||||||
|  |     // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||||||
|  |     "version": "0.2.0", | ||||||
|  |     "configurations": [ | ||||||
|  |         { | ||||||
|  |             "name": ".NET Core Launch (console) - Fab2ApprovalSystem", | ||||||
|  |             "type": "coreclr", | ||||||
|  |             "request": "launch", | ||||||
|  |             "preLaunchTask": "Fab2ApprovalSystem-build", | ||||||
|  |             "program": "${workspaceFolder}/Fab2ApprovalSystem/bin/Debug/net8.0/win-x64/Fab2ApprovalSystem.dll", | ||||||
|  |             "args": [], | ||||||
|  |             "cwd": "${workspaceFolder}", | ||||||
|  |             "console": "integratedTerminal", | ||||||
|  |             "stopAtEntry": false | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "name": ".NET Core Launch (console) - MesaFabApproval.API", | ||||||
|  |             "type": "coreclr", | ||||||
|  |             "request": "launch", | ||||||
|  |             "preLaunchTask": "MesaFabApproval.API-build", | ||||||
|  |             "program": "${workspaceFolder}/MesaFabApproval.API/bin/Debug/net8.0/MesaFabApproval.API.dll", | ||||||
|  |             "args": [], | ||||||
|  |             "cwd": "${workspaceFolder}", | ||||||
|  |             "console": "integratedTerminal", | ||||||
|  |             "stopAtEntry": false | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "name": ".NET Core Attach", | ||||||
|  |             "type": "coreclr", | ||||||
|  |             "request": "attach" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "type": "node", | ||||||
|  |             "request": "launch", | ||||||
|  |             "name": "node Launch Current Opened File", | ||||||
|  |             "program": "${file}" | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										424
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,424 @@ | |||||||
|  | { | ||||||
|  |   "[markdown]": { | ||||||
|  |     "editor.wordWrap": "off" | ||||||
|  |   }, | ||||||
|  |   "files.exclude": { | ||||||
|  |     "**/.git": false, | ||||||
|  |     "**/node_modules": true | ||||||
|  |   }, | ||||||
|  |   "files.watcherExclude": { | ||||||
|  |     "**/node_modules": true | ||||||
|  |   }, | ||||||
|  |   "cSpell.words": [ | ||||||
|  |     "abutton", | ||||||
|  |     "accessibilities", | ||||||
|  |     "accodingly", | ||||||
|  |     "acknowledgmentby", | ||||||
|  |     "Acks", | ||||||
|  |     "actionsheet", | ||||||
|  |     "Additonal", | ||||||
|  |     "Addtional", | ||||||
|  |     "againm", | ||||||
|  |     "agendaview", | ||||||
|  |     "Antlr", | ||||||
|  |     "Appover", | ||||||
|  |     "Appprrovers", | ||||||
|  |     "Approvalog", | ||||||
|  |     "Aprovers", | ||||||
|  |     "Aproverslist", | ||||||
|  |     "asax", | ||||||
|  |     "aspnetmvc", | ||||||
|  |     "Assignedto", | ||||||
|  |     "Atachments", | ||||||
|  |     "Attachemnt", | ||||||
|  |     "Attachemnts", | ||||||
|  |     "Attchment", | ||||||
|  |     "auditee", | ||||||
|  |     "Auditee", | ||||||
|  |     "Auditees", | ||||||
|  |     "automaically", | ||||||
|  |     "Autthorized", | ||||||
|  |     "beacuase", | ||||||
|  |     "beforeunload", | ||||||
|  |     "Belguim", | ||||||
|  |     "bfound", | ||||||
|  |     "bgcolor", | ||||||
|  |     "Bies", | ||||||
|  |     "binded", | ||||||
|  |     "blackbackground", | ||||||
|  |     "blackhover", | ||||||
|  |     "blackpressed", | ||||||
|  |     "blueenergy", | ||||||
|  |     "blueopal", | ||||||
|  |     "buttongroup", | ||||||
|  |     "BYMRB", | ||||||
|  |     "bytesgot", | ||||||
|  |     "CAID", | ||||||
|  |     "casection", | ||||||
|  |     "CAXXXX", | ||||||
|  |     "CCPCR", | ||||||
|  |     "CCPCRB", | ||||||
|  |     "cellspacing", | ||||||
|  |     "Cheeso's", | ||||||
|  |     "chkbx", | ||||||
|  |     "Clib", | ||||||
|  |     "colorpicker", | ||||||
|  |     "columnmenu", | ||||||
|  |     "columnsreorder", | ||||||
|  |     "columnsresize", | ||||||
|  |     "comming", | ||||||
|  |     "Containmen", | ||||||
|  |     "Copmments", | ||||||
|  |     "correctiv", | ||||||
|  |     "Correctivet", | ||||||
|  |     "Creat", | ||||||
|  |     "currentd", | ||||||
|  |     "Cyle", | ||||||
|  |     "dadada", | ||||||
|  |     "darkbluehover", | ||||||
|  |     "darkbluepressed", | ||||||
|  |     "darkred", | ||||||
|  |     "datafields", | ||||||
|  |     "datasource", | ||||||
|  |     "dataviz", | ||||||
|  |     "datepicker", | ||||||
|  |     "datetimepicker", | ||||||
|  |     "dayview", | ||||||
|  |     "Deletet", | ||||||
|  |     "Delgation", | ||||||
|  |     "DENITED", | ||||||
|  |     "Deparmtent", | ||||||
|  |     "departmentids", | ||||||
|  |     "Descirption", | ||||||
|  |     "devprog", | ||||||
|  |     "dfeffc", | ||||||
|  |     "Disp", | ||||||
|  |     "Dispo", | ||||||
|  |     "Dispoitio", | ||||||
|  |     "Dispos", | ||||||
|  |     "Dispositon", | ||||||
|  |     "Dispostion", | ||||||
|  |     "Dispostions", | ||||||
|  |     "dispotypevalidation", | ||||||
|  |     "Docbase", | ||||||
|  |     "Documentum", | ||||||
|  |     "Documetum", | ||||||
|  |     "dont", | ||||||
|  |     "downlaoded", | ||||||
|  |     "draganddrop", | ||||||
|  |     "dragcancel", | ||||||
|  |     "dropdownlist", | ||||||
|  |     "Eamils", | ||||||
|  |     "ECNPCRB", | ||||||
|  |     "Ecns", | ||||||
|  |     "edmx", | ||||||
|  |     "EECN", | ||||||
|  |     "emai", | ||||||
|  |     "emailparams", | ||||||
|  |     "Emergrncy", | ||||||
|  |     "energyblue", | ||||||
|  |     "Eran", | ||||||
|  |     "Esql", | ||||||
|  |     "ETECN", | ||||||
|  |     "EXCELOPENXML", | ||||||
|  |     "existinglocation", | ||||||
|  |     "Expando", | ||||||
|  |     "extrafield", | ||||||
|  |     "fadc", | ||||||
|  |     "fbec", | ||||||
|  |     "fcfdfd", | ||||||
|  |     "fdff", | ||||||
|  |     "fece", | ||||||
|  |     "feeebd", | ||||||
|  |     "ffdc", | ||||||
|  |     "ffdd", | ||||||
|  |     "fieldset", | ||||||
|  |     "FILIPE", | ||||||
|  |     "filtermenu", | ||||||
|  |     "Fldr", | ||||||
|  |     "flintstone", | ||||||
|  |     "FLOWLOCS", | ||||||
|  |     "FMEA", | ||||||
|  |     "ftplib", | ||||||
|  |     "FTPSPN", | ||||||
|  |     "GETDATE", | ||||||
|  |     "gitea", | ||||||
|  |     "globaldocudms", | ||||||
|  |     "glyphicons", | ||||||
|  |     "groupable", | ||||||
|  |     "Guids", | ||||||
|  |     "halflings", | ||||||
|  |     "Hexsize", | ||||||
|  |     "highcontrast", | ||||||
|  |     "Hmac", | ||||||
|  |     "holdsteps", | ||||||
|  |     "hostspecific", | ||||||
|  |     "icenium", | ||||||
|  |     "IECN", | ||||||
|  |     "imagebrowser", | ||||||
|  |     "IMRB", | ||||||
|  |     "Infineon", | ||||||
|  |     "Insertd", | ||||||
|  |     "inverseicons", | ||||||
|  |     "IPCRB", | ||||||
|  |     "ISADMIN", | ||||||
|  |     "islast", | ||||||
|  |     "ISNULL", | ||||||
|  |     "ITAR", | ||||||
|  |     "jquery", | ||||||
|  |     "jqueryval", | ||||||
|  |     "jqwidgets", | ||||||
|  |     "jqxbuttongroup", | ||||||
|  |     "jqxbuttons", | ||||||
|  |     "jqxcalendar", | ||||||
|  |     "jqxchart", | ||||||
|  |     "jqxcheckbox", | ||||||
|  |     "jqxcolorpicker", | ||||||
|  |     "jqxcombobox", | ||||||
|  |     "jqxcore", | ||||||
|  |     "jqxdata", | ||||||
|  |     "jqxdatatable", | ||||||
|  |     "jqxdatetimeinput", | ||||||
|  |     "jqxdocking", | ||||||
|  |     "jqxdockpanel", | ||||||
|  |     "jqxdragdrop", | ||||||
|  |     "jqxdropdownbutton", | ||||||
|  |     "jqxdropdownlist", | ||||||
|  |     "jqxexpander", | ||||||
|  |     "jqxgauge", | ||||||
|  |     "jqxgrid", | ||||||
|  |     "jqxinput", | ||||||
|  |     "jqxknockout", | ||||||
|  |     "jqxlistbox", | ||||||
|  |     "jqxlistmenu", | ||||||
|  |     "jqxmaskedinput", | ||||||
|  |     "jqxmenu", | ||||||
|  |     "jqxnavigationbar", | ||||||
|  |     "jqxnumberinput", | ||||||
|  |     "jqxpanel", | ||||||
|  |     "jqxpasswordinput", | ||||||
|  |     "jqxprogressbar", | ||||||
|  |     "jqxradiobutton", | ||||||
|  |     "jqxrangeselector", | ||||||
|  |     "jqxrating", | ||||||
|  |     "jqxresponse", | ||||||
|  |     "jqxscrollbar", | ||||||
|  |     "jqxscrollview", | ||||||
|  |     "jqxslider", | ||||||
|  |     "jqxsplitter", | ||||||
|  |     "jqxswitchbutton", | ||||||
|  |     "jqxtabs", | ||||||
|  |     "jqxtooltip", | ||||||
|  |     "jqxtouch", | ||||||
|  |     "jqxtree", | ||||||
|  |     "jqxtreegrid", | ||||||
|  |     "jqxtreemap", | ||||||
|  |     "jqxvalidator", | ||||||
|  |     "jqxwindow", | ||||||
|  |     "kendogridcustom", | ||||||
|  |     "kendoui", | ||||||
|  |     "labelelement", | ||||||
|  |     "labelledby", | ||||||
|  |     "Leanred", | ||||||
|  |     "lightgray", | ||||||
|  |     "linkbutton", | ||||||
|  |     "Linq", | ||||||
|  |     "Listdiv", | ||||||
|  |     "listview", | ||||||
|  |     "Lnks", | ||||||
|  |     "localfilename", | ||||||
|  |     "loclist", | ||||||
|  |     "logis", | ||||||
|  |     "logtext", | ||||||
|  |     "loopmis", | ||||||
|  |     "lotdispo", | ||||||
|  |     "LOTDISPSITION", | ||||||
|  |     "Lotfile", | ||||||
|  |     "lotlist", | ||||||
|  |     "lotstatusoption", | ||||||
|  |     "LTRIM", | ||||||
|  |     "MADUREIRA", | ||||||
|  |     "mailrelay", | ||||||
|  |     "MDTM", | ||||||
|  |     "meego", | ||||||
|  |     "meetingid", | ||||||
|  |     "menubutton", | ||||||
|  |     "mesafi", | ||||||
|  |     "metroblack", | ||||||
|  |     "metrodark", | ||||||
|  |     "miliseconds", | ||||||
|  |     "modalview", | ||||||
|  |     "modernizr", | ||||||
|  |     "Modernizr", | ||||||
|  |     "monthview", | ||||||
|  |     "MRBIs", | ||||||
|  |     "Mrbs", | ||||||
|  |     "msecs", | ||||||
|  |     "multipleextended", | ||||||
|  |     "Navigatable", | ||||||
|  |     "nbsp", | ||||||
|  |     "newbase", | ||||||
|  |     "newchange", | ||||||
|  |     "newdi", | ||||||
|  |     "newfilename", | ||||||
|  |     "newsource", | ||||||
|  |     "Newtonsoft", | ||||||
|  |     "notications", | ||||||
|  |     "Notifcation", | ||||||
|  |     "Notifyf", | ||||||
|  |     "NTLM", | ||||||
|  |     "Nullcc", | ||||||
|  |     "numerictextbox", | ||||||
|  |     "objdata", | ||||||
|  |     "OCAP", | ||||||
|  |     "occured", | ||||||
|  |     "odata", | ||||||
|  |     "oldfilename", | ||||||
|  |     "OLHOLD", | ||||||
|  |     "onclick", | ||||||
|  |     "onmousemove", | ||||||
|  |     "OPDESC", | ||||||
|  |     "OPENQUERY", | ||||||
|  |     "Oper", | ||||||
|  |     "operationslist", | ||||||
|  |     "Orginator", | ||||||
|  |     "Originatorname", | ||||||
|  |     "Ouellette", | ||||||
|  |     "Owin", | ||||||
|  |     "pageable", | ||||||
|  |     "Pageable", | ||||||
|  |     "panelbar", | ||||||
|  |     "parentid", | ||||||
|  |     "parminput", | ||||||
|  |     "parms", | ||||||
|  |     "Parms", | ||||||
|  |     "particula", | ||||||
|  |     "pasv", | ||||||
|  |     "PASV", | ||||||
|  |     "PATINDEX", | ||||||
|  |     "PCRB", | ||||||
|  |     "PCRBID", | ||||||
|  |     "pcrvalues", | ||||||
|  |     "pdbonly", | ||||||
|  |     "Preventitive", | ||||||
|  |     "preventivet", | ||||||
|  |     "Prevetative", | ||||||
|  |     "proces", | ||||||
|  |     "Processedl", | ||||||
|  |     "procs", | ||||||
|  |     "productfamilies", | ||||||
|  |     "progess", | ||||||
|  |     "progressbar", | ||||||
|  |     "qrcode", | ||||||
|  |     "Quanityt", | ||||||
|  |     "rangebar", | ||||||
|  |     "Recep", | ||||||
|  |     "Recepient", | ||||||
|  |     "recieved", | ||||||
|  |     "recordlock", | ||||||
|  |     "remotefilename", | ||||||
|  |     "reorderable", | ||||||
|  |     "reportform", | ||||||
|  |     "reportslist", | ||||||
|  |     "reportslistdiv", | ||||||
|  |     "Reqquired", | ||||||
|  |     "Reqs", | ||||||
|  |     "Requiest", | ||||||
|  |     "Responsibles", | ||||||
|  |     "RETR", | ||||||
|  |     "Revisioing", | ||||||
|  |     "Revisioned", | ||||||
|  |     "Revison", | ||||||
|  |     "rgba", | ||||||
|  |     "rkotian", | ||||||
|  |     "RNFR", | ||||||
|  |     "RNTO", | ||||||
|  |     "Roless", | ||||||
|  |     "roundbg", | ||||||
|  |     "RTRIM", | ||||||
|  |     "SAMDB", | ||||||
|  |     "scroller", | ||||||
|  |     "scrollview", | ||||||
|  |     "seleced", | ||||||
|  |     "selectionlog", | ||||||
|  |     "Selectpart", | ||||||
|  |     "sess", | ||||||
|  |     "Sfisharepoint", | ||||||
|  |     "shinyblack", | ||||||
|  |     "showpassword", | ||||||
|  |     "SIGNON", | ||||||
|  |     "simpleparser", | ||||||
|  |     "slddrw", | ||||||
|  |     "sldprt", | ||||||
|  |     "sortasc", | ||||||
|  |     "sortascbutton", | ||||||
|  |     "sortdesc", | ||||||
|  |     "sortdescbutton", | ||||||
|  |     "sortremove", | ||||||
|  |     "sparkline", | ||||||
|  |     "splitview", | ||||||
|  |     "SPNMRB", | ||||||
|  |     "SPNPDB", | ||||||
|  |     "SSRS", | ||||||
|  |     "Sssign", | ||||||
|  |     "Staus", | ||||||
|  |     "stylesheet", | ||||||
|  |     "Submited", | ||||||
|  |     "subrole", | ||||||
|  |     "subroles", | ||||||
|  |     "Succefully", | ||||||
|  |     "Succesfully", | ||||||
|  |     "sucessfully", | ||||||
|  |     "SURP", | ||||||
|  |     "Swashbuckle", | ||||||
|  |     "SWRN", | ||||||
|  |     "tabindex", | ||||||
|  |     "tabstrip", | ||||||
|  |     "Tahoma", | ||||||
|  |     "taskcompleted", | ||||||
|  |     "Tasklist", | ||||||
|  |     "Taveler", | ||||||
|  |     "TECN", | ||||||
|  |     "TECNs", | ||||||
|  |     "TEMIRWAP", | ||||||
|  |     "tempecd", | ||||||
|  |     "tempimplement", | ||||||
|  |     "templabel", | ||||||
|  |     "tempvalue", | ||||||
|  |     "TEMSA", | ||||||
|  |     "timepicker", | ||||||
|  |     "Tobe", | ||||||
|  |     "Toplevel", | ||||||
|  |     "Totrav", | ||||||
|  |     "trainingby", | ||||||
|  |     "Traininglist", | ||||||
|  |     "traininglistdiv", | ||||||
|  |     "transanction", | ||||||
|  |     "Trav", | ||||||
|  |     "Traveller", | ||||||
|  |     "Traverler", | ||||||
|  |     "TRAVLELER", | ||||||
|  |     "Travler", | ||||||
|  |     "TREEVIEW", | ||||||
|  |     "trigerred", | ||||||
|  |     "ttinclude", | ||||||
|  |     "Uhandled", | ||||||
|  |     "Updat", | ||||||
|  |     "Uplaod", | ||||||
|  |     "Upto", | ||||||
|  |     "userevents", | ||||||
|  |     "userids", | ||||||
|  |     "userlist", | ||||||
|  |     "Validatable", | ||||||
|  |     "valueelement", | ||||||
|  |     "Variabls", | ||||||
|  |     "Verdana", | ||||||
|  |     "vgrid", | ||||||
|  |     "viewmodel", | ||||||
|  |     "vsdoc", | ||||||
|  |     "whethere", | ||||||
|  |     "windowsphone", | ||||||
|  |     "Winsock", | ||||||
|  |     "worlflow" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										500
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										500
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,500 @@ | |||||||
|  | { | ||||||
|  |     "version": "2.0.0", | ||||||
|  |     "tasks": [ | ||||||
|  |         { | ||||||
|  |             "label": "MSBuild", | ||||||
|  |             "command": "C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/MSBuild/Current/Bin/MSBuild.exe", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "/target:Build", | ||||||
|  |                 "/restore:True", | ||||||
|  |                 "/p:RestoreSources=https://artifactory.intra.infineon.com/artifactory/api/nuget/ngt-fi-package-main-vir/%3Bhttps://packagemanagement.eu.infineon.com:4430/api/v2/%3Bhttps://api.nuget.org/v3/index.json", | ||||||
|  |                 "/detailedsummary", | ||||||
|  |                 "/consoleloggerparameters:PerformanceSummary;ErrorsOnly;", | ||||||
|  |                 "/property:Configuration=Debug;TargetFrameworkVersion=v4.8", | ||||||
|  |                 "Fab2ApprovalSystem/Fab2ApprovalSystem.csproj" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalMKLink-User Secrets Init", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "user-secrets", | ||||||
|  |                 "-p", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalMKLink/Fab2ApprovalMKLink.csproj", | ||||||
|  |                 "init" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalMKLink-User Secrets Set", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "user-secrets", | ||||||
|  |                 "-p", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalMKLink/Fab2ApprovalMKLink.csproj", | ||||||
|  |                 "set", | ||||||
|  |                 "_UserSecretsId", | ||||||
|  |                 "f2da5035-aba9-4676-9f8d-d6689f84663d" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalMKLink-Format", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "format", | ||||||
|  |                 "--report", | ||||||
|  |                 ".vscode", | ||||||
|  |                 "--verbosity", | ||||||
|  |                 "detailed", | ||||||
|  |                 "--severity", | ||||||
|  |                 "warn" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalMKLink-Format-Whitespaces", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "format", | ||||||
|  |                 "whitespace" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalMKLink-build", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "build", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalMKLink/Fab2ApprovalMKLink.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalMKLink-publish", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "publish", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalMKLink/Fab2ApprovalMKLink.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalMKLink-watch", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "watch", | ||||||
|  |                 "run", | ||||||
|  |                 "--project", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalMKLink/Fab2ApprovalMKLink.csproj" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalMKLink-Publish AOT", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "publish", | ||||||
|  |                 "-r", | ||||||
|  |                 "win-x64", | ||||||
|  |                 "-c", | ||||||
|  |                 "Release", | ||||||
|  |                 "-p:PublishAot=true", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalMKLink/Fab2ApprovalMKLink.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalTests-User Secrets Init", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "user-secrets", | ||||||
|  |                 "-p", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj", | ||||||
|  |                 "init" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalTests-User Secrets Set", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "user-secrets", | ||||||
|  |                 "-p", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj", | ||||||
|  |                 "set", | ||||||
|  |                 "_UserSecretsId", | ||||||
|  |                 "3942d1fb-d585-40ae-8985-d276d1b94b77" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalTests-Format", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "format", | ||||||
|  |                 "--report", | ||||||
|  |                 ".vscode", | ||||||
|  |                 "--verbosity", | ||||||
|  |                 "detailed", | ||||||
|  |                 "--severity", | ||||||
|  |                 "warn" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalTests-Format-Whitespaces", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "format", | ||||||
|  |                 "whitespace" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalTests-build", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "build", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalTests-testDebug", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "test", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalTests-testRelease", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "test", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary", | ||||||
|  |                 "-c", | ||||||
|  |                 "Release" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalTests-publish", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "publish", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalTests-watch", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "watch", | ||||||
|  |                 "run", | ||||||
|  |                 "--project", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Fab2ApprovalTests-Publish AOT", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "publish", | ||||||
|  |                 "-r", | ||||||
|  |                 "win-x64", | ||||||
|  |                 "-c", | ||||||
|  |                 "Release", | ||||||
|  |                 "-p:PublishAot=true", | ||||||
|  |                 "${workspaceFolder}/Fab2ApprovalTests/Fab2ApprovalTests.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.API-User Secrets Init", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "user-secrets", | ||||||
|  |                 "-p", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj", | ||||||
|  |                 "init" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.API-User Secrets Set", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "user-secrets", | ||||||
|  |                 "-p", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj", | ||||||
|  |                 "set", | ||||||
|  |                 "_UserSecretsId", | ||||||
|  |                 "0b98e1f2-95ed-4edd-8149-58cce51ca059" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.API-Format", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "format", | ||||||
|  |                 "--report", | ||||||
|  |                 ".vscode", | ||||||
|  |                 "--verbosity", | ||||||
|  |                 "detailed", | ||||||
|  |                 "--severity", | ||||||
|  |                 "warn" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.API-Format-Whitespaces", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "format", | ||||||
|  |                 "whitespace" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.API-build", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "build", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.API-testDebug", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "test", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.API-testRelease", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "test", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary", | ||||||
|  |                 "-c", | ||||||
|  |                 "Release" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.API-publish", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "publish", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.API-watch", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "watch", | ||||||
|  |                 "run", | ||||||
|  |                 "--project", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.API-Publish AOT", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "publish", | ||||||
|  |                 "-r", | ||||||
|  |                 "win-x64", | ||||||
|  |                 "-c", | ||||||
|  |                 "Release", | ||||||
|  |                 "-p:PublishAot=true", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API/MesaFabApproval.API.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.Client-User Secrets Init", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "user-secrets", | ||||||
|  |                 "-p", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj", | ||||||
|  |                 "init" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.Client-Format", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "format", | ||||||
|  |                 "--report", | ||||||
|  |                 ".vscode", | ||||||
|  |                 "--verbosity", | ||||||
|  |                 "detailed", | ||||||
|  |                 "--severity", | ||||||
|  |                 "warn" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.Client-Format-Whitespaces", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "format", | ||||||
|  |                 "whitespace" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.Client-build", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "build", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.Client-testDebug", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "test", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.Client-testRelease", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "test", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary", | ||||||
|  |                 "-c", | ||||||
|  |                 "Release" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.Client-publish", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "publish", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.Client-watch", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "watch", | ||||||
|  |                 "run", | ||||||
|  |                 "--project", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "MesaFabApproval.Client-Publish AOT", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "publish", | ||||||
|  |                 "-r", | ||||||
|  |                 "win-x64", | ||||||
|  |                 "-c", | ||||||
|  |                 "Release", | ||||||
|  |                 "-p:PublishAot=true", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client/MesaFabApproval.Client.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | } | ||||||
| @ -1,20 +1,20 @@ | |||||||
|  |  | ||||||
| Microsoft Visual Studio Solution File, Format Version 12.00 | Microsoft Visual Studio Solution File, Format Version 12.00 | ||||||
| # Visual Studio 15 | # Visual Studio Version 17 | ||||||
| VisualStudioVersion = 15.0.27130.2020 | VisualStudioVersion = 17.9.34616.47 | ||||||
| MinimumVisualStudioVersion = 10.0.40219.1 | MinimumVisualStudioVersion = 10.0.40219.1 | ||||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fab2ApprovalSystem", "Fab2ApprovalSystem\Fab2ApprovalSystem.csproj", "{AAE52608-4DD1-4732-92BD-CC8915DEC71E}" | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fab2ApprovalSystem", "Fab2ApprovalSystem\Fab2ApprovalSystem.csproj", "{AAE52608-4DD1-4732-92BD-CC8915DEC71E}" | ||||||
| EndProject | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MesaFabApproval.API", "MesaFabApproval.API\MesaFabApproval.API.csproj", "{852E528D-015A-43B5-999D-F281E3359E5E}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MesaFabApproval.Shared", "MesaFabApproval.Shared\MesaFabApproval.Shared.csproj", "{2C16014D-B04E-46AF-AB4C-D2691D44A339}" | ||||||
|  | EndProject | ||||||
|  | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MesaFabApproval.Client", "MesaFabApproval.Client\MesaFabApproval.Client.csproj", "{34D52F44-A81F-4247-8180-16E204824A07}" | ||||||
|  | 	ProjectSection(ProjectDependencies) = postProject | ||||||
|  | 		{2C16014D-B04E-46AF-AB4C-D2691D44A339} = {2C16014D-B04E-46AF-AB4C-D2691D44A339} | ||||||
|  | 	EndProjectSection | ||||||
|  | EndProject | ||||||
| Global | Global | ||||||
| 	GlobalSection(TeamFoundationVersionControl) = preSolution |  | ||||||
| 		SccNumberOfProjects = 2 |  | ||||||
| 		SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} |  | ||||||
| 		SccTeamFoundationServer = http://tfs.intra.infineon.com:8080/tfs/manufacturingit |  | ||||||
| 		SccLocalPath0 = . |  | ||||||
| 		SccProjectUniqueName1 = Fab2ApprovalSystem\\Fab2ApprovalSystem.csproj |  | ||||||
| 		SccProjectName1 = Fab2ApprovalSystem |  | ||||||
| 		SccLocalPath1 = Fab2ApprovalSystem |  | ||||||
| 	EndGlobalSection |  | ||||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||||
| 		Debug|Any CPU = Debug|Any CPU | 		Debug|Any CPU = Debug|Any CPU | ||||||
| 		Release|Any CPU = Release|Any CPU | 		Release|Any CPU = Release|Any CPU | ||||||
| @ -24,8 +24,23 @@ Global | |||||||
| 		{AAE52608-4DD1-4732-92BD-CC8915DEC71E}.Debug|Any CPU.Build.0 = Debug|Any CPU | 		{AAE52608-4DD1-4732-92BD-CC8915DEC71E}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
| 		{AAE52608-4DD1-4732-92BD-CC8915DEC71E}.Release|Any CPU.ActiveCfg = Release|Any CPU | 		{AAE52608-4DD1-4732-92BD-CC8915DEC71E}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
| 		{AAE52608-4DD1-4732-92BD-CC8915DEC71E}.Release|Any CPU.Build.0 = Release|Any CPU | 		{AAE52608-4DD1-4732-92BD-CC8915DEC71E}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{852E528D-015A-43B5-999D-F281E3359E5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{852E528D-015A-43B5-999D-F281E3359E5E}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{852E528D-015A-43B5-999D-F281E3359E5E}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{852E528D-015A-43B5-999D-F281E3359E5E}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{2C16014D-B04E-46AF-AB4C-D2691D44A339}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{2C16014D-B04E-46AF-AB4C-D2691D44A339}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{2C16014D-B04E-46AF-AB4C-D2691D44A339}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{2C16014D-B04E-46AF-AB4C-D2691D44A339}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
|  | 		{34D52F44-A81F-4247-8180-16E204824A07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||||
|  | 		{34D52F44-A81F-4247-8180-16E204824A07}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||||
|  | 		{34D52F44-A81F-4247-8180-16E204824A07}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||||
|  | 		{34D52F44-A81F-4247-8180-16E204824A07}.Release|Any CPU.Build.0 = Release|Any CPU | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
| 	GlobalSection(SolutionProperties) = preSolution | 	GlobalSection(SolutionProperties) = preSolution | ||||||
| 		HideSolutionNode = FALSE | 		HideSolutionNode = FALSE | ||||||
| 	EndGlobalSection | 	EndGlobalSection | ||||||
|  | 	GlobalSection(ExtensibilityGlobals) = postSolution | ||||||
|  | 		SolutionGuid = {A966A184-1FCD-4B6A-978C-5907CC12406B} | ||||||
|  | 	EndGlobalSection | ||||||
| EndGlobal | EndGlobal | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ namespace Fab2ApprovalSystem | |||||||
|                 LoginPath = new PathString("/Account/Login") |                 LoginPath = new PathString("/Account/Login") | ||||||
|             }); |             }); | ||||||
|             // Use a cookie to temporarily store information about a user logging in with a third party login provider |             // Use a cookie to temporarily store information about a user logging in with a third party login provider | ||||||
|             app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); |             // app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); | ||||||
|  |  | ||||||
|             // Uncomment the following lines to enable logging in with third party login providers |             // Uncomment the following lines to enable logging in with third party login providers | ||||||
|             //app.UseMicrosoftAccountAuthentication( |             //app.UseMicrosoftAccountAuthentication( | ||||||
|  | |||||||
| @ -1,10 +1,6 @@ | |||||||
| using System; | using System.Web.Http; | ||||||
| using System.Collections.Generic; |  | ||||||
| using System.Linq; |  | ||||||
| using System.Web.Http; |  | ||||||
|  |  | ||||||
| namespace Fab2ApprovalSystem | namespace Fab2ApprovalSystem { | ||||||
| { |  | ||||||
|     public static class WebApiConfig |     public static class WebApiConfig | ||||||
|     { |     { | ||||||
|         public static void Register(HttpConfiguration config) |         public static void Register(HttpConfiguration config) | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| using System; | using System; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.Linq; |  | ||||||
| using System.Security.Claims; | using System.Security.Claims; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
| using System.Web; | using System.Web; | ||||||
| @ -12,20 +11,24 @@ using Fab2ApprovalSystem.Models; | |||||||
| using System.Web.Security; | using System.Web.Security; | ||||||
| using Fab2ApprovalSystem.Misc; | using Fab2ApprovalSystem.Misc; | ||||||
| using Fab2ApprovalSystem.DMO; | using Fab2ApprovalSystem.DMO; | ||||||
|  | using Microsoft.AspNet.Identity.Owin; | ||||||
|  | using System.Net.Http; | ||||||
|  | using Newtonsoft.Json; | ||||||
|  | using System.Text; | ||||||
|  | using System.Net; | ||||||
|  |  | ||||||
| namespace Fab2ApprovalSystem.Controllers | namespace Fab2ApprovalSystem.Controllers { | ||||||
| { |  | ||||||
|     [Authorize] |     [Authorize] | ||||||
|     public class AccountController : Controller |     public class AccountController : Controller { | ||||||
|     { |         private string _apiBaseUrl; | ||||||
|  |  | ||||||
|         public AccountController() |         public AccountController() | ||||||
|             : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()))) |             : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()))) { | ||||||
|         { |             _apiBaseUrl = Environment.GetEnvironmentVariable("FabApprovalApiBaseUrl") ?? | ||||||
|  |                 throw new ArgumentNullException("FabApprovalApiBaseUrl environment variable not found"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         public AccountController(UserManager<ApplicationUser> userManager) { | ||||||
|         public AccountController(UserManager<ApplicationUser> userManager) |  | ||||||
|         { |  | ||||||
|             UserManager = userManager; |             UserManager = userManager; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @ -35,9 +38,8 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|         // GET: /Account/Login |         // GET: /Account/Login | ||||||
|         [AllowAnonymous] |         [AllowAnonymous] | ||||||
|         // try to make the browser refresh the login page every time, to prevent issues with changing usernames and the anti-forgery token validation |         // try to make the browser refresh the login page every time, to prevent issues with changing usernames and the anti-forgery token validation | ||||||
|         [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]  |         [OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")] | ||||||
|         public ActionResult Login(string returnUrl) |         public ActionResult Login(string returnUrl) { | ||||||
|         { |  | ||||||
|             ViewBag.ReturnUrl = returnUrl; |             ViewBag.ReturnUrl = returnUrl; | ||||||
|             return View(); |             return View(); | ||||||
|         } |         } | ||||||
| @ -45,18 +47,32 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|         [HttpPost] |         [HttpPost] | ||||||
|         [AllowAnonymous] |         [AllowAnonymous] | ||||||
|         [ValidateAntiForgeryToken] |         [ValidateAntiForgeryToken] | ||||||
|         public ActionResult Login(LoginModel model, string returnUrl) |         public async Task<ActionResult> Login(LoginModel model, string returnUrl) { | ||||||
|         { |             try { | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 //if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe)) |  | ||||||
|                 //{ |  | ||||||
|                 //    return RedirectToLocal(returnUrl); |  | ||||||
|                 //} |  | ||||||
|  |  | ||||||
|                 UserAccountDMO userDMO = new UserAccountDMO(); |  | ||||||
|                 bool isLoginValid; |                 bool isLoginValid; | ||||||
|                 MembershipProvider domainProvider; |  | ||||||
|  |                 HttpClient httpClient = HttpClientFactory.Create(); | ||||||
|  |                 httpClient.BaseAddress = new Uri(_apiBaseUrl); | ||||||
|  |  | ||||||
|  |                 AuthAttempt authAttempt = new AuthAttempt() { | ||||||
|  |                     LoginID = model.LoginID, | ||||||
|  |                     Password = model.Password | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "auth/login"); | ||||||
|  |  | ||||||
|  |                 request.Content = new StringContent(JsonConvert.SerializeObject(authAttempt), | ||||||
|  |                                                                   Encoding.UTF8, | ||||||
|  |                                                                   "application/json"); | ||||||
|  |  | ||||||
|  |                 HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(request); | ||||||
|  |  | ||||||
|  |                 if (!httpResponseMessage.IsSuccessStatusCode) | ||||||
|  |                     throw new Exception($"The authentication API failed, because {httpResponseMessage.ReasonPhrase}"); | ||||||
|  |  | ||||||
|  |                 string responseContent = await httpResponseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 LoginResult loginResult = JsonConvert.DeserializeObject<LoginResult>(responseContent); | ||||||
|  |  | ||||||
| #if(DEBUG) | #if(DEBUG) | ||||||
|                 isLoginValid = true; |                 isLoginValid = true; | ||||||
| @ -65,29 +81,26 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
| #if (!DEBUG) | #if (!DEBUG) | ||||||
|  |  | ||||||
|                 bool isIFX = false; |                 bool isIFX = false; | ||||||
|             //domainProvider = Membership.Providers["NA_ADMembershipProvider"]; |                 //domainProvider = Membership.Providers["NA_ADMembershipProvider"]; | ||||||
|             //isLoginValid = domainProvider.ValidateUser(model.LoginID, model.Password);   |                 //isLoginValid = domainProvider.ValidateUser(model.LoginID, model.Password);   | ||||||
|  |  | ||||||
|                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") |                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") { | ||||||
|                     isLoginValid = true; |                     isLoginValid = true; | ||||||
|                 else |                 } else { | ||||||
|                 { |                     isLoginValid = loginResult.IsAuthenticated; | ||||||
|                     isLoginValid = Functions.NA_ADAuthenticate(model.LoginID, model.Password); |                     if (isLoginValid) isIFX = true; | ||||||
|                     if (!isLoginValid) |  | ||||||
|                     { |  | ||||||
|                         isLoginValid = Functions.IFX_ADAuthenticate(model.LoginID, model.Password); |  | ||||||
|                         isIFX = true; |  | ||||||
|                     } |  | ||||||
|                      |  | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|                 if (isLoginValid) |                 if (isLoginValid) { | ||||||
|                 { |                     UserAccountDMO userDMO = new UserAccountDMO(); | ||||||
|                     LoginModel user = userDMO.GetUser(model.LoginID); |                     LoginModel user = userDMO.GetUser(model.LoginID); | ||||||
|                     if (user != null) |                     if (user != null) { | ||||||
|                     { |                         Session["JWT"] = loginResult.AuthTokens.JwtToken; | ||||||
|  |                         Session["RefreshToken"] = loginResult.AuthTokens.RefreshToken; | ||||||
|  |  | ||||||
|                         Session[GlobalVars.SESSION_USERID] = user.UserID; |                         Session[GlobalVars.SESSION_USERID] = user.UserID; | ||||||
|                         Session[GlobalVars.SESSION_USERNAME] = user.FullName; |                         Session[GlobalVars.SESSION_USERNAME] = user.FullName; | ||||||
|                         Session[GlobalVars.IS_ADMIN] = user.IsAdmin; |                         Session[GlobalVars.IS_ADMIN] = user.IsAdmin; | ||||||
| @ -96,23 +109,16 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|                         Session[GlobalVars.CAN_CREATE_PARTS_REQUEST] = user.IsAdmin || PartsRequestController.CanCreatePartsRequest(user.UserID); |                         Session[GlobalVars.CAN_CREATE_PARTS_REQUEST] = user.IsAdmin || PartsRequestController.CanCreatePartsRequest(user.UserID); | ||||||
|  |  | ||||||
|                         FormsAuthentication.SetAuthCookie(user.LoginID, true); |                         FormsAuthentication.SetAuthCookie(user.LoginID, true); | ||||||
|  |  | ||||||
|                         return RedirectToLocal(returnUrl); |                         return RedirectToLocal(returnUrl); | ||||||
|                     } |                     } else { | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         ModelState.AddModelError("", "The user name does not exist in the DB. Please contact the System Admin"); |                         ModelState.AddModelError("", "The user name does not exist in the DB. Please contact the System Admin"); | ||||||
|                     } |                     } | ||||||
|  |                 } else { | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     ModelState.AddModelError("", "The user name or password provided is incorrect."); |                     ModelState.AddModelError("", "The user name or password provided is incorrect."); | ||||||
|                 } |                 } | ||||||
|             } |             } catch (Exception ex) { | ||||||
|  |                 Functions.WriteEvent(@User.Identity.Name + " " + ex.InnerException, System.Diagnostics.EventLogEntryType.Error); | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 Functions.WriteEvent(@User.Identity.Name + " " + ex.InnerException , System.Diagnostics.EventLogEntryType.Error); |  | ||||||
|                 EventLogDMO.Add(new WinEventLog() { IssueID = 99999, UserID = @User.Identity.Name, DocumentType = "Login", OperationType = "Error", Comments = "Reject - " + ex.Message }); |                 EventLogDMO.Add(new WinEventLog() { IssueID = 99999, UserID = @User.Identity.Name, DocumentType = "Login", OperationType = "Error", Comments = "Reject - " + ex.Message }); | ||||||
|                 ModelState.AddModelError("", ex.Message); |                 ModelState.AddModelError("", ex.Message); | ||||||
|             } |             } | ||||||
| @ -122,285 +128,167 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         //// |         [HttpPost] | ||||||
|         //// POST: /Account/Login |         [AllowAnonymous] | ||||||
|         //[HttpPost] |         public async Task<HttpResponseMessage> ExternalAuthSetup(AuthAttempt authAttempt) { | ||||||
|         //[AllowAnonymous] |             try { | ||||||
|         //[ValidateAntiForgeryToken] |                 bool isLoginValid; | ||||||
|         //public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) |  | ||||||
|         //{ |  | ||||||
|         //    if (ModelState.IsValid) |  | ||||||
|         //    { |  | ||||||
|         //        var user = await UserManager.FindAsync(model.UserName, model.Password); |  | ||||||
|         //        if (user != null) |  | ||||||
|         //        { |  | ||||||
|         //            await SignInAsync(user, model.RememberMe); |  | ||||||
|         //            return RedirectToLocal(returnUrl); |  | ||||||
|         //        } |  | ||||||
|         //        else |  | ||||||
|         //        { |  | ||||||
|         //            ModelState.AddModelError("", "Invalid username or password."); |  | ||||||
|         //        } |  | ||||||
|         //    } |  | ||||||
|  |  | ||||||
|         //    // If we got this far, something failed, redisplay form |                 HttpClient httpClient = HttpClientFactory.Create(); | ||||||
|         //    return View(model); |                 httpClient.BaseAddress = new Uri(_apiBaseUrl); | ||||||
|         //} |  | ||||||
|  |                 HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "auth/refresh"); | ||||||
|  |  | ||||||
|  |                 request.Content = new StringContent(JsonConvert.SerializeObject(authAttempt), | ||||||
|  |                                                                   Encoding.UTF8, | ||||||
|  |                                                                   "application/json"); | ||||||
|  |  | ||||||
|  |                 HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(request); | ||||||
|  |  | ||||||
|  |                 if (!httpResponseMessage.IsSuccessStatusCode) | ||||||
|  |                     throw new Exception($"The authentication API failed, because {httpResponseMessage.ReasonPhrase}"); | ||||||
|  |  | ||||||
|  |                 string responseContent = await httpResponseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 LoginResult loginResult = JsonConvert.DeserializeObject<LoginResult>(responseContent); | ||||||
|  |  | ||||||
|  | #if(DEBUG) | ||||||
|  |                 isLoginValid = true; | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  | #if (!DEBUG) | ||||||
|  |  | ||||||
|  |                 bool isIFX = false; | ||||||
|  |                 //domainProvider = Membership.Providers["NA_ADMembershipProvider"]; | ||||||
|  |                 //isLoginValid = domainProvider.ValidateUser(model.LoginID, model.Password);   | ||||||
|  |  | ||||||
|  |                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") { | ||||||
|  |                     isLoginValid = true; | ||||||
|  |                 } else { | ||||||
|  |                     isLoginValid = loginResult.IsAuthenticated; | ||||||
|  |                     if (isLoginValid) isIFX = true; | ||||||
|  |  | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |                 if (isLoginValid) { | ||||||
|  |                     UserAccountDMO userDMO = new UserAccountDMO(); | ||||||
|  |                     LoginModel user = userDMO.GetUser(authAttempt.LoginID); | ||||||
|  |                     if (user != null) { | ||||||
|  |                         Session["JWT"] = loginResult.AuthTokens.JwtToken; | ||||||
|  |                         Session["RefreshToken"] = loginResult.AuthTokens.RefreshToken; | ||||||
|  |  | ||||||
|  |                         Session[GlobalVars.SESSION_USERID] = user.UserID; | ||||||
|  |                         Session[GlobalVars.SESSION_USERNAME] = user.FullName; | ||||||
|  |                         Session[GlobalVars.IS_ADMIN] = user.IsAdmin; | ||||||
|  |                         Session[GlobalVars.IS_MANAGER] = user.IsManager; | ||||||
|  |                         Session[GlobalVars.OOO] = user.OOO; | ||||||
|  |                         Session[GlobalVars.CAN_CREATE_PARTS_REQUEST] = user.IsAdmin || PartsRequestController.CanCreatePartsRequest(user.UserID); | ||||||
|  |  | ||||||
|  |                         FormsAuthentication.SetAuthCookie(user.LoginID, true); | ||||||
|  |  | ||||||
|  |                         return new HttpResponseMessage(HttpStatusCode.OK); | ||||||
|  |                     } else { | ||||||
|  |                         ModelState.AddModelError("", "The user name does not exist in the DB. Please contact the System Admin"); | ||||||
|  |  | ||||||
|  |                         return new HttpResponseMessage(HttpStatusCode.NotFound); | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     ModelState.AddModelError("", "The user name or password provided is incorrect."); | ||||||
|  |  | ||||||
|  |                     return new HttpResponseMessage(HttpStatusCode.Unauthorized); | ||||||
|  |                 } | ||||||
|  |             } catch (Exception ex) { | ||||||
|  |                 Functions.WriteEvent(@User.Identity.Name + " " + ex.InnerException, System.Diagnostics.EventLogEntryType.Error); | ||||||
|  |                 EventLogDMO.Add(new WinEventLog() { IssueID = 99999, UserID = @User.Identity.Name, DocumentType = "Login", OperationType = "Error", Comments = "Reject - " + ex.Message }); | ||||||
|  |                 ModelState.AddModelError("", ex.Message); | ||||||
|  |  | ||||||
|  |                 return new HttpResponseMessage(HttpStatusCode.InternalServerError); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // |  | ||||||
|         // GET: /Account/Register |         // GET: /Account/Register | ||||||
|         [AllowAnonymous] |         [AllowAnonymous] | ||||||
|         public ActionResult Register() |         public ActionResult Register() { | ||||||
|         { |  | ||||||
|             return View(); |             return View(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // |  | ||||||
|         // POST: /Account/Register |  | ||||||
|         //[HttpPost] |  | ||||||
|         //[AllowAnonymous] |  | ||||||
|         //[ValidateAntiForgeryToken] |  | ||||||
|         //public async Task<ActionResult> Register(RegisterViewModel model) |  | ||||||
|         //{ |  | ||||||
|         //    if (ModelState.IsValid) |  | ||||||
|         //    { |  | ||||||
|         //        var user = new ApplicationUser() { UserName = model.UserName }; |  | ||||||
|         //        var result = await UserManager.CreateAsync(user, model.Password); |  | ||||||
|         //        if (result.Succeeded) |  | ||||||
|         //        { |  | ||||||
|         //            await SignInAsync(user, isPersistent: false); |  | ||||||
|         //            return RedirectToAction("Index", "Home"); |  | ||||||
|         //        } |  | ||||||
|         //        else |  | ||||||
|         //        { |  | ||||||
|         //            AddErrors(result); |  | ||||||
|         //        } |  | ||||||
|         //    } |  | ||||||
|  |  | ||||||
|         //    // If we got this far, something failed, redisplay form |  | ||||||
|         //    return View(model); |  | ||||||
|         //} |  | ||||||
|  |  | ||||||
|         // |  | ||||||
|         // POST: /Account/Disassociate |         // POST: /Account/Disassociate | ||||||
|         [HttpPost] |         [HttpPost] | ||||||
|         [ValidateAntiForgeryToken] |         [ValidateAntiForgeryToken] | ||||||
|         public async Task<ActionResult> Disassociate(string loginProvider, string providerKey) |         public async Task<ActionResult> Disassociate(string loginProvider, string providerKey) { | ||||||
|         { |  | ||||||
|             ManageMessageId? message = null; |             ManageMessageId? message = null; | ||||||
|             IdentityResult result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey)); |             IdentityResult result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey)); | ||||||
|             if (result.Succeeded) |             if (result.Succeeded) { | ||||||
|             { |  | ||||||
|                 message = ManageMessageId.RemoveLoginSuccess; |                 message = ManageMessageId.RemoveLoginSuccess; | ||||||
|             } |             } else { | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 message = ManageMessageId.Error; |                 message = ManageMessageId.Error; | ||||||
|             } |             } | ||||||
|             return RedirectToAction("Manage", new { Message = message }); |             return RedirectToAction("Manage", new { Message = message }); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // |  | ||||||
|         // GET: /Account/Manage |         // GET: /Account/Manage | ||||||
|         public ActionResult Manage(ManageMessageId? message) | #pragma warning disable IDE0060 // Remove unused parameter | ||||||
|         { |         public ActionResult Manage(ManageMessageId? message) { | ||||||
|             //ViewBag.StatusMessage = |  | ||||||
|             //    message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed." |  | ||||||
|             //    : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set." |  | ||||||
|             //    : message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed." |  | ||||||
|             //    : message == ManageMessageId.Error ? "An error has occurred." |  | ||||||
|             //    : ""; |  | ||||||
|             //ViewBag.HasLocalPassword = HasPassword(); |  | ||||||
|             //ViewBag.ReturnUrl = Url.Action("Manage"); |  | ||||||
|             return View(); |             return View(); | ||||||
|         } |         } | ||||||
|  | #pragma warning restore IDE0060 // Remove unused parameter | ||||||
|  |  | ||||||
|         //// |  | ||||||
|         //// POST: /Account/Manage |  | ||||||
|         //[HttpPost] |  | ||||||
|         //[ValidateAntiForgeryToken] |  | ||||||
|         //public async Task<ActionResult> Manage(ManageUserViewModel model) |  | ||||||
|         //{ |  | ||||||
|         //    bool hasPassword = HasPassword(); |  | ||||||
|         //    ViewBag.HasLocalPassword = hasPassword; |  | ||||||
|         //    ViewBag.ReturnUrl = Url.Action("Manage"); |  | ||||||
|         //    if (hasPassword) |  | ||||||
|         //    { |  | ||||||
|         //        if (ModelState.IsValid) |  | ||||||
|         //        { |  | ||||||
|         //            IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword); |  | ||||||
|         //            if (result.Succeeded) |  | ||||||
|         //            { |  | ||||||
|         //                return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess }); |  | ||||||
|         //            } |  | ||||||
|         //            else |  | ||||||
|         //            { |  | ||||||
|         //                AddErrors(result); |  | ||||||
|         //            } |  | ||||||
|         //        } |  | ||||||
|         //    } |  | ||||||
|         //    else |  | ||||||
|         //    { |  | ||||||
|         //        // User does not have a password so remove any validation errors caused by a missing OldPassword field |  | ||||||
|         //        ModelState state = ModelState["OldPassword"]; |  | ||||||
|         //        if (state != null) |  | ||||||
|         //        { |  | ||||||
|         //            state.Errors.Clear(); |  | ||||||
|         //        } |  | ||||||
|  |  | ||||||
|         //        if (ModelState.IsValid) |  | ||||||
|         //        { |  | ||||||
|         //            IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword); |  | ||||||
|         //            if (result.Succeeded) |  | ||||||
|         //            { |  | ||||||
|         //                return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess }); |  | ||||||
|         //            } |  | ||||||
|         //            else |  | ||||||
|         //            { |  | ||||||
|         //                AddErrors(result); |  | ||||||
|         //            } |  | ||||||
|         //        } |  | ||||||
|         //    } |  | ||||||
|  |  | ||||||
|         //    // If we got this far, something failed, redisplay form |  | ||||||
|         //    return View(model); |  | ||||||
|         //} |  | ||||||
|  |  | ||||||
|         // |  | ||||||
|         // POST: /Account/ExternalLogin |         // POST: /Account/ExternalLogin | ||||||
|         [HttpPost] |         [HttpPost] | ||||||
|         [AllowAnonymous] |         [AllowAnonymous] | ||||||
|         [ValidateAntiForgeryToken] |         [ValidateAntiForgeryToken] | ||||||
|         public ActionResult ExternalLogin(string provider, string returnUrl) |         public ActionResult ExternalLogin(string provider, string returnUrl) { | ||||||
|         { |  | ||||||
|             // Request a redirect to the external login provider |             // Request a redirect to the external login provider | ||||||
|             return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl })); |             return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl })); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         //// |  | ||||||
|         //// GET: /Account/ExternalLoginCallback |  | ||||||
|         //[AllowAnonymous] |  | ||||||
|         //public async Task<ActionResult> ExternalLoginCallback(string returnUrl) |  | ||||||
|         //{ |  | ||||||
|         //    var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(); |  | ||||||
|         //    if (loginInfo == null) |  | ||||||
|         //    { |  | ||||||
|         //        return RedirectToAction("Login"); |  | ||||||
|         //    } |  | ||||||
|  |  | ||||||
|         //    // Sign in the user with this external login provider if the user already has a login |  | ||||||
|         //    var user = await UserManager.FindAsync(loginInfo.Login); |  | ||||||
|         //    if (user != null) |  | ||||||
|         //    { |  | ||||||
|         //        await SignInAsync(user, isPersistent: false); |  | ||||||
|         //        return RedirectToLocal(returnUrl); |  | ||||||
|         //    } |  | ||||||
|         //    else |  | ||||||
|         //    { |  | ||||||
|         //        // If the user does not have an account, then prompt the user to create an account |  | ||||||
|         //        ViewBag.ReturnUrl = returnUrl; |  | ||||||
|         //        ViewBag.LoginProvider = loginInfo.Login.LoginProvider; |  | ||||||
|         //        return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = loginInfo.DefaultUserName }); |  | ||||||
|         //    } |  | ||||||
|         //} |  | ||||||
|  |  | ||||||
|         // |  | ||||||
|         // POST: /Account/LinkLogin |         // POST: /Account/LinkLogin | ||||||
|         [HttpPost] |         [HttpPost] | ||||||
|         [ValidateAntiForgeryToken] |         [ValidateAntiForgeryToken] | ||||||
|         public ActionResult LinkLogin(string provider) |         public ActionResult LinkLogin(string provider) { | ||||||
|         { |  | ||||||
|             // Request a redirect to the external login provider to link a login for the current user |             // Request a redirect to the external login provider to link a login for the current user | ||||||
|             return new ChallengeResult(provider, Url.Action("LinkLoginCallback", "Account"), User.Identity.GetUserId()); |             return new ChallengeResult(provider, Url.Action("LinkLoginCallback", "Account"), User.Identity.GetUserId()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // |         // | ||||||
|         // GET: /Account/LinkLoginCallback |         // GET: /Account/LinkLoginCallback | ||||||
|         public async Task<ActionResult> LinkLoginCallback() |         public async Task<ActionResult> LinkLoginCallback() { | ||||||
|         { |             ExternalLoginInfo loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId()); | ||||||
|             var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId()); |             if (loginInfo == null) { | ||||||
|             if (loginInfo == null) |  | ||||||
|             { |  | ||||||
|                 return RedirectToAction("Manage", new { Message = ManageMessageId.Error }); |                 return RedirectToAction("Manage", new { Message = ManageMessageId.Error }); | ||||||
|             } |             } | ||||||
|             var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login); |             IdentityResult result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login); | ||||||
|             if (result.Succeeded) |             if (result.Succeeded) { | ||||||
|             { |  | ||||||
|                 return RedirectToAction("Manage"); |                 return RedirectToAction("Manage"); | ||||||
|             } |             } | ||||||
|             return RedirectToAction("Manage", new { Message = ManageMessageId.Error }); |             return RedirectToAction("Manage", new { Message = ManageMessageId.Error }); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // |  | ||||||
|         // POST: /Account/ExternalLoginConfirmation |  | ||||||
|         //[HttpPost] |  | ||||||
|         //[AllowAnonymous] |  | ||||||
|         //[ValidateAntiForgeryToken] |  | ||||||
|         //public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl) |  | ||||||
|         //{ |  | ||||||
|         //    if (User.Identity.IsAuthenticated) |  | ||||||
|         //    { |  | ||||||
|         //        return RedirectToAction("Manage"); |  | ||||||
|         //    } |  | ||||||
|  |  | ||||||
|         //    if (ModelState.IsValid) |  | ||||||
|         //    { |  | ||||||
|         //        // Get the information about the user from the external login provider |  | ||||||
|         //        var info = await AuthenticationManager.GetExternalLoginInfoAsync(); |  | ||||||
|         //        if (info == null) |  | ||||||
|         //        { |  | ||||||
|         //            return View("ExternalLoginFailure"); |  | ||||||
|         //        } |  | ||||||
|         //        var user = new ApplicationUser() { UserName = model.UserName }; |  | ||||||
|         //        var result = await UserManager.CreateAsync(user); |  | ||||||
|         //        if (result.Succeeded) |  | ||||||
|         //        { |  | ||||||
|         //            result = await UserManager.AddLoginAsync(user.Id, info.Login); |  | ||||||
|         //            if (result.Succeeded) |  | ||||||
|         //            { |  | ||||||
|         //                await SignInAsync(user, isPersistent: false); |  | ||||||
|         //                return RedirectToLocal(returnUrl); |  | ||||||
|         //            } |  | ||||||
|         //        } |  | ||||||
|         //        AddErrors(result); |  | ||||||
|         //    } |  | ||||||
|  |  | ||||||
|         //    ViewBag.ReturnUrl = returnUrl; |  | ||||||
|         //    return View(model); |  | ||||||
|         //} |  | ||||||
|  |  | ||||||
|         // |  | ||||||
|         // POST: /Account/LogOff |         // POST: /Account/LogOff | ||||||
|         [HttpPost] |         [HttpPost] | ||||||
|         [ValidateAntiForgeryToken] |         [ValidateAntiForgeryToken] | ||||||
|         public ActionResult LogOff() |         public ActionResult LogOff() { | ||||||
|         { |  | ||||||
|             //AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); |  | ||||||
|             //AuthenticationManager.SignOut(); |  | ||||||
|             FormsAuthentication.SignOut(); |             FormsAuthentication.SignOut(); | ||||||
|             return RedirectToAction("Login", "Account"); |             return RedirectToAction("Login", "Account"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // |  | ||||||
|         // GET: /Account/ExternalLoginFailure |         // GET: /Account/ExternalLoginFailure | ||||||
|         [AllowAnonymous] |         [AllowAnonymous] | ||||||
|         public ActionResult ExternalLoginFailure() |         public ActionResult ExternalLoginFailure() { | ||||||
|         { |  | ||||||
|             return View(); |             return View(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         [ChildActionOnly] |         [ChildActionOnly] | ||||||
|         public ActionResult RemoveAccountList() |         public ActionResult RemoveAccountList() { | ||||||
|         { |             IList<UserLoginInfo> linkedAccounts = UserManager.GetLogins(User.Identity.GetUserId()); | ||||||
|             var linkedAccounts = UserManager.GetLogins(User.Identity.GetUserId()); |  | ||||||
|             ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1; |             ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1; | ||||||
|             return (ActionResult)PartialView("_RemoveAccountPartial", linkedAccounts); |             return (ActionResult)PartialView("_RemoveAccountPartial", linkedAccounts); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         protected override void Dispose(bool disposing) |         protected override void Dispose(bool disposing) { | ||||||
|         { |             if (disposing && UserManager != null) { | ||||||
|             if (disposing && UserManager != null) |  | ||||||
|             { |  | ||||||
|                 UserManager.Dispose(); |                 UserManager.Dispose(); | ||||||
|                 UserManager = null; |                 UserManager = null; | ||||||
|             } |             } | ||||||
| @ -411,71 +299,52 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|         // Used for XSRF protection when adding external logins |         // Used for XSRF protection when adding external logins | ||||||
|         private const string XsrfKey = "XsrfId"; |         private const string XsrfKey = "XsrfId"; | ||||||
|  |  | ||||||
|         private IAuthenticationManager AuthenticationManager |         private IAuthenticationManager AuthenticationManager { | ||||||
|         { |             get { | ||||||
|             get |  | ||||||
|             { |  | ||||||
|                 return HttpContext.GetOwinContext().Authentication; |                 return HttpContext.GetOwinContext().Authentication; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private async Task SignInAsync(ApplicationUser user, bool isPersistent) |         private async Task SignInAsync(ApplicationUser user, bool isPersistent) { | ||||||
|         { |  | ||||||
|             AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); |             AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); | ||||||
|             var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); |             ClaimsIdentity identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); | ||||||
|             AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity); |             AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private void AddErrors(IdentityResult result) |         private void AddErrors(IdentityResult result) { | ||||||
|         { |             foreach (string error in result.Errors) { | ||||||
|             foreach (var error in result.Errors) |  | ||||||
|             { |  | ||||||
|                 ModelState.AddModelError("", error); |                 ModelState.AddModelError("", error); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private bool HasPassword() |         private bool HasPassword() { | ||||||
|         { |             ApplicationUser user = UserManager.FindById(User.Identity.GetUserId()); | ||||||
|             var user = UserManager.FindById(User.Identity.GetUserId()); |             if (user != null) { | ||||||
|             if (user != null) |  | ||||||
|             { |  | ||||||
|                 return user.PasswordHash != null; |                 return user.PasswordHash != null; | ||||||
|             } |             } | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public enum ManageMessageId |         public enum ManageMessageId { | ||||||
|         { |  | ||||||
|             ChangePasswordSuccess, |             ChangePasswordSuccess, | ||||||
|             SetPasswordSuccess, |             SetPasswordSuccess, | ||||||
|             RemoveLoginSuccess, |             RemoveLoginSuccess, | ||||||
|             Error |             Error | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private ActionResult RedirectToLocal(string returnUrl) |         private ActionResult RedirectToLocal(string returnUrl) { | ||||||
|         { |             if (Url.IsLocalUrl(returnUrl)) { | ||||||
|             if (Url.IsLocalUrl(returnUrl)) |  | ||||||
|             { |  | ||||||
|                 return Redirect(returnUrl); |                 return Redirect(returnUrl); | ||||||
|             } |             } else { | ||||||
|             else |  | ||||||
|             { |  | ||||||
|  |  | ||||||
|                 //return RedirectToAction("HierarchicalDataTest", "Home"); |  | ||||||
|  |  | ||||||
|                 return RedirectToAction("MyTasks", "Home"); |                 return RedirectToAction("MyTasks", "Home"); | ||||||
|                 //return RedirectToAction("Index", "Home", new { tabName = "MyTasks"}); |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private class ChallengeResult : HttpUnauthorizedResult |         private class ChallengeResult : HttpUnauthorizedResult { | ||||||
|         { |             public ChallengeResult(string provider, string redirectUri) : this(provider, redirectUri, null) { | ||||||
|             public ChallengeResult(string provider, string redirectUri) : this(provider, redirectUri, null) |  | ||||||
|             { |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             public ChallengeResult(string provider, string redirectUri, string userId) |             public ChallengeResult(string provider, string redirectUri, string userId) { | ||||||
|             { |  | ||||||
|                 LoginProvider = provider; |                 LoginProvider = provider; | ||||||
|                 RedirectUri = redirectUri; |                 RedirectUri = redirectUri; | ||||||
|                 UserId = userId; |                 UserId = userId; | ||||||
| @ -485,11 +354,9 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|             public string RedirectUri { get; set; } |             public string RedirectUri { get; set; } | ||||||
|             public string UserId { get; set; } |             public string UserId { get; set; } | ||||||
|  |  | ||||||
|             public override void ExecuteResult(ControllerContext context) |             public override void ExecuteResult(ControllerContext context) { | ||||||
|             { |                 AuthenticationProperties properties = new AuthenticationProperties() { RedirectUri = RedirectUri }; | ||||||
|                 var properties = new AuthenticationProperties() { RedirectUri = RedirectUri }; |                 if (UserId != null) { | ||||||
|                 if (UserId != null) |  | ||||||
|                 { |  | ||||||
|                     properties.Dictionary[XsrfKey] = UserId; |                     properties.Dictionary[XsrfKey] = UserId; | ||||||
|                 } |                 } | ||||||
|                 context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider); |                 context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider); | ||||||
|  | |||||||
| @ -102,53 +102,15 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|         // GET: /MRB/Edit/5 |         // GET: /MRB/Edit/5 | ||||||
|         public ActionResult Edit(int issueID) |         public ActionResult Edit(int issueID) | ||||||
|         { |         { | ||||||
|             MRB mrb = new MRB(); |             string jwt = Session["JWT"].ToString(); | ||||||
|             int isITARCompliant = 1; |             string encodedJwt = System.Net.WebUtility.UrlEncode(jwt); | ||||||
|             ViewBag.Status = "Pending"; |             string refreshToken = Session["RefreshToken"].ToString(); | ||||||
|             ViewBag.IsApprover = "false"; |             string encodedRefreshToken = System.Net.WebUtility.UrlEncode(refreshToken); | ||||||
|             ViewBag.IsCloser = "false"; |             string wasmClientUrl = Environment.GetEnvironmentVariable("FabApprovalWasmClientUrl") ?? | ||||||
|  |                 "https://localhost:7255"; | ||||||
|  |             string mrbUrl = $"{wasmClientUrl}/redirect?jwt={encodedJwt}&refreshToken={encodedRefreshToken}&redirectPath=/mrb/{issueID}"; | ||||||
|  |  | ||||||
|             //ViewBag.IsApproved = "false"; |             return Redirect(mrbUrl); | ||||||
|             //ViewBag.IsClosed = "false"; |  | ||||||
|             PopulateCloseToQDB(); |  | ||||||
|             mrb = mrbDMO.GetMRBItem(issueID, out isITARCompliant, (int)Session[GlobalVars.SESSION_USERID]); |  | ||||||
|             ViewBag.UserList = mrbDMO.GetUserList(); |  | ||||||
|  |  | ||||||
|             if (isITARCompliant == 0) // not ITAR Compliant |  | ||||||
|             { |  | ||||||
|                 return View("UnAuthorizedAccess"); |  | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 if (mrb.ApprovalStatus == (int)GlobalVars.ApprovalOption.Approved) |  | ||||||
|                 { |  | ||||||
|                     //ViewBag.IsApproved = "true"; |  | ||||||
|                     ViewBag.Status = "Approved"; |  | ||||||
|                 } |  | ||||||
|                 else if (mrb.ApprovalStatus == (int)GlobalVars.ApprovalOption.Closed) |  | ||||||
|                 { |  | ||||||
|                     ViewBag.Status = "Closed"; |  | ||||||
|                     //ViewBag.IsClosed = "true"; |  | ||||||
|                 } |  | ||||||
|                 List<ApproversListViewModel> userList = MiscDMO.GetApproversListByDocument(issueID, mrb.CurrentStep, (int)GlobalVars.DocumentType.MRB); |  | ||||||
|                 ApproversListViewModel appUser = userList.Find(delegate (ApproversListViewModel al) { return al.UserID == (int)Session[GlobalVars.SESSION_USERID]; }); |  | ||||||
|                 if (appUser != null) |  | ||||||
|                 { |  | ||||||
|                     ViewBag.IsApprover = "true"; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             // can edit |  | ||||||
|             ViewBag.Owners = MiscDMO.GetUserList(); |  | ||||||
|             ViewBag.Modules = mrbDMO.GetModules(); |  | ||||||
|             //ViewBag.Dispositions = mrbDMO.GetDispositions(); |  | ||||||
|             ViewBag.RiskAssessments = mrbDMO.GetRiskAssessments(); |  | ||||||
|             ViewBag.PartGroups = mrbDMO.GetPartGroups(); |  | ||||||
|             ViewBag.DispoTypes = mrbDMO.GetDispositions(issueID).Select(d => new { d.DispositionType }); |  | ||||||
|  |  | ||||||
|             return View(mrb); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // |         // | ||||||
| @ -178,39 +140,15 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public ActionResult ReadOnly(int issueID) |         public ActionResult ReadOnly(int issueID) | ||||||
|         { |         { | ||||||
|             MRB mrb = new MRB(); |             string jwt = Session["JWT"].ToString(); | ||||||
|             int isITARCompliant = 1; |             string encodedJwt = System.Net.WebUtility.UrlEncode(jwt); | ||||||
|  |             string refreshToken = Session["RefreshToken"].ToString(); | ||||||
|  |             string encodedRefreshToken = System.Net.WebUtility.UrlEncode(refreshToken); | ||||||
|  |             string wasmClientUrl = Environment.GetEnvironmentVariable("FabApprovalWasmClientUrl") ?? | ||||||
|  |                 "https://localhost:7255"; | ||||||
|  |             string mrbUrl = $"{wasmClientUrl}/redirect?jwt={encodedJwt}&refreshToken={encodedRefreshToken}&redirectPath=/mrb/{issueID}"; | ||||||
|  |  | ||||||
|  |             return Redirect(mrbUrl); | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 if (isITARCompliant == 0) // not ITAR Compliant |  | ||||||
|                 { |  | ||||||
|                     return View("UnAuthorizedAccess"); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     mrb = mrbDMO.GetMRBItem(issueID, out isITARCompliant, (int)Session[GlobalVars.SESSION_USERID]); |  | ||||||
|  |  | ||||||
|                     ViewBag.Owners = MiscDMO.GetUserList(); |  | ||||||
|                     ViewBag.Modules = mrbDMO.GetModules(); |  | ||||||
|                     //ViewBag.Dispositions = mrbDMO.GetDispositions(); |  | ||||||
|                     ViewBag.RiskAssessments = mrbDMO.GetRiskAssessments(); |  | ||||||
|                     ViewBag.PartGroups = mrbDMO.GetPartGroups(); |  | ||||||
|                     ViewBag.DispoTypes = mrbDMO.GetDispositions(issueID).Select(d => new { d.DispositionType }); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 return View(mrb); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             catch (Exception e) |  | ||||||
|             { |  | ||||||
|                 string exceptionString = e.Message.ToString().Trim().Length > 500 ? "IssueID=" + issueID.ToString() + "  " + e.Message.ToString().Substring(0, 250) : e.Message.ToString(); |  | ||||||
|                 Functions.WriteEvent(@User.Identity.Name + "\r\n ReadOnly Disposition\r\n" + e.Message.ToString(), System.Diagnostics.EventLogEntryType.Error); |  | ||||||
|                 EventLogDMO.Add(new WinEventLog() { IssueID = issueID, UserID = @User.Identity.Name, DocumentType = "Lot Disposition", OperationType = "Error", Comments = exceptionString }); |  | ||||||
|                 throw new Exception(e.Message); |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // |         // | ||||||
|  | |||||||
| @ -2,25 +2,18 @@ using Fab2ApprovalSystem.DMO; | |||||||
| using Fab2ApprovalSystem.Models; | using Fab2ApprovalSystem.Models; | ||||||
| using Fab2ApprovalSystem.ViewModels; | using Fab2ApprovalSystem.ViewModels; | ||||||
| using Fab2ApprovalSystem.Utilities; | using Fab2ApprovalSystem.Utilities; | ||||||
| using Kendo.Mvc.UI; |  | ||||||
| using System; | using System; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.Linq; | using System.Linq; | ||||||
| using System.Web; |  | ||||||
| using System.Web.Mvc; | using System.Web.Mvc; | ||||||
| using Kendo.Mvc.Extensions; | using Kendo.Mvc.Extensions; | ||||||
| using Fab2ApprovalSystem.Misc; | using Fab2ApprovalSystem.Misc; | ||||||
| using System.Configuration; | using System.Configuration; | ||||||
| using System.Threading.Tasks; |  | ||||||
|  |  | ||||||
| namespace Fab2ApprovalSystem.Controllers |  | ||||||
| { |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | namespace Fab2ApprovalSystem.Controllers { | ||||||
|     [Authorize] |     [Authorize] | ||||||
|     [SessionExpireFilter] |     [SessionExpireFilter] | ||||||
|     public class TrainingController : Controller |     public class TrainingController : Controller { | ||||||
|     { |  | ||||||
|         UserAccountDMO userDMO = new UserAccountDMO(); |         UserAccountDMO userDMO = new UserAccountDMO(); | ||||||
|         AdminDMO adminDMO = new AdminDMO(); |         AdminDMO adminDMO = new AdminDMO(); | ||||||
|         TrainingDMO trainingDMO = new TrainingDMO(); |         TrainingDMO trainingDMO = new TrainingDMO(); | ||||||
| @ -28,47 +21,39 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|         public EmailUtilities emailer = new EmailUtilities(); |         public EmailUtilities emailer = new EmailUtilities(); | ||||||
|  |  | ||||||
|         // GET: Training |         // GET: Training | ||||||
|         public ActionResult Index() |         public ActionResult Index() { | ||||||
|         { |  | ||||||
|             return View(); |             return View(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         //public int Create(int ecnId, List<int> groupIds) |         //public int Create(int ecnId, List<int> groupIds) | ||||||
|         public int Create(int ecnId) |         public int Create(int ecnId) { | ||||||
|         { |  | ||||||
|             ECN_DMO ecnDMO = new ECN_DMO(); |             ECN_DMO ecnDMO = new ECN_DMO(); | ||||||
|  |  | ||||||
|             //Delete old training if exists |             //Delete old training if exists | ||||||
|             int oldTrainingId = trainingDMO.GetTrainingId(ecnId); |             int oldTrainingId = trainingDMO.GetTrainingId(ecnId); | ||||||
|             if (oldTrainingId != null && oldTrainingId != 0) |             if (oldTrainingId != null && oldTrainingId != 0) { | ||||||
|             { |  | ||||||
|                 trainingDMO.DeleteTraining(oldTrainingId); |                 trainingDMO.DeleteTraining(oldTrainingId); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |  | ||||||
|             int trainingId = trainingDMO.Create(ecnId); |             int trainingId = trainingDMO.Create(ecnId); | ||||||
|             List<int> TrainingGroups = new List<int>(); |             List<int> TrainingGroups = new List<int>(); | ||||||
|             TrainingGroups = trainingDMO.GetECNAssignedTrainingGroups(ecnId); |             TrainingGroups = trainingDMO.GetECNAssignedTrainingGroups(ecnId); | ||||||
|             string ECNTitle = ecnDMO.GetECN(ecnId).Title; |             string ECNTitle = ecnDMO.GetECN(ecnId).Title; | ||||||
|             List<int> Trainees = new List<int>(); |             List<int> Trainees = new List<int>(); | ||||||
|             foreach (var group in TrainingGroups) |             foreach (int group in TrainingGroups) { | ||||||
|             { |  | ||||||
|                 Trainees.AddRange(trainingDMO.GetTrainees(group)); |                 Trainees.AddRange(trainingDMO.GetTrainees(group)); | ||||||
|             } |             } | ||||||
|             Trainees = (from a in Trainees select a).Distinct().ToList(); |             Trainees = (from a in Trainees select a).Distinct().ToList(); | ||||||
|  |  | ||||||
|             foreach (var trainee in Trainees) |             foreach (int trainee in Trainees) { | ||||||
|             { |  | ||||||
|                 int assignmentId = trainingDMO.CreateAssignment(trainingId, trainee); |                 int assignmentId = trainingDMO.CreateAssignment(trainingId, trainee); | ||||||
|                 NotifyTrainee(trainee, assignmentId, ecnId, ECNTitle); |                 NotifyTrainee(trainee, assignmentId, ecnId, ECNTitle); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |  | ||||||
|             return trainingId; |             return trainingId; | ||||||
|         } |         } | ||||||
|         public ActionResult AddUserToTrainingAdHoc(int trainingId, int traineeId, int ecnId) |         public ActionResult AddUserToTrainingAdHoc(int trainingId, int traineeId, int ecnId) { | ||||||
|         { |             if ((bool)Session[GlobalVars.IS_ADMIN]) { | ||||||
|             if ((bool)Session[GlobalVars.IS_ADMIN]) |  | ||||||
|             { |  | ||||||
|                 //Get ECN |                 //Get ECN | ||||||
|                 ECN ecn = ecnDMO.GetECN(ecnId); |                 ECN ecn = ecnDMO.GetECN(ecnId); | ||||||
|  |  | ||||||
| @ -77,178 +62,120 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|  |  | ||||||
|                 //Get Training |                 //Get Training | ||||||
|                 Training training = trainingDMO.GetTraining(trainingId); |                 Training training = trainingDMO.GetTraining(trainingId); | ||||||
|                 if (ecn != null) |                 if (ecn != null) { | ||||||
|                 { |                     if (user != null) { | ||||||
|                     if (user != null) |                         if (training != null) { | ||||||
|                     { |                             if (!trainingDMO.IsUserAssigned(traineeId, trainingId)) { | ||||||
|                         if (training != null) |                                 if (training.DeletedDate == null && !ecn.Deleted) { | ||||||
|                         { |  | ||||||
|                             if (!trainingDMO.IsUserAssigned(traineeId, trainingId)) |  | ||||||
|                             { |  | ||||||
|                                 if (training.DeletedDate == null && !ecn.Deleted) |  | ||||||
|                                 { |  | ||||||
|                                     //Both the ECN and training still exist |                                     //Both the ECN and training still exist | ||||||
|                                     if (training.CompletedDate != null) |                                     if (training.CompletedDate != null) { | ||||||
|                                     { |  | ||||||
|                                         //Training is completed and now we need to re-open it. |                                         //Training is completed and now we need to re-open it. | ||||||
|                                         trainingDMO.reOpenTraining(trainingId); |                                         trainingDMO.reOpenTraining(trainingId); | ||||||
|                                         int assignmentId = trainingDMO.CreateAssignment(trainingId, traineeId); |                                         int assignmentId = trainingDMO.CreateAssignment(trainingId, traineeId); | ||||||
|                                         NotifyTrainee(traineeId, assignmentId, ecnId, ecn.Title); |                                         NotifyTrainee(traineeId, assignmentId, ecnId, ecn.Title); | ||||||
|                                         return Content("Success"); |                                         return Content("Success"); | ||||||
|                                     } |                                     } else { | ||||||
|                                     else |  | ||||||
|                                     { |  | ||||||
|                                         //training is still open, just add a user and notify |                                         //training is still open, just add a user and notify | ||||||
|                                         int assignmentId = trainingDMO.CreateAssignment(trainingId, traineeId); |                                         int assignmentId = trainingDMO.CreateAssignment(trainingId, traineeId); | ||||||
|                                         NotifyTrainee(traineeId, assignmentId, ecnId, ecn.Title); |                                         NotifyTrainee(traineeId, assignmentId, ecnId, ecn.Title); | ||||||
|                                         return Content("Success"); |                                         return Content("Success"); | ||||||
|                                     } |                                     } | ||||||
|                                 } |                                 } else { | ||||||
|                                 else |  | ||||||
|                                 { |  | ||||||
|                                     //Ecn or training task have been deleted. |                                     //Ecn or training task have been deleted. | ||||||
|                                     return Content("Training or ECN has been deleted."); |                                     return Content("Training or ECN has been deleted."); | ||||||
|                                 } |                                 } | ||||||
|                             } |                             } else { | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 return Content("User already has an open or completed assignment for this training."); |                                 return Content("User already has an open or completed assignment for this training."); | ||||||
|                             } |                             } | ||||||
|  |                         } else { | ||||||
|                         } |  | ||||||
|                         else |  | ||||||
|                         { |  | ||||||
|                             return Content("Invalid training id."); |                             return Content("Invalid training id."); | ||||||
|                         } |                         } | ||||||
|                     } |                     } else { | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         return Content("invalid userId"); |                         return Content("invalid userId"); | ||||||
|                     } |                     } | ||||||
|                 } |                 } else { | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return Content("ECN invalid"); |                     return Content("ECN invalid"); | ||||||
|                 } |                 } | ||||||
|             } |             } else { | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return Content("Not Authorized"); |                 return Content("Not Authorized"); | ||||||
|             } |             } | ||||||
|              |  | ||||||
|          |  | ||||||
|         } |         } | ||||||
|         public ActionResult AddGroupToTrainingAdHoc(int trainingId, int groupId, int ecnId) |  | ||||||
|         { |         public ActionResult AddGroupToTrainingAdHoc(int trainingId, int groupId, int ecnId) { | ||||||
|             if ((bool)Session[GlobalVars.IS_ADMIN]) |             if ((bool)Session[GlobalVars.IS_ADMIN]) { | ||||||
|             { |  | ||||||
|                 ECN ecn = ecnDMO.GetECN(ecnId); |                 ECN ecn = ecnDMO.GetECN(ecnId); | ||||||
|                 Training training = trainingDMO.GetTraining(trainingId); |                 Training training = trainingDMO.GetTraining(trainingId); | ||||||
|                 TrainingGroup group = trainingDMO.GetTrainingGroupByID(groupId); |                 TrainingGroup group = trainingDMO.GetTrainingGroupByID(groupId); | ||||||
|                 List<int> groupMemberIds = trainingDMO.GetTrainees(groupId); |                 List<int> groupMemberIds = trainingDMO.GetTrainees(groupId); | ||||||
|                 int usersAdded = 0; |                 int usersAdded = 0; | ||||||
|  |  | ||||||
|                 if (ecn != null) |                 if (ecn != null) { | ||||||
|                 { |                     if (training != null) { | ||||||
|                     if (training != null) |                         if (training.DeletedDate == null && !ecn.Deleted) { | ||||||
|                     { |                             if (training.CompletedDate != null) { | ||||||
|                         if (training.DeletedDate == null && !ecn.Deleted) |  | ||||||
|                         { |  | ||||||
|                             if (training.CompletedDate != null) |  | ||||||
|                             { |  | ||||||
|                                 //Training is completed and now we need to re-open it. |                                 //Training is completed and now we need to re-open it. | ||||||
|                                 foreach (int id in groupMemberIds) |                                 foreach (int id in groupMemberIds) { | ||||||
|                                 { |  | ||||||
|                                     //Check to make sure user doesn't have an active assignment for this training |                                     //Check to make sure user doesn't have an active assignment for this training | ||||||
|                                     if (!trainingDMO.IsUserAssigned(id, trainingId)) |                                     if (!trainingDMO.IsUserAssigned(id, trainingId)) { | ||||||
|                                     { |  | ||||||
|                                         usersAdded++; |                                         usersAdded++; | ||||||
|                                         int assignmentId = trainingDMO.CreateAssignment(trainingId, id); |                                         int assignmentId = trainingDMO.CreateAssignment(trainingId, id); | ||||||
|                                         NotifyTrainee(id, assignmentId, ecnId, ecn.Title); |                                         NotifyTrainee(id, assignmentId, ecnId, ecn.Title); | ||||||
|                                     } |                                     } | ||||||
|  |  | ||||||
|                                 } |                                 } | ||||||
|                                 if (usersAdded > 0) |                                 if (usersAdded > 0) { | ||||||
|                                 { |  | ||||||
|                                     trainingDMO.reOpenTraining(trainingId); |                                     trainingDMO.reOpenTraining(trainingId); | ||||||
|                                 } |                                 } | ||||||
|  |                             } else { | ||||||
|                             } |  | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 //training is still open, just add a users and notify |                                 //training is still open, just add a users and notify | ||||||
|                                 foreach (int id in groupMemberIds) |                                 foreach (int id in groupMemberIds) { | ||||||
|                                 { |  | ||||||
|                                     //Check to make sure user doesn't have an active assignment for this training |                                     //Check to make sure user doesn't have an active assignment for this training | ||||||
|                                     if (!trainingDMO.IsUserAssigned(id, trainingId)) |                                     if (!trainingDMO.IsUserAssigned(id, trainingId)) { | ||||||
|                                     { |  | ||||||
|                                         usersAdded++; |                                         usersAdded++; | ||||||
|                                         int assignmentId = trainingDMO.CreateAssignment(trainingId, id); |                                         int assignmentId = trainingDMO.CreateAssignment(trainingId, id); | ||||||
|                                         NotifyTrainee(id, assignmentId, ecnId, ecn.Title); |                                         NotifyTrainee(id, assignmentId, ecnId, ecn.Title); | ||||||
|                                     } |                                     } | ||||||
|                                 } |                                 } | ||||||
|                             } |                             } | ||||||
|                             if(usersAdded > 0) |                             if (usersAdded > 0) { | ||||||
|                             { |                                 try { | ||||||
|                                 try |  | ||||||
|                                 { |  | ||||||
|                                     trainingDMO.AddTrainingGroupToECN(ecnId, groupId); |                                     trainingDMO.AddTrainingGroupToECN(ecnId, groupId); | ||||||
|                                 } |                                 } catch (Exception e) { | ||||||
|                                 catch(Exception e) |  | ||||||
|                                 { |  | ||||||
|                                     return Content(e.ToString()); |                                     return Content(e.ToString()); | ||||||
|                                 } |                                 } | ||||||
|                             } |                             } | ||||||
|                             return Content("Success. " + usersAdded + " users added."); |                             return Content("Success. " + usersAdded + " users added."); | ||||||
|                         } |                         } else { | ||||||
|                         else |  | ||||||
|                         { |  | ||||||
|                             return Content("Training or ECN has been deleted."); |                             return Content("Training or ECN has been deleted."); | ||||||
|                         } |                         } | ||||||
|                     } |                     } else { | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         return Content("Invalid training id."); |                         return Content("Invalid training id."); | ||||||
|                     } |                     } | ||||||
|                 } |                 } else { | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return Content("ECN invalid"); |                     return Content("ECN invalid"); | ||||||
|                 } |                 } | ||||||
|             } |             } else { | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return Content("Not Authorized"); |                 return Content("Not Authorized"); | ||||||
|             } |             } | ||||||
|              |  | ||||||
|              |  | ||||||
|         } |         } | ||||||
|         public ActionResult DeleteTrainingByECN(int ECNNumber) |  | ||||||
|         { |         public ActionResult DeleteTrainingByECN(int ECNNumber) { | ||||||
|             int trainingId = trainingDMO.GetTrainingId(ECNNumber); |             int trainingId = trainingDMO.GetTrainingId(ECNNumber); | ||||||
|             if (trainingId != null && trainingId != 0) |             if (trainingId != null && trainingId != 0) { | ||||||
|             { |  | ||||||
|                 trainingDMO.DeleteTraining(trainingId); |                 trainingDMO.DeleteTraining(trainingId); | ||||||
|             } |             } | ||||||
|             return RedirectToAction("ViewTrainings"); |             return RedirectToAction("ViewTrainings"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public ActionResult DeleteTrainingByID(int trainingId) |         public ActionResult DeleteTrainingByID(int trainingId) { | ||||||
|         { |             if (trainingId != null && trainingId != 0) { | ||||||
|             if (trainingId != null && trainingId != 0) |  | ||||||
|             { |  | ||||||
|                 trainingDMO.DeleteTraining(trainingId); |                 trainingDMO.DeleteTraining(trainingId); | ||||||
|             } |             } | ||||||
|             return RedirectToAction("ViewTrainings"); |             return RedirectToAction("ViewTrainings"); | ||||||
|         } |         } | ||||||
|         public void NotifyTrainee(int userId, int assignmentId, int ecnId, string title) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|             try |         public void NotifyTrainee(int userId, int assignmentId, int ecnId, string title) { | ||||||
|             { |             try { | ||||||
|                 string emailSentList = ""; |                 string emailSentList = ""; | ||||||
|                 //ECN ecn = ecnDMO.GetECN(ecnNumber); |  | ||||||
|                 //List<string> emailIst = ldDMO.GetApproverEmailList(@issueID, currentStep).Distinct().ToList(); |  | ||||||
|                 string recipient = userDMO.GetUserEmailByID(userId.ToString()); |                 string recipient = userDMO.GetUserEmailByID(userId.ToString()); | ||||||
|  |  | ||||||
|                 string emailTemplate = "ECNTrainingAssigned.txt"; |                 string emailTemplate = "ECNTrainingAssigned.txt"; | ||||||
| @ -258,132 +185,98 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|  |  | ||||||
|                 subject = "ECN# " + ecnId + " - Training Assignment Notice - " + title; |                 subject = "ECN# " + ecnId + " - Training Assignment Notice - " + title; | ||||||
|  |  | ||||||
|                     EmailNotification en = new EmailNotification(subject, ConfigurationManager.AppSettings["EmailTemplatesPath"]); |                 EmailNotification en = new EmailNotification(subject, ConfigurationManager.AppSettings["EmailTemplatesPath"]); | ||||||
|                     //string emailparams = ""; |                 userEmail = recipient; | ||||||
|                     userEmail = recipient; |                 string[] emailparams = new string[4]; | ||||||
|                     string[] emailparams = new string[4]; |                 emailparams[0] = assignmentId.ToString(); | ||||||
|                     emailparams[0] = assignmentId.ToString(); |                 emailparams[1] = ecnId.ToString(); | ||||||
|                     emailparams[1] = ecnId.ToString(); |                 emailparams[2] = GlobalVars.hostURL; | ||||||
|                     emailparams[2] = GlobalVars.hostURL; |  | ||||||
|                 //#if(DEBUG) |                 //#if(DEBUG) | ||||||
|                 //string SenderEmail = "MesaFabApproval@infineon.com"; |                 //string SenderEmail = "MesaFabApproval@infineon.com"; | ||||||
|                 //userEmail = "jonathan.ouellette@infineon.com"; |                 //userEmail = "jonathan.ouellette@infineon.com"; | ||||||
|                 //#endif |                 //#endif | ||||||
|  |  | ||||||
|                 en.SendNotificationEmail(emailTemplate, GlobalVars.SENDER_EMAIL, senderName, userEmail, null, subject, emailparams); |                 en.SendNotificationEmail(emailTemplate, GlobalVars.SENDER_EMAIL, senderName, userEmail, null, subject, emailparams); | ||||||
|                     //en.SendNotificationEmail(emailTemplate, SenderEmail, senderName, userEmail, null, subject, emailparams); |             } catch (Exception e) { | ||||||
|             } |  | ||||||
|             catch (Exception e) |  | ||||||
|             { |  | ||||||
|                 string detailedException = ""; |                 string detailedException = ""; | ||||||
|                 try |                 try { | ||||||
|                 { |  | ||||||
|                     detailedException = e.InnerException.ToString(); |                     detailedException = e.InnerException.ToString(); | ||||||
|                 } |                 } catch { | ||||||
|                 catch |  | ||||||
|                 { |  | ||||||
|                     detailedException = e.Message; |                     detailedException = e.Message; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|         public ActionResult ViewTrainingPartial(int trainingID, int userID) |  | ||||||
|         { |         public ActionResult ViewTrainingPartial(int trainingID, int userID) { | ||||||
|             List<TrainingAssignment> TrainingData = trainingDMO.GetTrainingAssignmentsByUser(trainingID, userID); |             List<TrainingAssignment> TrainingData = trainingDMO.GetTrainingAssignmentsByUser(trainingID, userID); | ||||||
|             if (trainingID > 0) |             if (trainingID > 0) { | ||||||
|             { |  | ||||||
|                 ViewBag.ECNNumber = trainingDMO.GetTraining(trainingID).ECN; |                 ViewBag.ECNNumber = trainingDMO.GetTraining(trainingID).ECN; | ||||||
|             } |             } | ||||||
|             return PartialView(TrainingData); |             return PartialView(TrainingData); | ||||||
|         } |         } | ||||||
|         public ActionResult ViewTrainingDocsPartial(int trainingAssignmentId) |  | ||||||
|         { |         public ActionResult ViewTrainingDocsPartial(int trainingAssignmentId) { | ||||||
|             ViewBag.trainingAssignmentId = trainingAssignmentId; |             ViewBag.trainingAssignmentId = trainingAssignmentId; | ||||||
|             //IEnumerable<TrainingDocAck> attachments = ecnDMO.GetECNAttachments(ecnNumber); |             //IEnumerable<TrainingDocAck> attachments = ecnDMO.GetECNAttachments(ecnNumber); | ||||||
|             IEnumerable<TrainingDocAck> attachments = trainingDMO.GetAssignedDocs(trainingAssignmentId); |             IEnumerable<TrainingDocAck> attachments = trainingDMO.GetAssignedDocs(trainingAssignmentId); | ||||||
|             return PartialView(attachments); |             return PartialView(attachments); | ||||||
|         } |         } | ||||||
|         public ActionResult AcknowledgeDocument(int trainingAssignmentID, int trainingDocAckID) |  | ||||||
|         { |         public ActionResult AcknowledgeDocument(int trainingAssignmentID, int trainingDocAckID) { | ||||||
|             //Check to see if acknowledgement is valid(Security Feature to protect data integrity) |             //Check to see if acknowledgement is valid(Security Feature to protect data integrity) | ||||||
|             if (trainingDMO.CheckValidDocAck(trainingDocAckID)) |             if (trainingDMO.CheckValidDocAck(trainingDocAckID)) { | ||||||
|             { |  | ||||||
|                 trainingDMO.AcknowledgeDocument(trainingDocAckID); |                 trainingDMO.AcknowledgeDocument(trainingDocAckID); | ||||||
|                 bool isFinishedTrainingAssignment = trainingDMO.CheckTrainingAssignmentStatus(trainingAssignmentID); |                 bool isFinishedTrainingAssignment = trainingDMO.CheckTrainingAssignmentStatus(trainingAssignmentID); | ||||||
|  |  | ||||||
|                 if (isFinishedTrainingAssignment) |                 if (isFinishedTrainingAssignment) { | ||||||
|                 { |                     try { | ||||||
|                     try |  | ||||||
|                     { |  | ||||||
|                         trainingDMO.UpdateAssignmentStatus(trainingAssignmentID); |                         trainingDMO.UpdateAssignmentStatus(trainingAssignmentID); | ||||||
|                         bool isFinishedTraining = trainingDMO.CheckTrainingStatus(trainingAssignmentID); |                         bool isFinishedTraining = trainingDMO.CheckTrainingStatus(trainingAssignmentID); | ||||||
|                         if (isFinishedTraining) |                         if (isFinishedTraining) { | ||||||
|                         { |  | ||||||
|                             int TrainingID = trainingDMO.GetTrainingIdByAssignment(trainingAssignmentID); |                             int TrainingID = trainingDMO.GetTrainingIdByAssignment(trainingAssignmentID); | ||||||
|                             trainingDMO.UpdateTrainingStatus(TrainingID); |                             trainingDMO.UpdateTrainingStatus(TrainingID); | ||||||
|                         } |                         } | ||||||
|                     } |                     } catch (Exception e) { | ||||||
|                     catch (Exception e) |  | ||||||
|                     { |  | ||||||
|                         string exception = e.ToString(); |                         string exception = e.ToString(); | ||||||
|                         return Content(exception); |                         return Content(exception); | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return Content("Marked Succesfully."); |             return Content("Marked Succesfully."); | ||||||
|         } |         } | ||||||
|         public ActionResult AcknowledgeReviewNoDocuments(int trainingAssignmentID) |  | ||||||
|         { |         public ActionResult AcknowledgeReviewNoDocuments(int trainingAssignmentID) { | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 trainingDMO.UpdateAssignmentStatus(trainingAssignmentID); |                 trainingDMO.UpdateAssignmentStatus(trainingAssignmentID); | ||||||
|                 bool isFinishedTraining = trainingDMO.CheckTrainingStatus(trainingAssignmentID); |                 bool isFinishedTraining = trainingDMO.CheckTrainingStatus(trainingAssignmentID); | ||||||
|                 if (isFinishedTraining) |                 if (isFinishedTraining) { | ||||||
|                 { |  | ||||||
|                     int TrainingID = trainingDMO.GetTrainingIdByAssignment(trainingAssignmentID); |                     int TrainingID = trainingDMO.GetTrainingIdByAssignment(trainingAssignmentID); | ||||||
|                     trainingDMO.UpdateTrainingStatus(TrainingID); |                     trainingDMO.UpdateTrainingStatus(TrainingID); | ||||||
|                 } |                 } | ||||||
|             } |             } catch (Exception e) { | ||||||
|             catch (Exception e) |  | ||||||
|             { |  | ||||||
|                 string exception = e.ToString(); |                 string exception = e.ToString(); | ||||||
|                 return Content(exception, "application/json"); |                 return Content(exception, "application/json"); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return Json(new { test = "Succesfully saved" }); |             return Json(new { test = "Succesfully saved" }); | ||||||
|         } |         } | ||||||
|         //public ActionResult ViewTrainings() |  | ||||||
|         //{ |  | ||||||
|         //    IEnumerable<Training> trainings = trainingDMO.GetTrainings(); |  | ||||||
|  |  | ||||||
|         //    return View(trainings); |  | ||||||
|         //} |  | ||||||
|         public ActionResult TrainingReports() |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|  |         public ActionResult TrainingReports() { | ||||||
|             return View(); |             return View(); | ||||||
|         } |         } | ||||||
|         public ActionResult TrainingReportsView(int? filterType, string filterValue) |  | ||||||
|         { |         public ActionResult TrainingReportsView(int? filterType, string filterValue) { | ||||||
|             ViewBag.TrainingGroups = adminDMO.GetTrainingGroups(); |             ViewBag.TrainingGroups = adminDMO.GetTrainingGroups(); | ||||||
|             IEnumerable<Training> trainingList = trainingDMO.GetAllTrainings(); |             IEnumerable<Training> trainingList = trainingDMO.GetAllTrainings(); | ||||||
|             //Group Filter |             //Group Filter | ||||||
|             if (filterType == 1 && filterValue != "") |             if (filterType == 1 && filterValue != "") { | ||||||
|             { |  | ||||||
|                 ViewBag.GroupFilter = filterValue; |                 ViewBag.GroupFilter = filterValue; | ||||||
|                 List<Training> filteredTraining = new List<Training>(); |                 List<Training> filteredTraining = new List<Training>(); | ||||||
|                 foreach (var item in trainingList) |                 foreach (Training item in trainingList) { | ||||||
|                 { |  | ||||||
|                     List<int> assignedTrainingGroups = trainingDMO.GetECNAssignedTrainingGroups(item.ECN); |                     List<int> assignedTrainingGroups = trainingDMO.GetECNAssignedTrainingGroups(item.ECN); | ||||||
|                     foreach (int id in assignedTrainingGroups) |                     foreach (int id in assignedTrainingGroups) { | ||||||
|                     { |                         if (filterValue == id.ToString()) { | ||||||
|                         if (filterValue == id.ToString()) |  | ||||||
|                         { |  | ||||||
|                             filteredTraining.Add(item); |                             filteredTraining.Add(item); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
| @ -392,11 +285,9 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|                 return PartialView(trainingList); |                 return PartialView(trainingList); | ||||||
|             } |             } | ||||||
|             //Status Filter |             //Status Filter | ||||||
|             if (filterType == 2 && filterValue != "") |             if (filterType == 2 && filterValue != "") { | ||||||
|             { |  | ||||||
|                 List<Training> filteredTraining = new List<Training>(); |                 List<Training> filteredTraining = new List<Training>(); | ||||||
|                 switch (filterValue) |                 switch (filterValue) { | ||||||
|                 { |  | ||||||
|                     case "1": |                     case "1": | ||||||
|                         //Completed |                         //Completed | ||||||
|                         filteredTraining = (from a in trainingList where a.Status == true && a.Deleted != true select a).ToList(); |                         filteredTraining = (from a in trainingList where a.Status == true && a.Deleted != true select a).ToList(); | ||||||
| @ -414,16 +305,12 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|                 return PartialView(trainingList); |                 return PartialView(trainingList); | ||||||
|             } |             } | ||||||
|             //Default return all. |             //Default return all. | ||||||
|             else |             else { | ||||||
|             { |  | ||||||
|                 return PartialView(trainingList); |                 return PartialView(trainingList); | ||||||
|             } |             } | ||||||
|              |  | ||||||
|              |  | ||||||
|              |  | ||||||
|         } |         } | ||||||
|         public ActionResult ViewTrainingAssignmentsReportView(int trainingID, string statusFilter, string groupFilter) |  | ||||||
|         { |         public ActionResult ViewTrainingAssignmentsReportView(int trainingID, string statusFilter, string groupFilter) { | ||||||
|             bool? trainingStatus = trainingDMO.GetTraining(trainingID).Status; |             bool? trainingStatus = trainingDMO.GetTraining(trainingID).Status; | ||||||
|             int ECNNumber = trainingDMO.GetTraining(trainingID).ECN; |             int ECNNumber = trainingDMO.GetTraining(trainingID).ECN; | ||||||
|             string ECNTitle = ecnDMO.GetECN(ECNNumber).Title; |             string ECNTitle = ecnDMO.GetECN(ECNNumber).Title; | ||||||
| @ -438,37 +325,30 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|             //float assignmentCount = trainingAssignments.Count(); |             //float assignmentCount = trainingAssignments.Count(); | ||||||
|             float assignmentCount = (from a in trainingAssignments where a.Deleted != true select a).Count(); |             float assignmentCount = (from a in trainingAssignments where a.Deleted != true select a).Count(); | ||||||
|             float totalCompleted = 0; |             float totalCompleted = 0; | ||||||
|             foreach (var assignment in trainingAssignments) |             foreach (TrainingAssignment assignment in trainingAssignments) { | ||||||
|             { |                 if (assignment.status == true && assignment.Deleted != true) { | ||||||
|                 if (assignment.status == true && assignment.Deleted != true) |  | ||||||
|                 { |  | ||||||
|                     totalCompleted++; |                     totalCompleted++; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             percentComplete = (totalCompleted / assignmentCount) * 100; |             percentComplete = totalCompleted / assignmentCount * 100; | ||||||
|             ViewBag.PercentComplete = percentComplete.ToString("0.00") + "%"; |             ViewBag.PercentComplete = percentComplete.ToString("0.00") + "%"; | ||||||
|             |  | ||||||
|             if (groupFilter != "" && groupFilter != null) |             if (groupFilter != "" && groupFilter != null) { | ||||||
|             { |  | ||||||
|                 ViewBag.GroupFilter = groupFilter; |                 ViewBag.GroupFilter = groupFilter; | ||||||
|                 List<TrainingAssignment> groupFilteredTraining = new List<TrainingAssignment>(); |                 List<TrainingAssignment> groupFilteredTraining = new List<TrainingAssignment>(); | ||||||
|                 List<int> groupMemberIds = trainingDMO.GetTrainees(Convert.ToInt32(groupFilter)); |                 List<int> groupMemberIds = trainingDMO.GetTrainees(Convert.ToInt32(groupFilter)); | ||||||
|                 foreach (var assignment in trainingAssignments) |                 foreach (TrainingAssignment assignment in trainingAssignments) { | ||||||
|                 { |                     if (trainingDMO.isUserTrainingMember(Convert.ToInt32(groupFilter), assignment.UserID)) { | ||||||
|                     if(trainingDMO.isUserTrainingMember(Convert.ToInt32(groupFilter), assignment.UserID)) |  | ||||||
|                     { |  | ||||||
|                         groupFilteredTraining.Add(assignment); |                         groupFilteredTraining.Add(assignment); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 trainingAssignments = groupFilteredTraining; |                 trainingAssignments = groupFilteredTraining; | ||||||
|  |  | ||||||
|             } |             } | ||||||
|             if (statusFilter != "" && statusFilter != null) |             if (statusFilter != "" && statusFilter != null) { | ||||||
|             { |  | ||||||
|                 List<TrainingAssignment> filteredTraining = new List<TrainingAssignment>(); |                 List<TrainingAssignment> filteredTraining = new List<TrainingAssignment>(); | ||||||
|                 switch (statusFilter) |                 switch (statusFilter) { | ||||||
|                 { |  | ||||||
|                      |  | ||||||
|                     case "1": |                     case "1": | ||||||
|                         //Completed |                         //Completed | ||||||
|                         filteredTraining = (from a in trainingAssignments where a.status == true && a.Deleted != true select a).ToList(); |                         filteredTraining = (from a in trainingAssignments where a.status == true && a.Deleted != true select a).ToList(); | ||||||
| @ -491,8 +371,8 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|  |  | ||||||
|             return PartialView(trainingAssignments); |             return PartialView(trainingAssignments); | ||||||
|         } |         } | ||||||
|         public ActionResult ViewTrainingAssignments(int trainingID) |  | ||||||
|         { |         public ActionResult ViewTrainingAssignments(int trainingID) { | ||||||
|             bool? trainingStatus = trainingDMO.GetTraining(trainingID).Status; |             bool? trainingStatus = trainingDMO.GetTraining(trainingID).Status; | ||||||
|             int ECNNumber = trainingDMO.GetTraining(trainingID).ECN; |             int ECNNumber = trainingDMO.GetTraining(trainingID).ECN; | ||||||
|             string ECNTitle = ecnDMO.GetECN(ECNNumber).Title; |             string ECNTitle = ecnDMO.GetECN(ECNNumber).Title; | ||||||
| @ -503,93 +383,78 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|             ViewBag.AllUsers = userDMO.GetAllActiveUsers(); |             ViewBag.AllUsers = userDMO.GetAllActiveUsers(); | ||||||
|             ViewBag.AllGroups = trainingDMO.GetTrainingGroups(); |             ViewBag.AllGroups = trainingDMO.GetTrainingGroups(); | ||||||
|             IEnumerable<TrainingAssignment> trainingAssignments = trainingDMO.GetTrainingAssignments(trainingID); |             IEnumerable<TrainingAssignment> trainingAssignments = trainingDMO.GetTrainingAssignments(trainingID); | ||||||
|              |  | ||||||
|             return View(trainingAssignments); |             return View(trainingAssignments); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// Method to return all the training assignments for a specified user |         /// Method to return all the training assignments for a specified user | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="userID"></param> |         /// <param name="userID"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public ActionResult ViewMyTrainingAssignments() |         public ActionResult ViewMyTrainingAssignments() { | ||||||
|         { |  | ||||||
|             int userID = (int)Session[GlobalVars.SESSION_USERID]; |             int userID = (int)Session[GlobalVars.SESSION_USERID]; | ||||||
|             List<TrainingAssignment> assignments = trainingDMO.GetTrainingAssignmentsByUserID(userID); |             List<TrainingAssignment> assignments = trainingDMO.GetTrainingAssignmentsByUserID(userID); | ||||||
|             List<ECNTrainingAssignments> ViewData = new List<ECNTrainingAssignments>(); |             List<ECNTrainingAssignments> ViewData = new List<ECNTrainingAssignments>(); | ||||||
|             foreach (var assignment in assignments) |             foreach (TrainingAssignment assignment in assignments) { | ||||||
|             { |  | ||||||
|                 Training training = trainingDMO.GetTraining(assignment.TrainingID); |                 Training training = trainingDMO.GetTraining(assignment.TrainingID); | ||||||
|                 if (training != null && !assignment.status) |                 if (training != null && !assignment.status) { | ||||||
|                 { |  | ||||||
|                     int ecnID = training.ECN; |                     int ecnID = training.ECN; | ||||||
|                     ViewData.Add(new ECNTrainingAssignments |                     ViewData.Add(new ECNTrainingAssignments { | ||||||
|                     { |  | ||||||
|                         TrainingAssignmentID = assignment.ID, |                         TrainingAssignmentID = assignment.ID, | ||||||
|                         ECN_ID = ecnID, |                         ECN_ID = ecnID, | ||||||
|                         TrainingID = assignment.TrainingID, |                         TrainingID = assignment.TrainingID, | ||||||
|                         DateAssigned = assignment.DateAssigned, |                         DateAssigned = assignment.DateAssigned, | ||||||
|                         DateCompleted = assignment.DateCompleted, |                         DateCompleted = assignment.DateCompleted, | ||||||
|                         Status = assignment.status |                         Status = assignment.status | ||||||
|  |  | ||||||
|  |  | ||||||
|                     }); |                     }); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return View(ViewData); |             return View(ViewData); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// Method to return all assigned documents for a specified training assignment |         /// Method to return all assigned documents for a specified training assignment | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="assignmentID"></param> |         /// <param name="assignmentID"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public ActionResult ViewMyTrainingAssignment(int assignmentID, int ECNNumber) |         public ActionResult ViewMyTrainingAssignment(int assignmentID, int ECNNumber) { | ||||||
|         { |  | ||||||
|             ViewBag.ECNNumber = ECNNumber; |             ViewBag.ECNNumber = ECNNumber; | ||||||
|             ViewBag.AssignmentID = assignmentID; |             ViewBag.AssignmentID = assignmentID; | ||||||
|             ViewBag.IsCompleted = trainingDMO.GetAssignment(assignmentID).status; |             ViewBag.IsCompleted = trainingDMO.GetAssignment(assignmentID).status; | ||||||
|             return View(trainingDMO.GetAssignedDocs(assignmentID)); |             return View(trainingDMO.GetAssignedDocs(assignmentID)); | ||||||
|         } |         } | ||||||
|         public ActionResult ViewTrainings(int? filterType, string filterValue) |  | ||||||
|         { |         public ActionResult ViewTrainings(int? filterType, string filterValue) { | ||||||
|             IEnumerable<Training> AllTrainings = trainingDMO.GetTrainings(); |             IEnumerable<Training> AllTrainings = trainingDMO.GetTrainings(); | ||||||
|             ViewBag.TrainingGroups = adminDMO.GetTrainingGroups(); |             ViewBag.TrainingGroups = adminDMO.GetTrainingGroups(); | ||||||
|             ViewBag.AllGroups = trainingDMO.GetTrainingGroups(); |             ViewBag.AllGroups = trainingDMO.GetTrainingGroups(); | ||||||
|             //Group Filter |             //Group Filter | ||||||
|             if (filterType == 1 && filterValue != "") |             if (filterType == 1 && filterValue != "") { | ||||||
|             { |  | ||||||
|                 ViewBag.GroupFilter = filterValue; |                 ViewBag.GroupFilter = filterValue; | ||||||
|                 List<Training> filteredTraining = new List<Training>(); |                 List<Training> filteredTraining = new List<Training>(); | ||||||
|                 foreach (var item in AllTrainings) |                 foreach (Training item in AllTrainings) { | ||||||
|                 { |  | ||||||
|                     List<int> assignedTrainingGroups = trainingDMO.GetECNAssignedTrainingGroups(item.ECN); |                     List<int> assignedTrainingGroups = trainingDMO.GetECNAssignedTrainingGroups(item.ECN); | ||||||
|                     foreach (int id in assignedTrainingGroups) |                     foreach (int id in assignedTrainingGroups) { | ||||||
|                     { |                         if (filterValue == id.ToString()) { | ||||||
|                         if (filterValue == id.ToString()) |  | ||||||
|                         { |  | ||||||
|                             filteredTraining.Add(item); |                             filteredTraining.Add(item); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 AllTrainings = filteredTraining; |                 AllTrainings = filteredTraining; | ||||||
|                 return View(AllTrainings); |                 return View(AllTrainings); | ||||||
|             } |             } else { | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 ViewBag.AllGroups = trainingDMO.GetTrainingGroups(); |                 ViewBag.AllGroups = trainingDMO.GetTrainingGroups(); | ||||||
|                 return View(AllTrainings); |                 return View(AllTrainings); | ||||||
|             } |             } | ||||||
|              |  | ||||||
|             |  | ||||||
|         } |         } | ||||||
|         public ActionResult ViewAllTrainings() |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|  |         public ActionResult ViewAllTrainings() { | ||||||
|             return View(); |             return View(); | ||||||
|         } |         } | ||||||
|         public ActionResult DeleteAssignment(int assignmentId) |  | ||||||
|         { |         public ActionResult DeleteAssignment(int assignmentId) { | ||||||
|             trainingDMO.DeleteTrainingAssignment(assignmentId); |             trainingDMO.DeleteTrainingAssignment(assignmentId); | ||||||
|             trainingDMO.DeleteTrainingDocAck(assignmentId); |             trainingDMO.DeleteTrainingDocAck(assignmentId); | ||||||
|  |  | ||||||
| @ -597,116 +462,81 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|             //TO-DO Put this in its own method. |             //TO-DO Put this in its own method. | ||||||
|             bool isFinishedTrainingAssignment = trainingDMO.CheckTrainingAssignmentStatus(assignmentId); |             bool isFinishedTrainingAssignment = trainingDMO.CheckTrainingAssignmentStatus(assignmentId); | ||||||
|  |  | ||||||
|             if (isFinishedTrainingAssignment) |             if (isFinishedTrainingAssignment) { | ||||||
|             { |                 try { | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     trainingDMO.UpdateAssignmentStatus(assignmentId); |                     trainingDMO.UpdateAssignmentStatus(assignmentId); | ||||||
|                     bool isFinishedTraining = trainingDMO.CheckTrainingStatus(assignmentId); |                     bool isFinishedTraining = trainingDMO.CheckTrainingStatus(assignmentId); | ||||||
|                     if (isFinishedTraining) |                     if (isFinishedTraining) { | ||||||
|                     { |  | ||||||
|                         int TrainingID = trainingDMO.GetTrainingIdByAssignment(assignmentId); |                         int TrainingID = trainingDMO.GetTrainingIdByAssignment(assignmentId); | ||||||
|                         trainingDMO.UpdateTrainingStatus(TrainingID); |                         trainingDMO.UpdateTrainingStatus(TrainingID); | ||||||
|                     } |                     } | ||||||
|                 } |                 } catch (Exception e) { | ||||||
|                 catch (Exception e) |  | ||||||
|                 { |  | ||||||
|                     string exception = e.ToString(); |                     string exception = e.ToString(); | ||||||
|                     return Content(exception, "application/json"); |                     return Content(exception, "application/json"); | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return Json(new { test = "Succesfully saved" }); |             return Json(new { test = "Succesfully saved" }); | ||||||
|         } |         } | ||||||
|         public ActionResult ManuallyExecuteECNTraining(int ecnId, int[] trainingGroupsIn) |  | ||||||
|         { |         public ActionResult ManuallyExecuteECNTraining(int ecnId, int[] trainingGroupsIn) { | ||||||
|             if ((bool)Session[GlobalVars.IS_ADMIN]) |             if ((bool)Session[GlobalVars.IS_ADMIN]) { | ||||||
|             { |  | ||||||
|                 List<int> newTrainingGroupIds = new List<int>(trainingGroupsIn); |                 List<int> newTrainingGroupIds = new List<int>(trainingGroupsIn); | ||||||
|                 //Get ECN |                 //Get ECN | ||||||
|                 ECN ecn = ecnDMO.GetECN(ecnId); |                 ECN ecn = ecnDMO.GetECN(ecnId); | ||||||
|                 if (ecn != null) |                 if (ecn != null) { | ||||||
|                 { |                     if (ecn.CloseDate != null) { | ||||||
|                     if(ecn.CloseDate != null) |                         if (newTrainingGroupIds.Count > 0) { | ||||||
|                     { |  | ||||||
|                         if (newTrainingGroupIds.Count > 0) |  | ||||||
|                         { |  | ||||||
|                             //Check each assigned group id and see if it's already saved to the ECN |                             //Check each assigned group id and see if it's already saved to the ECN | ||||||
|                             List<int> assignedTrainingGroups = trainingDMO.GetECNAssignedTrainingGroups(ecnId); |                             List<int> assignedTrainingGroups = trainingDMO.GetECNAssignedTrainingGroups(ecnId); | ||||||
|                             IEnumerable<int> onlyNewTrainingIds = newTrainingGroupIds.Except(assignedTrainingGroups); |                             IEnumerable<int> onlyNewTrainingIds = newTrainingGroupIds.Except(assignedTrainingGroups); | ||||||
|                             try |                             try { | ||||||
|                             { |                                 foreach (int trainingId in onlyNewTrainingIds) { | ||||||
|                                 foreach (int trainingId in onlyNewTrainingIds) |  | ||||||
|                                 { |  | ||||||
|                                     trainingDMO.AddTrainingGroupToECN(ecnId, trainingId); |                                     trainingDMO.AddTrainingGroupToECN(ecnId, trainingId); | ||||||
|                                 } |                                 } | ||||||
|                              |  | ||||||
|                                 trainingDMO.SetTrainingFlag(ecnId); |                                 trainingDMO.SetTrainingFlag(ecnId); | ||||||
|                                 Create(ecnId); |                                 Create(ecnId); | ||||||
|                                 return Content("Success"); |                                 return Content("Success"); | ||||||
|                             } |                             } catch (Exception e) { | ||||||
|                             catch(Exception e) |  | ||||||
|                             { |  | ||||||
|                                 return Content("Failed: " + e.Message.ToString()); |                                 return Content("Failed: " + e.Message.ToString()); | ||||||
|                             } |                             } | ||||||
|                         } |                         } else { | ||||||
|                         else |  | ||||||
|                         { |  | ||||||
|                             return Content("There were no training groups to assign to. Please select at least one training groups."); |                             return Content("There were no training groups to assign to. Please select at least one training groups."); | ||||||
|                         } |                         } | ||||||
|  |                     } else { | ||||||
|                     } |  | ||||||
|                     else |  | ||||||
|                     { |  | ||||||
|                         return Content("Selected ECN hasn't been approved yet."); |                         return Content("Selected ECN hasn't been approved yet."); | ||||||
|                     } |                     } | ||||||
|                 } |                 } else { | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return Content("Invalid ECN"); |                     return Content("Invalid ECN"); | ||||||
|                 } |                 } | ||||||
|             } |             } else { | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return Content("Not Autthorized"); |                 return Content("Not Autthorized"); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         public ActionResult CheckECN(int ecnId) |  | ||||||
|         { |         public ActionResult CheckECN(int ecnId) { | ||||||
|             ECN ecn = ecnDMO.GetECN(ecnId); |             ECN ecn = ecnDMO.GetECN(ecnId); | ||||||
|             if(ecn != null) |             if (ecn != null) { | ||||||
|             { |                 if (ecn.CloseDate != null) { | ||||||
|                 if(ecn.CloseDate != null) |  | ||||||
|                 { |  | ||||||
|                     List<int> trainingGroupIds = trainingDMO.GetECNAssignedTrainingGroups(ecnId); |                     List<int> trainingGroupIds = trainingDMO.GetECNAssignedTrainingGroups(ecnId); | ||||||
|                     List<TrainingGroup> assignedGroups = new List<TrainingGroup>(); |                     List<TrainingGroup> assignedGroups = new List<TrainingGroup>(); | ||||||
|                     foreach (int trainingGroupId in trainingGroupIds) |                     foreach (int trainingGroupId in trainingGroupIds) { | ||||||
|                     { |  | ||||||
|                         TrainingGroup trainingGroup = trainingDMO.GetTrainingGroupByID(trainingGroupId); |                         TrainingGroup trainingGroup = trainingDMO.GetTrainingGroupByID(trainingGroupId); | ||||||
|                         assignedGroups.Add(trainingGroup); |                         assignedGroups.Add(trainingGroup); | ||||||
|                     } |                     } | ||||||
|                     return Json(trainingGroupIds.ToList()); |                     return Json(trainingGroupIds.ToList()); | ||||||
|                 } |                 } else { | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     return Content("ECN not yet approved."); |                     return Content("ECN not yet approved."); | ||||||
|                 } |                 } | ||||||
|  |             } else { | ||||||
|             } |  | ||||||
|             else |  | ||||||
|             { |  | ||||||
|                 return Content("That ECN wasn't found."); |                 return Content("That ECN wasn't found."); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|         } |         } | ||||||
|         public bool RunTrainingReport() |  | ||||||
|         { |         public bool RunTrainingReport() { | ||||||
|             bool isSuccess = false; |             bool isSuccess = false; | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 string emailBody = "<h1>Mesa Approval Open Training Assignments Daily Report</h1> <br />"; |                 string emailBody = "<h1>Mesa Approval Open Training Assignments Daily Report</h1> <br />"; | ||||||
|                 emailBody += "<p>The following contains open training assignments in the Mesa Approval system. "; |                 emailBody += "<p>The following contains open training assignments in the Mesa Approval system. "; | ||||||
|                 emailBody += "Please ensure the following users complete their training assignments. "; |                 emailBody += "Please ensure the following users complete their training assignments. "; | ||||||
| @ -715,8 +545,7 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|                 //Get all users set up to receive the training report email. |                 //Get all users set up to receive the training report email. | ||||||
|                 List<TrainingReportUser> trainingReportUsers = adminDMO.GetTrainingReportUsers(); |                 List<TrainingReportUser> trainingReportUsers = adminDMO.GetTrainingReportUsers(); | ||||||
|                 List<string> emailList = new List<string>(); |                 List<string> emailList = new List<string>(); | ||||||
|                 foreach (var user in trainingReportUsers) |                 foreach (TrainingReportUser user in trainingReportUsers) { | ||||||
|                 { |  | ||||||
|                     string userEmail = userDMO.GetUserByID(user.UserId).Email; |                     string userEmail = userDMO.GetUserByID(user.UserId).Email; | ||||||
|                     emailList.Add(userEmail); |                     emailList.Add(userEmail); | ||||||
|                 } |                 } | ||||||
| @ -724,8 +553,7 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|                 //Get a list of open trainings |                 //Get a list of open trainings | ||||||
|                 List<Training> openTrainings = trainingDMO.GetAllOpenTrainings(); |                 List<Training> openTrainings = trainingDMO.GetAllOpenTrainings(); | ||||||
|  |  | ||||||
|                 foreach (Training training in openTrainings) |                 foreach (Training training in openTrainings) { | ||||||
|                 { |  | ||||||
|                     string trainingSection = ""; |                     string trainingSection = ""; | ||||||
|                     int trainingSectionUserCount = 0; |                     int trainingSectionUserCount = 0; | ||||||
|                     string ecnTitle = ecnDMO.GetECN(training.ECN).Title; |                     string ecnTitle = ecnDMO.GetECN(training.ECN).Title; | ||||||
| @ -734,23 +562,18 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|                     trainingSection += "<table>"; |                     trainingSection += "<table>"; | ||||||
|                     trainingSection += "<tr><th>Name</th><th>Date Assigned</th></tr>"; |                     trainingSection += "<tr><th>Name</th><th>Date Assigned</th></tr>"; | ||||||
|                     List<TrainingAssignment> openAssignments = trainingDMO.GetOpenAssignmentsByTrainingID(training.TrainingID); |                     List<TrainingAssignment> openAssignments = trainingDMO.GetOpenAssignmentsByTrainingID(training.TrainingID); | ||||||
|                     foreach (TrainingAssignment assignment in openAssignments) |                     foreach (TrainingAssignment assignment in openAssignments) { | ||||||
|                     { |  | ||||||
|  |  | ||||||
|                         if (!userDMO.GetUserByID(assignment.UserID).OOO) |                         if (!userDMO.GetUserByID(assignment.UserID).OOO) { | ||||||
|                         { |  | ||||||
|                             trainingSectionUserCount++; |                             trainingSectionUserCount++; | ||||||
|  |  | ||||||
|                             DateTime? assignmentDate = assignment.DateAssigned; |                             DateTime? assignmentDate = assignment.DateAssigned; | ||||||
|  |  | ||||||
|                             string DateAssigned = assignmentDate.HasValue ? assignmentDate.Value.ToString("MM/dd/yyyy") : "<not available>"; |                             string DateAssigned = assignmentDate.HasValue ? assignmentDate.Value.ToString("MM/dd/yyyy") : "<not available>"; | ||||||
|  |  | ||||||
|                             if (assignmentDate.HasValue && (DateTime.Now.Date - assignmentDate.Value.Date).TotalDays > 15) |                             if (assignmentDate.HasValue && (DateTime.Now.Date - assignmentDate.Value.Date).TotalDays > 15) { | ||||||
|                             { |  | ||||||
|                                 trainingSection += "<tr><td>" + assignment.FullName + "</td><td style=\"color:red;\">" + DateAssigned + "</td>"; |                                 trainingSection += "<tr><td>" + assignment.FullName + "</td><td style=\"color:red;\">" + DateAssigned + "</td>"; | ||||||
|                             } |                             } else { | ||||||
|                             else |  | ||||||
|                             { |  | ||||||
|                                 trainingSection += "<tr><td>" + assignment.FullName + "</td><td>" + DateAssigned + "</td>"; |                                 trainingSection += "<tr><td>" + assignment.FullName + "</td><td>" + DateAssigned + "</td>"; | ||||||
|                             } |                             } | ||||||
|  |  | ||||||
| @ -764,13 +587,10 @@ namespace Fab2ApprovalSystem.Controllers | |||||||
|                 List<string> ccRecipients = emailList; |                 List<string> ccRecipients = emailList; | ||||||
|                 emailer.SendNotification("MesaFabApproval@infineon.com", ccRecipients, "Mesa Approval Daily Open Training Report", emailBody, "Daily Open Training Report"); |                 emailer.SendNotification("MesaFabApproval@infineon.com", ccRecipients, "Mesa Approval Daily Open Training Report", emailBody, "Daily Open Training Report"); | ||||||
|                 isSuccess = true; |                 isSuccess = true; | ||||||
|             } |             } catch { | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|                 isSuccess = false; |                 isSuccess = false; | ||||||
|             } |             } | ||||||
|             return isSuccess; |             return isSuccess; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,11 +1,9 @@ | |||||||
| using System; | using System; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.Configuration; |  | ||||||
| using System.Data; | using System.Data; | ||||||
| using System.Data.SqlClient; | using System.Data.SqlClient; | ||||||
| using System.Linq; | using System.Linq; | ||||||
| using System.Text; | using System.Text; | ||||||
| using System.Web; |  | ||||||
| using Fab2ApprovalSystem.Models; | using Fab2ApprovalSystem.Models; | ||||||
| using Dapper; | using Dapper; | ||||||
| using System.Transactions; | using System.Transactions; | ||||||
| @ -13,8 +11,7 @@ using Fab2ApprovalSystem.ViewModels; | |||||||
| using System.Reflection; | using System.Reflection; | ||||||
| using Fab2ApprovalSystem.Misc; | using Fab2ApprovalSystem.Misc; | ||||||
|  |  | ||||||
| namespace Fab2ApprovalSystem.DMO | namespace Fab2ApprovalSystem.DMO { | ||||||
| { |  | ||||||
|     public class LotDispositionDMO |     public class LotDispositionDMO | ||||||
|     { |     { | ||||||
|         private IDbConnection db = new SqlConnection(GlobalVars.DB_CONNECTION_STRING); |         private IDbConnection db = new SqlConnection(GlobalVars.DB_CONNECTION_STRING); | ||||||
|  | |||||||
| @ -154,6 +154,10 @@ namespace Fab2ApprovalSystem.DMO | |||||||
|             FabApprovalTrainingEntities db = new FabApprovalTrainingEntities(); |             FabApprovalTrainingEntities db = new FabApprovalTrainingEntities(); | ||||||
|             var TrainingData = from a in db.TrainingAssignments where a.TrainingID == TrainingID select a; |             var TrainingData = from a in db.TrainingAssignments where a.TrainingID == TrainingID select a; | ||||||
|  |  | ||||||
|  |             RefreshTrainingData(TrainingID, TrainingData); | ||||||
|  |  | ||||||
|  |             TrainingData = from a in db.TrainingAssignments where a.TrainingID == TrainingID select a; | ||||||
|  |  | ||||||
|             return TrainingData.ToList(); |             return TrainingData.ToList(); | ||||||
|         } |         } | ||||||
|         public List<TrainingAssignment> GetTrainingAssignments(int TrainingID) |         public List<TrainingAssignment> GetTrainingAssignments(int TrainingID) | ||||||
| @ -161,6 +165,10 @@ namespace Fab2ApprovalSystem.DMO | |||||||
|             FabApprovalTrainingEntities db = new FabApprovalTrainingEntities(); |             FabApprovalTrainingEntities db = new FabApprovalTrainingEntities(); | ||||||
|             var TrainingData = from a in db.TrainingAssignments where a.TrainingID == TrainingID && a.Deleted != true select a; |             var TrainingData = from a in db.TrainingAssignments where a.TrainingID == TrainingID && a.Deleted != true select a; | ||||||
|  |  | ||||||
|  |             RefreshTrainingData(TrainingID, TrainingData); | ||||||
|  |  | ||||||
|  |             TrainingData = from a in db.TrainingAssignments where a.TrainingID == TrainingID select a; | ||||||
|  |  | ||||||
|             return TrainingData.ToList(); |             return TrainingData.ToList(); | ||||||
|         } |         } | ||||||
|         public List<TrainingAssignment> GetTrainingAssignmentsByUser(int TrainingID, int userID) |         public List<TrainingAssignment> GetTrainingAssignmentsByUser(int TrainingID, int userID) | ||||||
| @ -452,5 +460,20 @@ namespace Fab2ApprovalSystem.DMO | |||||||
|             return openAssignments; |             return openAssignments; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         private void RefreshTrainingData(int TrainingID, IQueryable<TrainingAssignment> TrainingData) | ||||||
|  |         { | ||||||
|  |             bool assignmentIsIncomplete = false; | ||||||
|  |             UserAccountDMO userAccountDMO = new UserAccountDMO(); | ||||||
|  |             foreach (TrainingAssignment assignment in TrainingData) | ||||||
|  |             { | ||||||
|  |                 LoginModel userModel = userAccountDMO.GetUserByID(assignment.UserID); | ||||||
|  |                 if (!userModel.IsActive) UpdateAssignmentStatus(assignment.ID); | ||||||
|  |                 if (assignment.Deleted != true && (assignment.DateCompleted is null || assignment.DateCompleted > DateTime.Now)) | ||||||
|  |                     assignmentIsIncomplete = true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (!assignmentIsIncomplete) | ||||||
|  |                 UpdateTrainingStatus(TrainingID); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -20,10 +20,14 @@ | |||||||
|     <IISExpressAnonymousAuthentication /> |     <IISExpressAnonymousAuthentication /> | ||||||
|     <IISExpressWindowsAuthentication /> |     <IISExpressWindowsAuthentication /> | ||||||
|     <IISExpressUseClassicPipelineMode /> |     <IISExpressUseClassicPipelineMode /> | ||||||
|     <SccProjectName>SAK</SccProjectName> |     <SccProjectName> | ||||||
|     <SccLocalPath>SAK</SccLocalPath> |     </SccProjectName> | ||||||
|     <SccAuxPath>SAK</SccAuxPath> |     <SccLocalPath> | ||||||
|     <SccProvider>SAK</SccProvider> |     </SccLocalPath> | ||||||
|  |     <SccAuxPath> | ||||||
|  |     </SccAuxPath> | ||||||
|  |     <SccProvider> | ||||||
|  |     </SccProvider> | ||||||
|     <UseGlobalApplicationHostFile /> |     <UseGlobalApplicationHostFile /> | ||||||
|     <Use64BitIISExpress>true</Use64BitIISExpress> |     <Use64BitIISExpress>true</Use64BitIISExpress> | ||||||
|     <TargetFrameworkProfile /> |     <TargetFrameworkProfile /> | ||||||
| @ -149,6 +153,8 @@ | |||||||
|     <Compile Include="Models\ApprovalLog.cs" /> |     <Compile Include="Models\ApprovalLog.cs" /> | ||||||
|     <Compile Include="Models\ApprovalLogHistory.cs" /> |     <Compile Include="Models\ApprovalLogHistory.cs" /> | ||||||
|     <Compile Include="Models\ApproveListModel.cs" /> |     <Compile Include="Models\ApproveListModel.cs" /> | ||||||
|  |     <Compile Include="Models\AuthAttempt.cs" /> | ||||||
|  |     <Compile Include="Models\AuthTokens.cs" /> | ||||||
|     <Compile Include="Models\ChangeControlModel.cs" /> |     <Compile Include="Models\ChangeControlModel.cs" /> | ||||||
|     <Compile Include="Models\Common.cs" /> |     <Compile Include="Models\Common.cs" /> | ||||||
|     <Compile Include="Models\C_8DAuditedStandard.cs"> |     <Compile Include="Models\C_8DAuditedStandard.cs"> | ||||||
| @ -178,6 +184,7 @@ | |||||||
|       <DesignTime>True</DesignTime> |       <DesignTime>True</DesignTime> | ||||||
|       <DependentUpon>FabApproval.edmx</DependentUpon> |       <DependentUpon>FabApproval.edmx</DependentUpon> | ||||||
|     </Compile> |     </Compile> | ||||||
|  |     <Compile Include="Models\LoginResult.cs" /> | ||||||
|     <Compile Include="Models\LotTravellerModel.cs" /> |     <Compile Include="Models\LotTravellerModel.cs" /> | ||||||
|     <Compile Include="Models\PartsRequestModels.cs" /> |     <Compile Include="Models\PartsRequestModels.cs" /> | ||||||
|     <Compile Include="Models\TECNNotificationsUser.cs"> |     <Compile Include="Models\TECNNotificationsUser.cs"> | ||||||
|  | |||||||
| @ -6,10 +6,8 @@ using System.Linq; | |||||||
| using System.Net.Mail; | using System.Net.Mail; | ||||||
| using System.Web; | using System.Web; | ||||||
|  |  | ||||||
| namespace Fab2ApprovalSystem.Misc | namespace Fab2ApprovalSystem.Misc { | ||||||
| { |     public class EmailNotification { | ||||||
|     public class EmailNotification |  | ||||||
|     { |  | ||||||
|         #region Variabls |         #region Variabls | ||||||
|         protected string _subject = null; |         protected string _subject = null; | ||||||
|         protected string _TemplatesPath = null; |         protected string _TemplatesPath = null; | ||||||
| @ -18,10 +16,8 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// Email subject |         /// Email subject | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         public string EmailSubject |         public string EmailSubject { | ||||||
|         { |  | ||||||
|             set { _subject = value; } |             set { _subject = value; } | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
| @ -29,11 +25,9 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="FileName">File Name</param> |         /// <param name="FileName">File Name</param> | ||||||
|         /// <returns>String: Containing the Entire content of the file</returns> |         /// <returns>String: Containing the Entire content of the file</returns> | ||||||
|         protected string ReadEmailFile(string FileName) |         protected string ReadEmailFile(string FileName) { | ||||||
|         { |  | ||||||
|             string retVal = null; |             string retVal = null; | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 //setting the file name path |                 //setting the file name path | ||||||
|                 string path = _TemplatesPath + FileName; |                 string path = _TemplatesPath + FileName; | ||||||
|                 FileInfo TheFile = new FileInfo(System.Web.HttpContext.Current.Server.MapPath(path)); |                 FileInfo TheFile = new FileInfo(System.Web.HttpContext.Current.Server.MapPath(path)); | ||||||
| @ -46,17 +40,12 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|                 StreamReader sr = new StreamReader(System.Web.HttpContext.Current.Server.MapPath(@path), System.Text.Encoding.GetEncoding(1256)); |                 StreamReader sr = new StreamReader(System.Web.HttpContext.Current.Server.MapPath(@path), System.Text.Encoding.GetEncoding(1256)); | ||||||
|                 retVal = sr.ReadToEnd(); // getting the entire text from the file. |                 retVal = sr.ReadToEnd(); // getting the entire text from the file. | ||||||
|                 sr.Close(); |                 sr.Close(); | ||||||
|             } |             } catch (Exception ex) { | ||||||
|  |  | ||||||
|  |  | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 throw new Exception("Error Reading File." + ex.Message); |                 throw new Exception("Error Reading File." + ex.Message); | ||||||
|  |  | ||||||
|  |  | ||||||
|             } |             } | ||||||
|             return retVal; |             return retVal; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// this function will send email. it will read the mail setting from the web.config |         /// this function will send email. it will read the mail setting from the web.config | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -66,8 +55,8 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <param name="cc">CC ids</param> |         /// <param name="cc">CC ids</param> | ||||||
|         /// <param name="email_title">Email Subject</param> |         /// <param name="email_title">Email Subject</param> | ||||||
|         /// <param name="email_body">Email Body</param> |         /// <param name="email_body">Email Body</param> | ||||||
|         protected void SendEmail(string SenderEmail, string SenderName, string Recep, string cc, string email_title, string email_body) | #pragma warning disable IDE0060 // Remove unused parameter | ||||||
|         { |         protected void SendEmail(string SenderEmail, string SenderName, string Recep, string cc, string email_title, string email_body) { | ||||||
|             // creating email message |             // creating email message | ||||||
|             MailMessage msg = new MailMessage(); |             MailMessage msg = new MailMessage(); | ||||||
|             msg.IsBodyHtml = true;// email body will allow html elements |             msg.IsBodyHtml = true;// email body will allow html elements | ||||||
| @ -87,27 +76,18 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             msg.Subject = email_title; |             msg.Subject = email_title; | ||||||
|             msg.Body = email_body; |             msg.Body = email_body; | ||||||
|  |  | ||||||
|             |             //create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section | ||||||
|  |             SmtpClient SmtpMail = new SmtpClient("mailrelay-internal.infineon.com"); | ||||||
|                 //create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section |  | ||||||
|                 SmtpClient SmtpMail = new SmtpClient("mailrelay-internal.infineon.com"); |  | ||||||
|  |  | ||||||
|             // sending the message. |             // sending the message. | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 SmtpMail.Send(msg); |                 SmtpMail.Send(msg); | ||||||
|             } |             } catch (Exception ex) { | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 Console.WriteLine("Exception caught in CreateTestMessage2(): {0}", |                 Console.WriteLine("Exception caught in CreateTestMessage2(): {0}", | ||||||
|                     ex.ToString()); |                     ex.ToString()); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  | #pragma warning restore IDE0060 // Remove unused parameter | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///  |         ///  | ||||||
| @ -119,8 +99,7 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <param name="email_title"></param> |         /// <param name="email_title"></param> | ||||||
|         /// <param name="email_body"></param> |         /// <param name="email_body"></param> | ||||||
|         /// <param name="attachmentPath"></param> |         /// <param name="attachmentPath"></param> | ||||||
|         protected void SendEmailWithAttachment(string SenderEmail, string SenderName, string Recep, string cc, string email_title, string email_body, string attachmentPath) |         protected void SendEmailWithAttachment(string SenderEmail, string SenderName, string Recep, string cc, string email_title, string email_body, string attachmentPath) { | ||||||
|         { |  | ||||||
|             // creating email message |             // creating email message | ||||||
|             MailMessage msg = new MailMessage(); |             MailMessage msg = new MailMessage(); | ||||||
|             msg.IsBodyHtml = true;// email body will allow html elements |             msg.IsBodyHtml = true;// email body will allow html elements | ||||||
| @ -140,22 +119,14 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             msg.Body = email_body; |             msg.Body = email_body; | ||||||
|             msg.Attachments.Add(new Attachment(attachmentPath)); |             msg.Attachments.Add(new Attachment(attachmentPath)); | ||||||
|  |  | ||||||
|  |  | ||||||
|             //create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section |             //create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section | ||||||
|             SmtpClient SmtpMail = new SmtpClient(); |             SmtpClient SmtpMail = new SmtpClient(); | ||||||
| #if(!DEBUG) | #if(!DEBUG) | ||||||
|             // sending the message. |             // sending the message. | ||||||
|             SmtpMail.Send(msg); |             SmtpMail.Send(msg); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///  |         ///  | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -165,8 +136,8 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <param name="cc"></param> |         /// <param name="cc"></param> | ||||||
|         /// <param name="email_title"></param> |         /// <param name="email_title"></param> | ||||||
|         /// <param name="email_body"></param> |         /// <param name="email_body"></param> | ||||||
|         protected void SendEmail(string SenderEmail, string SenderName, List<string> RecepientList, string cc, string email_title, string email_body) | #pragma warning disable IDE0060 // Remove unused parameter | ||||||
|         { |         protected void SendEmail(string SenderEmail, string SenderName, List<string> RecepientList, string cc, string email_title, string email_body) { | ||||||
|             // creating email message |             // creating email message | ||||||
|             MailMessage msg = new MailMessage(); |             MailMessage msg = new MailMessage(); | ||||||
|             msg.IsBodyHtml = true;// email body will allow html elements |             msg.IsBodyHtml = true;// email body will allow html elements | ||||||
| @ -175,8 +146,7 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             //msg.From = new MailAddress(SenderEmail, SenderName); |             //msg.From = new MailAddress(SenderEmail, SenderName); | ||||||
|             msg.From = new MailAddress("MesaFabApproval@infineon.com", "Mesa Fab Approval"); |             msg.From = new MailAddress("MesaFabApproval@infineon.com", "Mesa Fab Approval"); | ||||||
|             // adding the Recepient Email ID |             // adding the Recepient Email ID | ||||||
|             foreach (string recepient in RecepientList) |             foreach (string recepient in RecepientList) { | ||||||
|             { |  | ||||||
|                 msg.To.Add(recepient); |                 msg.To.Add(recepient); | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @ -188,26 +158,18 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             msg.Subject = email_title; |             msg.Subject = email_title; | ||||||
|             msg.Body = email_body; |             msg.Body = email_body; | ||||||
|  |  | ||||||
|              |             //create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section | ||||||
|                 //create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section |             SmtpClient SmtpMail = new SmtpClient(); | ||||||
|                 SmtpClient SmtpMail = new SmtpClient(); |  | ||||||
|  |  | ||||||
|             // sending the message. |             // sending the message. | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 SmtpMail.Send(msg); |                 SmtpMail.Send(msg); | ||||||
|             } |             } catch (Exception ex) { | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 Console.WriteLine("Exception caught in CreateTestMessage2(): {0}", |                 Console.WriteLine("Exception caught in CreateTestMessage2(): {0}", | ||||||
|                     ex.ToString()); |                     ex.ToString()); | ||||||
|             } |             } | ||||||
|                  |  | ||||||
|             |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  | #pragma warning restore IDE0060 // Remove unused parameter | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///  |         ///  | ||||||
| @ -219,8 +181,7 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <param name="email_title"></param> |         /// <param name="email_title"></param> | ||||||
|         /// <param name="email_body"></param> |         /// <param name="email_body"></param> | ||||||
|         /// <param name="attachmentPath"></param> |         /// <param name="attachmentPath"></param> | ||||||
|         protected void SendEmailWithAttachment(string SenderEmail, string SenderName, List<string> RecepientList, string cc, string email_title, string email_body, string attachmentPath) |         protected void SendEmailWithAttachment(string SenderEmail, string SenderName, List<string> RecepientList, string cc, string email_title, string email_body, string attachmentPath) { | ||||||
|         { |  | ||||||
|             // creating email message |             // creating email message | ||||||
|             MailMessage msg = new MailMessage(); |             MailMessage msg = new MailMessage(); | ||||||
|             msg.IsBodyHtml = true;// email body will allow html elements |             msg.IsBodyHtml = true;// email body will allow html elements | ||||||
| @ -229,8 +190,7 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             msg.From = new MailAddress(SenderEmail, SenderName); |             msg.From = new MailAddress(SenderEmail, SenderName); | ||||||
|  |  | ||||||
|             // adding the Recepient Email ID |             // adding the Recepient Email ID | ||||||
|             foreach (string recepient in RecepientList) |             foreach (string recepient in RecepientList) { | ||||||
|             { |  | ||||||
|                 if (recepient != null) |                 if (recepient != null) | ||||||
|                     msg.To.Add(recepient); |                     msg.To.Add(recepient); | ||||||
|             } |             } | ||||||
| @ -244,19 +204,13 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             msg.Body = email_body; |             msg.Body = email_body; | ||||||
|             msg.Attachments.Add(new Attachment(attachmentPath)); |             msg.Attachments.Add(new Attachment(attachmentPath)); | ||||||
|  |  | ||||||
|  |  | ||||||
|             //create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section |             //create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section | ||||||
|             SmtpClient SmtpMail = new SmtpClient(); |             SmtpClient SmtpMail = new SmtpClient(); | ||||||
|  |  | ||||||
|             // sending the message. |             // sending the message. | ||||||
|             SmtpMail.Send(msg); |             SmtpMail.Send(msg); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///  |         ///  | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -267,8 +221,7 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <param name="email_title"></param> |         /// <param name="email_title"></param> | ||||||
|         /// <param name="email_body"></param> |         /// <param name="email_body"></param> | ||||||
|         /// <param name="attachments"></param> |         /// <param name="attachments"></param> | ||||||
|         protected void SendEmailWithAttachments(string SenderEmail, string SenderName, string Recep, string cc, string email_title, string email_body, List<string> attachments) |         protected void SendEmailWithAttachments(string SenderEmail, string SenderName, string Recep, string cc, string email_title, string email_body, List<string> attachments) { | ||||||
|         { |  | ||||||
|             // creating email message |             // creating email message | ||||||
|             MailMessage msg = new MailMessage(); |             MailMessage msg = new MailMessage(); | ||||||
|             msg.IsBodyHtml = true;// email body will allow html elements |             msg.IsBodyHtml = true;// email body will allow html elements | ||||||
| @ -286,35 +239,29 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             //setting email subject and body |             //setting email subject and body | ||||||
|             msg.Subject = email_title; |             msg.Subject = email_title; | ||||||
|             msg.Body = email_body; |             msg.Body = email_body; | ||||||
|             foreach (string attachment in attachments) |             foreach (string attachment in attachments) { | ||||||
|             { |  | ||||||
|                 msg.Attachments.Add(new Attachment(attachment)); |                 msg.Attachments.Add(new Attachment(attachment)); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |  | ||||||
|             //create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section |             //create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section | ||||||
|             SmtpClient SmtpMail = new SmtpClient(); |             SmtpClient SmtpMail = new SmtpClient(); | ||||||
| #if(!DEBUG) | #if(!DEBUG) | ||||||
|             // sending the message. |             // sending the message. | ||||||
|             SmtpMail.Send(msg); |             SmtpMail.Send(msg); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|        /// <summary> |         /// <summary> | ||||||
|        ///  |         ///  | ||||||
|        /// </summary> |         /// </summary> | ||||||
|        /// <param name="SenderEmail"></param> |         /// <param name="SenderEmail"></param> | ||||||
|        /// <param name="SenderName"></param> |         /// <param name="SenderName"></param> | ||||||
|        /// <param name="RecepientList"></param> |         /// <param name="RecepientList"></param> | ||||||
|        /// <param name="cc"></param> |         /// <param name="cc"></param> | ||||||
|        /// <param name="email_title"></param> |         /// <param name="email_title"></param> | ||||||
|        /// <param name="email_body"></param> |         /// <param name="email_body"></param> | ||||||
|        /// <param name="attachments"></param> |         /// <param name="attachments"></param> | ||||||
|         protected void SendEmailWithAttachments(string SenderEmail, string SenderName, List<string> RecepientList, string cc, string email_title, string email_body, List<string> attachments) |         protected void SendEmailWithAttachments(string SenderEmail, string SenderName, List<string> RecepientList, string cc, string email_title, string email_body, List<string> attachments) { | ||||||
|         { |  | ||||||
|             // creating email message |             // creating email message | ||||||
|             MailMessage msg = new MailMessage(); |             MailMessage msg = new MailMessage(); | ||||||
|             msg.IsBodyHtml = true;// email body will allow html elements |             msg.IsBodyHtml = true;// email body will allow html elements | ||||||
| @ -323,8 +270,7 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             msg.From = new MailAddress(SenderEmail, SenderName); |             msg.From = new MailAddress(SenderEmail, SenderName); | ||||||
|  |  | ||||||
|             // adding the Recepient Email ID |             // adding the Recepient Email ID | ||||||
|             foreach (string recepient in RecepientList) |             foreach (string recepient in RecepientList) { | ||||||
|             { |  | ||||||
|                 if (recepient != null) |                 if (recepient != null) | ||||||
|                     msg.To.Add(recepient); |                     msg.To.Add(recepient); | ||||||
|             } |             } | ||||||
| @ -337,44 +283,32 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             msg.Subject = email_title; |             msg.Subject = email_title; | ||||||
|             msg.Body = email_body; |             msg.Body = email_body; | ||||||
|  |  | ||||||
|             foreach (string attachment in attachments) |             foreach (string attachment in attachments) { | ||||||
|             { |  | ||||||
|                 msg.Attachments.Add(new Attachment(attachment)); |                 msg.Attachments.Add(new Attachment(attachment)); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |  | ||||||
|             //create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section |             //create a Smtp Mail which will automatically get the smtp server details from web.config mailSettings section | ||||||
|             SmtpClient SmtpMail = new SmtpClient(); |             SmtpClient SmtpMail = new SmtpClient(); | ||||||
|  |  | ||||||
|             // sending the message. |             // sending the message. | ||||||
|             SmtpMail.Send(msg); |             SmtpMail.Send(msg); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         public EmailNotification() { | ||||||
|         public EmailNotification() |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// The Constructor Function |         /// The Constructor Function | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="EmailHeaderSubject">Email Header Subject</param> |         /// <param name="EmailHeaderSubject">Email Header Subject</param> | ||||||
|         /// <param name="TemplatesPath">Emails Files Templates</param> |         /// <param name="TemplatesPath">Emails Files Templates</param> | ||||||
|         public EmailNotification(string EmailHeaderSubject, string TemplatesPath) |         public EmailNotification(string EmailHeaderSubject, string TemplatesPath) { | ||||||
|         { |  | ||||||
|             _subject = EmailHeaderSubject; |             _subject = EmailHeaderSubject; | ||||||
|             _TemplatesPath = TemplatesPath; |             _TemplatesPath = TemplatesPath; | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// This function will send the email notification by reading the email template and substitute the arguments |         /// This function will send the email notification by reading the email template and substitute the arguments | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -386,43 +320,33 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <param name="Subject">EMail Subject</param> |         /// <param name="Subject">EMail Subject</param> | ||||||
|         /// <param name="Args">Arguments</param> |         /// <param name="Args">Arguments</param> | ||||||
|         /// <returns>String: Return the body of the email to be send</returns> |         /// <returns>String: Return the body of the email to be send</returns> | ||||||
|         public string SendNotificationEmail(string EmailTemplateFile, string SenderEmail, string SenderName, string RecepientEmail, string CC, string Subject, params string[] Args) |         public string SendNotificationEmail(string EmailTemplateFile, string SenderEmail, string SenderName, string RecepientEmail, string CC, string Subject, params string[] Args) { | ||||||
|         { |  | ||||||
|             string retVal = null; |             string retVal = null; | ||||||
|  |  | ||||||
|             //reading the file |             //reading the file | ||||||
|             string FileContents = ReadEmailFile(EmailTemplateFile); |             string FileContents = ReadEmailFile(EmailTemplateFile); | ||||||
|        |  | ||||||
|             string emailBody = FileContents; |             string emailBody = FileContents; | ||||||
|  |  | ||||||
|             //setting formatting the string |             //setting formatting the string | ||||||
|             retVal = string.Format(emailBody, Args); |             retVal = string.Format(emailBody, Args); | ||||||
|  |  | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 //check if we are in debug mode or not. to send email |                 //check if we are in debug mode or not. to send email | ||||||
|                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") |                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") { | ||||||
|                 { |  | ||||||
|                     SendEmail(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? Subject + " for: " + RecepientEmail : _subject), retVal); |                     SendEmail(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? Subject + " for: " + RecepientEmail : _subject), retVal); | ||||||
|                 } |                 } else { | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
| #if(!DEBUG) | #if(!DEBUG) | ||||||
|                     SendEmail(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject  : _subject), retVal); |                     SendEmail(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject  : _subject), retVal); | ||||||
| #endif | #endif | ||||||
|                 } |                 } | ||||||
|             } |             } catch (Exception ex) { | ||||||
|             catch (Exception ex) |                 throw ex; | ||||||
|             { |  | ||||||
|                  throw ex; |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return retVal; |             return retVal; | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// This function will send the email notification by reading the email template and substitute the arguments along with the attachments |         /// This function will send the email notification by reading the email template and substitute the arguments along with the attachments | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -435,8 +359,7 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <param name="attachmentPath"></param> |         /// <param name="attachmentPath"></param> | ||||||
|         /// <param name="Args"></param> |         /// <param name="Args"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public string SendNotificationEmailWithAttachment(string EmailTemplateFile, string SenderEmail, string SenderName, string RecepientEmail, string CC, string Subject, string attachmentPath,  params string[] Args) |         public string SendNotificationEmailWithAttachment(string EmailTemplateFile, string SenderEmail, string SenderName, string RecepientEmail, string CC, string Subject, string attachmentPath, params string[] Args) { | ||||||
|         { |  | ||||||
|             string retVal = null; |             string retVal = null; | ||||||
|  |  | ||||||
|             //reading the file |             //reading the file | ||||||
| @ -447,32 +370,22 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             //setting formatting the string |             //setting formatting the string | ||||||
|             retVal = string.Format(emailBody, Args); |             retVal = string.Format(emailBody, Args); | ||||||
|  |  | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 //check if we are in debug mode or not. to send email |                 //check if we are in debug mode or not. to send email | ||||||
|                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") |                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") { | ||||||
|                 { |  | ||||||
|                     SendEmailWithAttachment(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? " TESTING ONLY -IGNORE : " + Subject + RecepientEmail : _subject), retVal, attachmentPath); |                     SendEmailWithAttachment(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? " TESTING ONLY -IGNORE : " + Subject + RecepientEmail : _subject), retVal, attachmentPath); | ||||||
|                 } |                 } else { | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
| #if(!DEBUG) | #if(!DEBUG) | ||||||
|                     SendEmailWithAttachment(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal, attachmentPath); |                     SendEmailWithAttachment(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal, attachmentPath); | ||||||
| #endif | #endif | ||||||
|                 } |                 } | ||||||
|             } |             } catch (Exception ex) { | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 throw ex; |                 throw ex; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return retVal; |             return retVal; | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///  |         ///  | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -485,8 +398,7 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <param name="attachmentPath"></param> |         /// <param name="attachmentPath"></param> | ||||||
|         /// <param name="Args"></param> |         /// <param name="Args"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public string SendNotificationEmailWithAttachment(string EmailTemplateFile, string SenderEmail, string SenderName, List<string> RecepientEmail, string CC, string Subject, string attachmentPath, params string[] Args) |         public string SendNotificationEmailWithAttachment(string EmailTemplateFile, string SenderEmail, string SenderName, List<string> RecepientEmail, string CC, string Subject, string attachmentPath, params string[] Args) { | ||||||
|         { |  | ||||||
|             string retVal = null; |             string retVal = null; | ||||||
|  |  | ||||||
|             //reading the file |             //reading the file | ||||||
| @ -497,41 +409,28 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             //setting formatting the string |             //setting formatting the string | ||||||
|             retVal = string.Format(emailBody, Args); |             retVal = string.Format(emailBody, Args); | ||||||
|  |  | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 //check if we are in debug mode or not. to send email |                 //check if we are in debug mode or not. to send email | ||||||
|                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") |                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") { | ||||||
|                 { |                     foreach (string email in RecepientEmail) { | ||||||
|                     foreach(string email in RecepientEmail) |  | ||||||
|                     { |  | ||||||
|                         Subject += email + ";"; |                         Subject += email + ";"; | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     RecepientEmail.Clear(); |                     RecepientEmail.Clear(); | ||||||
|                     SendEmailWithAttachment(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? " TESTING ONLY -IGNORE : " + Subject : _subject), retVal, attachmentPath); |                     SendEmailWithAttachment(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? " TESTING ONLY -IGNORE : " + Subject : _subject), retVal, attachmentPath); | ||||||
|                 } |                 } else { | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
| #if (!DEBUG) | #if (!DEBUG) | ||||||
|                     SendEmailWithAttachment(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal, attachmentPath);                     |                     SendEmailWithAttachment(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal, attachmentPath);                     | ||||||
| #endif | #endif | ||||||
|                 } |                 } | ||||||
|             } |             } catch (Exception ex) { | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 throw ex; |                 throw ex; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return retVal; |             return retVal; | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|          |  | ||||||
|  |  | ||||||
|         /////////============================================================ |         public string SendNotificationEmailWithAttachments(string EmailTemplateFile, string SenderEmail, string SenderName, string RecepientEmail, string CC, string Subject, List<string> attachments, params string[] Args) { | ||||||
|  |  | ||||||
|         public string SendNotificationEmailWithAttachments(string EmailTemplateFile, string SenderEmail, string SenderName, string RecepientEmail, string CC, string Subject, List<string> attachments, params string[] Args) |  | ||||||
|         { |  | ||||||
|             string retVal = null; |             string retVal = null; | ||||||
|  |  | ||||||
|             //reading the file |             //reading the file | ||||||
| @ -542,32 +441,22 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             //setting formatting the string |             //setting formatting the string | ||||||
|             retVal = string.Format(emailBody, Args); |             retVal = string.Format(emailBody, Args); | ||||||
|  |  | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 //check if we are in debug mode or not. to send email |                 //check if we are in debug mode or not. to send email | ||||||
|                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") |                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") { | ||||||
|                 { |  | ||||||
|                     SendEmailWithAttachments(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? " TESTING ONLY -IGNORE : " + Subject + RecepientEmail : _subject), retVal, attachments); |                     SendEmailWithAttachments(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? " TESTING ONLY -IGNORE : " + Subject + RecepientEmail : _subject), retVal, attachments); | ||||||
|                 } |                 } else { | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
| #if(!DEBUG) | #if(!DEBUG) | ||||||
|                     SendEmailWithAttachments(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal, attachments); |                     SendEmailWithAttachments(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal, attachments); | ||||||
| #endif | #endif | ||||||
|                 } |                 } | ||||||
|             } |             } catch (Exception ex) { | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 throw ex; |                 throw ex; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return retVal; |             return retVal; | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///  |         ///  | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -580,8 +469,7 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <param name="attachmentPath"></param> |         /// <param name="attachmentPath"></param> | ||||||
|         /// <param name="Args"></param> |         /// <param name="Args"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public string SendNotificationEmailWithAttachments(string EmailTemplateFile, string SenderEmail, string SenderName, List<string> RecepientEmail, string CC, string Subject, List<string> attachments, params string[] Args) |         public string SendNotificationEmailWithAttachments(string EmailTemplateFile, string SenderEmail, string SenderName, List<string> RecepientEmail, string CC, string Subject, List<string> attachments, params string[] Args) { | ||||||
|         { |  | ||||||
|             string retVal = null; |             string retVal = null; | ||||||
|  |  | ||||||
|             //reading the file |             //reading the file | ||||||
| @ -592,39 +480,27 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             //setting formatting the string |             //setting formatting the string | ||||||
|             retVal = string.Format(emailBody, Args); |             retVal = string.Format(emailBody, Args); | ||||||
|  |  | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 //check if we are in debug mode or not. to send email |                 //check if we are in debug mode or not. to send email | ||||||
|                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") |                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") { | ||||||
|                 { |                     foreach (string email in RecepientEmail) { | ||||||
|                     foreach(string email in RecepientEmail) |  | ||||||
|                     { |  | ||||||
|                         Subject += email + ";"; |                         Subject += email + ";"; | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     RecepientEmail.Clear(); |                     RecepientEmail.Clear(); | ||||||
|                     SendEmailWithAttachments(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? " TESTING ONLY -IGNORE : " + Subject : _subject), retVal, attachments); |                     SendEmailWithAttachments(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? " TESTING ONLY -IGNORE : " + Subject : _subject), retVal, attachments); | ||||||
|                 } |                 } else { | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
| #if (!DEBUG) | #if (!DEBUG) | ||||||
|                     SendEmailWithAttachments(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal, attachments);                     |                     SendEmailWithAttachments(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal, attachments);                     | ||||||
| #endif | #endif | ||||||
|                 } |                 } | ||||||
|             } |             } catch (Exception ex) { | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 throw ex; |                 throw ex; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return retVal; |             return retVal; | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///  |         ///  | ||||||
|         /// </summary> |         /// </summary> | ||||||
| @ -636,8 +512,7 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <param name="Subject"></param> |         /// <param name="Subject"></param> | ||||||
|         /// <param name="Args"></param> |         /// <param name="Args"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public string SendNotificationEmail(string EmailTemplateFile, string SenderEmail, string SenderName, List<string> RecepientEmail, string CC, string Subject, params string[] Args) |         public string SendNotificationEmail(string EmailTemplateFile, string SenderEmail, string SenderName, List<string> RecepientEmail, string CC, string Subject, params string[] Args) { | ||||||
|         { |  | ||||||
|             string retVal = null; |             string retVal = null; | ||||||
|  |  | ||||||
|             //reading the file |             //reading the file | ||||||
| @ -648,33 +523,24 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             //setting formatting the string |             //setting formatting the string | ||||||
|             retVal = string.Format(emailBody, Args); |             retVal = string.Format(emailBody, Args); | ||||||
|  |  | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 //check if we are in debug mode or not. to send email |                 //check if we are in debug mode or not. to send email | ||||||
|                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") |                 if (GlobalVars.DBConnection.ToUpper() == "TEST" || GlobalVars.DBConnection.ToUpper() == "QUALITY") { | ||||||
|                 { |                     foreach (string email in RecepientEmail) { | ||||||
|                     foreach (string email in RecepientEmail) |  | ||||||
|                     { |  | ||||||
|                         Subject += email + ";"; |                         Subject += email + ";"; | ||||||
|                     } |                     } | ||||||
|                     RecepientEmail.Clear(); |                     RecepientEmail.Clear(); | ||||||
|                     SendEmail(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal); |                     SendEmail(SenderEmail, SenderName, GetTestRecipientsList(), CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal); | ||||||
|                 } |                 } else { | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
| #if (!DEBUG) | #if (!DEBUG) | ||||||
|                         SendEmail(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal); |                         SendEmail(SenderEmail, SenderName, RecepientEmail, CC, (!string.IsNullOrEmpty(Subject) ? Subject : _subject), retVal); | ||||||
| #endif | #endif | ||||||
|                 } |                 } | ||||||
|             } |             } catch (Exception ex) { | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 throw ex; |                 throw ex; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return retVal; |             return retVal; | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
| @ -683,10 +549,8 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <param name="subject"></param> |         /// <param name="subject"></param> | ||||||
|         /// <param name="body"></param> |         /// <param name="body"></param> | ||||||
|         /// <param name="importance"></param> |         /// <param name="importance"></param> | ||||||
|         public void SendNotificationEmailToAdmin(string subject, string body, MailPriority importance) |         public void SendNotificationEmailToAdmin(string subject, string body, MailPriority importance) { | ||||||
|         { |             try { | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 System.Configuration.ConfigurationManager.RefreshSection("appSettings"); |                 System.Configuration.ConfigurationManager.RefreshSection("appSettings"); | ||||||
|  |  | ||||||
|                 SmtpClient client = new SmtpClient(ConfigurationManager.AppSettings["SMTP Server"]); |                 SmtpClient client = new SmtpClient(ConfigurationManager.AppSettings["SMTP Server"]); | ||||||
| @ -704,30 +568,23 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|                 msg.Subject = subject; |                 msg.Subject = subject; | ||||||
|                 msg.Body = temp; |                 msg.Body = temp; | ||||||
|                 msg.Priority = importance; |                 msg.Priority = importance; | ||||||
| //#if(!DEBUG) |                 //#if(!DEBUG) | ||||||
|                 client.Send(msg); |                 client.Send(msg); | ||||||
| //#endif |                 //#endif | ||||||
|             } |             } catch (Exception ex) { | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 throw ex; |                 throw ex; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public List<string> GetTestRecipientsList() |         public List<string> GetTestRecipientsList() { | ||||||
|         { |             List<string> r = new List<string>(); | ||||||
|             var r = new List<string>(); |             try { | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 string emails = ConfigurationManager.AppSettings["Test Email Recipients"]; |                 string emails = ConfigurationManager.AppSettings["Test Email Recipients"]; | ||||||
|                 foreach (string s in emails.Split(';', ',')) |                 foreach (string s in emails.Split(';', ',')) { | ||||||
|                 { |  | ||||||
|                     if (!String.IsNullOrWhiteSpace(s)) |                     if (!String.IsNullOrWhiteSpace(s)) | ||||||
|                         r.Add(s); |                         r.Add(s); | ||||||
|                 } |                 } | ||||||
|             } |             } catch { | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|                 r.Add("dhuang2@infineon.com"); |                 r.Add("dhuang2@infineon.com"); | ||||||
|             } |             } | ||||||
|             return r; |             return r; | ||||||
|  | |||||||
| @ -10,57 +10,44 @@ using System.Net.Mail; | |||||||
| using System.DirectoryServices; | using System.DirectoryServices; | ||||||
| using System.DirectoryServices.AccountManagement; | using System.DirectoryServices.AccountManagement; | ||||||
|  |  | ||||||
| namespace Fab2ApprovalSystem.Misc | namespace Fab2ApprovalSystem.Misc { | ||||||
| { |     public static class Functions { | ||||||
|     public static class Functions |  | ||||||
|     { |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// Writes to the Application Event Log and sends an email notification if appropriate |         /// Writes to the Application Event Log and sends an email notification if appropriate | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="logtext"></param> |         /// <param name="logtext"></param> | ||||||
|         /// <param name="eventType"></param> |         /// <param name="eventType"></param> | ||||||
|         public static void WriteEvent(string logtext, System.Diagnostics.EventLogEntryType eventType) |         public static void WriteEvent(string logtext, System.Diagnostics.EventLogEntryType eventType) { | ||||||
|         { |  | ||||||
|             //#if(!DEBUG) |             //#if(!DEBUG) | ||||||
|             EmailNotification en = new EmailNotification(); |             EmailNotification en = new EmailNotification(); | ||||||
|             EventLog ev = new EventLog("Application"); |             EventLog ev = new EventLog("Application"); | ||||||
|             ev.Source = "Fab Approval System"; |             ev.Source = "Fab Approval System"; | ||||||
|  |  | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 //Write to the Event Log |                 //Write to the Event Log | ||||||
|                 ev.WriteEntry(logtext, eventType); |                 ev.WriteEntry(logtext, eventType); | ||||||
|  |  | ||||||
|                 ////Send an email notification if appropriate |                 ////Send an email notification if appropriate | ||||||
|                 ////Don't attempt to send an email if the error is pertaining to an email problem |                 ////Don't attempt to send an email if the error is pertaining to an email problem | ||||||
|                 if (!logtext.Contains("SendEmailNotification()")) |                 if (!logtext.Contains("SendEmailNotification()")) { | ||||||
|                 { |  | ||||||
|                     //Only send email notifications for Error and Warning level events |                     //Only send email notifications for Error and Warning level events | ||||||
|                     if (eventType == System.Diagnostics.EventLogEntryType.Error) |                     if (eventType == System.Diagnostics.EventLogEntryType.Error) | ||||||
|                         en.SendNotificationEmailToAdmin(ev.Source + " - Error Notification", logtext, MailPriority.High); |                         en.SendNotificationEmailToAdmin(ev.Source + " - Error Notification", logtext, MailPriority.High); | ||||||
|                     //else if (eventType == System.Diagnostics.EventLogEntryType.Warning) |                     //else if (eventType == System.Diagnostics.EventLogEntryType.Warning) | ||||||
|                     //    SendEmailNotification(ErrorRecipient(), ev.Source + " Warning Event Logged", logtext, NORMAL_PRI); |                     //    SendEmailNotification(ErrorRecipient(), ev.Source + " Warning Event Logged", logtext, NORMAL_PRI); | ||||||
|                 } |                 } | ||||||
|             } |             } catch { | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|                 //throw; |                 //throw; | ||||||
|             } |             } finally { | ||||||
|             finally |  | ||||||
|             { |  | ||||||
|                 ev = null; |                 ev = null; | ||||||
|             } |             } | ||||||
|             //#endif |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// Returns the FTP Server Name |         /// Returns the FTP Server Name | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public static string FTPServer() |         public static string FTPServer() { | ||||||
|         { |  | ||||||
|             ConfigurationManager.RefreshSection("appSettings"); |             ConfigurationManager.RefreshSection("appSettings"); | ||||||
|             return ConfigurationManager.AppSettings["FTP Server"]; |             return ConfigurationManager.AppSettings["FTP Server"]; | ||||||
|         } |         } | ||||||
| @ -69,8 +56,7 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// Returns the FTP User Name |         /// Returns the FTP User Name | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public static string FTPUser() |         public static string FTPUser() { | ||||||
|         { |  | ||||||
|             ConfigurationManager.RefreshSection("appSettings"); |             ConfigurationManager.RefreshSection("appSettings"); | ||||||
|             return ConfigurationManager.AppSettings["FTP User"]; |             return ConfigurationManager.AppSettings["FTP User"]; | ||||||
|         } |         } | ||||||
| @ -79,8 +65,7 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// Returns the FTP Password |         /// Returns the FTP Password | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public static string FTPPassword() |         public static string FTPPassword() { | ||||||
|         { |  | ||||||
|             ConfigurationManager.RefreshSection("appSettings"); |             ConfigurationManager.RefreshSection("appSettings"); | ||||||
|             return ConfigurationManager.AppSettings["FTP Password"]; |             return ConfigurationManager.AppSettings["FTP Password"]; | ||||||
|         } |         } | ||||||
| @ -89,41 +74,32 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         ///  |         ///  | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public static string GetAttachmentFolder() |         public static string GetAttachmentFolder() { | ||||||
|         { |  | ||||||
|             ConfigurationManager.RefreshSection("appSettings"); |             ConfigurationManager.RefreshSection("appSettings"); | ||||||
|             return ConfigurationManager.AppSettings["AttachmentFolder"]; |             return ConfigurationManager.AppSettings["AttachmentFolder"]; | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         ///  |         ///  | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="oldECNNumber"></param> |         /// <param name="oldECNNumber"></param> | ||||||
|         /// <param name="newECNNumber"></param> |         /// <param name="newECNNumber"></param> | ||||||
|         public static void CopyAttachments(int oldECNNumber, int newECNNumber) |         public static void CopyAttachments(int oldECNNumber, int newECNNumber) { | ||||||
|         { |  | ||||||
|             // The Name of the Upload component is "files" |             // The Name of the Upload component is "files" | ||||||
|             string oldFolderPath = Functions.GetAttachmentFolder() + "ECN\\" + oldECNNumber.ToString(); |             string oldFolderPath = Functions.GetAttachmentFolder() + "ECN\\" + oldECNNumber.ToString(); | ||||||
|             string newFolderPath  = Functions.GetAttachmentFolder() + "ECN\\" + newECNNumber.ToString() ; |             string newFolderPath = Functions.GetAttachmentFolder() + "ECN\\" + newECNNumber.ToString(); | ||||||
|  |  | ||||||
|             DirectoryInfo newdi = new DirectoryInfo(newFolderPath); |             DirectoryInfo newdi = new DirectoryInfo(newFolderPath); | ||||||
|                      |  | ||||||
|             if (!newdi.Exists) |             if (!newdi.Exists) | ||||||
|                 newdi.Create(); |                 newdi.Create(); | ||||||
|  |  | ||||||
|  |             FileInfo[] existingFiles = new DirectoryInfo(oldFolderPath).GetFiles(); | ||||||
|             FileInfo[] existingFiles = new DirectoryInfo(oldFolderPath ).GetFiles(); |             foreach (FileInfo file in existingFiles) { | ||||||
|             foreach (FileInfo file in existingFiles) |                 if (!file.Name.Contains("ECNApprovalLog_" + oldECNNumber.ToString()) && !file.Name.Contains("ECNForm_" + oldECNNumber.ToString())) | ||||||
|                 { |  | ||||||
|                     if (!file.Name.Contains("ECNApprovalLog_" + oldECNNumber.ToString()) && !file.Name.Contains("ECNForm_" + oldECNNumber.ToString())) |  | ||||||
|                     //var fileName = Path.GetFileName(file.FullName); |                     //var fileName = Path.GetFileName(file.FullName); | ||||||
|                     file.CopyTo(Path.Combine(newFolderPath, file.Name)); |                     file.CopyTo(Path.Combine(newFolderPath, file.Name)); | ||||||
|  |             } | ||||||
|                 } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
| @ -132,13 +108,11 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <param name="userID"></param> |         /// <param name="userID"></param> | ||||||
|         /// <param name="pwd"></param> |         /// <param name="pwd"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public static bool NA_ADAuthenticate(string userID, string pwd) |         public static bool NA_ADAuthenticate(string userID, string pwd) { | ||||||
|         { |  | ||||||
|  |  | ||||||
|             string naContainer = ConfigurationManager.AppSettings["NAContainer"]; |             string naContainer = ConfigurationManager.AppSettings["NAContainer"]; | ||||||
|             string naDomain = ConfigurationManager.AppSettings["NADomain"]; |             string naDomain = ConfigurationManager.AppSettings["NADomain"]; | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 PrincipalContext contextUser = new PrincipalContext(ContextType.Domain, |                 PrincipalContext contextUser = new PrincipalContext(ContextType.Domain, | ||||||
|                                            naDomain, |                                            naDomain, | ||||||
|                                             naContainer, |                                             naContainer, | ||||||
| @ -149,12 +123,9 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|                     return false; |                     return false; | ||||||
|                 else |                 else | ||||||
|                     return true; |                     return true; | ||||||
|             } |             } catch { | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
|          |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
| @ -163,13 +134,11 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// <param name="userID"></param> |         /// <param name="userID"></param> | ||||||
|         /// <param name="pwd"></param> |         /// <param name="pwd"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public static bool IFX_ADAuthenticate(string userID, string pwd) |         public static bool IFX_ADAuthenticate(string userID, string pwd) { | ||||||
|         { |  | ||||||
|  |  | ||||||
|             string container = ConfigurationManager.AppSettings["IFXContainer"]; |             string container = ConfigurationManager.AppSettings["IFXContainer"]; | ||||||
|             string domain = ConfigurationManager.AppSettings["IFXDomain"]; |             string domain = ConfigurationManager.AppSettings["IFXDomain"]; | ||||||
|             try |             try { | ||||||
|             { |  | ||||||
|                 PrincipalContext contextUser = new PrincipalContext(ContextType.Domain, |                 PrincipalContext contextUser = new PrincipalContext(ContextType.Domain, | ||||||
|                                            domain, |                                            domain, | ||||||
|                                             container, |                                             container, | ||||||
| @ -180,18 +149,12 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|                     return false; |                     return false; | ||||||
|                 else |                 else | ||||||
|                     return true; |                     return true; | ||||||
|             } |             } catch { | ||||||
|             catch |  | ||||||
|             { |  | ||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         |         public static string FTPSPNBatch() { | ||||||
|  |  | ||||||
|         public static string FTPSPNBatch() |  | ||||||
|         { |  | ||||||
|             ConfigurationManager.RefreshSection("appSettings"); |             ConfigurationManager.RefreshSection("appSettings"); | ||||||
|             return ConfigurationManager.AppSettings["FTPSPNBatchFileName"]; |             return ConfigurationManager.AppSettings["FTPSPNBatchFileName"]; | ||||||
|         } |         } | ||||||
| @ -200,8 +163,7 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         ///  |         ///  | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public static string FTPSPNBatch_Test() |         public static string FTPSPNBatch_Test() { | ||||||
|         { |  | ||||||
|             ConfigurationManager.RefreshSection("appSettings"); |             ConfigurationManager.RefreshSection("appSettings"); | ||||||
|             return ConfigurationManager.AppSettings["FTPSPNBatchFileName_Test"]; |             return ConfigurationManager.AppSettings["FTPSPNBatchFileName_Test"]; | ||||||
|         } |         } | ||||||
| @ -211,50 +173,44 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="casection"></param> |         /// <param name="casection"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public static string CASectionMapper(GlobalVars.CASection casection) |         public static string CASectionMapper(GlobalVars.CASection casection) { | ||||||
|         { |             switch (casection) { | ||||||
|             switch (casection) |  | ||||||
|             { |  | ||||||
|                 case GlobalVars.CASection.Main: |                 case GlobalVars.CASection.Main: | ||||||
|                     return "Main"; |                     return "Main"; | ||||||
|  |  | ||||||
|                 case GlobalVars.CASection.D1: |                 case GlobalVars.CASection.D1: | ||||||
|                     return "D1"; |                     return "D1"; | ||||||
|                      |  | ||||||
|                 case GlobalVars.CASection.D2: |                 case GlobalVars.CASection.D2: | ||||||
|                     return "D2"; |                     return "D2"; | ||||||
|                      |  | ||||||
|                 case GlobalVars.CASection.D3: |                 case GlobalVars.CASection.D3: | ||||||
|                     return "D3"; |                     return "D3"; | ||||||
|                      |  | ||||||
|                 case GlobalVars.CASection.D4: |                 case GlobalVars.CASection.D4: | ||||||
|                     return "D4"; |                     return "D4"; | ||||||
|                      |  | ||||||
|                 case GlobalVars.CASection.D5: |                 case GlobalVars.CASection.D5: | ||||||
|                     return "D5"; |                     return "D5"; | ||||||
|                      |  | ||||||
|                 case GlobalVars.CASection.D6: |                 case GlobalVars.CASection.D6: | ||||||
|                     return "D6"; |                     return "D6"; | ||||||
|                      |  | ||||||
|                 case GlobalVars.CASection.D7: |                 case GlobalVars.CASection.D7: | ||||||
|                     return "D7"; |                     return "D7"; | ||||||
|                      |  | ||||||
|                 case GlobalVars.CASection.D8: |                 case GlobalVars.CASection.D8: | ||||||
|                     return "D8"; |                     return "D8"; | ||||||
|                 case GlobalVars.CASection.CF: // CA Findings  |                 case GlobalVars.CASection.CF: // CA Findings  | ||||||
|                     return "CF"; |                     return "CF"; | ||||||
|                      |  | ||||||
|  |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return ""; |             return ""; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public static string DocumentTypeMapper(GlobalVars.DocumentType docType) |         public static string DocumentTypeMapper(GlobalVars.DocumentType docType) { | ||||||
|         { |             switch (docType) { | ||||||
|             switch (docType) |                 case GlobalVars.DocumentType.Audit: | ||||||
|             { |  | ||||||
|                 case GlobalVars.DocumentType.Audit:                |  | ||||||
|                     return "Audit"; |                     return "Audit"; | ||||||
|                 case GlobalVars.DocumentType.ChangeControl: |                 case GlobalVars.DocumentType.ChangeControl: | ||||||
|                     return "ChangeControl"; |                     return "ChangeControl"; | ||||||
| @ -280,17 +236,15 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|         /// </summary> |         /// </summary> | ||||||
|         /// <param name="caNo"></param> |         /// <param name="caNo"></param> | ||||||
|         /// <returns></returns> |         /// <returns></returns> | ||||||
|         public static string ReturnCANoStringFormat(int caNo) |         public static string ReturnCANoStringFormat(int caNo) { | ||||||
|         { |  | ||||||
|             string caNoString = ""; |             string caNoString = ""; | ||||||
|             if(caNo == 0) |             if (caNo == 0) | ||||||
|                 return ""; |                 return ""; | ||||||
|             caNoString = "C" + caNo.ToString().PadLeft(5, '0'); |             caNoString = "C" + caNo.ToString().PadLeft(5, '0'); | ||||||
|             return caNoString; |             return caNoString; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public static string ReturnAuditNoStringFormat(int auditNo) |         public static string ReturnAuditNoStringFormat(int auditNo) { | ||||||
|         { |  | ||||||
|             string auditNoString = ""; |             string auditNoString = ""; | ||||||
|             if (auditNo == 0) |             if (auditNo == 0) | ||||||
|                 return ""; |                 return ""; | ||||||
| @ -298,12 +252,10 @@ namespace Fab2ApprovalSystem.Misc | |||||||
|             return auditNoString; |             return auditNoString; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public static string ReturnPartsRequestNoStringFormat(int PRNumber) |         public static string ReturnPartsRequestNoStringFormat(int PRNumber) { | ||||||
|         { |  | ||||||
|             if (PRNumber == 0) |             if (PRNumber == 0) | ||||||
|                 return ""; |                 return ""; | ||||||
|             return String.Format("PR{0:000000}", PRNumber); |             return String.Format("PR{0:000000}", PRNumber); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										7
									
								
								Fab2ApprovalSystem/Models/AuthAttempt.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Fab2ApprovalSystem/Models/AuthAttempt.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | |||||||
|  | namespace Fab2ApprovalSystem.Models { | ||||||
|  |     public class AuthAttempt { | ||||||
|  |         public string LoginID { get; set; } | ||||||
|  |         public string Password { get; set; } = ""; | ||||||
|  |         public AuthTokens AuthTokens { get; set; } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								Fab2ApprovalSystem/Models/AuthTokens.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Fab2ApprovalSystem/Models/AuthTokens.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | namespace Fab2ApprovalSystem.Models { | ||||||
|  |     public class AuthTokens { | ||||||
|  |         public string JwtToken { get; set; } | ||||||
|  |         public string RefreshToken { get; set; } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								Fab2ApprovalSystem/Models/LoginResult.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Fab2ApprovalSystem/Models/LoginResult.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | namespace Fab2ApprovalSystem.Models { | ||||||
|  |     public class LoginResult { | ||||||
|  |         public bool IsAuthenticated { get; set; } | ||||||
|  |         public AuthTokens AuthTokens { get; set; } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -14,6 +14,6 @@ namespace Fab2ApprovalSystem.ViewModels | |||||||
|         public string Originator { get; set; } |         public string Originator { get; set; } | ||||||
|         public DateTime? AssignedDate { get; set; } |         public DateTime? AssignedDate { get; set; } | ||||||
|         public DateTime? DueDate { get; set; } |         public DateTime? DueDate { get; set; } | ||||||
|         public string pcrMesaID { get; set; } |         public string pcrMesaID { get; set; } = string.Empty; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -227,7 +227,7 @@ | |||||||
|                             ) |                             ) | ||||||
|                         </div> |                         </div> | ||||||
|                         <div class="col-sm-6 col-sm-offset-4" style="color:red;"> |                         <div class="col-sm-6 col-sm-offset-4" style="color:red;"> | ||||||
|                             ECN: Qualtiy and Dept. Specific<br />MRB: Quality, Production, Engineering, OPC<br />PCRB: Quality, Production, Engineering, Dept. Specific (scope of change) |                             ECN: Qualtiy and Dept. Specific<br />PCRB: Quality, Production, Engineering, Dept. Specific (scope of change) | ||||||
|                         </div> |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
|                     <div class="form-group"> |                     <div class="form-group"> | ||||||
|  | |||||||
| @ -171,7 +171,7 @@ | |||||||
|                             ) |                             ) | ||||||
|                         </div> |                         </div> | ||||||
|                         <div class="col-sm-6 col-sm-offset-4" style="color:red;"> |                         <div class="col-sm-6 col-sm-offset-4" style="color:red;"> | ||||||
|                             ECN: Qualtiy and Dept. Specific<br />MRB: Quality, Production, Engineering, OPC<br />PCRB: Quality, Production, Engineering, Dept. Specific (scope of change) |                             ECN: Qualtiy and Dept. Specific<br />PCRB: Quality, Production, Engineering, Dept. Specific (scope of change) | ||||||
|                         </div> |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
|                     <div class="form-group"> |                     <div class="form-group"> | ||||||
|  | |||||||
| @ -259,7 +259,7 @@ | |||||||
|                             ) |                             ) | ||||||
|                         </div> |                         </div> | ||||||
|                         <div class="col-sm-6 col-sm-offset-4" style="color:red;"> |                         <div class="col-sm-6 col-sm-offset-4" style="color:red;"> | ||||||
|                             ECN: Qualtiy and Dept. Specific<br />MRB: Quality, Production, Engineering, OPC<br />PCRB: Quality, Production, Engineering, Dept. Specific (scope of change) |                             ECN: Qualtiy and Dept. Specific<br />PCRB: Quality, Production, Engineering, Dept. Specific (scope of change) | ||||||
|                         </div> |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
|                     <div class="form-group"> |                     <div class="form-group"> | ||||||
|  | |||||||
| @ -83,14 +83,33 @@ | |||||||
|                         @*<li><a href=@Url.Action("Create", "LotDisposition")>Lot Dispostion</a></li>*@ |                         @*<li><a href=@Url.Action("Create", "LotDisposition")>Lot Dispostion</a></li>*@ | ||||||
|                         @*<li><a href=@Url.Action("Create", "MRB")>Create MRB</a></li>*@ |                         @*<li><a href=@Url.Action("Create", "MRB")>Create MRB</a></li>*@ | ||||||
|                         <li><a href=@Url.Action("Create", "ECN")>Create ECN/TECN</a></li> |                         <li><a href=@Url.Action("Create", "ECN")>Create ECN/TECN</a></li> | ||||||
|  |                         @if (!string.IsNullOrWhiteSpace(Session["JWT"].ToString())) { | ||||||
|  |                             string jwt = Session["JWT"].ToString(); | ||||||
|  |                             string encodedJwt = System.Net.WebUtility.UrlEncode(jwt); | ||||||
|  |                             string refreshToken = Session["RefreshToken"].ToString(); | ||||||
|  |                             string encodedRefreshToken = System.Net.WebUtility.UrlEncode(refreshToken); | ||||||
|  |                             string wasmClientUrl = Environment.GetEnvironmentVariable("FabApprovalWasmClientUrl") ?? | ||||||
|  |                                 "https://localhost:7255"; | ||||||
|  |                             string mrbUrl = wasmClientUrl + "/redirect?jwt=" + encodedJwt + "&refreshToken=" + encodedRefreshToken + "&redirectPath=/mrb/new"; | ||||||
|  |                             <li><a href="@mrbUrl">Create MRB</a></li> | ||||||
|  |                             @*string pcrbUrl = wasmClientUrl + "/redirect?jwt=" + encodedJwt + "&refreshToken=" + encodedRefreshToken + "&redirectPath=/pcrb/new"; | ||||||
|  |                             <li><a href="@pcrbUrl">Create PCRB</a></li>*@ | ||||||
|  |                         } else { | ||||||
|  |                             string wasmClientUrl = Environment.GetEnvironmentVariable("FabApprovalWasmClientUrl") ?? | ||||||
|  |                                                         "https://localhost:7255"; | ||||||
|  |                             string mrbUrl = wasmClientUrl + "/redirect?redirectPath=/mrb/new"; | ||||||
|  |                             <li><a href="@mrbUrl">Create MRB</a></li> | ||||||
|  |                             @*string pcrbUrl = wasmClientUrl + "/redirect?redirectPath=/pcrb/new"; | ||||||
|  |                             <li><a href="@pcrbUrl">Create PCRB</a></li>*@ | ||||||
|  |                         } | ||||||
|                         @*<li><a href=@Url.Action("CreateWorkRequest", "LotTraveler")>Create Special Work Request</a></li>*@ |                         @*<li><a href=@Url.Action("CreateWorkRequest", "LotTraveler")>Create Special Work Request</a></li>*@ | ||||||
|                         @*<li><a href=@Url.Action("Create", "ChangeControl")>Create PCR</a></li>*@ |                         @*<li><a href=@Url.Action("Create", "ChangeControl")>Create PCR</a></li>*@ | ||||||
|                         <li><a href=@Url.Action("Create", "Audit")>Create Audit</a></li> |                         <li><a href=@Url.Action("Create", "Audit")>Create Audit</a></li> | ||||||
|                         <li><a href=@Url.Action("Create", "CorrectiveAction")>Create Corrective Action</a></li> |                         <li><a href=@Url.Action("Create", "CorrectiveAction")>Create Corrective Action</a></li> | ||||||
|                         @*@if (Convert.ToBoolean(Session[GlobalVars.CAN_CREATE_PARTS_REQUEST])) |                         @*@if (Convert.ToBoolean(Session[GlobalVars.CAN_CREATE_PARTS_REQUEST])) | ||||||
|                         { |         { | ||||||
|                         <li><a href=@Url.Action("Create", "PartsRequest")>Create New/Repair Spare Parts Request</a></li> |         <li><a href=@Url.Action("Create", "PartsRequest")>Create New/Repair Spare Parts Request</a></li> | ||||||
|                         }*@ |         }*@ | ||||||
|                         @*<li><a href="#">Another Doc</a></li>*@ |                         @*<li><a href="#">Another Doc</a></li>*@ | ||||||
|                     </ul> |                     </ul> | ||||||
|                 </li> |                 </li> | ||||||
| @ -125,6 +144,16 @@ | |||||||
|             menu.Add().Text("My Training").Action("ViewMyTrainingAssignments", "Training"); |             menu.Add().Text("My Training").Action("ViewMyTrainingAssignments", "Training"); | ||||||
|             menu.Add().Text("Training Reports").Action("TrainingReports", "Training"); |             menu.Add().Text("Training Reports").Action("TrainingReports", "Training"); | ||||||
|             menu.Add().Text("All Documents").Action("AllDocuments", "Home"); |             menu.Add().Text("All Documents").Action("AllDocuments", "Home"); | ||||||
|  |             string jwt = Session["JWT"].ToString(); | ||||||
|  |             string encodedJwt = System.Net.WebUtility.UrlEncode(jwt); | ||||||
|  |             string refreshToken = Session["RefreshToken"].ToString(); | ||||||
|  |             string encodedRefreshToken = System.Net.WebUtility.UrlEncode(refreshToken); | ||||||
|  |             string wasmClientUrl = Environment.GetEnvironmentVariable("FabApprovalWasmClientUrl") ?? | ||||||
|  |                 "https://localhost:7255"; | ||||||
|  |             string mrbUrl = wasmClientUrl + "/redirect?jwt=" + encodedJwt + "&refreshToken=" + encodedRefreshToken + "&redirectPath=/mrb/all"; | ||||||
|  |             menu.Add().Text("MRB").Url(mrbUrl); | ||||||
|  |             //string pcrbUrl = wasmClientUrl + "/redirect?jwt=" + encodedJwt + "&refreshToken=" + encodedRefreshToken + "&redirectPath=/pcrb/all"; | ||||||
|  |             //menu.Add().Text("PCRB").Url(pcrbUrl); | ||||||
|             //menu.Add().Text("Special Work Requests").Action("SpecialWorkRequestList", "Home"); |             //menu.Add().Text("Special Work Requests").Action("SpecialWorkRequestList", "Home"); | ||||||
|             //menu.Add().Text("PCRB").Action("ChangeControlList", "Home"); |             //menu.Add().Text("PCRB").Action("ChangeControlList", "Home"); | ||||||
|             //menu.Add().Text("MRB").Action("MRBList", "Home"); |             //menu.Add().Text("MRB").Action("MRBList", "Home"); | ||||||
|  | |||||||
| @ -11,18 +11,6 @@ | |||||||
| <link rel="stylesheet" href="/Content/kendo/kendo.blueopal.min.css" /> | <link rel="stylesheet" href="/Content/kendo/kendo.blueopal.min.css" /> | ||||||
| <link rel="stylesheet" href="~/Content/kendogridcustom.css" /> | <link rel="stylesheet" href="~/Content/kendogridcustom.css" /> | ||||||
|  |  | ||||||
| @*<link rel="stylesheet" href="~/Scripts/jqwidgets/styles/jqx.base.css" type="text/css" /> |  | ||||||
|     <link rel="stylesheet" href="~/Scripts/jqwidgets/styles/jqx.energyblue.css" type="text/css" /> |  | ||||||
|     <link rel="stylesheet" href="~/Scripts/jqwidgets/styles/jqx.arctic.css" type="text/css" /> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     <script type="text/javascript" src="~/Scripts/jqwidgets/jqxcore.js"></script> |  | ||||||
|     <script type="text/javascript" src="~/Scripts/jqwidgets/jqxdata.js"></script> |  | ||||||
|     <script type="text/javascript" src="~/Scripts/jqwidgets/jqxbuttons.js"></script> |  | ||||||
|     <script type="text/javascript" src="~/Scripts/jqwidgets/jqxscrollbar.js"></script> |  | ||||||
|     <script type="text/javascript" src="~/Scripts/jqwidgets/jqxlistbox.js"></script> |  | ||||||
|     <script type="text/javascript" src="~/Scripts/jqwidgets/jqxpanel.js"></script> |  | ||||||
|     <script type="text/javascript" src="~/Scripts/jqwidgets/jqxtree.js"></script>*@ |  | ||||||
| <style> | <style> | ||||||
|     .k-grid .k-grid-header .k-header .k-link { |     .k-grid .k-grid-header .k-header .k-link { | ||||||
|         height: auto; |         height: auto; | ||||||
|  | |||||||
| @ -132,6 +132,11 @@ | |||||||
|         <requestLimits maxAllowedContentLength="1073741824" /> |         <requestLimits maxAllowedContentLength="1073741824" /> | ||||||
|       </requestFiltering> |       </requestFiltering> | ||||||
|     </security> |     </security> | ||||||
|  |       <httpProtocol> | ||||||
|  |           <customHeaders> | ||||||
|  |               <add name="Access-Control-Allow-Origin" value="*" /> | ||||||
|  |           </customHeaders> | ||||||
|  |       </httpProtocol> | ||||||
|   </system.webServer> |   </system.webServer> | ||||||
|   <runtime> |   <runtime> | ||||||
|     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> |     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								MesaFabApproval.API/.config/dotnet-tools.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								MesaFabApproval.API/.config/dotnet-tools.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | { | ||||||
|  |   "version": 1, | ||||||
|  |   "isRoot": true, | ||||||
|  |   "tools": { | ||||||
|  |     "dotnet-ef": { | ||||||
|  |       "version": "8.0.6", | ||||||
|  |       "commands": [ | ||||||
|  |         "dotnet-ef" | ||||||
|  |       ], | ||||||
|  |       "rollForward": false | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										260
									
								
								MesaFabApproval.API/.editorconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								MesaFabApproval.API/.editorconfig
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,260 @@ | |||||||
|  | # Remove the line below if you want to inherit .editorconfig settings from higher directories | ||||||
|  | root = true | ||||||
|  |  | ||||||
|  | # C# files | ||||||
|  | [*.cs] | ||||||
|  |  | ||||||
|  | #### Core EditorConfig Options #### | ||||||
|  |  | ||||||
|  | # Indentation and spacing | ||||||
|  | indent_size = 4 | ||||||
|  | indent_style = space | ||||||
|  | tab_width = 4 | ||||||
|  |  | ||||||
|  | # New line preferences | ||||||
|  | end_of_line = crlf | ||||||
|  | insert_final_newline = false | ||||||
|  |  | ||||||
|  | #### .NET Coding Conventions #### | ||||||
|  |  | ||||||
|  | # Organize usings | ||||||
|  | dotnet_separate_import_directive_groups = true | ||||||
|  | dotnet_sort_system_directives_first = true | ||||||
|  | file_header_template = unset | ||||||
|  |  | ||||||
|  | # this. and Me. preferences | ||||||
|  | dotnet_style_qualification_for_event = true | ||||||
|  | dotnet_style_qualification_for_field = true | ||||||
|  | dotnet_style_qualification_for_method = true | ||||||
|  | dotnet_style_qualification_for_property = true | ||||||
|  |  | ||||||
|  | # Language keywords vs BCL types preferences | ||||||
|  | dotnet_style_predefined_type_for_locals_parameters_members = true | ||||||
|  | dotnet_style_predefined_type_for_member_access = true | ||||||
|  |  | ||||||
|  | # Parentheses preferences | ||||||
|  | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:error | ||||||
|  | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:error | ||||||
|  | dotnet_style_parentheses_in_other_operators = never_if_unnecessary | ||||||
|  | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:error | ||||||
|  |  | ||||||
|  | # Modifier preferences | ||||||
|  | dotnet_style_require_accessibility_modifiers = for_non_interface_members | ||||||
|  |  | ||||||
|  | # Expression-level preferences | ||||||
|  | dotnet_style_coalesce_expression = false | ||||||
|  | dotnet_style_collection_initializer = true | ||||||
|  | dotnet_style_explicit_tuple_names = true:error | ||||||
|  | dotnet_style_namespace_match_folder = true | ||||||
|  | dotnet_style_null_propagation = true | ||||||
|  | dotnet_style_object_initializer = true | ||||||
|  | dotnet_style_operator_placement_when_wrapping = beginning_of_line | ||||||
|  | dotnet_style_prefer_auto_properties = true | ||||||
|  | dotnet_style_prefer_compound_assignment = true | ||||||
|  | dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion | ||||||
|  | dotnet_style_prefer_conditional_expression_over_return = true:suggestion | ||||||
|  | dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed | ||||||
|  | dotnet_style_prefer_inferred_anonymous_type_member_names = false | ||||||
|  | dotnet_style_prefer_inferred_tuple_names = false | ||||||
|  | dotnet_style_prefer_is_null_check_over_reference_equality_method = true | ||||||
|  | dotnet_style_prefer_simplified_boolean_expressions = true | ||||||
|  | dotnet_style_prefer_simplified_interpolation = true | ||||||
|  |  | ||||||
|  | # Field preferences | ||||||
|  | dotnet_style_readonly_field = true:warning | ||||||
|  |  | ||||||
|  | # Parameter preferences | ||||||
|  | dotnet_code_quality_unused_parameters = all:error | ||||||
|  |  | ||||||
|  | # Suppression preferences | ||||||
|  | dotnet_remove_unnecessary_suppression_exclusions = none | ||||||
|  |  | ||||||
|  | # New line preferences | ||||||
|  | dotnet_style_allow_multiple_blank_lines_experimental = false:error | ||||||
|  | dotnet_style_allow_statement_immediately_after_block_experimental = false:warning | ||||||
|  |  | ||||||
|  | #### C# Coding Conventions #### | ||||||
|  |  | ||||||
|  | # var preferences | ||||||
|  | csharp_style_var_elsewhere = false:error | ||||||
|  | csharp_style_var_for_built_in_types = false:error | ||||||
|  | csharp_style_var_when_type_is_apparent = false:error | ||||||
|  |  | ||||||
|  | # Expression-bodied members | ||||||
|  | csharp_style_expression_bodied_accessors = false | ||||||
|  | csharp_style_expression_bodied_constructors = false | ||||||
|  | csharp_style_expression_bodied_indexers = false | ||||||
|  | csharp_style_expression_bodied_lambdas = true | ||||||
|  | csharp_style_expression_bodied_local_functions = false | ||||||
|  | csharp_style_expression_bodied_methods = when_on_single_line:suggestion | ||||||
|  | csharp_style_expression_bodied_operators = false | ||||||
|  | csharp_style_expression_bodied_properties = false | ||||||
|  |  | ||||||
|  | # Pattern matching preferences | ||||||
|  | csharp_style_pattern_matching_over_as_with_null_check = false | ||||||
|  | csharp_style_pattern_matching_over_is_with_cast_check = false | ||||||
|  | csharp_style_prefer_extended_property_pattern = true | ||||||
|  | csharp_style_prefer_not_pattern = true | ||||||
|  | csharp_style_prefer_pattern_matching = true | ||||||
|  | csharp_style_prefer_switch_expression = false | ||||||
|  |  | ||||||
|  | # Null-checking preferences | ||||||
|  | csharp_style_conditional_delegate_call = false | ||||||
|  |  | ||||||
|  | # Modifier preferences | ||||||
|  | csharp_prefer_static_local_function = false | ||||||
|  | csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async | ||||||
|  | csharp_style_prefer_readonly_struct = true:warning | ||||||
|  | csharp_style_prefer_readonly_struct_member = true | ||||||
|  |  | ||||||
|  | # Code-block preferences | ||||||
|  | csharp_prefer_braces = when_multiline:error | ||||||
|  | csharp_prefer_simple_using_statement = false | ||||||
|  | csharp_style_namespace_declarations = file_scoped:error | ||||||
|  | csharp_style_prefer_method_group_conversion = true:suggestion | ||||||
|  | csharp_style_prefer_top_level_statements = true:error | ||||||
|  |  | ||||||
|  | # Expression-level preferences | ||||||
|  | csharp_prefer_simple_default_expression = true | ||||||
|  | csharp_style_deconstructed_variable_declaration = false | ||||||
|  | csharp_style_implicit_object_creation_when_type_is_apparent = false | ||||||
|  | csharp_style_inlined_variable_declaration = true | ||||||
|  | csharp_style_prefer_index_operator = false:error | ||||||
|  | csharp_style_prefer_local_over_anonymous_function = true:error | ||||||
|  | csharp_style_prefer_null_check_over_type_check = true | ||||||
|  | csharp_style_prefer_range_operator = false:error | ||||||
|  | csharp_style_prefer_tuple_swap = true | ||||||
|  | csharp_style_prefer_utf8_string_literals = true | ||||||
|  | csharp_style_throw_expression = false | ||||||
|  | csharp_style_unused_value_assignment_preference = unused_local_variable | ||||||
|  | csharp_style_unused_value_expression_statement_preference = unused_local_variable | ||||||
|  |  | ||||||
|  | # 'using' directive preferences | ||||||
|  | csharp_using_directive_placement = outside_namespace:error | ||||||
|  |  | ||||||
|  | # New line preferences | ||||||
|  | csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true | ||||||
|  | csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true | ||||||
|  | csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true | ||||||
|  | csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:error | ||||||
|  | csharp_style_allow_embedded_statements_on_same_line_experimental = true | ||||||
|  |  | ||||||
|  | #### C# Formatting Rules #### | ||||||
|  |  | ||||||
|  | # New line preferences | ||||||
|  | csharp_new_line_before_catch = false | ||||||
|  | csharp_new_line_before_else = false | ||||||
|  | csharp_new_line_before_finally = false | ||||||
|  | csharp_new_line_before_members_in_anonymous_types = true | ||||||
|  | csharp_new_line_before_members_in_object_initializers = true | ||||||
|  | csharp_new_line_before_open_brace = none | ||||||
|  | csharp_new_line_between_query_expression_clauses = true | ||||||
|  |  | ||||||
|  | # Indentation preferences | ||||||
|  | csharp_indent_block_contents = true | ||||||
|  | csharp_indent_braces = false | ||||||
|  | csharp_indent_case_contents = true | ||||||
|  | csharp_indent_case_contents_when_block = true | ||||||
|  | csharp_indent_labels = one_less_than_current | ||||||
|  | csharp_indent_switch_labels = true | ||||||
|  |  | ||||||
|  | # Space preferences | ||||||
|  | csharp_space_after_cast = false | ||||||
|  | csharp_space_after_colon_in_inheritance_clause = true | ||||||
|  | csharp_space_after_comma = true | ||||||
|  | csharp_space_after_dot = false | ||||||
|  | csharp_space_after_keywords_in_control_flow_statements = true | ||||||
|  | csharp_space_after_semicolon_in_for_statement = true | ||||||
|  | csharp_space_around_binary_operators = before_and_after | ||||||
|  | csharp_space_around_declaration_statements = false | ||||||
|  | csharp_space_before_colon_in_inheritance_clause = true | ||||||
|  | csharp_space_before_comma = false | ||||||
|  | csharp_space_before_dot = false | ||||||
|  | csharp_space_before_open_square_brackets = false | ||||||
|  | csharp_space_before_semicolon_in_for_statement = false | ||||||
|  | csharp_space_between_empty_square_brackets = false | ||||||
|  | csharp_space_between_method_call_empty_parameter_list_parentheses = false | ||||||
|  | csharp_space_between_method_call_name_and_opening_parenthesis = false | ||||||
|  | csharp_space_between_method_call_parameter_list_parentheses = false | ||||||
|  | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false | ||||||
|  | csharp_space_between_method_declaration_name_and_open_parenthesis = false | ||||||
|  | csharp_space_between_method_declaration_parameter_list_parentheses = false | ||||||
|  | csharp_space_between_parentheses = false | ||||||
|  | csharp_space_between_square_brackets = false | ||||||
|  |  | ||||||
|  | # Wrapping preferences | ||||||
|  | csharp_preserve_single_line_blocks = true | ||||||
|  | csharp_preserve_single_line_statements = true | ||||||
|  |  | ||||||
|  | #### Naming styles #### | ||||||
|  |  | ||||||
|  | # Naming rules | ||||||
|  |  | ||||||
|  | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion | ||||||
|  | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface | ||||||
|  | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i | ||||||
|  |  | ||||||
|  | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion | ||||||
|  | dotnet_naming_rule.types_should_be_pascal_case.symbols = types | ||||||
|  | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case | ||||||
|  |  | ||||||
|  | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion | ||||||
|  | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members | ||||||
|  | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case | ||||||
|  |  | ||||||
|  | # Symbol specifications | ||||||
|  |  | ||||||
|  | dotnet_naming_symbols.interface.applicable_kinds = interface | ||||||
|  | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected | ||||||
|  | dotnet_naming_symbols.interface.required_modifiers =  | ||||||
|  |  | ||||||
|  | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum | ||||||
|  | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected | ||||||
|  | dotnet_naming_symbols.types.required_modifiers =  | ||||||
|  |  | ||||||
|  | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method | ||||||
|  | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected | ||||||
|  | dotnet_naming_symbols.non_field_members.required_modifiers =  | ||||||
|  |  | ||||||
|  | # Naming styles | ||||||
|  |  | ||||||
|  | dotnet_naming_style.pascal_case.required_prefix =  | ||||||
|  | dotnet_naming_style.pascal_case.required_suffix =  | ||||||
|  | dotnet_naming_style.pascal_case.word_separator =  | ||||||
|  | dotnet_naming_style.pascal_case.capitalization = pascal_case | ||||||
|  |  | ||||||
|  | dotnet_naming_style.begins_with_i.required_prefix = I | ||||||
|  | dotnet_naming_style.begins_with_i.required_suffix =  | ||||||
|  | dotnet_naming_style.begins_with_i.word_separator =  | ||||||
|  | dotnet_naming_style.begins_with_i.capitalization = pascal_case | ||||||
|  |  | ||||||
|  | # Question | ||||||
|  |  | ||||||
|  | dotnet_diagnostic.ASP0025.severity = none # Use AddAuthorizationBuilder to register authorization services and construct policies [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.CA1510.severity = none # Use 'ArgumentNullException.ThrowIfNull' instead of explicitly throwing a new exception instance [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.CA1806.severity = none # 'MRBNumberIsValid' calls 'Append' but does not use the value the method returns. Linq methods are known to not have side effects. Use the result in a conditional statement, assign the result to a variable, or pass it as an argument to another method. [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.CA1822.severity = none # Member 'GenerateRefreshToken' does not access instance data and can be marked as static [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.CA1825.severity = none # Avoid unnecessary zero-length array allocations.  Use Array.Empty<string>() instead. [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.CA1827.severity = none # Count() is used where Any() could be used instead to improve performance [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.CA1829.severity = none # Use the \"Count\" property instead of Enumerable.Count() [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.CA1861.severity = none # Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.CA2208.severity = none # Method UpdateMRBAction passes 'MRB action cannot be null' as the paramName argument to a ArgumentNullException constructor. Replace this argument with one of the method's parameter names. Note that the provided parameter name should have the exact casing as declared on the method. [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.CA2254.severity = none # The type or namespace name 'AspNetCore' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?) [MesaFabApproval.Shared]", | ||||||
|  | dotnet_diagnostic.CS0234.severity = none # The type or namespace name 'Extensions' does not exist in the namespace 'Microsoft' (are you missing an assembly reference?) [MesaFabApproval.Shared]", | ||||||
|  | dotnet_diagnostic.CS0246.severity = none # The type or namespace name 'ILogger<>' could not be found (are you missing a using directive or an assembly reference?) [MesaFabApproval.Shared]", | ||||||
|  | dotnet_diagnostic.CS1998.severity = none # This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.CS8019.severity = none # Unnecessary using directive | ||||||
|  | dotnet_diagnostic.CS8600.severity = none # Converting null literal or possible null value to non-nullable type. [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.CS8625.severity = none # Cannot convert null literal to non-nullable reference type. [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.CS8765.severity = none # Nullability of type of parameter 'obj' doesn't match overridden member (possibly because of nullability attributes). [MesaFabApproval.Shared]", | ||||||
|  | dotnet_diagnostic.IDE0001.severity = none # Name can be simplified | ||||||
|  | dotnet_diagnostic.IDE0017.severity = none # Object initialization can be simplified [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.IDE0022.severity = none # Use expression body for method [MesaFabApproval.Shared]", | ||||||
|  | dotnet_diagnostic.IDE0028.severity = none # Collection initialization can be simplified [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.IDE0044.severity = none # Make field readonly [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.IDE0046.severity = none # "'if' statement can be simplified [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.IDE0052.severity = none # Private member 'CustomerController._cache' can be removed as the value assigned to it is never read [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.IDE0074.severity = none # Use compound assignment [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.IDE0290.severity = none # Use primary constructor [MesaFabApproval.API]", | ||||||
|  | dotnet_diagnostic.IDE0305.severity = none # Collection initialization can be simplified [MesaFabApproval.API]", | ||||||
|  | dotnet_style_prefer_conditional_expression_over_return = false | ||||||
							
								
								
									
										1
									
								
								MesaFabApproval.API/.vscode/format-report.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								MesaFabApproval.API/.vscode/format-report.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | [] | ||||||
							
								
								
									
										30
									
								
								MesaFabApproval.API/.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								MesaFabApproval.API/.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | { | ||||||
|  |     // Use IntelliSense to learn about possible attributes. | ||||||
|  |     // Hover to view descriptions of existing attributes. | ||||||
|  |     // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||||||
|  |     "version": "0.2.0", | ||||||
|  |     "configurations": [ | ||||||
|  |         { | ||||||
|  |             "name": ".NET Core Launch (console)", | ||||||
|  |             "type": "coreclr", | ||||||
|  |             "request": "launch", | ||||||
|  |             "preLaunchTask": "build", | ||||||
|  |             "program": "${workspaceFolder}/bin/Debug/net8.0/MesaFabApproval.API.dll", | ||||||
|  |             "args": [], | ||||||
|  |             "cwd": "${workspaceFolder}", | ||||||
|  |             "console": "integratedTerminal", | ||||||
|  |             "stopAtEntry": false | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "name": ".NET Core Attach", | ||||||
|  |             "type": "coreclr", | ||||||
|  |             "request": "attach" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "type": "node", | ||||||
|  |             "request": "launch", | ||||||
|  |             "name": "node Launch Current Opened File", | ||||||
|  |             "program": "${file}" | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								MesaFabApproval.API/.vscode/mklink.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								MesaFabApproval.API/.vscode/mklink.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | # mklink | ||||||
|  |  | ||||||
|  | ```bash 1731705389065 = 638673021890650000 = Fri Nov 15 2024 14:16:28 GMT-0700 (Mountain Standard Time) | ||||||
|  | mklink /J "L:\DevOps\Mesa_FI\MesaFabApproval\MesaFabApproval.API\.vscode\.UserSecrets" "C:\Users\phares\AppData\Roaming\Microsoft\UserSecrets\0b98e1f2-95ed-4edd-8149-58cce51ca059" | ||||||
|  | dotnet run --urls=https://localhost:7114/ -C Release | ||||||
|  | ``` | ||||||
							
								
								
									
										424
									
								
								MesaFabApproval.API/.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								MesaFabApproval.API/.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,424 @@ | |||||||
|  | { | ||||||
|  |   "[markdown]": { | ||||||
|  |     "editor.wordWrap": "off" | ||||||
|  |   }, | ||||||
|  |   "files.exclude": { | ||||||
|  |     "**/.git": false, | ||||||
|  |     "**/node_modules": true | ||||||
|  |   }, | ||||||
|  |   "files.watcherExclude": { | ||||||
|  |     "**/node_modules": true | ||||||
|  |   }, | ||||||
|  |   "cSpell.words": [ | ||||||
|  |     "abutton", | ||||||
|  |     "accessibilities", | ||||||
|  |     "accodingly", | ||||||
|  |     "acknowledgmentby", | ||||||
|  |     "Acks", | ||||||
|  |     "actionsheet", | ||||||
|  |     "Additonal", | ||||||
|  |     "Addtional", | ||||||
|  |     "againm", | ||||||
|  |     "agendaview", | ||||||
|  |     "Antlr", | ||||||
|  |     "Appover", | ||||||
|  |     "Appprrovers", | ||||||
|  |     "Approvalog", | ||||||
|  |     "Aprovers", | ||||||
|  |     "Aproverslist", | ||||||
|  |     "asax", | ||||||
|  |     "aspnetmvc", | ||||||
|  |     "Assignedto", | ||||||
|  |     "Atachments", | ||||||
|  |     "Attachemnt", | ||||||
|  |     "Attachemnts", | ||||||
|  |     "Attchment", | ||||||
|  |     "auditee", | ||||||
|  |     "Auditee", | ||||||
|  |     "Auditees", | ||||||
|  |     "automaically", | ||||||
|  |     "Autthorized", | ||||||
|  |     "beacuase", | ||||||
|  |     "beforeunload", | ||||||
|  |     "Belguim", | ||||||
|  |     "bfound", | ||||||
|  |     "bgcolor", | ||||||
|  |     "Bies", | ||||||
|  |     "binded", | ||||||
|  |     "blackbackground", | ||||||
|  |     "blackhover", | ||||||
|  |     "blackpressed", | ||||||
|  |     "blueenergy", | ||||||
|  |     "blueopal", | ||||||
|  |     "buttongroup", | ||||||
|  |     "BYMRB", | ||||||
|  |     "bytesgot", | ||||||
|  |     "CAID", | ||||||
|  |     "casection", | ||||||
|  |     "CAXXXX", | ||||||
|  |     "CCPCR", | ||||||
|  |     "CCPCRB", | ||||||
|  |     "cellspacing", | ||||||
|  |     "Cheeso's", | ||||||
|  |     "chkbx", | ||||||
|  |     "Clib", | ||||||
|  |     "colorpicker", | ||||||
|  |     "columnmenu", | ||||||
|  |     "columnsreorder", | ||||||
|  |     "columnsresize", | ||||||
|  |     "comming", | ||||||
|  |     "Containmen", | ||||||
|  |     "Copmments", | ||||||
|  |     "correctiv", | ||||||
|  |     "Correctivet", | ||||||
|  |     "Creat", | ||||||
|  |     "currentd", | ||||||
|  |     "Cyle", | ||||||
|  |     "dadada", | ||||||
|  |     "darkbluehover", | ||||||
|  |     "darkbluepressed", | ||||||
|  |     "darkred", | ||||||
|  |     "datafields", | ||||||
|  |     "datasource", | ||||||
|  |     "dataviz", | ||||||
|  |     "datepicker", | ||||||
|  |     "datetimepicker", | ||||||
|  |     "dayview", | ||||||
|  |     "Deletet", | ||||||
|  |     "Delgation", | ||||||
|  |     "DENITED", | ||||||
|  |     "Deparmtent", | ||||||
|  |     "departmentids", | ||||||
|  |     "Descirption", | ||||||
|  |     "devprog", | ||||||
|  |     "dfeffc", | ||||||
|  |     "Disp", | ||||||
|  |     "Dispo", | ||||||
|  |     "Dispoitio", | ||||||
|  |     "Dispos", | ||||||
|  |     "Dispositon", | ||||||
|  |     "Dispostion", | ||||||
|  |     "Dispostions", | ||||||
|  |     "dispotypevalidation", | ||||||
|  |     "Docbase", | ||||||
|  |     "Documentum", | ||||||
|  |     "Documetum", | ||||||
|  |     "dont", | ||||||
|  |     "downlaoded", | ||||||
|  |     "draganddrop", | ||||||
|  |     "dragcancel", | ||||||
|  |     "dropdownlist", | ||||||
|  |     "Eamils", | ||||||
|  |     "ECNPCRB", | ||||||
|  |     "Ecns", | ||||||
|  |     "edmx", | ||||||
|  |     "EECN", | ||||||
|  |     "emai", | ||||||
|  |     "emailparams", | ||||||
|  |     "Emergrncy", | ||||||
|  |     "energyblue", | ||||||
|  |     "Eran", | ||||||
|  |     "Esql", | ||||||
|  |     "ETECN", | ||||||
|  |     "EXCELOPENXML", | ||||||
|  |     "existinglocation", | ||||||
|  |     "Expando", | ||||||
|  |     "extrafield", | ||||||
|  |     "fadc", | ||||||
|  |     "fbec", | ||||||
|  |     "fcfdfd", | ||||||
|  |     "fdff", | ||||||
|  |     "fece", | ||||||
|  |     "feeebd", | ||||||
|  |     "ffdc", | ||||||
|  |     "ffdd", | ||||||
|  |     "fieldset", | ||||||
|  |     "FILIPE", | ||||||
|  |     "filtermenu", | ||||||
|  |     "Fldr", | ||||||
|  |     "flintstone", | ||||||
|  |     "FLOWLOCS", | ||||||
|  |     "FMEA", | ||||||
|  |     "ftplib", | ||||||
|  |     "FTPSPN", | ||||||
|  |     "GETDATE", | ||||||
|  |     "gitea", | ||||||
|  |     "globaldocudms", | ||||||
|  |     "glyphicons", | ||||||
|  |     "groupable", | ||||||
|  |     "Guids", | ||||||
|  |     "halflings", | ||||||
|  |     "Hexsize", | ||||||
|  |     "highcontrast", | ||||||
|  |     "Hmac", | ||||||
|  |     "holdsteps", | ||||||
|  |     "hostspecific", | ||||||
|  |     "icenium", | ||||||
|  |     "IECN", | ||||||
|  |     "imagebrowser", | ||||||
|  |     "IMRB", | ||||||
|  |     "Infineon", | ||||||
|  |     "Insertd", | ||||||
|  |     "inverseicons", | ||||||
|  |     "IPCRB", | ||||||
|  |     "ISADMIN", | ||||||
|  |     "islast", | ||||||
|  |     "ISNULL", | ||||||
|  |     "ITAR", | ||||||
|  |     "jquery", | ||||||
|  |     "jqueryval", | ||||||
|  |     "jqwidgets", | ||||||
|  |     "jqxbuttongroup", | ||||||
|  |     "jqxbuttons", | ||||||
|  |     "jqxcalendar", | ||||||
|  |     "jqxchart", | ||||||
|  |     "jqxcheckbox", | ||||||
|  |     "jqxcolorpicker", | ||||||
|  |     "jqxcombobox", | ||||||
|  |     "jqxcore", | ||||||
|  |     "jqxdata", | ||||||
|  |     "jqxdatatable", | ||||||
|  |     "jqxdatetimeinput", | ||||||
|  |     "jqxdocking", | ||||||
|  |     "jqxdockpanel", | ||||||
|  |     "jqxdragdrop", | ||||||
|  |     "jqxdropdownbutton", | ||||||
|  |     "jqxdropdownlist", | ||||||
|  |     "jqxexpander", | ||||||
|  |     "jqxgauge", | ||||||
|  |     "jqxgrid", | ||||||
|  |     "jqxinput", | ||||||
|  |     "jqxknockout", | ||||||
|  |     "jqxlistbox", | ||||||
|  |     "jqxlistmenu", | ||||||
|  |     "jqxmaskedinput", | ||||||
|  |     "jqxmenu", | ||||||
|  |     "jqxnavigationbar", | ||||||
|  |     "jqxnumberinput", | ||||||
|  |     "jqxpanel", | ||||||
|  |     "jqxpasswordinput", | ||||||
|  |     "jqxprogressbar", | ||||||
|  |     "jqxradiobutton", | ||||||
|  |     "jqxrangeselector", | ||||||
|  |     "jqxrating", | ||||||
|  |     "jqxresponse", | ||||||
|  |     "jqxscrollbar", | ||||||
|  |     "jqxscrollview", | ||||||
|  |     "jqxslider", | ||||||
|  |     "jqxsplitter", | ||||||
|  |     "jqxswitchbutton", | ||||||
|  |     "jqxtabs", | ||||||
|  |     "jqxtooltip", | ||||||
|  |     "jqxtouch", | ||||||
|  |     "jqxtree", | ||||||
|  |     "jqxtreegrid", | ||||||
|  |     "jqxtreemap", | ||||||
|  |     "jqxvalidator", | ||||||
|  |     "jqxwindow", | ||||||
|  |     "kendogridcustom", | ||||||
|  |     "kendoui", | ||||||
|  |     "labelelement", | ||||||
|  |     "labelledby", | ||||||
|  |     "Leanred", | ||||||
|  |     "lightgray", | ||||||
|  |     "linkbutton", | ||||||
|  |     "Linq", | ||||||
|  |     "Listdiv", | ||||||
|  |     "listview", | ||||||
|  |     "Lnks", | ||||||
|  |     "localfilename", | ||||||
|  |     "loclist", | ||||||
|  |     "logis", | ||||||
|  |     "logtext", | ||||||
|  |     "loopmis", | ||||||
|  |     "lotdispo", | ||||||
|  |     "LOTDISPSITION", | ||||||
|  |     "Lotfile", | ||||||
|  |     "lotlist", | ||||||
|  |     "lotstatusoption", | ||||||
|  |     "LTRIM", | ||||||
|  |     "MADUREIRA", | ||||||
|  |     "mailrelay", | ||||||
|  |     "MDTM", | ||||||
|  |     "meego", | ||||||
|  |     "meetingid", | ||||||
|  |     "menubutton", | ||||||
|  |     "mesafi", | ||||||
|  |     "metroblack", | ||||||
|  |     "metrodark", | ||||||
|  |     "miliseconds", | ||||||
|  |     "modalview", | ||||||
|  |     "modernizr", | ||||||
|  |     "Modernizr", | ||||||
|  |     "monthview", | ||||||
|  |     "MRBIs", | ||||||
|  |     "Mrbs", | ||||||
|  |     "msecs", | ||||||
|  |     "multipleextended", | ||||||
|  |     "Navigatable", | ||||||
|  |     "nbsp", | ||||||
|  |     "newbase", | ||||||
|  |     "newchange", | ||||||
|  |     "newdi", | ||||||
|  |     "newfilename", | ||||||
|  |     "newsource", | ||||||
|  |     "Newtonsoft", | ||||||
|  |     "notications", | ||||||
|  |     "Notifcation", | ||||||
|  |     "Notifyf", | ||||||
|  |     "NTLM", | ||||||
|  |     "Nullcc", | ||||||
|  |     "numerictextbox", | ||||||
|  |     "objdata", | ||||||
|  |     "OCAP", | ||||||
|  |     "occured", | ||||||
|  |     "odata", | ||||||
|  |     "oldfilename", | ||||||
|  |     "OLHOLD", | ||||||
|  |     "onclick", | ||||||
|  |     "onmousemove", | ||||||
|  |     "OPDESC", | ||||||
|  |     "OPENQUERY", | ||||||
|  |     "Oper", | ||||||
|  |     "operationslist", | ||||||
|  |     "Orginator", | ||||||
|  |     "Originatorname", | ||||||
|  |     "Ouellette", | ||||||
|  |     "Owin", | ||||||
|  |     "pageable", | ||||||
|  |     "Pageable", | ||||||
|  |     "panelbar", | ||||||
|  |     "parentid", | ||||||
|  |     "parminput", | ||||||
|  |     "parms", | ||||||
|  |     "Parms", | ||||||
|  |     "particula", | ||||||
|  |     "pasv", | ||||||
|  |     "PASV", | ||||||
|  |     "PATINDEX", | ||||||
|  |     "PCRB", | ||||||
|  |     "PCRBID", | ||||||
|  |     "pcrvalues", | ||||||
|  |     "pdbonly", | ||||||
|  |     "Preventitive", | ||||||
|  |     "preventivet", | ||||||
|  |     "Prevetative", | ||||||
|  |     "proces", | ||||||
|  |     "Processedl", | ||||||
|  |     "procs", | ||||||
|  |     "productfamilies", | ||||||
|  |     "progess", | ||||||
|  |     "progressbar", | ||||||
|  |     "qrcode", | ||||||
|  |     "Quanityt", | ||||||
|  |     "rangebar", | ||||||
|  |     "Recep", | ||||||
|  |     "Recepient", | ||||||
|  |     "recieved", | ||||||
|  |     "recordlock", | ||||||
|  |     "remotefilename", | ||||||
|  |     "reorderable", | ||||||
|  |     "reportform", | ||||||
|  |     "reportslist", | ||||||
|  |     "reportslistdiv", | ||||||
|  |     "Reqquired", | ||||||
|  |     "Reqs", | ||||||
|  |     "Requiest", | ||||||
|  |     "Responsibles", | ||||||
|  |     "RETR", | ||||||
|  |     "Revisioing", | ||||||
|  |     "Revisioned", | ||||||
|  |     "Revison", | ||||||
|  |     "rgba", | ||||||
|  |     "rkotian", | ||||||
|  |     "RNFR", | ||||||
|  |     "RNTO", | ||||||
|  |     "Roless", | ||||||
|  |     "roundbg", | ||||||
|  |     "RTRIM", | ||||||
|  |     "SAMDB", | ||||||
|  |     "scroller", | ||||||
|  |     "scrollview", | ||||||
|  |     "seleced", | ||||||
|  |     "selectionlog", | ||||||
|  |     "Selectpart", | ||||||
|  |     "sess", | ||||||
|  |     "Sfisharepoint", | ||||||
|  |     "shinyblack", | ||||||
|  |     "showpassword", | ||||||
|  |     "SIGNON", | ||||||
|  |     "simpleparser", | ||||||
|  |     "slddrw", | ||||||
|  |     "sldprt", | ||||||
|  |     "sortasc", | ||||||
|  |     "sortascbutton", | ||||||
|  |     "sortdesc", | ||||||
|  |     "sortdescbutton", | ||||||
|  |     "sortremove", | ||||||
|  |     "sparkline", | ||||||
|  |     "splitview", | ||||||
|  |     "SPNMRB", | ||||||
|  |     "SPNPDB", | ||||||
|  |     "SSRS", | ||||||
|  |     "Sssign", | ||||||
|  |     "Staus", | ||||||
|  |     "stylesheet", | ||||||
|  |     "Submited", | ||||||
|  |     "subrole", | ||||||
|  |     "subroles", | ||||||
|  |     "Succefully", | ||||||
|  |     "Succesfully", | ||||||
|  |     "sucessfully", | ||||||
|  |     "SURP", | ||||||
|  |     "Swashbuckle", | ||||||
|  |     "SWRN", | ||||||
|  |     "tabindex", | ||||||
|  |     "tabstrip", | ||||||
|  |     "Tahoma", | ||||||
|  |     "taskcompleted", | ||||||
|  |     "Tasklist", | ||||||
|  |     "Taveler", | ||||||
|  |     "TECN", | ||||||
|  |     "TECNs", | ||||||
|  |     "TEMIRWAP", | ||||||
|  |     "tempecd", | ||||||
|  |     "tempimplement", | ||||||
|  |     "templabel", | ||||||
|  |     "tempvalue", | ||||||
|  |     "TEMSA", | ||||||
|  |     "timepicker", | ||||||
|  |     "Tobe", | ||||||
|  |     "Toplevel", | ||||||
|  |     "Totrav", | ||||||
|  |     "trainingby", | ||||||
|  |     "Traininglist", | ||||||
|  |     "traininglistdiv", | ||||||
|  |     "transanction", | ||||||
|  |     "Trav", | ||||||
|  |     "Traveller", | ||||||
|  |     "Traverler", | ||||||
|  |     "TRAVLELER", | ||||||
|  |     "Travler", | ||||||
|  |     "TREEVIEW", | ||||||
|  |     "trigerred", | ||||||
|  |     "ttinclude", | ||||||
|  |     "Uhandled", | ||||||
|  |     "Updat", | ||||||
|  |     "Uplaod", | ||||||
|  |     "Upto", | ||||||
|  |     "userevents", | ||||||
|  |     "userids", | ||||||
|  |     "userlist", | ||||||
|  |     "Validatable", | ||||||
|  |     "valueelement", | ||||||
|  |     "Variabls", | ||||||
|  |     "Verdana", | ||||||
|  |     "vgrid", | ||||||
|  |     "viewmodel", | ||||||
|  |     "vsdoc", | ||||||
|  |     "whethere", | ||||||
|  |     "windowsphone", | ||||||
|  |     "Winsock", | ||||||
|  |     "worlflow" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										135
									
								
								MesaFabApproval.API/.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								MesaFabApproval.API/.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | |||||||
|  | { | ||||||
|  |     "version": "2.0.0", | ||||||
|  |     "tasks": [ | ||||||
|  |         { | ||||||
|  |             "label": "User Secrets Init", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "user-secrets", | ||||||
|  |                 "-p", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API.csproj", | ||||||
|  |                 "init" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "User Secrets Set", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "user-secrets", | ||||||
|  |                 "-p", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API.csproj", | ||||||
|  |                 "set", | ||||||
|  |                 "_UserSecretsId", | ||||||
|  |                 "0b98e1f2-95ed-4edd-8149-58cce51ca059" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Format", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "format", | ||||||
|  |                 "--report", | ||||||
|  |                 ".vscode", | ||||||
|  |                 "--verbosity", | ||||||
|  |                 "detailed", | ||||||
|  |                 "--severity", | ||||||
|  |                 "warn" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Format-Whitespaces", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "format", | ||||||
|  |                 "whitespace" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "build", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "build", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "testDebug", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "test", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "testRelease", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "test", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary", | ||||||
|  |                 "-c", | ||||||
|  |                 "Release" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "publish", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "publish", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "watch", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "watch", | ||||||
|  |                 "run", | ||||||
|  |                 "--project", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API.csproj" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Publish AOT", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "publish", | ||||||
|  |                 "-r", | ||||||
|  |                 "win-x64", | ||||||
|  |                 "-c", | ||||||
|  |                 "Release", | ||||||
|  |                 "-p:PublishAot=true", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.API.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								MesaFabApproval.API/Clients/SmtpClientWrapper.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								MesaFabApproval.API/Clients/SmtpClientWrapper.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | using System.Net.Mail; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Clients; | ||||||
|  |  | ||||||
|  | public interface ISmtpClientWrapper { | ||||||
|  |     void Send(MailMessage message); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class SmtpClientWrapper : ISmtpClientWrapper { | ||||||
|  |     private readonly SmtpClient _client; | ||||||
|  |  | ||||||
|  |     public SmtpClientWrapper(SmtpClient client) { | ||||||
|  |         _client = client ?? | ||||||
|  |             throw new ArgumentNullException("SmtpClient not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void Send(MailMessage message) { | ||||||
|  |         _client.Send(message); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										401
									
								
								MesaFabApproval.API/Controllers/ApprovalController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										401
									
								
								MesaFabApproval.API/Controllers/ApprovalController.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,401 @@ | |||||||
|  | using MesaFabApproval.API.Services; | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  | using MesaFabApproval.Shared.Services; | ||||||
|  |  | ||||||
|  | using Microsoft.AspNetCore.Authorization; | ||||||
|  | using Microsoft.AspNetCore.Mvc; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Controllers; | ||||||
|  | [ApiController] | ||||||
|  | [Authorize] | ||||||
|  | public class ApprovalController : ControllerBase { | ||||||
|  |     private readonly ILogger<ApprovalController> _logger; | ||||||
|  |     private readonly IApprovalService _approvalService; | ||||||
|  |     private readonly IMonInWorkerClient _monInClient; | ||||||
|  |  | ||||||
|  |     public ApprovalController(ILogger<ApprovalController> logger, IApprovalService approvalService, | ||||||
|  |                               IMonInWorkerClient monInClient) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _approvalService = approvalService ?? throw new ArgumentNullException("IApprovalService not injected"); | ||||||
|  |         _monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("approval")] | ||||||
|  |     public async Task<IActionResult> CreateApproval(Approval approval) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to generate a new approval"); | ||||||
|  |  | ||||||
|  |             if (approval is null) throw new ArgumentNullException("Approval cannot be null"); | ||||||
|  |  | ||||||
|  |             await _approvalService.CreateApproval(approval); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot create new approval, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "CreateApproval"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("approval/issue")] | ||||||
|  |     public async Task<IActionResult> GetApprovalsForIssueId(int issueId, bool bypassCache) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get approvals for issue {issueId}"); | ||||||
|  |  | ||||||
|  |             if (issueId <= 0) throw new ArgumentException($"{issueId} is not a valid issue ID"); | ||||||
|  |  | ||||||
|  |             IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(issueId, bypassCache); | ||||||
|  |  | ||||||
|  |             return Ok(approvals); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get approvals, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetApprovalsForIssueId"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("approval/user")] | ||||||
|  |     public async Task<IActionResult> GetApprovalsForUserId(int userId, bool bypassCache) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get approvals for user ID {userId}"); | ||||||
|  |  | ||||||
|  |             if (userId <= 0) throw new ArgumentException($"{userId} is not a valid user ID"); | ||||||
|  |  | ||||||
|  |             IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForUserId(userId, bypassCache); | ||||||
|  |  | ||||||
|  |             return Ok(approvals); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get approvals, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetApprovalsForUserId"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("approval/members")] | ||||||
|  |     public async Task<IActionResult> GetApprovalGroupMembers(int subRoleId) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get approval group members for group {subRoleId}"); | ||||||
|  |  | ||||||
|  |             if (subRoleId <= 0) throw new ArgumentException($"{subRoleId} is not a valid sub role ID"); | ||||||
|  |  | ||||||
|  |             IEnumerable<User> members = await _approvalService.GetApprovalGroupMembers(subRoleId); | ||||||
|  |  | ||||||
|  |             return Ok(members); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get approval group members, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetApprovalsGroupMembers"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPut] | ||||||
|  |     [Route("approval")] | ||||||
|  |     public async Task<IActionResult> UpdateApproval(Approval approval) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to update approval"); | ||||||
|  |  | ||||||
|  |             if (approval is null) throw new ArgumentNullException($"approval cannot be null"); | ||||||
|  |  | ||||||
|  |             await _approvalService.UpdateApproval(approval); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot update approval, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "UpdateApproval"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPut] | ||||||
|  |     [Route("approval/approve")] | ||||||
|  |     public async Task<IActionResult> Approve(Approval approval) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"attempting to submit approval"); | ||||||
|  |  | ||||||
|  |             if (approval is null) throw new ArgumentNullException($"approval cannot be null"); | ||||||
|  |  | ||||||
|  |             await _approvalService.Approve(approval); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot approve, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "Approve"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPut] | ||||||
|  |     [Route("approval/deny")] | ||||||
|  |     public async Task<IActionResult> Deny(Approval approval) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"attempting to deny approval"); | ||||||
|  |  | ||||||
|  |             if (approval is null) throw new ArgumentNullException($"approval cannot be null"); | ||||||
|  |  | ||||||
|  |             await _approvalService.Deny(approval); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Approval denial failed, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "Deny"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("approval/roleId")] | ||||||
|  |     public async Task<IActionResult> GetRoleIdForRoleName(string roleName) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get role ID by role name"); | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(roleName)) throw new ArgumentException("role name cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             int roleId = await _approvalService.GetRoleIdForRoleName(roleName); | ||||||
|  |  | ||||||
|  |             return Ok(roleId); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get role ID, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetRoleIdForRoleName"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("approval/subRoles")] | ||||||
|  |     public async Task<IActionResult> GetSubRolesForSubRoleName(string subRoleName, int roleId) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get sub roles by sub role name"); | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(subRoleName)) throw new ArgumentException("sub role name cannot be null or empty"); | ||||||
|  |             if (roleId <= 0) throw new ArgumentException($"{roleId} is not a valid role ID"); | ||||||
|  |  | ||||||
|  |             IEnumerable<SubRole> subRoles = await _approvalService.GetSubRolesForSubRoleName(subRoleName, roleId); | ||||||
|  |  | ||||||
|  |             return Ok(subRoles); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get role ID, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetSubRoleIdForSubRoleName"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										178
									
								
								MesaFabApproval.API/Controllers/AuthenticationController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								MesaFabApproval.API/Controllers/AuthenticationController.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,178 @@ | |||||||
|  | using System.Security.Authentication; | ||||||
|  | using System.Security.Principal; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  | using MesaFabApproval.Shared.Services; | ||||||
|  |  | ||||||
|  | using MesaFabApprovalAPI.Services; | ||||||
|  |  | ||||||
|  | using Microsoft.AspNetCore.Authorization; | ||||||
|  | using Microsoft.AspNetCore.Mvc; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Controllers; | ||||||
|  |  | ||||||
|  | [ApiController] | ||||||
|  | [AllowAnonymous] | ||||||
|  | public class AuthenticationController : ControllerBase { | ||||||
|  |     private readonly ILogger<AuthenticationController> _logger; | ||||||
|  |     private readonly IMonInWorkerClient _monInClient; | ||||||
|  |     private readonly IAuthenticationService _authenticationService; | ||||||
|  |  | ||||||
|  |     public AuthenticationController(ILogger<AuthenticationController> logger, | ||||||
|  |                                     IMonInWorkerClient monInClient, | ||||||
|  |                                     IAuthenticationService authenticationService) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected"); | ||||||
|  |         _authenticationService = authenticationService ?? | ||||||
|  |             throw new ArgumentNullException("IAuthenticationService not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("auth/login")] | ||||||
|  |     public async Task<IActionResult> Login(AuthAttempt login) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to perform authentication"); | ||||||
|  |  | ||||||
|  |             if (login is null) throw new ArgumentNullException("Login cannot be null"); | ||||||
|  |  | ||||||
|  |             LoginResult loginResult = await _authenticationService.AuthenticateUser(login); | ||||||
|  |  | ||||||
|  |             if (loginResult.IsAuthenticated) | ||||||
|  |                 return Ok(loginResult); | ||||||
|  |  | ||||||
|  |             return Unauthorized(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = $"Invalid argument. {ex.Message}"; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot authenticate user, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "Login"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("auth/login/localWindows")] | ||||||
|  |     public async Task<IActionResult> LoginLocalWindows(WindowsIdentity identity) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to perform local Windows authentication"); | ||||||
|  |  | ||||||
|  |             if (identity is null) throw new ArgumentNullException("identity cannot be null"); | ||||||
|  |  | ||||||
|  |             LoginResult loginResult = await _authenticationService.AttemptLocalUserAuth(identity); | ||||||
|  |  | ||||||
|  |             if (loginResult.IsAuthenticated) | ||||||
|  |                 return Ok(loginResult); | ||||||
|  |  | ||||||
|  |             return Unauthorized(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = $"Invalid argument. {ex.Message}"; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot authenticate local Windows user, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "LoginLocalWindows"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("auth/refresh")] | ||||||
|  |     public async Task<IActionResult> Refresh(AuthAttempt authAttempt) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to refresh auth tokens"); | ||||||
|  |  | ||||||
|  |             if (authAttempt is null) throw new ArgumentNullException("AuthAttempt cannot be null"); | ||||||
|  |             if (authAttempt.AuthTokens is null) throw new ArgumentNullException("AuthTokens cannot be null"); | ||||||
|  |  | ||||||
|  |             LoginResult loginResult = await _authenticationService.RefreshAuthTokens(authAttempt); | ||||||
|  |  | ||||||
|  |             return Ok(loginResult); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = $"Invalid argument. {ex.Message}"; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (AuthenticationException ex) { | ||||||
|  |             _logger.LogInformation($"Unable to refresh tokens, because {ex.Message}"); | ||||||
|  |             return Unauthorized(); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = $"Cannot authenticate user, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "RefreshTokens"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpOptions] | ||||||
|  |     [Route("auth/refresh")] | ||||||
|  |     public IActionResult RefreshOptions() { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Auth refresh options"); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Error in auth refresh options. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										56
									
								
								MesaFabApproval.API/Controllers/CAController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								MesaFabApproval.API/Controllers/CAController.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | using MesaFabApproval.API.Services; | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  | using MesaFabApproval.Shared.Services; | ||||||
|  |  | ||||||
|  | using Microsoft.AspNetCore.Authorization; | ||||||
|  | using Microsoft.AspNetCore.Mvc; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Controllers; | ||||||
|  | [ApiController] | ||||||
|  | [Authorize] | ||||||
|  | public class CAController : ControllerBase { | ||||||
|  |     private readonly ILogger<ApprovalController> _logger; | ||||||
|  |     private readonly ICAService _caService; | ||||||
|  |     private readonly IMonInWorkerClient _monInClient; | ||||||
|  |  | ||||||
|  |     public CAController(ILogger<ApprovalController> logger, ICAService caService, | ||||||
|  |                               IMonInWorkerClient monInClient) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _caService = caService ?? throw new ArgumentNullException("ICAService not injected"); | ||||||
|  |         _monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("ca/isValidCANumber")] | ||||||
|  |     public async Task<IActionResult> IsValidCANumber(int number) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to determine if {number} is a valid CA#"); | ||||||
|  |  | ||||||
|  |             if (number <= 0) return Ok(false); | ||||||
|  |  | ||||||
|  |             bool isValid = await _caService.IsValidCANumber(number); | ||||||
|  |  | ||||||
|  |             return Ok(isValid); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot determine if {number} is a valid CA#, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "IsValidCANumber"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										57
									
								
								MesaFabApproval.API/Controllers/CustomerController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								MesaFabApproval.API/Controllers/CustomerController.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | |||||||
|  | using MesaFabApproval.API.Services; | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  | using MesaFabApproval.Shared.Services; | ||||||
|  |  | ||||||
|  | using Microsoft.AspNetCore.Authorization; | ||||||
|  | using Microsoft.AspNetCore.Mvc; | ||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Controllers; | ||||||
|  |  | ||||||
|  | [ApiController] | ||||||
|  | [Authorize] | ||||||
|  | public class CustomerController : ControllerBase { | ||||||
|  |     private readonly ILogger<CustomerController> _logger; | ||||||
|  |     private readonly IMonInWorkerClient _monInClient; | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly ICustomerService _customerService; | ||||||
|  |  | ||||||
|  |     public CustomerController(ILogger<CustomerController> logger, IMonInWorkerClient monInClient, IMemoryCache cache, ICustomerService customerService) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected"); | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _customerService = customerService ?? throw new ArgumentNullException("ICustomerService"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("customer/all")] | ||||||
|  |     public async Task<IActionResult> GetAllCustomerNames() { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get all customer names"); | ||||||
|  |  | ||||||
|  |             IEnumerable<string> customerNames = await _customerService.GetCustomerNames(); | ||||||
|  |  | ||||||
|  |             return Ok(customerNames); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get user by LoginID, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetAllCustomerNames"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										56
									
								
								MesaFabApproval.API/Controllers/ECNController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								MesaFabApproval.API/Controllers/ECNController.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | using MesaFabApproval.API.Services; | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  | using MesaFabApproval.Shared.Services; | ||||||
|  |  | ||||||
|  | using Microsoft.AspNetCore.Authorization; | ||||||
|  | using Microsoft.AspNetCore.Mvc; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Controllers; | ||||||
|  | [ApiController] | ||||||
|  | [Authorize] | ||||||
|  | public class ECNController : ControllerBase { | ||||||
|  |     private readonly ILogger<ApprovalController> _logger; | ||||||
|  |     private readonly IECNService _ecnService; | ||||||
|  |     private readonly IMonInWorkerClient _monInClient; | ||||||
|  |  | ||||||
|  |     public ECNController(ILogger<ApprovalController> logger, IECNService ecnService, | ||||||
|  |                               IMonInWorkerClient monInClient) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _ecnService = ecnService ?? throw new ArgumentNullException("IECNService not injected"); | ||||||
|  |         _monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("ecn/isValidEcnNumber")] | ||||||
|  |     public async Task<IActionResult> IsValidEcnNumber(int number) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to determine if {number} is a valid ECN#"); | ||||||
|  |  | ||||||
|  |             if (number <= 0) return Ok(false); | ||||||
|  |  | ||||||
|  |             bool isValid = await _ecnService.IsValidECNNumber(number); | ||||||
|  |  | ||||||
|  |             return Ok(isValid); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot determine if {number} is a valid ECN#, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "IsValidEcnNumber"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										975
									
								
								MesaFabApproval.API/Controllers/MRBController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										975
									
								
								MesaFabApproval.API/Controllers/MRBController.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,975 @@ | |||||||
|  | using MesaFabApproval.API.Services; | ||||||
|  | using MesaFabApproval.Models; | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  | using MesaFabApproval.Shared.Services; | ||||||
|  |  | ||||||
|  | using Microsoft.AspNetCore.Authorization; | ||||||
|  | using Microsoft.AspNetCore.Mvc; | ||||||
|  | using Microsoft.AspNetCore.StaticFiles; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Controllers; | ||||||
|  |  | ||||||
|  | [ApiController] | ||||||
|  | [Authorize] | ||||||
|  | public class MRBController : ControllerBase { | ||||||
|  |     private readonly ILogger<MRBController> _logger; | ||||||
|  |     private readonly IMRBService _mrbService; | ||||||
|  |     private readonly IMonInWorkerClient _monInClient; | ||||||
|  |  | ||||||
|  |     private readonly string _mrbAttachmentPath; | ||||||
|  |  | ||||||
|  |     public MRBController(ILogger<MRBController> logger, | ||||||
|  |                          IMRBService mrbService, | ||||||
|  |                          IMonInWorkerClient monInClient, | ||||||
|  |                          AppSettings appSettings) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _mrbService = mrbService ?? throw new ArgumentNullException("IMRBService not injected"); | ||||||
|  |         _monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected"); | ||||||
|  |         _mrbAttachmentPath = appSettings.MrbAttachmentPath; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("mrb/new")] | ||||||
|  |     public async Task<IActionResult> CreateNewMRB(MRB mrb) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to generate a new MRB"); | ||||||
|  |  | ||||||
|  |             if (mrb is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |  | ||||||
|  |             await _mrbService.CreateNewMRB(mrb); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot create new MRB, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "CreateNewMRB"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpDelete] | ||||||
|  |     [Route("mrb/delete")] | ||||||
|  |     public async Task<IActionResult> DeleteMRB(int mrbNumber) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to delete MRB# {mrbNumber}"); | ||||||
|  |  | ||||||
|  |             if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number"); | ||||||
|  |  | ||||||
|  |             await _mrbService.DeleteMRB(mrbNumber); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot delete MRB {mrbNumber}, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "DeleteMRB"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("mrb/all")] | ||||||
|  |     public async Task<IActionResult> GetAllMRBs(bool bypassCache) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get all MRBs"); | ||||||
|  |  | ||||||
|  |             IEnumerable<MRB> allMrbs = await _mrbService.GetAllMRBs(bypassCache); | ||||||
|  |  | ||||||
|  |             return Ok(allMrbs); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get all MRBs, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetAllMRBs"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("mrb/numberIsValid")] | ||||||
|  |     public async Task<IActionResult> NumberIsValid(int number) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to determine if {number} is a valid MRB#"); | ||||||
|  |  | ||||||
|  |             bool isValid = await _mrbService.MRBNumberIsValid(number); | ||||||
|  |  | ||||||
|  |             return Ok(isValid); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Unable to determine if {number} is a valid MRB#, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "IsValidMRBNumber"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("mrb/getById")] | ||||||
|  |     public async Task<IActionResult> GetMRBById(int id, bool bypassCache = false) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get an MRB by Id"); | ||||||
|  |  | ||||||
|  |             if (id <= 0) throw new ArgumentException("Invalid MRB number"); | ||||||
|  |  | ||||||
|  |             MRB mrb = await _mrbService.GetMRBById(id, bypassCache); | ||||||
|  |  | ||||||
|  |             return Ok(mrb); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get MRB by Id, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetMRBbyId"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("mrb/getByTitle")] | ||||||
|  |     public async Task<IActionResult> GetMRBByTitle(string title, bool bypassCache) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get an MRB by Title"); | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             MRB mrb = await _mrbService.GetMRBByTitle(title, bypassCache); | ||||||
|  |  | ||||||
|  |             return Ok(mrb); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get MRB by title, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetMRBbyTitle"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPut] | ||||||
|  |     [Route("mrb")] | ||||||
|  |     public async Task<IActionResult> UpdateMRB(MRB mrb) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to update an MRB"); | ||||||
|  |  | ||||||
|  |             if (mrb is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |  | ||||||
|  |             await _mrbService.UpdateMRB(mrb); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot update MRB, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "UpdateMRB"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("mrbAction")] | ||||||
|  |     public async Task<IActionResult> CreateMRBAction(MRBAction mrbAction) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to generate a new MRB"); | ||||||
|  |  | ||||||
|  |             if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null"); | ||||||
|  |  | ||||||
|  |             await _mrbService.CreateMRBAction(mrbAction); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot create new MRB action, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "CreateNewMRBAction"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("mrbAction")] | ||||||
|  |     public async Task<IActionResult> GetMRBActionsForMRB(int mrbNumber, bool bypassCache) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get all MRBs"); | ||||||
|  |  | ||||||
|  |             if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number"); | ||||||
|  |  | ||||||
|  |             IEnumerable<MRBAction> mrbActions = await _mrbService.GetMRBActionsForMRB(mrbNumber, bypassCache); | ||||||
|  |  | ||||||
|  |             return Ok(mrbActions); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get all MRBs, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetMRBActionsForMRB"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPut] | ||||||
|  |     [Route("mrbAction")] | ||||||
|  |     public async Task<IActionResult> UpdateMRBAction(MRBAction mrbAction) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to update an MRB action"); | ||||||
|  |  | ||||||
|  |             if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null"); | ||||||
|  |  | ||||||
|  |             await _mrbService.UpdateMRBAction(mrbAction); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot update MRB action, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "UpdateMRBAction"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpDelete] | ||||||
|  |     [Route("mrbAction")] | ||||||
|  |     public async Task<IActionResult> DeleteMRBAction(int mrbActionID, int mrbNumber) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to delete MRB action {mrbActionID}"); | ||||||
|  |  | ||||||
|  |             if (mrbActionID <= 0) throw new ArgumentException($"{mrbActionID} is not a valid MRB ActionID"); | ||||||
|  |             if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRBNumber"); | ||||||
|  |  | ||||||
|  |             await _mrbService.DeleteMRBAction(mrbActionID, mrbNumber); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot delete MRB action, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "DeleteMRBAction"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("mrb/attachments")] | ||||||
|  |     public async Task<IActionResult> GetAttachmentsForMRB(int mrbNumber, bool bypassCache) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get MRB attachments for MRB {mrbNumber}"); | ||||||
|  |  | ||||||
|  |             if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number"); | ||||||
|  |  | ||||||
|  |             List<MRBAttachment> attachments = (await _mrbService.GetAllAttachmentsForMRB(mrbNumber, bypassCache)).ToList(); | ||||||
|  |  | ||||||
|  |             return Ok(attachments); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get attachments for MRB {mrbNumber}, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetMRBAttachments"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("mrb/action/attachments")] | ||||||
|  |     public async Task<IActionResult> GetActionAttachmentsForMRB(int mrbNumber, bool bypassCache) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get action attachments for MRB {mrbNumber}"); | ||||||
|  |  | ||||||
|  |             if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#"); | ||||||
|  |  | ||||||
|  |             List<MRBActionAttachment> attachments = | ||||||
|  |                 (await _mrbService.GetAllActionAttachmentsForMRB(mrbNumber, bypassCache)).ToList(); | ||||||
|  |  | ||||||
|  |             return Ok(attachments); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get action attachments for MRB# {mrbNumber}, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetMRBActionAttachments"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("mrb/attach")] | ||||||
|  |     public async Task<IActionResult> SaveMRBAttachment([FromForm] IEnumerable<IFormFile> files, int mrbNumber) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to save MRB attachments"); | ||||||
|  |  | ||||||
|  |             if (files is null) throw new ArgumentNullException("Files cannot be null"); | ||||||
|  |             if (files.Count() <= 0) throw new ArgumentException("Files cannot be empty"); | ||||||
|  |             if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number"); | ||||||
|  |  | ||||||
|  |             IEnumerable<UploadResult> uploadResults = (await _mrbService.UploadAttachments(files, mrbNumber)).ToList(); | ||||||
|  |  | ||||||
|  |             return Ok(uploadResults); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot save MRB attachments, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "SaveMRBAttachments"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("mrb/action/attach")] | ||||||
|  |     public async Task<IActionResult> SaveMRBActionAttachment([FromForm] IEnumerable<IFormFile> files, int actionId) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to save MRB action attachments"); | ||||||
|  |  | ||||||
|  |             if (files is null) throw new ArgumentNullException("Files cannot be null"); | ||||||
|  |             if (files.Count() <= 0) throw new ArgumentException("Files cannot be empty"); | ||||||
|  |             if (actionId <= 0) throw new ArgumentException($"{actionId} is not a valid MRB action ID"); | ||||||
|  |  | ||||||
|  |             IEnumerable<UploadResult> uploadResults = (await _mrbService.UploadActionAttachments(files, actionId)).ToList(); | ||||||
|  |  | ||||||
|  |             return Ok(uploadResults); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot save MRB action attachments, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "SaveMRBActionAttachments"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [AllowAnonymous] | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("mrb/attachmentFile")] | ||||||
|  |     public async Task<IActionResult> GetMRBAttachmentFile(string path, string fileName) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get MRB attachment file"); | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Path cannot be null or empty"); | ||||||
|  |             if (!System.IO.File.Exists(path)) throw new ArgumentException("No file exists at provided path"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(fileName)) throw new ArgumentException("Filename cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             byte[] fs = System.IO.File.ReadAllBytes(path); | ||||||
|  |  | ||||||
|  |             const string defaultContentType = "application/octet-stream"; | ||||||
|  |  | ||||||
|  |             FileExtensionContentTypeProvider contentTypeProvider = new FileExtensionContentTypeProvider(); | ||||||
|  |  | ||||||
|  |             if (!contentTypeProvider.TryGetContentType(path, out string? contentType)) { | ||||||
|  |                 contentType = defaultContentType; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return new FileContentResult(fs, contentType) { | ||||||
|  |                 FileDownloadName = fileName | ||||||
|  |             }; | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get MRB attachment file, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetMRBAttachmentFile"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [AllowAnonymous] | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("mrb/actions/csvFile")] | ||||||
|  |     public async Task<IActionResult> GetMRBActionsCsvFile(int mrbNumber) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get MRB actions CSC file"); | ||||||
|  |  | ||||||
|  |             if (!(await _mrbService.MRBNumberIsValid(mrbNumber))) | ||||||
|  |                 throw new ArgumentException($"{mrbNumber} is not a valid MRB#"); | ||||||
|  |  | ||||||
|  |             string path = $"{_mrbAttachmentPath}\\{mrbNumber}\\mrb{mrbNumber}Actions.csv"; | ||||||
|  |  | ||||||
|  |             await _mrbService.ConvertActionsToCsvFile(mrbNumber, path); | ||||||
|  |  | ||||||
|  |             byte[] fs = System.IO.File.ReadAllBytes(path); | ||||||
|  |  | ||||||
|  |             const string defaultContentType = "application/octet-stream"; | ||||||
|  |  | ||||||
|  |             FileExtensionContentTypeProvider contentTypeProvider = new FileExtensionContentTypeProvider(); | ||||||
|  |  | ||||||
|  |             if (!contentTypeProvider.TryGetContentType(path, out string? contentType)) { | ||||||
|  |                 contentType = defaultContentType; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return new FileContentResult(fs, contentType) { | ||||||
|  |                 FileDownloadName = $"mrb{mrbNumber}Actions.csv" | ||||||
|  |             }; | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get MRB actions CSC file, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetMRBActionsCSVFile"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpDelete] | ||||||
|  |     [Route("mrb/attach")] | ||||||
|  |     public async Task<IActionResult> DeleteMRBAttachment(MRBAttachment attachment) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to delete MRB attachment"); | ||||||
|  |  | ||||||
|  |             if (attachment is null) throw new ArgumentNullException("Attachment cannot be null"); | ||||||
|  |  | ||||||
|  |             await _mrbService.DeleteAttachment(attachment); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get MRB attachment file, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "DeleteMRBAttachment"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("mrb/notify/new-approvals")] | ||||||
|  |     public async Task<IActionResult> NotifyNewApprovals(MRB mrb) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to notify new approvers"); | ||||||
|  |  | ||||||
|  |             if (mrb is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |  | ||||||
|  |             await _mrbService.NotifyNewApprovals(mrb); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Unable to notify new approvers, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "NotifyNewMRBApprovers"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("mrb/notify/approvers")] | ||||||
|  |     public async Task<IActionResult> NotifyApprovers(MRBNotification notification) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to notify approvers"); | ||||||
|  |  | ||||||
|  |             if (notification is null) throw new ArgumentNullException("notification cannot be null"); | ||||||
|  |             if (notification.MRB is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             await _mrbService.NotifyApprovers(notification); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Unable to notify approvers, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "NotifyMRBApprovers"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("mrb/notify/originator")] | ||||||
|  |     public async Task<IActionResult> NotifyOriginator(MRBNotification notification) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to notify originator"); | ||||||
|  |  | ||||||
|  |             if (notification is null) throw new ArgumentNullException("MRBNotification cannot be null"); | ||||||
|  |             if (notification.MRB is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("Message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             await _mrbService.NotifyOriginator(notification); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Unable to notify originator, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "NotifyMRBOriginator"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpPost] | ||||||
|  |     [Route("mrb/notify/qa-pre-approver")] | ||||||
|  |     public async Task<IActionResult> NotifyQAPreApprover(MRBNotification notification) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to notify QA pre approver"); | ||||||
|  |  | ||||||
|  |             if (notification is null) throw new ArgumentNullException("MRBNotification cannot be null"); | ||||||
|  |             if (notification.MRB is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("Message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             await _mrbService.NotifyQAPreApprover(notification); | ||||||
|  |  | ||||||
|  |             return Ok(); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = ex.Message; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Unable to notify QA pre approver, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "NotifyQAPreApprover"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										1126
									
								
								MesaFabApproval.API/Controllers/PCRBController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1126
									
								
								MesaFabApproval.API/Controllers/PCRBController.cs
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										223
									
								
								MesaFabApproval.API/Controllers/UserController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								MesaFabApproval.API/Controllers/UserController.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,223 @@ | |||||||
|  | using MesaFabApproval.API.Services; | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  | using MesaFabApproval.Shared.Services; | ||||||
|  |  | ||||||
|  | using Microsoft.AspNetCore.Authorization; | ||||||
|  | using Microsoft.AspNetCore.Mvc; | ||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Controllers; | ||||||
|  |  | ||||||
|  | [ApiController] | ||||||
|  | public class UserController : ControllerBase { | ||||||
|  |     private readonly ILogger<UserController> _logger; | ||||||
|  |     private readonly IMonInWorkerClient _monInClient; | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly IUserService _userService; | ||||||
|  |  | ||||||
|  |     public UserController(ILogger<UserController> logger, | ||||||
|  |                           IMonInWorkerClient monInClient, | ||||||
|  |                           IMemoryCache cache, | ||||||
|  |                           IUserService userService) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _monInClient = monInClient ?? throw new ArgumentNullException("IMonInWorkerClient not injected"); | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _userService = userService ?? throw new ArgumentNullException("IUserService not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("/user/loginId")] | ||||||
|  |     [Authorize] | ||||||
|  |     public async Task<IActionResult> GetUserByLoginId(string loginId) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get user by LoginID"); | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(loginId)) | ||||||
|  |                 throw new ArgumentException("LoginID cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             User? user = _cache.Get<User>($"user{loginId}"); | ||||||
|  |  | ||||||
|  |             if (user is null) { | ||||||
|  |                 user = await _userService.GetUserByLoginId(loginId); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"user{loginId}", user, DateTimeOffset.Now.AddDays(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (user is not null) return Ok(user); | ||||||
|  |  | ||||||
|  |             throw new Exception($"User with LoginID {loginId} not found"); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = $"Invalid argument. {ex.Message}"; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get user by LoginID, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetUserByLoginId"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("/user/userId")] | ||||||
|  |     [Authorize] | ||||||
|  |     public async Task<IActionResult> GetUserByUserId(int userId) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get user by LoginID"); | ||||||
|  |  | ||||||
|  |             if (userId <= 0) throw new ArgumentException($"{userId} is not a valid user ID"); | ||||||
|  |  | ||||||
|  |             User? user = _cache.Get<User>($"user{userId}"); | ||||||
|  |  | ||||||
|  |             if (user is null) { | ||||||
|  |                 user = await _userService.GetUserByUserId(userId); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"user{userId}", user, DateTimeOffset.Now.AddDays(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (user is not null) return Ok(user); | ||||||
|  |  | ||||||
|  |             throw new Exception($"User with UserID {userId} not found"); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = $"Invalid argument. {ex.Message}"; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get user by User ID, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetUserByUserId"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("/users/active")] | ||||||
|  |     [Authorize] | ||||||
|  |     public async Task<IActionResult> GetAllActiveUsers() { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get all active users"); | ||||||
|  |  | ||||||
|  |             IEnumerable<User>? activeUsers = _cache.Get<IEnumerable<User>>($"activeUsers"); | ||||||
|  |  | ||||||
|  |             if (activeUsers is null) { | ||||||
|  |                 activeUsers = await _userService.GetAllActiveUsers(); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"activeUsers", activeUsers, DateTimeOffset.Now.AddDays(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (activeUsers is not null) return Ok(activeUsers); | ||||||
|  |  | ||||||
|  |             throw new Exception($"No active users found"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get all active users, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetAllActiveUsers"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet] | ||||||
|  |     [Route("/approver")] | ||||||
|  |     [Authorize] | ||||||
|  |     public async Task<IActionResult> GetApproverUserIdsForSubRoleCategoryItem(string subRoleCategoryItem) { | ||||||
|  |         DateTime start = DateTime.Now; | ||||||
|  |         bool isArgumentError = false; | ||||||
|  |         bool isInternalError = false; | ||||||
|  |         string errorMessage = ""; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get approver user IDs"); | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(subRoleCategoryItem)) | ||||||
|  |                 throw new ArgumentException("SubRoleCategoryItem cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             IEnumerable<int>? approverUserIds = _cache.Get<IEnumerable<int>>($"approvers{subRoleCategoryItem}"); | ||||||
|  |  | ||||||
|  |             if (approverUserIds is null) { | ||||||
|  |                 approverUserIds = await _userService.GetApproverUserIdsBySubRoleCategoryItem(subRoleCategoryItem); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"approvers{subRoleCategoryItem}", approverUserIds, DateTimeOffset.Now.AddDays(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (approverUserIds is not null) return Ok(approverUserIds); | ||||||
|  |  | ||||||
|  |             throw new Exception($"Approvers for SubRoleCategoryItem {subRoleCategoryItem} not found"); | ||||||
|  |         } catch (ArgumentException ex) { | ||||||
|  |             isArgumentError = true; | ||||||
|  |             errorMessage = $"Invalid argument. {ex.Message}"; | ||||||
|  |             return BadRequest(errorMessage); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             isInternalError = true; | ||||||
|  |             errorMessage = $"Cannot get approver user IDs, because {ex.Message}"; | ||||||
|  |             return Problem(errorMessage); | ||||||
|  |         } finally { | ||||||
|  |             string metricName = "GetApproverUserIds"; | ||||||
|  |             DateTime end = DateTime.Now; | ||||||
|  |             double millisecondsDiff = (end - start).TotalMilliseconds; | ||||||
|  |             _monInClient.PostAverage(metricName + "Latency", millisecondsDiff); | ||||||
|  |  | ||||||
|  |             if (isArgumentError) { | ||||||
|  |                 _logger.LogWarning(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } else if (isInternalError) { | ||||||
|  |                 _logger.LogError(errorMessage); | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Critical); | ||||||
|  |             } else { | ||||||
|  |                 _monInClient.PostStatus(metricName, StatusValue.Ok); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								MesaFabApproval.API/GlobalSuppressions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								MesaFabApproval.API/GlobalSuppressions.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | // This file is used by Code Analysis to maintain SuppressMessage | ||||||
|  | // attributes that are applied to this project. | ||||||
|  | // Project-level suppressions either have no target or are given | ||||||
|  | // a specific target and scoped to a namespace, type, member, etc. | ||||||
|  |  | ||||||
|  | using System.Diagnostics.CodeAnalysis; | ||||||
|  |  | ||||||
|  | [assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>", Scope = "member", Target = "~M:MesaFabApprovalAPI.Services.AuthenticationService.AuthenticateUser(MesaFabApproval.Shared.Models.AuthAttempt)~System.Threading.Tasks.Task{MesaFabApproval.Shared.Models.LoginResult}")] | ||||||
|  | [assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>", Scope = "member", Target = "~M:MesaFabApprovalAPI.Services.AuthenticationService.AttemptLocalUserAuth(System.Security.Principal.WindowsIdentity)~System.Threading.Tasks.Task{MesaFabApproval.Shared.Models.LoginResult}")] | ||||||
							
								
								
									
										28
									
								
								MesaFabApproval.API/MesaFabApproval.API.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								MesaFabApproval.API/MesaFabApproval.API.csproj
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | <Project Sdk="Microsoft.NET.Sdk.Web"> | ||||||
|  |   <PropertyGroup> | ||||||
|  |     <TargetFramework>net8.0</TargetFramework> | ||||||
|  |     <Nullable>enable</Nullable> | ||||||
|  |     <ImplicitUsings>enable</ImplicitUsings> | ||||||
|  |     <UserSecretsId>0b98e1f2-95ed-4edd-8149-58cce51ca059</UserSecretsId> | ||||||
|  |   </PropertyGroup> | ||||||
|  |   <ItemGroup> | ||||||
|  |     <PackageReference Include="Dapper" Version="2.1.35" /> | ||||||
|  |     <PackageReference Include="Dapper.Contrib" Version="2.0.78" /> | ||||||
|  |     <PackageReference Include="dotenv.net" Version="3.2.0" /> | ||||||
|  |     <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.8" /> | ||||||
|  |     <PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.1" /> | ||||||
|  |     <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" /> | ||||||
|  |     <PackageReference Include="NLog" Version="5.2.8" /> | ||||||
|  |     <PackageReference Include="NLog.Web.AspNetCore" Version="5.3.8" /> | ||||||
|  |     <PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.0" /> | ||||||
|  |     <PackageReference Include="System.DirectoryServices.AccountManagement" Version="8.0.0" /> | ||||||
|  |   </ItemGroup> | ||||||
|  |   <ItemGroup> | ||||||
|  |     <ProjectReference Include="..\MesaFabApproval.Shared\MesaFabApproval.Shared.csproj" /> | ||||||
|  |   </ItemGroup> | ||||||
|  |   <ItemGroup> | ||||||
|  |     <Reference Include="System.DirectoryServices.AccountManagement"> | ||||||
|  |       <HintPath>..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.DirectoryServices.AccountManagement.dll</HintPath> | ||||||
|  |     </Reference> | ||||||
|  |   </ItemGroup> | ||||||
|  | </Project> | ||||||
							
								
								
									
										93
									
								
								MesaFabApproval.API/Models/AppSettings.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								MesaFabApproval.API/Models/AppSettings.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | |||||||
|  | using System; | ||||||
|  | using System.Text.Json; | ||||||
|  | using System.Text.Json.Serialization; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.Models; | ||||||
|  |  | ||||||
|  | public record AppSettings(string Company, | ||||||
|  |                           string DbConnectionString, | ||||||
|  |                           string JwtAudience, | ||||||
|  |                           string JwtIssuer, | ||||||
|  |                           string JwtKey, | ||||||
|  |                           string MrbAttachmentPath, | ||||||
|  |                           string PcrbAttachmentPath, | ||||||
|  |                           bool ShouldSendEmail, | ||||||
|  |                           string SiteBaseUrl, | ||||||
|  |                           string WorkingDirectoryName) { | ||||||
|  |  | ||||||
|  |     public override string ToString() { | ||||||
|  |         string result = JsonSerializer.Serialize(this, AppSettingsSourceGenerationContext.Default.AppSettings); | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static AppSettings Get(IConfigurationRoot configurationRoot) { | ||||||
|  |         AppSettings? result; | ||||||
|  |         try { | ||||||
|  | #pragma warning disable IL3050, IL2026 | ||||||
|  |             result = configurationRoot.Get<AppSettings>() ?? throw new Exception(); | ||||||
|  | #pragma warning restore IL3050, IL2026 | ||||||
|  |         } catch (Exception) { | ||||||
|  |             List<string> paths = []; | ||||||
|  |             foreach (IConfigurationProvider configurationProvider in configurationRoot.Providers) { | ||||||
|  |                 if (configurationProvider is not Microsoft.Extensions.Configuration.Json.JsonConfigurationProvider jsonConfigurationProvider) | ||||||
|  |                     continue; | ||||||
|  |                 if (jsonConfigurationProvider.Source.FileProvider is not Microsoft.Extensions.FileProviders.PhysicalFileProvider physicalFileProvider) | ||||||
|  |                     continue; | ||||||
|  |                 paths.Add(physicalFileProvider.Root); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             throw new NotSupportedException($"Not found!{Environment.NewLine}{string.Join(Environment.NewLine, paths.Distinct())}"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     internal static void SetEnvironmentVariables(WebApplicationBuilder builder) { | ||||||
|  |         builder.Configuration.AddUserSecrets<Program>(); | ||||||
|  |         AppSettings appSettings = Get(builder.Configuration); | ||||||
|  |         Environment.SetEnvironmentVariable("FabApprovalDbConnectionString", appSettings.DbConnectionString); | ||||||
|  |         Environment.SetEnvironmentVariable("FabApprovalJwtAudience", appSettings.JwtAudience); | ||||||
|  |         Environment.SetEnvironmentVariable("FabApprovalJwtIssuer", appSettings.JwtIssuer); | ||||||
|  |         Environment.SetEnvironmentVariable("FabApprovalJwtKey", appSettings.JwtKey); | ||||||
|  |         Environment.SetEnvironmentVariable("FabApprovalMrbAttachmentPath", appSettings.MrbAttachmentPath); | ||||||
|  |         Environment.SetEnvironmentVariable("FabApprovalPcrbAttachmentPath", appSettings.PcrbAttachmentPath); | ||||||
|  |         Environment.SetEnvironmentVariable("FabApprovalShouldSendEmail", appSettings.ShouldSendEmail.ToString()); | ||||||
|  |         Environment.SetEnvironmentVariable("NewFabApprovalBaseUrl", appSettings.SiteBaseUrl); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     internal static AppSettings LoadEnvironmentVariables() { | ||||||
|  |         AppSettings result; | ||||||
|  |         string dbConnectionString = Environment.GetEnvironmentVariable("FabApprovalDbConnectionString") ?? | ||||||
|  |             throw new ArgumentNullException("FabApprovalDbConnectionString environment variable not found"); | ||||||
|  |         string jwtAudience = Environment.GetEnvironmentVariable("FabApprovalJwtAudience") ?? | ||||||
|  |             throw new ArgumentNullException("FabApprovalJwtAudience environment variable not found"); | ||||||
|  |         string jwtIssuer = Environment.GetEnvironmentVariable("FabApprovalJwtIssuer") ?? | ||||||
|  |             throw new ArgumentNullException("FabApprovalJwtIssuer environment variable not found"); | ||||||
|  |         string jwtKey = Environment.GetEnvironmentVariable("FabApprovalJwtKey") ?? | ||||||
|  |             throw new ArgumentNullException("FabApprovalJwtKey environment variable not found"); | ||||||
|  |         string mrbAttachmentPath = Environment.GetEnvironmentVariable("FabApprovalMrbAttachmentPath") ?? | ||||||
|  |             throw new ArgumentNullException("FabApprovalMrbAttachmentPath environment variable not found"); | ||||||
|  |         string pcrbAttachmentPath = Environment.GetEnvironmentVariable("FabApprovalPcrbAttachmentPath") ?? | ||||||
|  |             throw new ArgumentNullException("FabApprovalPcrbAttachmentPath environment variable not found"); | ||||||
|  |         if (!bool.TryParse(Environment.GetEnvironmentVariable("FabApprovalShouldSendEmail"), out bool shouldSendEmail)) | ||||||
|  |             throw new ArgumentNullException("FabApprovalShouldSendEmail environment variable not found"); | ||||||
|  |         string siteBaseUrl = Environment.GetEnvironmentVariable("NewFabApprovalBaseUrl") ?? | ||||||
|  |             throw new ArgumentNullException("FabApprovalBaseUrl environment variable not found"); | ||||||
|  |         result = new("Infineon Technologies Americas Corp.", | ||||||
|  |                      DbConnectionString: dbConnectionString, | ||||||
|  |                      JwtAudience: jwtAudience, | ||||||
|  |                      JwtIssuer: jwtIssuer, | ||||||
|  |                      JwtKey: jwtKey, | ||||||
|  |                      MrbAttachmentPath: mrbAttachmentPath, | ||||||
|  |                      PcrbAttachmentPath: pcrbAttachmentPath, | ||||||
|  |                      ShouldSendEmail: shouldSendEmail, | ||||||
|  |                      SiteBaseUrl: siteBaseUrl, | ||||||
|  |                      "IFXApps"); | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | [JsonSourceGenerationOptions(WriteIndented = true)] | ||||||
|  | [JsonSerializable(typeof(AppSettings))] | ||||||
|  | internal partial class AppSettingsSourceGenerationContext : JsonSerializerContext { | ||||||
|  | } | ||||||
							
								
								
									
										157
									
								
								MesaFabApproval.API/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								MesaFabApproval.API/Program.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,157 @@ | |||||||
|  | using System.Diagnostics; | ||||||
|  | using System.Net.Mail; | ||||||
|  | using System.Text; | ||||||
|  |  | ||||||
|  | using dotenv.net; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.API.Clients; | ||||||
|  | using MesaFabApproval.API.Services; | ||||||
|  | using MesaFabApproval.Models; | ||||||
|  | using MesaFabApproval.Shared.Services; | ||||||
|  |  | ||||||
|  | using MesaFabApprovalAPI.Services; | ||||||
|  |  | ||||||
|  | using Microsoft.AspNetCore.Authentication.JwtBearer; | ||||||
|  | using Microsoft.AspNetCore.Authorization; | ||||||
|  | using Microsoft.AspNetCore.HttpLogging; | ||||||
|  | using Microsoft.IdentityModel.Tokens; | ||||||
|  | using Microsoft.OpenApi.Models; | ||||||
|  |  | ||||||
|  | using NLog.Extensions.Logging; | ||||||
|  | using NLog.Web; | ||||||
|  |  | ||||||
|  | WebApplicationBuilder builder = WebApplication.CreateBuilder(args); | ||||||
|  |  | ||||||
|  | DotEnv.Load(); | ||||||
|  |  | ||||||
|  | builder.Logging.ClearProviders(); | ||||||
|  | builder.Logging.SetMinimumLevel(LogLevel.Trace); | ||||||
|  | builder.Logging.AddNLog(); | ||||||
|  |  | ||||||
|  | /*builder.Services.AddHttpLogging(o => { | ||||||
|  |     o.LoggingFields = HttpLoggingFields.All; | ||||||
|  |     o.RequestHeaders.Add("bearer"); | ||||||
|  |     o.MediaTypeOptions.AddText("application/javascript"); | ||||||
|  |     o.RequestBodyLogLimit = 4096; | ||||||
|  |     o.ResponseBodyLogLimit = 4096; | ||||||
|  |     o.CombineLogs = true; | ||||||
|  | });*/ | ||||||
|  |  | ||||||
|  | builder.Services.AddMemoryCache(); | ||||||
|  |  | ||||||
|  | if (Debugger.IsAttached) { | ||||||
|  |     string? jwtIssuer = Environment.GetEnvironmentVariable("FabApprovalJwtIssuer"); | ||||||
|  |     if (string.IsNullOrEmpty(jwtIssuer)) { | ||||||
|  |         AppSettings.SetEnvironmentVariables(builder); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | AppSettings appSettings = AppSettings.LoadEnvironmentVariables(); | ||||||
|  | builder.Services.AddSingleton(_ => appSettings); | ||||||
|  |  | ||||||
|  | builder.Services.AddAuthentication(options => { | ||||||
|  |     options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; | ||||||
|  |     options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; | ||||||
|  | }) | ||||||
|  | .AddJwtBearer(options => { | ||||||
|  |     options.RequireHttpsMetadata = false; | ||||||
|  |     options.SaveToken = true; | ||||||
|  |     options.TokenValidationParameters = new TokenValidationParameters { | ||||||
|  |         ValidateIssuerSigningKey = true, | ||||||
|  |         ValidIssuer = appSettings.JwtIssuer, | ||||||
|  |         ValidateAudience = false, | ||||||
|  |         IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(appSettings.JwtKey)), | ||||||
|  |         ClockSkew = TimeSpan.Zero | ||||||
|  |     }; | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | builder.Services.AddAuthorization(options => { | ||||||
|  |     options.DefaultPolicy = new AuthorizationPolicyBuilder() | ||||||
|  |                                 .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme) | ||||||
|  |                                 .RequireAuthenticatedUser() | ||||||
|  |                                 .Build(); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | builder.Services.AddHttpClient(); | ||||||
|  |  | ||||||
|  | builder.Services.AddCors(options => { | ||||||
|  |     options.AddDefaultPolicy(options => { | ||||||
|  |         options.AllowAnyOrigin(); | ||||||
|  |         options.AllowAnyMethod(); | ||||||
|  |         options.AllowAnyHeader(); | ||||||
|  |     }); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | builder.Services.AddScoped<IDbConnectionService, DbConnectionService>(); | ||||||
|  | builder.Services.AddScoped<IDalService, DalService>(); | ||||||
|  | builder.Services.AddScoped<SmtpClient>((serviceProvider) => { | ||||||
|  |     return new SmtpClient("mailrelay-external.infineon.com"); | ||||||
|  | }); | ||||||
|  | builder.Services.AddScoped<ISmtpClientWrapper, SmtpClientWrapper>(); | ||||||
|  | builder.Services.AddScoped<ICustomerService, CustomerService>(); | ||||||
|  | builder.Services.AddScoped<ICAService, CAService>(); | ||||||
|  | builder.Services.AddScoped<IECNService, ECNService>(); | ||||||
|  | builder.Services.AddScoped<ISmtpService, SmtpService>(); | ||||||
|  | builder.Services.AddScoped<IUserService, UserService>(); | ||||||
|  | builder.Services.AddScoped<IMonInWorkerClient, MonInWorkerClient>(); | ||||||
|  | builder.Services.AddScoped<IAuthenticationService, AuthenticationService>(); | ||||||
|  | builder.Services.AddScoped<IMRBService, MRBService>(); | ||||||
|  | builder.Services.AddScoped<IPCRBService, PCRBService>(); | ||||||
|  | builder.Services.AddScoped<IApprovalService, ApprovalService>(); | ||||||
|  |  | ||||||
|  | builder.Services.AddControllers(); | ||||||
|  |  | ||||||
|  | #if DEBUG | ||||||
|  | builder.Services.AddEndpointsApiExplorer(); | ||||||
|  | builder.Services.AddSwaggerGen(c => { | ||||||
|  |     c.SwaggerDoc("v1", new OpenApiInfo { | ||||||
|  |         Title = "Mesa Fab Approval API", | ||||||
|  |         Version = "v1" | ||||||
|  |     }); | ||||||
|  |     c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { | ||||||
|  |         In = ParameterLocation.Header, | ||||||
|  |         Description = "Please insert JWT with Bearer into field", | ||||||
|  |         Name = "Authorization", | ||||||
|  |         Type = SecuritySchemeType.ApiKey | ||||||
|  |     }); | ||||||
|  |     c.AddSecurityRequirement(new OpenApiSecurityRequirement { | ||||||
|  |    { | ||||||
|  |      new OpenApiSecurityScheme | ||||||
|  |      { | ||||||
|  |        Reference = new OpenApiReference | ||||||
|  |        { | ||||||
|  |          Type = ReferenceType.SecurityScheme, | ||||||
|  |          Id = "Bearer" | ||||||
|  |        } | ||||||
|  |       }, | ||||||
|  |       new string[] { } | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | }); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | WebApplication app = builder.Build(); | ||||||
|  |  | ||||||
|  | if (Debugger.IsAttached) | ||||||
|  |     app.Services.GetRequiredService<IApprovalService>(); | ||||||
|  |  | ||||||
|  | app.UseCors(); | ||||||
|  |  | ||||||
|  | // Configure the HTTP request pipeline. | ||||||
|  | if (app.Environment.IsDevelopment()) { | ||||||
|  |     app.UseSwagger(); | ||||||
|  |     app.UseSwaggerUI(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // app.UseHttpLogging(); | ||||||
|  |  | ||||||
|  | app.UseAuthentication(); | ||||||
|  |  | ||||||
|  | app.UseAuthorization(); | ||||||
|  |  | ||||||
|  | app.MapControllers(); | ||||||
|  |  | ||||||
|  | app.Run(); | ||||||
|  |  | ||||||
|  | NLog.LogManager.Flush(); | ||||||
|  | NLog.LogManager.Shutdown(); | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <!-- | ||||||
|  | https://go.microsoft.com/fwlink/?LinkID=208121. | ||||||
|  | --> | ||||||
|  | <Project> | ||||||
|  |   <PropertyGroup> | ||||||
|  |     <DeleteExistingFiles>true</DeleteExistingFiles> | ||||||
|  |     <ExcludeApp_Data>false</ExcludeApp_Data> | ||||||
|  |     <LaunchSiteAfterPublish>true</LaunchSiteAfterPublish> | ||||||
|  |     <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration> | ||||||
|  |     <LastUsedPlatform>Any CPU</LastUsedPlatform> | ||||||
|  |     <PublishProvider>FileSystem</PublishProvider> | ||||||
|  |     <PublishUrl>bin\Release\net8.0\publish\</PublishUrl> | ||||||
|  |     <WebPublishMethod>FileSystem</WebPublishMethod> | ||||||
|  |     <_TargetId>Folder</_TargetId> | ||||||
|  |     <SiteUrlToLaunchAfterPublish /> | ||||||
|  |     <TargetFramework>net8.0</TargetFramework> | ||||||
|  |     <RuntimeIdentifier>win-x64</RuntimeIdentifier> | ||||||
|  |     <ProjectGuid>852e528d-015a-43b5-999d-f281e3359e5e</ProjectGuid> | ||||||
|  |     <SelfContained>true</SelfContained> | ||||||
|  |     <PublishReadyToRun>true</PublishReadyToRun> | ||||||
|  |   </PropertyGroup> | ||||||
|  | </Project> | ||||||
							
								
								
									
										320
									
								
								MesaFabApproval.API/Services/ApprovalService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										320
									
								
								MesaFabApproval.API/Services/ApprovalService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,320 @@ | |||||||
|  | using System.Text; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  | using MesaFabApproval.Shared.Utilities; | ||||||
|  |  | ||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Services; | ||||||
|  |  | ||||||
|  | public interface IApprovalService { | ||||||
|  |     Task<int> GetRoleIdForRoleName(string roleName); | ||||||
|  |     Task<IEnumerable<SubRole>> GetSubRolesForSubRoleName(string subRoleName, int roleId); | ||||||
|  |     Task<IEnumerable<User>> GetApprovalGroupMembers(int subRoleId); | ||||||
|  |     Task CreateApproval(Approval approval); | ||||||
|  |     Task UpdateApproval(Approval approval); | ||||||
|  |     Task Approve(Approval approval); | ||||||
|  |     Task Deny(Approval approval); | ||||||
|  |     Task<IEnumerable<Approval>> GetApprovalsForIssueId(int issueId, bool bypassCache); | ||||||
|  |     Task<IEnumerable<Approval>> GetApprovalsForUserId(int userId, bool bypassCache); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class ApprovalService : IApprovalService { | ||||||
|  |     private readonly ILogger<ApprovalService> _logger; | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly IDalService _dalService; | ||||||
|  |     private readonly IUserService _userService; | ||||||
|  |  | ||||||
|  |     public ApprovalService(ILogger<ApprovalService> logger, IMemoryCache cache, IDalService dalService, IUserService userService) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _dalService = dalService ?? throw new ArgumentNullException("IDalService not injected"); | ||||||
|  |         _userService = userService ?? throw new ArgumentNullException("IUserService not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task CreateApproval(Approval approval) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to generate new Approval"); | ||||||
|  |  | ||||||
|  |             if (approval is null) throw new ArgumentNullException("Approval cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append("insert into Approval (IssueID, RoleName, SubRole, UserID, SubRoleID, ItemStatus, "); | ||||||
|  |             queryBuilder.Append("AssignedDate, DocumentTypeID, DisplayDeniedDocument, Step, TaskID) "); | ||||||
|  |             queryBuilder.Append($"values ({approval.IssueID}, '{approval.RoleName}', '{approval.SubRole}', {approval.UserID}, "); | ||||||
|  |             queryBuilder.Append($"{approval.SubRoleID}, 0, '{approval.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"3, 0, {approval.Step}, {approval.TaskID});"); | ||||||
|  |  | ||||||
|  |             int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsCreated <= 0) throw new Exception("Unable to insert approval in database"); | ||||||
|  |  | ||||||
|  |             await GetApprovalsForIssueId(approval.IssueID, true); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to create new Approval. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<Approval>> GetApprovalsForIssueId(int issueId, bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get all approvals for issue {issueId}"); | ||||||
|  |  | ||||||
|  |             if (issueId <= 0) throw new ArgumentException($"{issueId} is not a valid issue ID"); | ||||||
|  |  | ||||||
|  |             IEnumerable<Approval>? approvals = new List<Approval>(); | ||||||
|  |  | ||||||
|  |             if (!bypassCache) | ||||||
|  |                 approvals = _cache.Get<IEnumerable<Approval>>($"approvals{issueId}"); | ||||||
|  |  | ||||||
|  |             if (approvals is null || approvals.Count() == 0) { | ||||||
|  |                 StringBuilder queryBuilder = new(); | ||||||
|  |                 queryBuilder.Append("select a.*, src.SubRoleCategoryItem from Approval a "); | ||||||
|  |                 queryBuilder.Append("join SubRole sr on a.SubRoleID=sr.SubRoleID "); | ||||||
|  |                 queryBuilder.Append("join SubRoleCategory src on sr.SubRoleCategoryID=src.SubRoleCategoryID "); | ||||||
|  |                 queryBuilder.Append($"where a.IssueID={issueId}"); | ||||||
|  |  | ||||||
|  |                 approvals = (await _dalService.QueryAsync<Approval>(queryBuilder.ToString())).ToList(); | ||||||
|  |  | ||||||
|  |                 foreach (Approval approval in approvals) { | ||||||
|  |                     int successfulUpdates = 0; | ||||||
|  |  | ||||||
|  |                     User? user = await _userService.GetUserByUserId(approval.UserID); | ||||||
|  |                     if (user is not null) { | ||||||
|  |                         approval.User = user; | ||||||
|  |                         successfulUpdates++; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     if (approval.ItemStatus < 0) | ||||||
|  |                         approval.StatusMessage = "Denied"; | ||||||
|  |                     if (approval.ItemStatus == 0) | ||||||
|  |                         approval.StatusMessage = "Assigned"; | ||||||
|  |                     if (approval.ItemStatus > 0) | ||||||
|  |                         approval.StatusMessage = "Approved"; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 _cache.Set($"approvals{issueId}", approvals, DateTimeOffset.Now.AddMinutes(5)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return approvals; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to fetch approvals for issue {issueId}, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<int> GetRoleIdForRoleName(string roleName) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get role ID by name"); | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(roleName)) | ||||||
|  |                 throw new ArgumentException("Role name cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             int roleId = _cache.Get<int>($"role{roleName}"); | ||||||
|  |  | ||||||
|  |             if (roleId <= 0) { | ||||||
|  |                 string sql = $"select RoleID from Role where RoleName = '{roleName}'"; | ||||||
|  |  | ||||||
|  |                 roleId = (await _dalService.QueryAsync<int>(sql)).ToList().FirstOrDefault(); | ||||||
|  |  | ||||||
|  |                 if (roleId > 0) | ||||||
|  |                     _cache.Set($"role{roleName}", roleId, DateTimeOffset.Now.AddDays(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (roleId <= 0) | ||||||
|  |                 throw new Exception($"Unable to find role with name {roleName}"); | ||||||
|  |  | ||||||
|  |             return roleId; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to find role ID, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<SubRole>> GetSubRolesForSubRoleName(string subRoleName, int roleId) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get sub role ID by name for role ID {roleId}"); | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(subRoleName)) | ||||||
|  |                 throw new ArgumentException("sub role name cannot be null or empty"); | ||||||
|  |             if (roleId <= 0) throw new ArgumentException($"{roleId} is not a valid role ID"); | ||||||
|  |  | ||||||
|  |             IEnumerable<SubRole>? subRoles = _cache.Get<IEnumerable<SubRole>>($"subRoles{subRoleName}"); | ||||||
|  |  | ||||||
|  |             if (subRoles is null || subRoles.Count() <= 0) { | ||||||
|  |                 StringBuilder queryBuilder = new(); | ||||||
|  |                 queryBuilder.Append("select src.SubRoleCategoryID, sr.SubRole as SubRoleName, src.SubRoleCategoryItem, sr.SubRoleID "); | ||||||
|  |                 queryBuilder.Append("from SubRole sr join SubRoleCategory src on sr.SubRoleCategoryID=src.SubRoleCategoryID "); | ||||||
|  |                 queryBuilder.Append($"where sr.RoleID={roleId} and sr.SubRole='{subRoleName}' and sr.Inactive=0"); | ||||||
|  |  | ||||||
|  |                 subRoles = (await _dalService.QueryAsync<SubRole>(queryBuilder.ToString())).ToList(); | ||||||
|  |  | ||||||
|  |                 if (subRoles is not null && subRoles.Count() > 0) | ||||||
|  |                     _cache.Set($"subRole{subRoleName}", subRoles, DateTimeOffset.Now.AddDays(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (subRoles is null || subRoles.Count() <= 0) | ||||||
|  |                 throw new Exception($"Unable to find sub role with name {subRoleName} for role {roleId}"); | ||||||
|  |  | ||||||
|  |             return subRoles; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to find sub roles, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<User>> GetApprovalGroupMembers(int subRoleId) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get members of sub role {subRoleId}"); | ||||||
|  |  | ||||||
|  |             if (subRoleId <= 0) throw new ArgumentException($"{subRoleId} is not a valid sub role ID"); | ||||||
|  |  | ||||||
|  |             List<User>? members = _cache.Get<List<User>>($"approvalMembers{subRoleId}"); | ||||||
|  |  | ||||||
|  |             if (members is null || members.Count() <= 0) { | ||||||
|  |                 IEnumerable<int>? memberIds = _cache.Get<IEnumerable<int>>($"approvalMemberIds{subRoleId}"); | ||||||
|  |  | ||||||
|  |                 if (memberIds is null) { | ||||||
|  |                     string sql = $"select UserID from UserSubRole where SubRoleID = {subRoleId};"; | ||||||
|  |  | ||||||
|  |                     memberIds = await _dalService.QueryAsync<int>(sql); | ||||||
|  |  | ||||||
|  |                     if (memberIds is null || memberIds.Count() <= 0) | ||||||
|  |                         throw new Exception($"No members found in sub role {subRoleId}"); | ||||||
|  |  | ||||||
|  |                     _cache.Set($"approvalMemberIds{subRoleId}", memberIds, DateTimeOffset.Now.AddMinutes(5)); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 members = new(); | ||||||
|  |                 foreach (int id in memberIds) { | ||||||
|  |                     User member = await _userService.GetUserByUserId(id); | ||||||
|  |  | ||||||
|  |                     members.Add(member); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if (members.Count() <= 0) throw new Exception("No users found with IDs matching those found in SubRole"); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"approvalMembers{subRoleId}", members, DateTimeOffset.Now.AddMinutes(5)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return members; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to get sub role {subRoleId} members, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<Approval>> GetApprovalsForUserId(int userId, bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get approvals for user ID {userId}"); | ||||||
|  |  | ||||||
|  |             if (userId <= 0) throw new ArgumentException($"{userId} is not a valid user ID"); | ||||||
|  |  | ||||||
|  |             IEnumerable<Approval>? approvals = null; | ||||||
|  |  | ||||||
|  |             if (!bypassCache) approvals = _cache.Get<IEnumerable<Approval>>($"approvalMembers{userId}"); | ||||||
|  |  | ||||||
|  |             if (approvals is null) { | ||||||
|  |                 StringBuilder queryBuilder = new(); | ||||||
|  |                 queryBuilder.Append($"select a.*, src.SubRoleCategoryItem from Approval a "); | ||||||
|  |                 queryBuilder.Append("join SubRole sr on a.SubRoleID=sr.SubRoleID "); | ||||||
|  |                 queryBuilder.Append("join SubRoleCategory src on sr.SubRoleCategoryID=src.SubRoleCategoryID "); | ||||||
|  |                 queryBuilder.Append($"where UserID={userId} and "); | ||||||
|  |                 queryBuilder.Append($"((CompletedDate >= '{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}') or "); | ||||||
|  |                 queryBuilder.Append($"(CompletedDate is null));"); | ||||||
|  |                 string sql = queryBuilder.ToString(); | ||||||
|  |  | ||||||
|  |                 approvals = (await _dalService.QueryAsync<Approval>(sql)).ToList(); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"approvalMembers{userId}", approvals, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return approvals; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to get approvals for user ID {userId}, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdateApproval(Approval approval) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to update an approval"); | ||||||
|  |  | ||||||
|  |             if (approval is null) throw new ArgumentNullException("Approval cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append($"update Approval set IssueID={approval.IssueID}, RoleName='{approval.RoleName}', "); | ||||||
|  |             queryBuilder.Append($"SubRole='{approval.SubRole}', UserID={approval.UserID}, SubRoleID={approval.SubRoleID}, "); | ||||||
|  |             queryBuilder.Append($"ItemStatus={Convert.ToInt32(approval.ItemStatus)}, Step={approval.Step}, "); | ||||||
|  |             queryBuilder.Append($"NotifyDate='{approval.NotifyDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"AssignedDate='{approval.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"CompletedDate='{approval.CompletedDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"Comments='{approval.Comments.Replace("'", "''")}', "); | ||||||
|  |             queryBuilder.Append($"TaskID={approval.TaskID} "); | ||||||
|  |             queryBuilder.Append($"where ApprovalID={approval.ApprovalID};"); | ||||||
|  |  | ||||||
|  |             int rowsUpdated = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsUpdated <= 0) throw new Exception("Unable to update approval in database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Approval update failed, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task Approve(Approval approval) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to submit approval"); | ||||||
|  |  | ||||||
|  |             if (approval is null) throw new ArgumentNullException("Approval cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append($"update Approval set IssueID={approval.IssueID}, RoleName='{approval.RoleName}', "); | ||||||
|  |             queryBuilder.Append($"SubRole='{approval.SubRole}', UserID={approval.UserID}, SubRoleID={approval.SubRoleID}, "); | ||||||
|  |             queryBuilder.Append($"ItemStatus=1, Step={approval.Step}, "); | ||||||
|  |             if (approval.NotifyDate < DateTimeUtilities.MIN_DT) | ||||||
|  |                 approval.NotifyDate = DateTimeUtilities.MIN_DT; | ||||||
|  |             queryBuilder.Append($"NotifyDate='{approval.NotifyDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"AssignedDate='{approval.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"CompletedDate='{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"Comments='{approval.Comments}', "); | ||||||
|  |             queryBuilder.Append($"TaskID={approval.TaskID} "); | ||||||
|  |             queryBuilder.Append($"where ApprovalID={approval.ApprovalID};"); | ||||||
|  |  | ||||||
|  |             int rowsUpdated = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsUpdated <= 0) throw new Exception("Unable to submit approval in database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Approval failed, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task Deny(Approval approval) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to deny approval"); | ||||||
|  |  | ||||||
|  |             if (approval is null) throw new ArgumentNullException("Approval cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append($"update Approval set IssueID={approval.IssueID}, RoleName='{approval.RoleName}', "); | ||||||
|  |             queryBuilder.Append($"SubRole='{approval.SubRole}', UserID={approval.UserID}, SubRoleID={approval.SubRoleID}, "); | ||||||
|  |             queryBuilder.Append($"ItemStatus=-1, Step={approval.Step}, "); | ||||||
|  |             if (approval.NotifyDate < DateTimeUtilities.MIN_DT) | ||||||
|  |                 approval.NotifyDate = DateTimeUtilities.MIN_DT; | ||||||
|  |             queryBuilder.Append($"NotifyDate='{approval.NotifyDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"AssignedDate='{approval.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"CompletedDate='{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"Comments='{approval.Comments}', "); | ||||||
|  |             queryBuilder.Append($"TaskID={approval.TaskID} "); | ||||||
|  |             queryBuilder.Append($"where ApprovalID={approval.ApprovalID};"); | ||||||
|  |  | ||||||
|  |             int rowsUpdated = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsUpdated <= 0) throw new Exception("Unable to deny approval in database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Approval denial failed, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										251
									
								
								MesaFabApproval.API/Services/AuthenticationService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								MesaFabApproval.API/Services/AuthenticationService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,251 @@ | |||||||
|  | using System.DirectoryServices.AccountManagement; | ||||||
|  | using System.IdentityModel.Tokens.Jwt; | ||||||
|  | using System.Security.Authentication; | ||||||
|  | using System.Security.Claims; | ||||||
|  | using System.Security.Cryptography; | ||||||
|  | using System.Security.Principal; | ||||||
|  | using System.Text; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.API.Services; | ||||||
|  | using MesaFabApproval.Models; | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  |  | ||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  | using Microsoft.IdentityModel.Tokens; | ||||||
|  |  | ||||||
|  | namespace MesaFabApprovalAPI.Services; | ||||||
|  |  | ||||||
|  | public interface IAuthenticationService { | ||||||
|  |     public Task<LoginResult> AuthenticateUser(AuthAttempt login); | ||||||
|  |     public Task<LoginResult> AttemptLocalUserAuth(WindowsIdentity identity); | ||||||
|  |     public AuthTokens GenerateAuthTokens(AuthAttempt authAttempt, IEnumerable<string> roles); | ||||||
|  |     public Task<LoginResult> RefreshAuthTokens(AuthAttempt authAttempt); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class AuthenticationService : IAuthenticationService { | ||||||
|  |     private readonly ILogger<AuthenticationService> _logger; | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly IUserService _userService; | ||||||
|  |  | ||||||
|  |     private readonly string _jwtIssuer; | ||||||
|  |     private readonly string _jwtAudience; | ||||||
|  |     private readonly string _jwtKey; | ||||||
|  |  | ||||||
|  |     public AuthenticationService(ILogger<AuthenticationService> logger, IMemoryCache cache, IUserService userService, AppSettings appSettings) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _userService = userService ?? throw new ArgumentNullException("IUserService not injected"); | ||||||
|  |         _jwtKey = appSettings.JwtKey; | ||||||
|  |         _jwtIssuer = appSettings.JwtIssuer; | ||||||
|  |         _jwtAudience = appSettings.JwtAudience; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<LoginResult> AuthenticateUser(AuthAttempt login) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to authenticate user"); | ||||||
|  |  | ||||||
|  |             if (login is null) throw new ArgumentNullException("Login cannot be null"); | ||||||
|  |  | ||||||
|  |             string domain = "infineon.com"; | ||||||
|  |  | ||||||
|  |             using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain)) { | ||||||
|  |                 bool isValid = pc.ValidateCredentials(login.LoginID, login.Password); | ||||||
|  |  | ||||||
|  |                 if (isValid) { | ||||||
|  |                     User? user = _cache.Get<User>($"user{login.LoginID}"); | ||||||
|  |  | ||||||
|  |                     if (user is null) { | ||||||
|  |                         user = await _userService.GetUserByLoginId(login.LoginID); | ||||||
|  |  | ||||||
|  |                         _cache.Set<User>($"user{login.LoginID}", user, DateTimeOffset.Now.AddDays(1)); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     List<string> roles = new(); | ||||||
|  |  | ||||||
|  |                     if (user.IsManager) roles.Add("manager"); | ||||||
|  |                     if (user.IsAdmin) roles.Add("admin"); | ||||||
|  |  | ||||||
|  |                     AuthTokens tokens = GenerateAuthTokens(login, roles); | ||||||
|  |  | ||||||
|  |                     return new LoginResult { | ||||||
|  |                         IsAuthenticated = true, | ||||||
|  |                         AuthTokens = tokens, | ||||||
|  |                         User = user | ||||||
|  |                     }; | ||||||
|  |                 } else { | ||||||
|  |                     return new LoginResult() { | ||||||
|  |                         IsAuthenticated = false, | ||||||
|  |                         AuthTokens = new() { | ||||||
|  |                             JwtToken = "", | ||||||
|  |                             RefreshToken = "" | ||||||
|  |                         }, | ||||||
|  |                         User = null | ||||||
|  |                     }; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to authenticate user. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<LoginResult> AttemptLocalUserAuth(WindowsIdentity identity) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to authenticate local Windows system user"); | ||||||
|  |  | ||||||
|  |             if (identity is null) throw new ArgumentNullException("WindowsIdentity cannot be null"); | ||||||
|  |  | ||||||
|  |             User user = await _userService.GetUserByLoginId(identity.Name); | ||||||
|  |  | ||||||
|  |             List<string> roles = new(); | ||||||
|  |  | ||||||
|  |             if (user.IsManager) roles.Add("manager"); | ||||||
|  |             if (user.IsAdmin) roles.Add("admin"); | ||||||
|  |  | ||||||
|  |             AuthAttempt authAttempt = new() { | ||||||
|  |                 LoginID = user.LoginID, | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             AuthTokens tokens = GenerateAuthTokens(authAttempt, roles); | ||||||
|  |  | ||||||
|  |             return new LoginResult { | ||||||
|  |                 IsAuthenticated = true, | ||||||
|  |                 AuthTokens = tokens, | ||||||
|  |                 User = user | ||||||
|  |             }; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to authenticate local Windows system user, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public AuthTokens GenerateAuthTokens(AuthAttempt authAttempt, IEnumerable<string> roles) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to generate JWT"); | ||||||
|  |  | ||||||
|  |             if (authAttempt is null) throw new ArgumentNullException("AuthAttempt cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(authAttempt.LoginID)) throw new ArgumentException("UserName cannot be null or empty"); | ||||||
|  |             if (roles is null) throw new ArgumentNullException("roles cannot be null"); | ||||||
|  |  | ||||||
|  |             byte[] key = Encoding.ASCII.GetBytes(_jwtKey); | ||||||
|  |  | ||||||
|  |             List<Claim> claims = new() { | ||||||
|  |                 new Claim(nameof(authAttempt.LoginID), authAttempt.LoginID) | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             foreach (string role in roles) { | ||||||
|  |                 claims.Add(new Claim(ClaimTypes.Role, role)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             ClaimsIdentity identity = new ClaimsIdentity(claims); | ||||||
|  |  | ||||||
|  |             SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor { | ||||||
|  |                 Issuer = _jwtIssuer, | ||||||
|  |                 Audience = _jwtAudience, | ||||||
|  |                 Subject = identity, | ||||||
|  |                 NotBefore = DateTime.Now, | ||||||
|  |                 Expires = DateTime.Now.AddHours(8), | ||||||
|  |                 SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); | ||||||
|  |  | ||||||
|  |             JwtSecurityToken token = tokenHandler.CreateJwtSecurityToken(tokenDescriptor); | ||||||
|  |  | ||||||
|  |             string jwt = tokenHandler.WriteToken(token); | ||||||
|  |  | ||||||
|  |             string refreshToken = GenerateRefreshToken(); | ||||||
|  |  | ||||||
|  |             List<string>? refreshTokensForUser = _cache.Get<List<string>>(authAttempt.LoginID); | ||||||
|  |  | ||||||
|  |             if (refreshTokensForUser is null) | ||||||
|  |                 refreshTokensForUser = new List<string>(); | ||||||
|  |  | ||||||
|  |             if (refreshTokensForUser.Count > 9) | ||||||
|  |                 refreshTokensForUser.RemoveRange(9, refreshTokensForUser.Count - 9); | ||||||
|  |  | ||||||
|  |             refreshTokensForUser.Insert(0, refreshToken); | ||||||
|  |  | ||||||
|  |             _cache.Set<List<string>>(authAttempt.LoginID, refreshTokensForUser, DateTimeOffset.Now.AddHours(4)); | ||||||
|  |  | ||||||
|  |             return new AuthTokens { | ||||||
|  |                 JwtToken = jwt, | ||||||
|  |                 RefreshToken = refreshToken | ||||||
|  |             }; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to generate JWT. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<LoginResult> RefreshAuthTokens(AuthAttempt authAttempt) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to refresh auth tokens"); | ||||||
|  |  | ||||||
|  |             if (authAttempt is null) throw new ArgumentNullException("AuthAttempt cannot be null"); | ||||||
|  |             if (authAttempt.AuthTokens is null) throw new ArgumentNullException("AuthTokens cannot be null"); | ||||||
|  |  | ||||||
|  |             bool refreshTokenIsValid = IsRefreshTokenValid(authAttempt.LoginID, authAttempt.AuthTokens.RefreshToken); | ||||||
|  |  | ||||||
|  |             if (refreshTokenIsValid) { | ||||||
|  |                 User? user = _cache.Get<User>($"user{authAttempt.LoginID}"); | ||||||
|  |  | ||||||
|  |                 if (user is null) { | ||||||
|  |                     user = await _userService.GetUserByLoginId(authAttempt.LoginID); | ||||||
|  |  | ||||||
|  |                     _cache.Set<User>($"user{authAttempt.LoginID}", user, DateTimeOffset.Now.AddDays(1)); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 List<string> roles = new(); | ||||||
|  |  | ||||||
|  |                 if (user.IsManager) roles.Add("manager"); | ||||||
|  |                 if (user.IsAdmin) roles.Add("admin"); | ||||||
|  |  | ||||||
|  |                 AuthTokens refreshedTokens = GenerateAuthTokens(authAttempt, roles); | ||||||
|  |  | ||||||
|  |                 LoginResult loginResult = new LoginResult() { | ||||||
|  |                     IsAuthenticated = true, | ||||||
|  |                     AuthTokens = refreshedTokens, | ||||||
|  |                     User = user | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 return loginResult; | ||||||
|  |             } else { | ||||||
|  |                 throw new AuthenticationException("Invalid refresh token"); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to refresh auth tokens. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private string GenerateRefreshToken() { | ||||||
|  |         byte[] randomNumber = new byte[32]; | ||||||
|  |         using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) { | ||||||
|  |             rng.GetBytes(randomNumber); | ||||||
|  |             return Convert.ToBase64String(randomNumber); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private bool IsRefreshTokenValid(string loginId, string refreshToken) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to determine if refresh token is valid"); | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(loginId)) throw new ArgumentNullException("LoginID cannot be null or empty"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(refreshToken)) | ||||||
|  |                 throw new ArgumentNullException("Refresh token cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             List<string>? cachedRefreshTokensForUser = _cache.Get<List<string>>(loginId); | ||||||
|  |  | ||||||
|  |             if (cachedRefreshTokensForUser is null || !cachedRefreshTokensForUser.Contains(refreshToken)) { | ||||||
|  |                 _logger.LogInformation($"Could not find cached refresh tokens for user {loginId}"); | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return true; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to validate refresh token. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										46
									
								
								MesaFabApproval.API/Services/CAService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								MesaFabApproval.API/Services/CAService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | |||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Services; | ||||||
|  |  | ||||||
|  | public interface ICAService { | ||||||
|  |     Task<bool> IsValidCANumber(int number); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class CAService : ICAService { | ||||||
|  |     private readonly ILogger<CAService> _logger; | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly IDalService _dalService; | ||||||
|  |  | ||||||
|  |     public CAService(ILogger<CAService> logger, IMemoryCache cache, IDalService dalService) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _dalService = dalService ?? throw new ArgumentNullException("IDalService not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<bool> IsValidCANumber(int number) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to determine if {number} is a valid CA#"); | ||||||
|  |  | ||||||
|  |             if (number <= 0) return false; | ||||||
|  |  | ||||||
|  |             IEnumerable<int> caNumbers = _cache.Get<IEnumerable<int>>("caNumbers") ?? new HashSet<int>(); | ||||||
|  |  | ||||||
|  |             if (caNumbers.Contains(number)) return true; | ||||||
|  |  | ||||||
|  |             string sql = $"select count(CANo) as count from _8DCorrectiveAction where CANo={number}"; | ||||||
|  |  | ||||||
|  |             int rowsReturned = (await _dalService.QueryAsync<int>(sql)).FirstOrDefault(); | ||||||
|  |  | ||||||
|  |             if (rowsReturned > 0) { | ||||||
|  |                 caNumbers.Append(number); | ||||||
|  |                 _cache.Set("caNumbers", caNumbers); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to determine if {number} is a valid CA#, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										38
									
								
								MesaFabApproval.API/Services/CustomerService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								MesaFabApproval.API/Services/CustomerService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | |||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Services; | ||||||
|  |  | ||||||
|  | public interface ICustomerService { | ||||||
|  |     Task<IEnumerable<string>> GetCustomerNames(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class CustomerService : ICustomerService { | ||||||
|  |     private readonly ILogger<CustomerService> _logger; | ||||||
|  |     private readonly IDalService _dalService; | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |  | ||||||
|  |     public CustomerService(ILogger<CustomerService> logger, IDalService dalService, IMemoryCache cache) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _dalService = dalService ?? throw new ArgumentNullException("IDalService not injected"); | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<string>> GetCustomerNames() { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get customer names"); | ||||||
|  |  | ||||||
|  |             IEnumerable<string>? customerNames = _cache.Get<IEnumerable<string>>("allCustomerNames"); | ||||||
|  |  | ||||||
|  |             if (customerNames is null) { | ||||||
|  |                 string sql = "select ProductFamily from ProductFamilies;"; | ||||||
|  |  | ||||||
|  |                 customerNames = (await _dalService.QueryAsync<string>(sql)).ToList(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return customerNames; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to get customer names, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										89
									
								
								MesaFabApproval.API/Services/DalService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								MesaFabApproval.API/Services/DalService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,89 @@ | |||||||
|  | using System.Data; | ||||||
|  |  | ||||||
|  | using Dapper; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Services; | ||||||
|  |  | ||||||
|  | public interface IDalService { | ||||||
|  |     Task<IEnumerable<T>> QueryAsync<T>(string sql); | ||||||
|  |     Task<int> ExecuteAsync(string sql); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class DalService : IDalService { | ||||||
|  |     private static readonly int RETRIES = 3; | ||||||
|  |     private static readonly int BACKOFF_SECONDS_INTERVAL = 30; | ||||||
|  |  | ||||||
|  |     private readonly ILogger<DalService> _logger; | ||||||
|  |     private readonly IDbConnectionService _dbConnectionService; | ||||||
|  |  | ||||||
|  |     public DalService(IDbConnectionService dbConnectionService, ILogger<DalService> logger) { | ||||||
|  |         _dbConnectionService = dbConnectionService ?? | ||||||
|  |             throw new ArgumentNullException("IDbConnectionService not injected"); | ||||||
|  |         _logger = logger ?? | ||||||
|  |             throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<T>> QueryAsync<T>(string sql) { | ||||||
|  |         if (sql is null) throw new ArgumentNullException("sql cannot be null"); | ||||||
|  |  | ||||||
|  |         int remainingRetries = RETRIES; | ||||||
|  |         bool queryWasSuccessful = false; | ||||||
|  |         Exception exception = null; | ||||||
|  |         IEnumerable<T> result = new List<T>(); | ||||||
|  |         while (!queryWasSuccessful && remainingRetries > 0) { | ||||||
|  |             int backoffSeconds = (RETRIES - remainingRetries--) * BACKOFF_SECONDS_INTERVAL; | ||||||
|  |             Task.Delay(backoffSeconds * 1000).Wait(); | ||||||
|  |  | ||||||
|  |             try { | ||||||
|  |                 _logger.LogInformation($"Attempting to perform query with {sql}. Remaining retries: {remainingRetries}"); | ||||||
|  |  | ||||||
|  |                 using (IDbConnection conn = _dbConnectionService.GetConnection()) { | ||||||
|  |                     result = await conn.QueryAsync<T>(sql); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 queryWasSuccessful = true; | ||||||
|  |             } catch (Exception ex) { | ||||||
|  |                 _logger.LogError($"An exception occurred while attempting to perform a query. Exception: {ex.Message}"); | ||||||
|  |                 exception = ex; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!queryWasSuccessful && exception is not null) { | ||||||
|  |             throw exception; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<int> ExecuteAsync(string sql) { | ||||||
|  |         if (sql is null) throw new ArgumentNullException("sql cannot be null"); | ||||||
|  |  | ||||||
|  |         int remainingRetries = RETRIES; | ||||||
|  |         bool queryWasSuccessful = false; | ||||||
|  |         Exception exception = null; | ||||||
|  |         int rowsAffected = 0; | ||||||
|  |         while (!queryWasSuccessful && remainingRetries > 0) { | ||||||
|  |             int backoffSeconds = (RETRIES - remainingRetries--) * BACKOFF_SECONDS_INTERVAL; | ||||||
|  |             Task.Delay(backoffSeconds * 1000).Wait(); | ||||||
|  |  | ||||||
|  |             try { | ||||||
|  |                 _logger.LogInformation($"Attempting to execute {sql}. Remaining retries: {remainingRetries}"); | ||||||
|  |  | ||||||
|  |                 using (IDbConnection conn = _dbConnectionService.GetConnection()) { | ||||||
|  |                     rowsAffected = await conn.ExecuteAsync(sql); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 queryWasSuccessful = true; | ||||||
|  |             } catch (Exception ex) { | ||||||
|  |                 _logger.LogError($"An exception occurred while attempting to execute a query. Exception: {ex.Message}"); | ||||||
|  |                 exception = ex; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!queryWasSuccessful && exception is not null) { | ||||||
|  |             throw exception; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return rowsAffected; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								MesaFabApproval.API/Services/DbConnectionService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								MesaFabApproval.API/Services/DbConnectionService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | using System.Data; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.Models; | ||||||
|  |  | ||||||
|  | using Microsoft.Data.SqlClient; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Services; | ||||||
|  |  | ||||||
|  | public interface IDbConnectionService { | ||||||
|  |     IDbConnection GetConnection(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class DbConnectionService : IDbConnectionService { | ||||||
|  |     private readonly string _dbConnectionString; | ||||||
|  |  | ||||||
|  |     public DbConnectionService(AppSettings appSettings) { | ||||||
|  |         _dbConnectionString = appSettings.DbConnectionString; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public IDbConnection GetConnection() => | ||||||
|  |         new SqlConnection(_dbConnectionString); | ||||||
|  | } | ||||||
							
								
								
									
										46
									
								
								MesaFabApproval.API/Services/ECNService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								MesaFabApproval.API/Services/ECNService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | |||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Services; | ||||||
|  |  | ||||||
|  | public interface IECNService { | ||||||
|  |     Task<bool> IsValidECNNumber(int number); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class ECNService : IECNService { | ||||||
|  |     private readonly ILogger<ECNService> _logger; | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly IDalService _dalService; | ||||||
|  |  | ||||||
|  |     public ECNService(ILogger<ECNService> logger, IMemoryCache cache, IDalService dalService) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _dalService = dalService ?? throw new ArgumentNullException("IDalService not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<bool> IsValidECNNumber(int number) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to determine if {number} is a valid ECN#"); | ||||||
|  |  | ||||||
|  |             if (number <= 0) return false; | ||||||
|  |  | ||||||
|  |             IEnumerable<int> ecnNumbers = _cache.Get<IEnumerable<int>>("ecnNumbers") ?? new HashSet<int>(); | ||||||
|  |  | ||||||
|  |             if (ecnNumbers.Contains(number)) return true; | ||||||
|  |  | ||||||
|  |             string sql = $"select count(ECNNumber) as count from ECN where ECNNumber={number}"; | ||||||
|  |  | ||||||
|  |             int rowsReturned = (await _dalService.QueryAsync<int>(sql)).FirstOrDefault(); | ||||||
|  |  | ||||||
|  |             if (rowsReturned > 0) { | ||||||
|  |                 ecnNumbers.Append(number); | ||||||
|  |                 _cache.Set("ecnNumbers", ecnNumbers); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to determine if {number} is a valid ECN#, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										938
									
								
								MesaFabApproval.API/Services/MRBService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										938
									
								
								MesaFabApproval.API/Services/MRBService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,938 @@ | |||||||
|  | using System.Data; | ||||||
|  | using System.Net; | ||||||
|  | using System.Net.Mail; | ||||||
|  | using System.Text; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.API.Utilities; | ||||||
|  | using MesaFabApproval.Models; | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  | using MesaFabApproval.Shared.Utilities; | ||||||
|  |  | ||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Services; | ||||||
|  |  | ||||||
|  | public interface IMRBService { | ||||||
|  |     Task<IEnumerable<MRB>> GetAllMRBs(bool bypassCache); | ||||||
|  |     Task<bool> MRBNumberIsValid(int number); | ||||||
|  |     Task<MRB> GetMRBById(int id, bool bypassCache = false); | ||||||
|  |     Task<MRB> GetMRBByTitle(string title, bool bypassCache); | ||||||
|  |     Task CreateNewMRB(MRB mrb); | ||||||
|  |     Task UpdateMRB(MRB mrb); | ||||||
|  |     Task CreateMRBAction(MRBAction mrbAction); | ||||||
|  |     Task<IEnumerable<MRBAction>> GetMRBActionsForMRB(int mrbNumber, bool bypassCache); | ||||||
|  |     Task UpdateMRBAction(MRBAction mrbAction); | ||||||
|  |     Task DeleteMRBAction(int mrbActionID, int mrbNumber); | ||||||
|  |     Task<IEnumerable<UploadResult>> UploadAttachments(IEnumerable<IFormFile> files, int mrbNumber); | ||||||
|  |     Task<IEnumerable<UploadResult>> UploadActionAttachments(IEnumerable<IFormFile> files, int actionId); | ||||||
|  |     Task<IEnumerable<MRBAttachment>> GetAllAttachmentsForMRB(int mrbNumber, bool bypassCache); | ||||||
|  |     Task<IEnumerable<MRBActionAttachment>> GetAllActionAttachmentsForMRB(int mrbNumber, bool bypassCache); | ||||||
|  |     Task DeleteAttachment(MRBAttachment attachment); | ||||||
|  |     Task NotifyNewApprovals(MRB mrb); | ||||||
|  |     Task NotifyApprovers(MRBNotification notification); | ||||||
|  |     Task NotifyOriginator(MRBNotification notification); | ||||||
|  |     Task NotifyQAPreApprover(MRBNotification notification); | ||||||
|  |     Task DeleteMRB(int mrbNumber); | ||||||
|  |     Task ConvertActionsToCsvFile(int mrbNumber, string path); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class MRBService : IMRBService { | ||||||
|  |     private readonly ILogger<MRBService> _logger; | ||||||
|  |     private readonly IDalService _dalService; | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly IUserService _userService; | ||||||
|  |     private readonly IApprovalService _approvalService; | ||||||
|  |     private readonly ISmtpService _smtpService; | ||||||
|  |  | ||||||
|  |     private readonly string _siteBaseUrl; | ||||||
|  |     private readonly string _mrbAttachmentPath; | ||||||
|  |  | ||||||
|  |     public MRBService(ILogger<MRBService> logger, | ||||||
|  |                       IDalService dalService, | ||||||
|  |                       IMemoryCache cache, | ||||||
|  |                       IUserService userService, | ||||||
|  |                       IApprovalService approvalService, | ||||||
|  |                       ISmtpService smtpService, | ||||||
|  |                       AppSettings appSettings) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _dalService = dalService ?? throw new ArgumentNullException("IDalService not injected"); | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _userService = userService ?? throw new ArgumentNullException("IUserService not injected"); | ||||||
|  |         _approvalService = approvalService ?? throw new ArgumentNullException("IApprovalService not injected"); | ||||||
|  |         _smtpService = smtpService ?? throw new ArgumentNullException("ISmtpService not injected"); | ||||||
|  |         _siteBaseUrl = appSettings.SiteBaseUrl; | ||||||
|  |         _mrbAttachmentPath = appSettings.MrbAttachmentPath; | ||||||
|  |     } | ||||||
|  |     public async Task CreateNewMRB(MRB mrb) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to generate new MRB"); | ||||||
|  |  | ||||||
|  |             if (mrb is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append("insert into MRB (OriginatorID, Title, SubmittedDate, "); | ||||||
|  |             queryBuilder.Append("CloseDate, CancelDate, NumberOfLotsAffected, ApprovalDate, "); | ||||||
|  |             queryBuilder.Append("IssueDescription, CustomerImpacted, Department, Process, Val, RMANo, "); | ||||||
|  |             queryBuilder.Append("PCRBNo, SpecsImpacted, TrainingRequired, Status, StageNo, "); | ||||||
|  |             queryBuilder.Append("CustomerImpactedName, ProcessECNNumber, Tool, Category) values ("); | ||||||
|  |             queryBuilder.Append($"{mrb.OriginatorID}, '{mrb.Title}', "); | ||||||
|  |             if (mrb.SubmittedDate < DateTimeUtilities.MIN_DT) | ||||||
|  |                 mrb.SubmittedDate = DateTimeUtilities.MIN_DT; | ||||||
|  |             queryBuilder.Append($"'{mrb.SubmittedDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             if (mrb.CloseDate > DateTimeUtilities.MAX_DT) | ||||||
|  |                 mrb.CloseDate = DateTimeUtilities.MAX_DT; | ||||||
|  |             queryBuilder.Append($"'{mrb.CloseDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             if (mrb.CancelDate > DateTimeUtilities.MAX_DT) | ||||||
|  |                 mrb.CancelDate = DateTimeUtilities.MAX_DT; | ||||||
|  |             queryBuilder.Append($"'{mrb.CancelDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"{mrb.NumberOfLotsAffected}, "); | ||||||
|  |             if (mrb.ApprovalDate > DateTimeUtilities.MAX_DT) | ||||||
|  |                 mrb.ApprovalDate = DateTimeUtilities.MAX_DT; | ||||||
|  |             queryBuilder.Append($"'{mrb.ApprovalDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"'{mrb.IssueDescription}', {Convert.ToUInt32(mrb.CustomerImpacted)}, "); | ||||||
|  |             queryBuilder.Append($"'{mrb.Department}', '{mrb.Process}', {mrb.Val}, {mrb.RMANo}, '{mrb.PCRBNo}', "); | ||||||
|  |             queryBuilder.Append($"{Convert.ToInt32(mrb.SpecsImpacted)}, {Convert.ToInt32(mrb.TrainingRequired)}, "); | ||||||
|  |             queryBuilder.Append($"'{mrb.Status}', {mrb.StageNo}, '{mrb.CustomerImpactedName}', "); | ||||||
|  |             queryBuilder.Append($"{mrb.ProcessECNNumber}, '{mrb.Tool}', '{mrb.Category}');"); | ||||||
|  |  | ||||||
|  |             int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsCreated <= 0) throw new Exception("Unable to create new MRB"); | ||||||
|  |  | ||||||
|  |             mrb = await GetMRBByTitle(mrb.Title, true); | ||||||
|  |  | ||||||
|  |             _cache.Set($"mrb{mrb.MRBNumber}", mrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             _cache.Set($"mrb{mrb.Title}", mrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |  | ||||||
|  |             IEnumerable<MRB>? allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs"); | ||||||
|  |             if (allMrbs is not null) { | ||||||
|  |                 List<MRB> mrbList = allMrbs.ToList(); | ||||||
|  |                 mrbList.Add(mrb); | ||||||
|  |                 _cache.Set("allMrbs", mrbList, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to create new MRB. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<MRB>> GetAllMRBs(bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get all MRBs"); | ||||||
|  |  | ||||||
|  |             IEnumerable<MRB>? allMrbs = null; | ||||||
|  |             if (!bypassCache) allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs"); | ||||||
|  |  | ||||||
|  |             if (allMrbs is null) { | ||||||
|  |                 StringBuilder queryBuilder = new(); | ||||||
|  |                 queryBuilder.Append("select (u.FirstName + ' ' + u.LastName) as OriginatorName, m.* "); | ||||||
|  |                 queryBuilder.Append("from MRB m join Users u on m.OriginatorID = u.UserID;"); | ||||||
|  |  | ||||||
|  |                 allMrbs = (await _dalService.QueryAsync<MRB>(queryBuilder.ToString())).ToList(); | ||||||
|  |  | ||||||
|  |                 _cache.Set("allMrbs", allMrbs, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return allMrbs; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to get all MRBs. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<bool> MRBNumberIsValid(int number) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to determine if {number} is a valid MRB#"); | ||||||
|  |  | ||||||
|  |             if (number <= 0) return false; | ||||||
|  |  | ||||||
|  |             IEnumerable<int> mrbNumbers = _cache.Get<IEnumerable<int>>("mrbNumbers") ?? | ||||||
|  |                                             new HashSet<int>(); | ||||||
|  |  | ||||||
|  |             if (mrbNumbers.Contains(number)) return true; | ||||||
|  |  | ||||||
|  |             string sql = $"select count(MRBNumber) as count from MRB where MRBNumber={number}"; | ||||||
|  |  | ||||||
|  |             int rowsReturned = (await _dalService.QueryAsync<int>(sql)).FirstOrDefault(); | ||||||
|  |  | ||||||
|  |             if (rowsReturned > 0) { | ||||||
|  |                 mrbNumbers.Append(number); | ||||||
|  |                 _cache.Set("mrbNumbers", mrbNumbers); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to determine if {number} is a valid MRB#, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<MRB> GetMRBById(int id, bool bypassCache = false) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get an MRB by ID"); | ||||||
|  |  | ||||||
|  |             if (id < 0) throw new ArgumentException("Invalid MRB number"); | ||||||
|  |  | ||||||
|  |             MRB? mrb = null; | ||||||
|  |             if (!bypassCache) | ||||||
|  |                 mrb = _cache.Get<MRB>($"mrb{id}"); | ||||||
|  |  | ||||||
|  |             if (mrb is null) { | ||||||
|  |                 StringBuilder queryBuilder = new(); | ||||||
|  |                 queryBuilder.Append("select (u.FirstName + ' ' + u.LastName) as OriginatorName, m.* "); | ||||||
|  |                 queryBuilder.Append("from MRB m join Users u on m.OriginatorID = u.UserID "); | ||||||
|  |                 queryBuilder.Append($"where m.MRBNumber = {id}"); | ||||||
|  |  | ||||||
|  |                 mrb = (await _dalService.QueryAsync<MRB>(queryBuilder.ToString())).FirstOrDefault(); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"mrb{id}", mrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (mrb is null) throw new Exception($"Unable to get MRB {id}"); | ||||||
|  |  | ||||||
|  |             return mrb; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to get an MRB. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<MRB> GetMRBByTitle(string title, bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get an MRB by title"); | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             MRB? mrb = null; | ||||||
|  |  | ||||||
|  |             if (!bypassCache) mrb = _cache.Get<MRB>($"mrb{title}"); | ||||||
|  |  | ||||||
|  |             if (mrb is null) { | ||||||
|  |                 StringBuilder queryBuilder = new(); | ||||||
|  |                 queryBuilder.Append("select (u.FirstName + ' ' + u.LastName) as OriginatorName, m.* "); | ||||||
|  |                 queryBuilder.Append("from MRB m join Users u on m.OriginatorID = u.UserID "); | ||||||
|  |                 queryBuilder.Append($"where m.Title = '{title}'"); | ||||||
|  |  | ||||||
|  |                 mrb = (await _dalService.QueryAsync<MRB>(queryBuilder.ToString())).FirstOrDefault(); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"mrb{title}", mrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (mrb is null) throw new Exception($"Unable to get MRB {title}"); | ||||||
|  |  | ||||||
|  |             return mrb; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to get an MRB. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdateMRB(MRB mrb) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to update an MRB"); | ||||||
|  |  | ||||||
|  |             if (mrb is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append($"update MRB set OriginatorID = {mrb.OriginatorID}, "); | ||||||
|  |             queryBuilder.Append($"Title = '{mrb.Title.Replace("'", "''")}', "); | ||||||
|  |             if (mrb.SubmittedDate < DateTimeUtilities.MIN_DT) | ||||||
|  |                 mrb.SubmittedDate = DateTimeUtilities.MIN_DT; | ||||||
|  |             queryBuilder.Append($"SubmittedDate = '{mrb.SubmittedDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             if (mrb.CloseDate > DateTimeUtilities.MAX_DT) | ||||||
|  |                 mrb.CloseDate = DateTimeUtilities.MAX_DT; | ||||||
|  |             queryBuilder.Append($"CloseDate = '{mrb.CloseDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             if (mrb.CancelDate > DateTimeUtilities.MAX_DT) | ||||||
|  |                 mrb.CancelDate = DateTimeUtilities.MAX_DT; | ||||||
|  |             queryBuilder.Append($"CancelDate = '{mrb.CancelDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"NumberOfLotsAffected = {mrb.NumberOfLotsAffected}, "); | ||||||
|  |             if (mrb.ApprovalDate > DateTimeUtilities.MAX_DT) | ||||||
|  |                 mrb.ApprovalDate = DateTimeUtilities.MAX_DT; | ||||||
|  |             queryBuilder.Append($"ApprovalDate = '{mrb.ApprovalDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"IssueDescription = '{mrb.IssueDescription.Replace("'", "''")}', "); | ||||||
|  |             queryBuilder.Append($"CustomerImpacted = {Convert.ToInt32(mrb.CustomerImpacted)}, "); | ||||||
|  |             queryBuilder.Append($"Department = '{mrb.Department.Replace("'", "''")}', "); | ||||||
|  |             queryBuilder.Append($"Process = '{mrb.Process.Replace("'", "''")}', "); | ||||||
|  |             queryBuilder.Append($"Val = {mrb.Val}, "); | ||||||
|  |             queryBuilder.Append($"RMANo = {mrb.RMANo}, "); | ||||||
|  |             queryBuilder.Append($"PCRBNo = '{mrb.PCRBNo}', "); | ||||||
|  |             queryBuilder.Append($"SpecsImpacted = {Convert.ToInt32(mrb.SpecsImpacted)}, "); | ||||||
|  |             queryBuilder.Append($"TrainingRequired = {Convert.ToInt32(mrb.TrainingRequired)}, "); | ||||||
|  |             queryBuilder.Append($"Status = '{mrb.Status}', StageNo = {mrb.StageNo}, "); | ||||||
|  |             queryBuilder.Append($"CustomerImpactedName = '{mrb.CustomerImpactedName.Replace("'", "''")}', "); | ||||||
|  |             queryBuilder.Append($"ProcessECNNumber = '{mrb.ProcessECNNumber}', "); | ||||||
|  |             queryBuilder.Append($"Tool = '{mrb.Tool.Replace("'", "''")}', Category = '{mrb.Category.Replace("'", "''")}' "); | ||||||
|  |             queryBuilder.Append($"where MRBNumber = {mrb.MRBNumber};"); | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception($"Unable to update MRB {mrb.MRBNumber}"); | ||||||
|  |  | ||||||
|  |             _cache.Set($"mrb{mrb.MRBNumber}", mrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             _cache.Set($"mrb{mrb.Title}", mrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |  | ||||||
|  |             IEnumerable<MRB>? allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs"); | ||||||
|  |             if (allMrbs is not null) { | ||||||
|  |                 List<MRB> mrbList = allMrbs.ToList(); | ||||||
|  |                 mrbList.RemoveAll(m => m.MRBNumber == mrb.MRBNumber); | ||||||
|  |                 mrbList.Add(mrb); | ||||||
|  |                 _cache.Set("allMrbs", mrbList, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to update an MRB. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task CreateMRBAction(MRBAction mrbAction) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to generate new MRB action"); | ||||||
|  |  | ||||||
|  |             if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append("insert into MRBAction (Action, Customer, Quantity, PartNumber, LotNumber, MRBNumber, "); | ||||||
|  |             queryBuilder.Append("ConvertFrom, ConvertTo, Justification) "); | ||||||
|  |             queryBuilder.Append($"values ('{mrbAction.Action}', '{mrbAction.Customer}', {mrbAction.Quantity}, "); | ||||||
|  |             queryBuilder.Append($"'{mrbAction.PartNumber}', '{mrbAction.LotNumber}', {mrbAction.MRBNumber}, "); | ||||||
|  |             queryBuilder.Append($"'{mrbAction.ConvertFrom}', '{mrbAction.ConvertTo}', '{mrbAction.Justification}');"); | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception("Unable to create MRB action in database"); | ||||||
|  |  | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to create new MRB action. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<MRBAction>> GetMRBActionsForMRB(int mrbNumber, bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get MRB actions for MRB {mrbNumber}"); | ||||||
|  |  | ||||||
|  |             if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number"); | ||||||
|  |  | ||||||
|  |             IEnumerable<MRBAction>? mrbActions = null; | ||||||
|  |  | ||||||
|  |             if (!bypassCache) | ||||||
|  |                 _cache.Get<IEnumerable<MRBAction>>($"mrbActions{mrbNumber}"); | ||||||
|  |  | ||||||
|  |             if (mrbActions is null) { | ||||||
|  |                 string sql = $"select * from MRBAction where MRBNumber = {mrbNumber}"; | ||||||
|  |  | ||||||
|  |                 mrbActions = (await _dalService.QueryAsync<MRBAction>(sql)).ToList(); | ||||||
|  |  | ||||||
|  |                 if (mrbActions is not null) { | ||||||
|  |                     foreach (MRBAction action in mrbActions) { | ||||||
|  |                         if (action.CompletedDate < DateTime.MaxValue && action.CompletedByUserID > 0) { | ||||||
|  |                             action.CompletedByUser = await _userService.GetUserByUserId(action.CompletedByUserID); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     _cache.Set($"mrbActions{mrbNumber}", mrbActions, DateTimeOffset.Now.AddMinutes(30)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (mrbActions is null) throw new Exception($"Unable to find MRB actions for MRB {mrbNumber}"); | ||||||
|  |  | ||||||
|  |             return mrbActions; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to get MRB actions for MRB {mrbNumber}, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdateMRBAction(MRBAction mrbAction) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to update MRB action"); | ||||||
|  |  | ||||||
|  |             if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append($"update MRBAction set Action = '{mrbAction.Action}', "); | ||||||
|  |             queryBuilder.Append($"Customer = '{mrbAction.Customer.Replace("'", "''")}', "); | ||||||
|  |             queryBuilder.Append($"Quantity = {mrbAction.Quantity}, "); | ||||||
|  |             queryBuilder.Append($"PartNumber = '{mrbAction.PartNumber.Replace("'", "''")}', "); | ||||||
|  |             queryBuilder.Append($"LotNumber = '{mrbAction.LotNumber.Replace("'", "''")}', "); | ||||||
|  |             if (mrbAction.AssignedDate < DateTimeUtilities.MIN_DT) | ||||||
|  |                 mrbAction.AssignedDate = DateTimeUtilities.MIN_DT; | ||||||
|  |             queryBuilder.Append($"AssignedDate= '{mrbAction.AssignedDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             if (mrbAction.CompletedDate > DateTimeUtilities.MAX_DT) | ||||||
|  |                 mrbAction.CompletedDate = DateTimeUtilities.MAX_DT; | ||||||
|  |             queryBuilder.Append($"CompletedDate= '{mrbAction.CompletedDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"CompletedByUserID={mrbAction.CompletedByUserID}, "); | ||||||
|  |             queryBuilder.Append($"ConvertFrom='{mrbAction.ConvertFrom.Replace("'", "''")}', "); | ||||||
|  |             queryBuilder.Append($"ConvertTo='{mrbAction.ConvertTo.Replace("'", "''")}', "); | ||||||
|  |             queryBuilder.Append($"Justification='{mrbAction.Justification.Replace("'", "''")}' "); | ||||||
|  |             queryBuilder.Append($"where ActionID={mrbAction.ActionID};"); | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception($"There were no MRB actions found with MRB# {mrbAction.MRBNumber}"); | ||||||
|  |  | ||||||
|  |             List<MRBAction>? mrbActions = _cache.Get<IEnumerable<MRBAction>>($"mrbActions{mrbAction.MRBNumber}")?.ToList(); | ||||||
|  |             if (mrbActions is not null) { | ||||||
|  |                 mrbActions.RemoveAll(m => m.ActionID == mrbAction.ActionID); | ||||||
|  |                 mrbActions.Add(mrbAction); | ||||||
|  |                 _cache.Set($"mrbActions{mrbAction.MRBNumber}", mrbActions, DateTimeOffset.Now.AddMinutes(30)); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to update MRB action, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeleteMRBAction(int mrbActionID, int mrbNumber) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to delete MRB action {mrbActionID}"); | ||||||
|  |  | ||||||
|  |             if (mrbActionID <= 0) throw new ArgumentException($"{mrbActionID} is not a valid MRBActionID"); | ||||||
|  |             if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRBNumber"); | ||||||
|  |  | ||||||
|  |             string sql = $"delete from MRBAction where ActionID = {mrbActionID};"; | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(sql); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception($"No MRB action was found to delete for ActionID {mrbActionID}"); | ||||||
|  |  | ||||||
|  |             List<MRBAction>? mrbActions = _cache.Get<IEnumerable<MRBAction>>($"mrbActions{mrbNumber}")?.ToList(); | ||||||
|  |             if (mrbActions is not null) { | ||||||
|  |                 mrbActions.RemoveAll(m => m.ActionID == mrbActionID); | ||||||
|  |                 _cache.Set($"mrbActions{mrbNumber}", mrbActions, DateTimeOffset.Now.AddMinutes(30)); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to delete MRB action {mrbActionID}. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<UploadResult>> UploadAttachments(IEnumerable<IFormFile> files, int mrbNumber) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to upload attachments"); | ||||||
|  |  | ||||||
|  |             List<UploadResult> uploadResults = new(); | ||||||
|  |  | ||||||
|  |             if (files is null) throw new ArgumentNullException("Files cannot be null"); | ||||||
|  |             if (files.Count() <= 0) throw new ArgumentException("Files cannot be empty"); | ||||||
|  |             if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number"); | ||||||
|  |  | ||||||
|  |             foreach (IFormFile file in files) { | ||||||
|  |                 try { | ||||||
|  |                     if (file is null) throw new ArgumentException("File cannot be null"); | ||||||
|  |                     if (file.Length <= 0) throw new ArgumentException("File size cannot be zero"); | ||||||
|  |  | ||||||
|  |                     string encodedName = WebUtility.HtmlEncode(file.FileName); | ||||||
|  |                     string path = $"{_mrbAttachmentPath}\\{mrbNumber}\\{encodedName}"; | ||||||
|  |  | ||||||
|  |                     await FileUtilities.SaveFileToFileSystem(file, path); | ||||||
|  |                     await SaveAttachmentInDb(file, path, mrbNumber); | ||||||
|  |  | ||||||
|  |                     UploadResult uploadResult = new() { | ||||||
|  |                         UploadSuccessful = true, | ||||||
|  |                         FileName = file.FileName | ||||||
|  |                     }; | ||||||
|  |                     uploadResults.Add(uploadResult); | ||||||
|  |                 } catch (Exception ex) { | ||||||
|  |                     UploadResult uploadResult = new() { | ||||||
|  |                         UploadSuccessful = false, | ||||||
|  |                         FileName = file.FileName, | ||||||
|  |                         Error = ex.Message | ||||||
|  |                     }; | ||||||
|  |                     uploadResults.Add(uploadResult); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return uploadResults; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to upload attachment. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<UploadResult>> UploadActionAttachments(IEnumerable<IFormFile> files, int actionId) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to upload action attachments"); | ||||||
|  |  | ||||||
|  |             List<UploadResult> uploadResults = new(); | ||||||
|  |  | ||||||
|  |             if (files is null) throw new ArgumentNullException("Files cannot be null"); | ||||||
|  |             if (files.Count() <= 0) throw new ArgumentException("Files cannot be empty"); | ||||||
|  |             if (actionId <= 0) throw new ArgumentException($"{actionId} is not a valid MRB action ID"); | ||||||
|  |  | ||||||
|  |             List<Task> taskList = new(); | ||||||
|  |             foreach (IFormFile file in files) { | ||||||
|  |                 try { | ||||||
|  |                     if (file is null) throw new ArgumentException("File cannot be null"); | ||||||
|  |                     if (file.Length <= 0) throw new ArgumentException("File size cannot be zero"); | ||||||
|  |  | ||||||
|  |                     string encodedName = WebUtility.HtmlEncode(file.FileName); | ||||||
|  |                     string path = $"{_mrbAttachmentPath}\\{actionId}\\{encodedName}"; | ||||||
|  |  | ||||||
|  |                     taskList.Add(FileUtilities.SaveFileToFileSystem(file, path)); | ||||||
|  |                     taskList.Add(SaveActionAttachmentInDb(file, path, actionId)); | ||||||
|  |  | ||||||
|  |                     UploadResult uploadResult = new() { | ||||||
|  |                         UploadSuccessful = true, | ||||||
|  |                         FileName = file.Name | ||||||
|  |                     }; | ||||||
|  |                     uploadResults.Add(uploadResult); | ||||||
|  |                 } catch (Exception ex) { | ||||||
|  |                     UploadResult uploadResult = new() { | ||||||
|  |                         UploadSuccessful = false, | ||||||
|  |                         FileName = file.Name, | ||||||
|  |                         Error = ex.Message | ||||||
|  |                     }; | ||||||
|  |                     uploadResults.Add(uploadResult); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             Task.WaitAll(taskList.ToArray()); | ||||||
|  |  | ||||||
|  |             return uploadResults; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to upload action attachment. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<MRBAttachment>> GetAllAttachmentsForMRB(int mrbNumber, bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get all attachments for MRB {mrbNumber}"); | ||||||
|  |  | ||||||
|  |             if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number"); | ||||||
|  |  | ||||||
|  |             IEnumerable<MRBAttachment>? attachments = null; | ||||||
|  |             if (!bypassCache) | ||||||
|  |                 _cache.Get<IEnumerable<MRBAttachment>>($"mrbAttachments{mrbNumber}"); | ||||||
|  |  | ||||||
|  |             if (attachments is null) { | ||||||
|  |                 string sql = $"select * from MRBAttachment where MRBNumber = {mrbNumber};"; | ||||||
|  |  | ||||||
|  |                 attachments = (await _dalService.QueryAsync<MRBAttachment>(sql)).ToList(); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"mrbAttachments{mrbNumber}", attachments, DateTimeOffset.Now.AddMinutes(15)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return attachments; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             StringBuilder errMsgBuilder = new(); | ||||||
|  |             errMsgBuilder.Append($"An error occurred when attempting to get all attachments for MRB {mrbNumber}. "); | ||||||
|  |             errMsgBuilder.Append($"Exception: {ex.Message}"); | ||||||
|  |             _logger.LogError(errMsgBuilder.ToString()); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<MRBActionAttachment>> GetAllActionAttachmentsForMRB(int mrbNumber, bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get all action attachments for MRB {mrbNumber}"); | ||||||
|  |  | ||||||
|  |             if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#"); | ||||||
|  |  | ||||||
|  |             List<MRBActionAttachment>? attachments = null; | ||||||
|  |             if (!bypassCache) | ||||||
|  |                 attachments = _cache.Get<List<MRBActionAttachment>>($"mrbActionAttachments{mrbNumber}"); | ||||||
|  |  | ||||||
|  |             if (attachments is null) { | ||||||
|  |                 attachments = new List<MRBActionAttachment>(); | ||||||
|  |  | ||||||
|  |                 foreach (MRBAction action in await GetMRBActionsForMRB(mrbNumber, false)) { | ||||||
|  |                     string sql = $"select * from MRBActionAttachment where ActionID = {action.ActionID};"; | ||||||
|  |  | ||||||
|  |                     IEnumerable<MRBActionAttachment> newAttachments = | ||||||
|  |                         (await _dalService.QueryAsync<MRBActionAttachment>(sql)).ToList(); | ||||||
|  |  | ||||||
|  |                     attachments.AddRange(newAttachments); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 _cache.Set($"mrbActionAttachments{mrbNumber}", attachments, DateTimeOffset.Now.AddMinutes(15)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return attachments; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             StringBuilder errMsgBuilder = new(); | ||||||
|  |             errMsgBuilder.Append($"An error occurred when attempting to get all attachments for MRB action {mrbNumber}. "); | ||||||
|  |             errMsgBuilder.Append($"Exception: {ex.Message}"); | ||||||
|  |             _logger.LogError(errMsgBuilder.ToString()); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeleteAttachment(MRBAttachment attachment) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to delete an attachment"); | ||||||
|  |  | ||||||
|  |             if (attachment is null) throw new ArgumentNullException("Attachment cannot be null"); | ||||||
|  |             if (!File.Exists(attachment.Path)) throw new FileNotFoundException("No file found at provided path"); | ||||||
|  |  | ||||||
|  |             File.Delete(attachment.Path); | ||||||
|  |  | ||||||
|  |             string sql = $"delete from MRBAttachment where AttachmentID = {attachment.AttachmentID};"; | ||||||
|  |  | ||||||
|  |             int rowsDeleted = await _dalService.ExecuteAsync(sql); | ||||||
|  |  | ||||||
|  |             if (rowsDeleted <= 0) | ||||||
|  |                 throw new Exception($"No attachments found in the database with attachment ID {attachment.AttachmentID}"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to delete an attachment. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyNewApprovals(MRB mrb) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to notify approvers"); | ||||||
|  |  | ||||||
|  |             if (mrb is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |  | ||||||
|  |             IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(mrb.MRBNumber, true); | ||||||
|  |  | ||||||
|  |             List<Approval> approvalsNeedingNotification = approvals.Where(a => a.NotifyDate <= DateTimeUtilities.MIN_DT).ToList(); | ||||||
|  |  | ||||||
|  |             HashSet<string> emailsAlreadySent = new(); | ||||||
|  |             foreach (Approval approval in approvalsNeedingNotification) { | ||||||
|  |                 User user = await _userService.GetUserByUserId(approval.UserID); | ||||||
|  |  | ||||||
|  |                 if (!emailsAlreadySent.Contains(user.Email)) { | ||||||
|  |                     emailsAlreadySent.Add(user.Email); | ||||||
|  |  | ||||||
|  |                     List<MailAddress> toAddresses = new(); | ||||||
|  |                     toAddresses.Add(new MailAddress(user.Email)); | ||||||
|  |  | ||||||
|  |                     List<MailAddress> ccAddresses = new(); | ||||||
|  |  | ||||||
|  |                     string subject = $"[New Task] Mesa Fab Approval - MRB# {mrb.MRBNumber} - {mrb.Title}"; | ||||||
|  |  | ||||||
|  |                     StringBuilder bodyBuilder = new(); | ||||||
|  |                     bodyBuilder.Append($"MRB# {mrb.MRBNumber} [{mrb.Title}] is ready for your approval. "); | ||||||
|  |                     bodyBuilder.Append($"The assigned role is {approval.SubRoleCategoryItem}. <br /> <br />"); | ||||||
|  |                     bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=mrb/{approval.IssueID} to view the task."); | ||||||
|  |  | ||||||
|  |                     await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString()); | ||||||
|  |  | ||||||
|  |                     approval.NotifyDate = DateTime.Now; | ||||||
|  |                     await _approvalService.UpdateApproval(approval); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to notify approvers, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyApprovers(MRBNotification notification) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to send notification to approvers"); | ||||||
|  |  | ||||||
|  |             if (notification is null) throw new ArgumentNullException("notification cannot be null"); | ||||||
|  |             if (notification.MRB is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(notification.MRB.MRBNumber, true); | ||||||
|  |  | ||||||
|  |             HashSet<string> emailsAlreadySent = new(); | ||||||
|  |             foreach (Approval approval in approvals) { | ||||||
|  |                 User user = await _userService.GetUserByUserId(approval.UserID); | ||||||
|  |  | ||||||
|  |                 if (!emailsAlreadySent.Contains(user.Email)) { | ||||||
|  |                     emailsAlreadySent.Add(user.Email); | ||||||
|  |  | ||||||
|  |                     List<MailAddress> toAddresses = new(); | ||||||
|  |                     toAddresses.Add(new MailAddress(user.Email)); | ||||||
|  |  | ||||||
|  |                     List<MailAddress> ccAddresses = new(); | ||||||
|  |  | ||||||
|  |                     string subject = $"[Update] Mesa Fab Approval - MRB# {notification.MRB.MRBNumber} - {notification.MRB.Title}"; | ||||||
|  |  | ||||||
|  |                     StringBuilder bodyBuilder = new(); | ||||||
|  |                     bodyBuilder.Append($"{notification.Message} <br /> <br />"); | ||||||
|  |                     bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=mrb/{approval.IssueID} to view the MRB."); | ||||||
|  |  | ||||||
|  |                     await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString()); | ||||||
|  |  | ||||||
|  |                     approval.NotifyDate = DateTime.Now; | ||||||
|  |                     await _approvalService.UpdateApproval(approval); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to send notification to originator, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyOriginator(MRBNotification notification) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to send notification to originator"); | ||||||
|  |  | ||||||
|  |             if (notification is null) throw new ArgumentNullException("notification cannot be null"); | ||||||
|  |             if (notification.MRB is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             User user = await _userService.GetUserByUserId(notification.MRB.OriginatorID); | ||||||
|  |  | ||||||
|  |             List<MailAddress> toAddresses = new(); | ||||||
|  |             toAddresses.Add(new MailAddress(user.Email)); | ||||||
|  |  | ||||||
|  |             List<MailAddress> ccAddresses = new(); | ||||||
|  |  | ||||||
|  |             string subject = $"[Update] Mesa Fab Approval - MRB# {notification.MRB.MRBNumber} - {notification.MRB.Title}"; | ||||||
|  |  | ||||||
|  |             StringBuilder bodyBuilder = new(); | ||||||
|  |             bodyBuilder.Append($"{notification.Message} <br /> <br />"); | ||||||
|  |             bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=mrb/{notification.MRB.MRBNumber} to view the MRB."); | ||||||
|  |  | ||||||
|  |             await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString()); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to send notification to originator, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyQAPreApprover(MRBNotification notification) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to send notification to QA pre approver"); | ||||||
|  |  | ||||||
|  |             if (notification is null) throw new ArgumentNullException("notification cannot be null"); | ||||||
|  |             if (notification.MRB is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             string roleName = "QA_PRE_APPROVAL"; | ||||||
|  |  | ||||||
|  |             int roleId = await _approvalService.GetRoleIdForRoleName(roleName); | ||||||
|  |  | ||||||
|  |             if (roleId <= 0) throw new Exception($"could not find {roleName} role ID"); | ||||||
|  |  | ||||||
|  |             SubRole? subRole = (await _approvalService.GetSubRolesForSubRoleName(roleName, roleId)).FirstOrDefault(); | ||||||
|  |  | ||||||
|  |             if (subRole is null) | ||||||
|  |                 throw new Exception("Unable to find QA pre approver role"); | ||||||
|  |  | ||||||
|  |             IEnumerable<User> members = await _approvalService.GetApprovalGroupMembers(subRole.SubRoleID); | ||||||
|  |  | ||||||
|  |             List<MailAddress> toAddresses = new(); | ||||||
|  |             foreach (User member in members) | ||||||
|  |                 toAddresses.Add(new MailAddress(member.Email)); | ||||||
|  |  | ||||||
|  |             List<MailAddress> ccAddresses = new(); | ||||||
|  |  | ||||||
|  |             string subject = $"[Update] Mesa Fab Approval - MRB# {notification.MRB.MRBNumber} - {notification.MRB.Title}"; | ||||||
|  |  | ||||||
|  |             StringBuilder bodyBuilder = new(); | ||||||
|  |             bodyBuilder.Append($"{notification.Message} <br /> <br />"); | ||||||
|  |             bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=mrb/{notification.MRB.MRBNumber} to view the MRB."); | ||||||
|  |  | ||||||
|  |             await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString()); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to send notification to QA pre approver, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeleteMRB(int mrbNumber) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to delete MRB# {mrbNumber}"); | ||||||
|  |  | ||||||
|  |             if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number"); | ||||||
|  |  | ||||||
|  |             string sql = $"delete from MRB where MRBNumber={mrbNumber}"; | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(sql); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception($"MRB {mrbNumber} not deleted from database"); | ||||||
|  |  | ||||||
|  |             IEnumerable<MRB>? allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs"); | ||||||
|  |             if (allMrbs is not null) { | ||||||
|  |                 List<MRB> mrbList = allMrbs.ToList(); | ||||||
|  |                 mrbList.RemoveAll(m => m.MRBNumber == mrbNumber); | ||||||
|  |                 _cache.Set("allMrbs", mrbList, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to delete MRB {mrbNumber}, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task ConvertActionsToCsvFile(int mrbNumber, string path) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to convert MRB {mrbNumber} actions to a CSV file"); | ||||||
|  |  | ||||||
|  |             if (!(await MRBNumberIsValid(mrbNumber))) throw new ArgumentException($"{mrbNumber} is not a valid "); | ||||||
|  |             if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Path cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             if (File.Exists(path)) File.Delete(path); | ||||||
|  |  | ||||||
|  |             string? directoryPath = Path.GetDirectoryName(path); | ||||||
|  |             if (!string.IsNullOrWhiteSpace(directoryPath)) | ||||||
|  |                 Directory.CreateDirectory(directoryPath); | ||||||
|  |  | ||||||
|  |             IEnumerable<MRBAction> actions = await GetMRBActionsForMRB(mrbNumber, false); | ||||||
|  |  | ||||||
|  |             DataTable dt = await ConvertActionsToDataTable(actions); | ||||||
|  |  | ||||||
|  |             using StreamWriter sw = new StreamWriter(path, false); | ||||||
|  |  | ||||||
|  |             for (int i = 0; i < dt.Columns.Count; i++) { | ||||||
|  |                 sw.Write(dt.Columns[i]); | ||||||
|  |                 if (i < dt.Columns.Count - 1) sw.Write(","); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             sw.Write(sw.NewLine); | ||||||
|  |  | ||||||
|  |             foreach (DataRow dr in dt.Rows) { | ||||||
|  |                 for (int i = 0; i < dt.Columns.Count; i++) { | ||||||
|  |                     if (!Convert.IsDBNull(dr[i])) { | ||||||
|  |                         string? value = dr[i].ToString(); | ||||||
|  |                         if (value is null) { | ||||||
|  |                             sw.Write(""); | ||||||
|  |                         } else if (value.Contains(',')) { | ||||||
|  |                             value = String.Format("\"{0}\"", value); | ||||||
|  |                             sw.Write(value); | ||||||
|  |                         } else { | ||||||
|  |                             sw.Write(dr[i].ToString()); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     if (i < dt.Columns.Count - 1) { | ||||||
|  |                         sw.Write(","); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 sw.Write(sw.NewLine); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             sw.Close(); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to convert MRB {mrbNumber} actions to a CSV file, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task<DataTable> ConvertActionsToDataTable(IEnumerable<MRBAction> actions) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to convert MRB actions to a DataTable"); | ||||||
|  |  | ||||||
|  |             if (actions is null) throw new ArgumentNullException("MRB actions cannot be null"); | ||||||
|  |  | ||||||
|  |             DataTable dt = new(); | ||||||
|  |  | ||||||
|  |             if (actions.Count() > 0 && actions.First().Action.Equals("Convert", StringComparison.InvariantCultureIgnoreCase)) { | ||||||
|  |                 dt.Columns.Add("Action", typeof(string)); | ||||||
|  |                 dt.Columns.Add("From Customer", typeof(string)); | ||||||
|  |                 dt.Columns.Add("From Part Number", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Batch Number / Lot Number", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Qty", typeof(string)); | ||||||
|  |                 dt.Columns.Add("To Customer", typeof(string)); | ||||||
|  |                 dt.Columns.Add("To Part Number", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Assigned Date", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Completed Date", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Completed By", typeof(string)); | ||||||
|  |  | ||||||
|  |                 foreach (MRBAction action in actions) { | ||||||
|  |                     if (action.CompletedByUser is null && action.CompletedByUserID > 0) | ||||||
|  |                         action.CompletedByUser = await _userService.GetUserByUserId(action.CompletedByUserID); | ||||||
|  |  | ||||||
|  |                     string convertFromCustomer = string.Empty; | ||||||
|  |                     string convertFromPart = string.Empty; | ||||||
|  |                     string convertToCustomer = string.Empty; | ||||||
|  |                     string convertToPart = string.Empty; | ||||||
|  |  | ||||||
|  |                     string[] convertFrom = action.ConvertFrom.Split(" "); | ||||||
|  |                     if (convertFrom.Length > 1) { | ||||||
|  |                         convertFromCustomer = convertFrom[0]; | ||||||
|  |                         foreach (string partStr in convertFrom.Skip(1)) | ||||||
|  |                             convertFromPart += partStr; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     string[] convertTo = action.ConvertTo.Split(" "); | ||||||
|  |                     if (convertTo.Length > 1) { | ||||||
|  |                         convertToCustomer = convertTo[0]; | ||||||
|  |                         foreach (string partStr in convertTo.Skip(1)) | ||||||
|  |                             convertToPart += partStr; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     dt.Rows.Add(action.Action, convertFromCustomer, convertFromPart, action.Quantity.ToString(), | ||||||
|  |                                 convertToCustomer, convertToPart, | ||||||
|  |                                 DateTimeUtilities.GetDateAsStringMinDefault(action.AssignedDate), | ||||||
|  |                                 DateTimeUtilities.GetDateAsStringMaxDefault(action.CompletedDate), | ||||||
|  |                                 action.CompletedByUser is null ? "" : action.CompletedByUser.GetFullName()); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 dt.Columns.Add("Action", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Customer", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Qty", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Convert From", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Convert To", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Part Number", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Batch Number / Lot Number", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Justification", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Assigned Date", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Completed Date", typeof(string)); | ||||||
|  |                 dt.Columns.Add("Completed By", typeof(string)); | ||||||
|  |  | ||||||
|  |                 foreach (MRBAction action in actions) { | ||||||
|  |                     if (action.CompletedByUser is null && action.CompletedByUserID > 0) | ||||||
|  |                         action.CompletedByUser = await _userService.GetUserByUserId(action.CompletedByUserID); | ||||||
|  |  | ||||||
|  |                     dt.Rows.Add(action.Action, action.Customer, action.Quantity.ToString(), action.ConvertFrom, action.ConvertTo, | ||||||
|  |                                 action.PartNumber, action.LotNumber, action.Justification, | ||||||
|  |                                 DateTimeUtilities.GetDateAsStringMinDefault(action.AssignedDate), | ||||||
|  |                                 DateTimeUtilities.GetDateAsStringMaxDefault(action.CompletedDate), | ||||||
|  |                                 action.CompletedByUser is null ? "" : action.CompletedByUser.GetFullName()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return dt; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to convert MRB actions to a DataTable, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task SaveAttachmentInDb(IFormFile file, string path, int mrbNumber) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to save attachment to database"); | ||||||
|  |  | ||||||
|  |             if (file is null) throw new ArgumentNullException("File cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Path cannot be null or empty"); | ||||||
|  |             if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append("insert into MRBAttachment (MRBNumber, FileName, UploadDate, Path) "); | ||||||
|  |             queryBuilder.Append($"values ({mrbNumber}, '{file.FileName}', "); | ||||||
|  |             queryBuilder.Append($"'{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', '{path}');"); | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) | ||||||
|  |                 throw new Exception("Unable to insert attachment in database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to save file to DB. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task SaveActionAttachmentInDb(IFormFile file, string path, int actionId) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to save action attachment to database"); | ||||||
|  |  | ||||||
|  |             if (file is null) throw new ArgumentNullException("File cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Path cannot be null or empty"); | ||||||
|  |             if (actionId <= 0) throw new ArgumentException($"{actionId} is not a valid MRB action ID"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append("insert into MRBActionAttachment (ActionID, FileName, UploadDate, Path) "); | ||||||
|  |             queryBuilder.Append($"values ({actionId}, '{file.FileName}', "); | ||||||
|  |             queryBuilder.Append($"'{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', '{path}');"); | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) | ||||||
|  |                 throw new Exception("Unable to insert action attachment in database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"An exception occurred when attempting to save file to DB. Exception: {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										767
									
								
								MesaFabApproval.API/Services/PCRBService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										767
									
								
								MesaFabApproval.API/Services/PCRBService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,767 @@ | |||||||
|  | using System.Net; | ||||||
|  | using System.Net.Mail; | ||||||
|  | using System.Text; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.API.Utilities; | ||||||
|  | using MesaFabApproval.Models; | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  | using MesaFabApproval.Shared.Utilities; | ||||||
|  |  | ||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Services; | ||||||
|  |  | ||||||
|  | public interface IPCRBService { | ||||||
|  |     Task CreateNewPCRB(PCRB pcrb); | ||||||
|  |     Task<IEnumerable<PCRB>> GetAllPCRBs(bool bypassCache); | ||||||
|  |     Task<PCRB> GetPCRBByPlanNumber(int planNumber, bool bypassCache); | ||||||
|  |     Task<PCRB> GetPCRBByTitle(string title, bool bypassCache); | ||||||
|  |     Task UpdatePCRB(PCRB pcrb); | ||||||
|  |     Task DeletePCRB(int planNumber); | ||||||
|  |     Task<UploadResult> UploadAttachment(IFormFile file, PCRBAttachment attachment); | ||||||
|  |     Task<IEnumerable<PCRBAttachment>> GetAttachmentsByPlanNumber(int planNumber, bool bypassCache); | ||||||
|  |     Task UpdateAttachment(PCRBAttachment attachment); | ||||||
|  |     Task DeleteAttachment(PCRBAttachment attachment); | ||||||
|  |     Task CreateNewActionItem(PCRBActionItem actionItem); | ||||||
|  |     Task UpdateActionItem(PCRBActionItem actionItem); | ||||||
|  |     Task DeleteActionItem(int id); | ||||||
|  |     Task<IEnumerable<PCRBActionItem>> GetActionItemsForPlanNumber(int planNumber, bool bypassCache); | ||||||
|  |     Task CreateNewAttendee(PCRBAttendee attendee); | ||||||
|  |     Task UpdateAttendee(PCRBAttendee attendee); | ||||||
|  |     Task DeleteAttendee(int id); | ||||||
|  |     Task<IEnumerable<PCRBAttendee>> GetAttendeesByPlanNumber(int planNumber, bool bypassCache); | ||||||
|  |     Task CreatePCR3Document(PCR3Document document); | ||||||
|  |     Task UpdatePCR3Document(PCR3Document document); | ||||||
|  |     Task<IEnumerable<PCR3Document>> GetPCR3DocumentsForPlanNumber(int planNumber, bool bypassCache); | ||||||
|  |     Task NotifyNewApprovals(PCRB pcrb); | ||||||
|  |     Task NotifyApprovers(PCRBNotification notification); | ||||||
|  |     Task NotifyOriginator(PCRBNotification notification); | ||||||
|  |     Task NotifyResponsiblePerson(PCRBActionItemNotification notification); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class PCRBService : IPCRBService { | ||||||
|  |     private readonly ILogger<PCRBService> _logger; | ||||||
|  |     private readonly IDalService _dalService; | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly IUserService _userService; | ||||||
|  |     private readonly IApprovalService _approvalService; | ||||||
|  |     private readonly ISmtpService _smtpService; | ||||||
|  |  | ||||||
|  |     private readonly string _pcrbAttachmentPath; | ||||||
|  |     private readonly string _siteBaseUrl; | ||||||
|  |  | ||||||
|  |     public PCRBService(ILogger<PCRBService> logger, | ||||||
|  |                        IDalService dalService, | ||||||
|  |                        IMemoryCache cache, | ||||||
|  |                        IUserService userService, | ||||||
|  |                        IApprovalService approvalService, | ||||||
|  |                        ISmtpService smtpService, | ||||||
|  |                        AppSettings appSettings) { | ||||||
|  |         _logger = logger ?? throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _dalService = dalService ?? throw new ArgumentNullException("IDalService not injected"); | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _userService = userService ?? throw new ArgumentNullException("IUserService not injected"); | ||||||
|  |         _approvalService = approvalService ?? | ||||||
|  |             throw new ArgumentNullException("IApprovalService not injected"); | ||||||
|  |         _smtpService = smtpService ?? throw new ArgumentNullException("ISmtpService not injected"); | ||||||
|  |         _siteBaseUrl = appSettings.SiteBaseUrl; | ||||||
|  |         _pcrbAttachmentPath = appSettings.PcrbAttachmentPath; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task CreateNewPCRB(PCRB pcrb) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to create new PCRB"); | ||||||
|  |  | ||||||
|  |             if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append("insert into CCChangeControl (OwnerID, Title, ChangeLevel, ReasonForChange, "); | ||||||
|  |             queryBuilder.Append("ChangeDescription, IsITAR, CurrentStep, InsertTimeStamp, LastUpdateDate) "); | ||||||
|  |             queryBuilder.Append($"values ({pcrb.OwnerID}, '{pcrb.Title}', '{pcrb.ChangeLevel}', "); | ||||||
|  |             queryBuilder.Append($"'{pcrb.ReasonForChange}', '{pcrb.ChangeDescription}', "); | ||||||
|  |             queryBuilder.Append($"{Convert.ToInt32(pcrb.IsITAR)}, {pcrb.CurrentStep}, "); | ||||||
|  |             queryBuilder.Append($"'{pcrb.InsertTimeStamp.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"'{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}')"); | ||||||
|  |  | ||||||
|  |             int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsCreated <= 0) throw new Exception("unable to insert new PCRB in the database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to create new PCRB, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<PCRB>> GetAllPCRBs(bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get all PCRBs"); | ||||||
|  |  | ||||||
|  |             IEnumerable<PCRB>? allPCRBs = null; | ||||||
|  |             if (!bypassCache) allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs"); | ||||||
|  |  | ||||||
|  |             if (allPCRBs is null) { | ||||||
|  |                 string sql = "select * from CCChangeControl"; | ||||||
|  |  | ||||||
|  |                 allPCRBs = (await _dalService.QueryAsync<PCRB>(sql)).ToList(); | ||||||
|  |  | ||||||
|  |                 foreach (PCRB pcrb in allPCRBs) { | ||||||
|  |                     if (string.IsNullOrWhiteSpace(pcrb.OwnerName) && pcrb.OwnerID > 0) | ||||||
|  |                         pcrb.OwnerName = (await _userService.GetUserByUserId(pcrb.OwnerID)).GetFullName(); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 _cache.Set("allPCRBs", allPCRBs, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (allPCRBs is null || allPCRBs.Count() == 0) | ||||||
|  |                 throw new Exception("no PCRBs found"); | ||||||
|  |  | ||||||
|  |             return allPCRBs; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to get all PCRBs, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<PCRB> GetPCRBByPlanNumber(int planNumber, bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get a PCRB by plan#"); | ||||||
|  |  | ||||||
|  |             if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB#"); | ||||||
|  |  | ||||||
|  |             PCRB? pcrb = null; | ||||||
|  |  | ||||||
|  |             if (!bypassCache) pcrb = _cache.Get<PCRB>($"pcrb{planNumber}"); | ||||||
|  |  | ||||||
|  |             if (pcrb is null) { | ||||||
|  |                 string sql = $"select * from CCChangeControl where PlanNumber={planNumber}"; | ||||||
|  |  | ||||||
|  |                 pcrb = (await _dalService.QueryAsync<PCRB>(sql)).FirstOrDefault(); | ||||||
|  |  | ||||||
|  |                 if (pcrb is not null) { | ||||||
|  |                     if (string.IsNullOrWhiteSpace(pcrb.OwnerName) && pcrb.OwnerID > 0) | ||||||
|  |                         pcrb.OwnerName = (await _userService.GetUserByUserId(pcrb.OwnerID)).GetFullName(); | ||||||
|  |  | ||||||
|  |                     _cache.Set($"pcrb{planNumber}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |                     _cache.Set($"pcrb{pcrb.Title}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (pcrb is null) throw new Exception($"unable to find PCRB {planNumber}"); | ||||||
|  |  | ||||||
|  |             return pcrb; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to get PCRB by Plan #, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<PCRB> GetPCRBByTitle(string title, bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get a PCRB by title"); | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             PCRB? pcrb = null; | ||||||
|  |  | ||||||
|  |             if (!bypassCache) pcrb = _cache.Get<PCRB>($"pcrb{title}"); | ||||||
|  |  | ||||||
|  |             if (pcrb is null) { | ||||||
|  |                 string sql = $"select * from CCChangeControl where Title='{title}'"; | ||||||
|  |  | ||||||
|  |                 pcrb = (await _dalService.QueryAsync<PCRB>(sql)).FirstOrDefault(); | ||||||
|  |  | ||||||
|  |                 if (pcrb is not null) { | ||||||
|  |                     if (string.IsNullOrWhiteSpace(pcrb.OwnerName) && pcrb.OwnerID > 0) | ||||||
|  |                         pcrb.OwnerName = (await _userService.GetUserByUserId(pcrb.OwnerID)).GetFullName(); | ||||||
|  |  | ||||||
|  |                     _cache.Set($"pcrb{title}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |                     _cache.Set($"pcrb{pcrb.PlanNumber}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (pcrb is null) throw new Exception($"unable to find PCRB {title}"); | ||||||
|  |  | ||||||
|  |             return pcrb; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to get PCRB by title, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdatePCRB(PCRB pcrb) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to update PCRB"); | ||||||
|  |  | ||||||
|  |             if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append($"update CCChangeControl set OwnerID={pcrb.OwnerID}, "); | ||||||
|  |             queryBuilder.Append($"Title='{pcrb.Title.Replace("'", "''")}', ChangeLevel='{pcrb.ChangeLevel}', "); | ||||||
|  |             queryBuilder.Append($"CurrentStep={pcrb.CurrentStep}, ReasonForChange='{pcrb.ReasonForChange.Replace("'", "''")}', "); | ||||||
|  |             queryBuilder.Append($"ChangeDescription='{pcrb.ChangeDescription.Replace("'", "''")}', "); | ||||||
|  |             queryBuilder.Append($"IsITAR={Convert.ToInt32(pcrb.IsITAR)}, "); | ||||||
|  |             queryBuilder.Append($"InsertTimeStamp='{pcrb.InsertTimeStamp.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"ClosedDate='{pcrb.ClosedDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"LastUpdateDate='{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}' "); | ||||||
|  |             queryBuilder.Append($"where PlanNumber={pcrb.PlanNumber}"); | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception("unable to perform update in database"); | ||||||
|  |  | ||||||
|  |             _cache.Set($"pcrb{pcrb.Title}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             _cache.Set($"pcrb{pcrb.PlanNumber}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |  | ||||||
|  |             IEnumerable<PCRB>? allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs"); | ||||||
|  |             if (allPCRBs is not null) { | ||||||
|  |                 List<PCRB> pcrbList = allPCRBs.ToList(); | ||||||
|  |                 pcrbList.RemoveAll(p => p.PlanNumber == pcrb.PlanNumber); | ||||||
|  |                 pcrbList.Add(pcrb); | ||||||
|  |                 _cache.Set("allPCRBs", pcrbList, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to update PCRB, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeletePCRB(int planNumber) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to delete PCRB {planNumber}"); | ||||||
|  |  | ||||||
|  |             if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB Plan #"); | ||||||
|  |  | ||||||
|  |             string sql = $"delete from CCChangeControl where PlanNumber={planNumber}"; | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(sql); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception("delete operation failed in database"); | ||||||
|  |  | ||||||
|  |             IEnumerable<PCRB>? allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs"); | ||||||
|  |             if (allPCRBs is not null) { | ||||||
|  |                 List<PCRB> pcrbList = allPCRBs.ToList(); | ||||||
|  |                 pcrbList.RemoveAll(p => p.PlanNumber == planNumber); | ||||||
|  |                 _cache.Set("allPCRBs", pcrbList, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to delete PCRB {planNumber}, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<UploadResult> UploadAttachment(IFormFile file, PCRBAttachment attachment) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to upload attachment"); | ||||||
|  |  | ||||||
|  |             UploadResult? uploadResult = null; | ||||||
|  |  | ||||||
|  |             if (file is null) throw new ArgumentNullException("File cannot be null"); | ||||||
|  |             if (file.Length <= 0) throw new ArgumentException("File size cannot be zero"); | ||||||
|  |             if (attachment is null) throw new ArgumentNullException("Attachment cannot be null"); | ||||||
|  |  | ||||||
|  |             try { | ||||||
|  |                 string encodedName = WebUtility.HtmlEncode(file.FileName); | ||||||
|  |                 string path = $"{_pcrbAttachmentPath}\\{attachment.PlanNumber}\\{attachment.Step}\\{encodedName}"; | ||||||
|  |  | ||||||
|  |                 attachment.Path = path; | ||||||
|  |  | ||||||
|  |                 await FileUtilities.SaveFileToFileSystem(file, path); | ||||||
|  |                 await SaveAttachmentInDb(file, attachment); | ||||||
|  |  | ||||||
|  |                 uploadResult = new() { | ||||||
|  |                     UploadSuccessful = true, | ||||||
|  |                     FileName = file.FileName | ||||||
|  |                 }; | ||||||
|  |             } catch (Exception ex) { | ||||||
|  |                 uploadResult = new() { | ||||||
|  |                     UploadSuccessful = false, | ||||||
|  |                     FileName = file.FileName, | ||||||
|  |                     Error = ex.Message | ||||||
|  |                 }; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return uploadResult; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to upload attachment, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<PCRBAttachment>> GetAttachmentsByPlanNumber(int planNumber, bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get all attachments for PCRB Plan# {planNumber}"); | ||||||
|  |  | ||||||
|  |             if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB Plan#"); | ||||||
|  |  | ||||||
|  |             IEnumerable<PCRBAttachment>? attachments = null; | ||||||
|  |  | ||||||
|  |             if (!bypassCache) | ||||||
|  |                 attachments = _cache.Get<IEnumerable<PCRBAttachment>>($"pcrbAttachments{planNumber}"); | ||||||
|  |  | ||||||
|  |             if (attachments is null) { | ||||||
|  |                 string sql = $"select * from CCAttachment where PlanNumber={planNumber}"; | ||||||
|  |  | ||||||
|  |                 attachments = await _dalService.QueryAsync<PCRBAttachment>(sql); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"pcrbAttachments{planNumber}", attachments, DateTimeOffset.Now.AddMinutes(15)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return attachments; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to get all attachments for PCRB Plan# {planNumber}, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdateAttachment(PCRBAttachment attachment) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to update an attachment"); | ||||||
|  |  | ||||||
|  |             if (attachment is null) | ||||||
|  |                 throw new ArgumentNullException("attachment cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append($"update CCAttachment "); | ||||||
|  |             queryBuilder.Append($"set Title='{attachment.Title.Replace("'", "''")}' where ID={attachment.ID}"); | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception("update failed in database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to update attachment, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeleteAttachment(PCRBAttachment attachment) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to update an attachment"); | ||||||
|  |  | ||||||
|  |             if (attachment is null) | ||||||
|  |                 throw new ArgumentNullException("attachment cannot be null"); | ||||||
|  |  | ||||||
|  |             if (!File.Exists(attachment.Path)) throw new FileNotFoundException("No file found at provided path"); | ||||||
|  |  | ||||||
|  |             File.Delete(attachment.Path); | ||||||
|  |  | ||||||
|  |             string sql = $"delete from CCAttachment where ID={attachment.ID}"; | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(sql); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception("update failed in database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to update attachment, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task CreateNewActionItem(PCRBActionItem actionItem) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to create new action item"); | ||||||
|  |  | ||||||
|  |             if (actionItem is null) throw new ArgumentNullException("action item cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append("insert into CCPCRBActionItem (Name, Gating, ClosedStatus, ClosedDate, "); | ||||||
|  |             queryBuilder.Append("ClosedByID, UploadedByID, UploadedDateTime, ResponsiblePersonID, PlanNumber, "); | ||||||
|  |             queryBuilder.Append($"Step) values ('{actionItem.Name}', {Convert.ToInt32(actionItem.Gating)}, "); | ||||||
|  |             queryBuilder.Append($"{Convert.ToInt32(actionItem.ClosedStatus)}, "); | ||||||
|  |             DateTime closedDateCopy = actionItem.ClosedDate ?? DateTimeUtilities.MAX_DT; | ||||||
|  |             queryBuilder.Append($"'{closedDateCopy.ToString("yyyy-MM-dd HH:mm:ss")}', {actionItem.ClosedByID}, "); | ||||||
|  |             queryBuilder.Append($"{actionItem.UploadedByID}, '{actionItem.UploadedDateTime.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"{actionItem.ResponsiblePersonID}, {actionItem.PlanNumber}, "); | ||||||
|  |             queryBuilder.Append($"{actionItem.Step});"); | ||||||
|  |  | ||||||
|  |             int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsCreated <= 0) throw new Exception("unable to insert new action item in the database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to create new action item, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdateActionItem(PCRBActionItem actionItem) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to update an action item"); | ||||||
|  |  | ||||||
|  |             if (actionItem is null) | ||||||
|  |                 throw new ArgumentNullException("action item cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append($"update CCPCRBActionItem set Name='{actionItem.Name.Replace("'", "''")}', Gating={Convert.ToInt32(actionItem.Gating)}, "); | ||||||
|  |             queryBuilder.Append($"ClosedStatus={Convert.ToInt32(actionItem.ClosedStatus)}, "); | ||||||
|  |             DateTime closedDateCopy = actionItem.ClosedDate ?? DateTimeUtilities.MAX_DT; | ||||||
|  |             queryBuilder.Append($"ClosedDate='{closedDateCopy.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"ClosedByID={actionItem.ClosedByID}, ResponsiblePersonID={actionItem.ResponsiblePersonID}, "); | ||||||
|  |             queryBuilder.Append($"Step={actionItem.Step} where ID={actionItem.ID}"); | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception("update failed in database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to update attachment, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeleteActionItem(int id) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to delete action item {id}"); | ||||||
|  |  | ||||||
|  |             if (id <= 0) throw new ArgumentException($"{id} is not a valid PCRB action item ID"); | ||||||
|  |  | ||||||
|  |             string sql = $"delete from CCPCRBActionItem where ID={id}"; | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(sql); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception("delete operation failed in database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to delete action item {id}, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<PCRBActionItem>> GetActionItemsForPlanNumber(int planNumber, bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get all action items for PCRB plan# {planNumber}"); | ||||||
|  |  | ||||||
|  |             if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB plan#"); | ||||||
|  |  | ||||||
|  |             IEnumerable<PCRBActionItem>? actionItems = null; | ||||||
|  |  | ||||||
|  |             if (!bypassCache) | ||||||
|  |                 actionItems = _cache.Get<IEnumerable<PCRBActionItem>>($"pcrbActionItems{planNumber}"); | ||||||
|  |  | ||||||
|  |             if (actionItems is null) { | ||||||
|  |                 string sql = $"select * from CCPCRBActionItem where PlanNumber={planNumber}"; | ||||||
|  |  | ||||||
|  |                 actionItems = await _dalService.QueryAsync<PCRBActionItem>(sql); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"pcrbActionItems{planNumber}", actionItems, DateTimeOffset.Now.AddMinutes(15)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return actionItems; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to get all action items for PCRB plan# {planNumber}, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task CreateNewAttendee(PCRBAttendee attendee) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to create new attendee"); | ||||||
|  |  | ||||||
|  |             if (attendee is null) throw new ArgumentNullException("attendee item cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append("insert into CCPCRBAttendee (PlanNumber, JobTitle, Location, Attended, AttendeeID, Step) "); | ||||||
|  |             queryBuilder.Append($"values ({attendee.PlanNumber}, '{attendee.JobTitle}', '{attendee.Location}', "); | ||||||
|  |             queryBuilder.Append($"{Convert.ToInt32(attendee.Attended)}, {attendee.AttendeeID}, "); | ||||||
|  |             queryBuilder.Append($"{attendee.Step});"); | ||||||
|  |  | ||||||
|  |             int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsCreated <= 0) throw new Exception("unable to insert new attendee in the database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to create new attendee, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdateAttendee(PCRBAttendee attendee) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to update an attendee"); | ||||||
|  |  | ||||||
|  |             if (attendee is null) | ||||||
|  |                 throw new ArgumentNullException("attendee cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append($"update CCPCRBAttendee set JobTitle='{attendee.JobTitle}', "); | ||||||
|  |             queryBuilder.Append($"Location='{attendee.Location}', Attended={Convert.ToInt32(attendee.Attended)}, "); | ||||||
|  |             queryBuilder.Append($"AttendeeID={attendee.AttendeeID}, "); | ||||||
|  |             queryBuilder.Append($"Step={attendee.Step} where ID={attendee.ID}"); | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception("update failed in database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to update attendee, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeleteAttendee(int id) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to delete attendee {id}"); | ||||||
|  |  | ||||||
|  |             if (id <= 0) throw new ArgumentException($"{id} is not a valid attendee ID"); | ||||||
|  |  | ||||||
|  |             string sql = $"delete from CCPCRBAttendee where ID={id}"; | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(sql); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception("delete operation failed in database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to delete attendee {id}, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<PCRBAttendee>> GetAttendeesByPlanNumber(int planNumber, bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get all attendees for PCRB plan# {planNumber}"); | ||||||
|  |  | ||||||
|  |             if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB plan#"); | ||||||
|  |  | ||||||
|  |             IEnumerable<PCRBAttendee>? attendees = null; | ||||||
|  |  | ||||||
|  |             if (!bypassCache) | ||||||
|  |                 attendees = _cache.Get<IEnumerable<PCRBAttendee>>($"pcrbAttendees{planNumber}"); | ||||||
|  |  | ||||||
|  |             if (attendees is null) { | ||||||
|  |                 string sql = $"select * from CCPCRBAttendee where PlanNumber={planNumber}"; | ||||||
|  |  | ||||||
|  |                 attendees = await _dalService.QueryAsync<PCRBAttendee>(sql); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"pcrbAttendees{planNumber}", attendees, DateTimeOffset.Now.AddMinutes(15)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return attendees; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to get all attendees for PCRB plan# {planNumber}, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task CreatePCR3Document(PCR3Document document) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to create new PCR3 document"); | ||||||
|  |  | ||||||
|  |             if (document is null) throw new ArgumentNullException("document item cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append("insert into CCPCR3Document (PlanNumber, DocType) "); | ||||||
|  |             queryBuilder.Append($"values ({document.PlanNumber}, '{document.DocType}')"); | ||||||
|  |  | ||||||
|  |             int rowsCreated = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsCreated <= 0) throw new Exception("unable to insert new PCR3 document in the database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to create new PCR3 document, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdatePCR3Document(PCR3Document document) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to update a PCR3 document"); | ||||||
|  |  | ||||||
|  |             if (document is null) throw new ArgumentNullException("document cannot be null"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append($"update CCPCR3Document set DocNumbers='{document.DocNumbers}', "); | ||||||
|  |             queryBuilder.Append($"Comment='{document.Comment.Replace("'", "''")}', ECNNumber={document.ECNNumber}, "); | ||||||
|  |             queryBuilder.Append($"CompletedDate='{document.CompletedDate.ToString("yyyy-MM-dd HH:mm:ss")}', "); | ||||||
|  |             queryBuilder.Append($"CompletedByID={document.CompletedByID} "); | ||||||
|  |             queryBuilder.Append($"where ID={document.ID}"); | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) throw new Exception("update failed in database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to update PCR3 document, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<PCR3Document>> GetPCR3DocumentsForPlanNumber(int planNumber, bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to get all PCR3 documents for PCRB plan# {planNumber}"); | ||||||
|  |  | ||||||
|  |             if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB plan#"); | ||||||
|  |  | ||||||
|  |             IEnumerable<PCR3Document>? documents = null; | ||||||
|  |  | ||||||
|  |             if (!bypassCache) | ||||||
|  |                 documents = _cache.Get<IEnumerable<PCR3Document>>($"pcr3Documents{planNumber}"); | ||||||
|  |  | ||||||
|  |             if (documents is null) { | ||||||
|  |                 string sql = $"select * from CCPCR3Document where PlanNumber={planNumber}"; | ||||||
|  |  | ||||||
|  |                 documents = await _dalService.QueryAsync<PCR3Document>(sql); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"pcr3Documents{planNumber}", documents, DateTimeOffset.Now.AddMinutes(15)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return documents; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to get all PCR3 documents for PCRB plan# {planNumber}, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyNewApprovals(PCRB pcrb) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to notify approvers"); | ||||||
|  |  | ||||||
|  |             if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null"); | ||||||
|  |  | ||||||
|  |             IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(pcrb.PlanNumber, true); | ||||||
|  |  | ||||||
|  |             List<Approval> approvalsNeedingNotification = approvals.Where(a => a.Step == pcrb.CurrentStep && | ||||||
|  |                                                                                a.NotifyDate <= DateTimeUtilities.MIN_DT && | ||||||
|  |                                                                                a.AssignedDate > DateTimeUtilities.MIN_DT).ToList(); | ||||||
|  |  | ||||||
|  |             HashSet<string> emailsAlreadySent = new(); | ||||||
|  |             foreach (Approval approval in approvalsNeedingNotification) { | ||||||
|  |                 User user = await _userService.GetUserByUserId(approval.UserID); | ||||||
|  |  | ||||||
|  |                 if (!emailsAlreadySent.Contains(user.Email.ToLower())) { | ||||||
|  |                     emailsAlreadySent.Add(user.Email); | ||||||
|  |  | ||||||
|  |                     List<MailAddress> toAddresses = new(); | ||||||
|  |                     toAddresses.Add(new MailAddress(user.Email.ToLower())); | ||||||
|  |  | ||||||
|  |                     List<MailAddress> ccAddresses = new(); | ||||||
|  |  | ||||||
|  |                     string subject = $"[New Task] Mesa Fab Approval - PCRB# {pcrb.PlanNumber} - {pcrb.Title}"; | ||||||
|  |  | ||||||
|  |                     StringBuilder bodyBuilder = new(); | ||||||
|  |                     bodyBuilder.Append($"PCRB# {pcrb.PlanNumber} [{pcrb.Title}] PCR{approval.Step} is ready for your approval. "); | ||||||
|  |                     bodyBuilder.Append($"The assigned role is {approval.SubRoleCategoryItem}. <br /> <br />"); | ||||||
|  |                     bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=pcrb/{approval.IssueID} to view the PCRB."); | ||||||
|  |  | ||||||
|  |                     await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString()); | ||||||
|  |  | ||||||
|  |                     approval.NotifyDate = DateTime.Now; | ||||||
|  |                     await _approvalService.UpdateApproval(approval); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to notify approvers, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyApprovers(PCRBNotification notification) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to send notification to approvers"); | ||||||
|  |  | ||||||
|  |             if (notification is null) throw new ArgumentNullException("notification cannot be null"); | ||||||
|  |             if (notification.PCRB is null) throw new ArgumentNullException("PCRB cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(notification.PCRB.PlanNumber, true); | ||||||
|  |  | ||||||
|  |             HashSet<string> emailsAlreadySent = new(); | ||||||
|  |             foreach (Approval approval in approvals) { | ||||||
|  |                 User user = await _userService.GetUserByUserId(approval.UserID); | ||||||
|  |  | ||||||
|  |                 if (!emailsAlreadySent.Contains(user.Email)) { | ||||||
|  |                     emailsAlreadySent.Add(user.Email); | ||||||
|  |  | ||||||
|  |                     List<MailAddress> toAddresses = new(); | ||||||
|  |                     toAddresses.Add(new MailAddress(user.Email)); | ||||||
|  |  | ||||||
|  |                     List<MailAddress> ccAddresses = new(); | ||||||
|  |  | ||||||
|  |                     string subject = $"[Update] Mesa Fab Approval - PCRB# {notification.PCRB.PlanNumber} - {notification.PCRB.Title}"; | ||||||
|  |  | ||||||
|  |                     StringBuilder bodyBuilder = new(); | ||||||
|  |                     bodyBuilder.Append($"{notification.Message} <br /> <br />"); | ||||||
|  |                     bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=pcrb/{approval.IssueID} to view the PCRB."); | ||||||
|  |  | ||||||
|  |                     await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString()); | ||||||
|  |  | ||||||
|  |                     approval.NotifyDate = DateTime.Now; | ||||||
|  |                     await _approvalService.UpdateApproval(approval); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to send notification to originator, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyOriginator(PCRBNotification notification) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to send notification to originator"); | ||||||
|  |  | ||||||
|  |             if (notification is null) throw new ArgumentNullException("notification cannot be null"); | ||||||
|  |             if (notification.PCRB is null) throw new ArgumentNullException("PCRB cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             User user = await _userService.GetUserByUserId(notification.PCRB.OwnerID); | ||||||
|  |  | ||||||
|  |             List<MailAddress> toAddresses = new(); | ||||||
|  |             toAddresses.Add(new MailAddress(user.Email)); | ||||||
|  |  | ||||||
|  |             List<MailAddress> ccAddresses = new(); | ||||||
|  |  | ||||||
|  |             string subject = $"[Update] Mesa Fab Approval - PCRB# {notification.PCRB.PlanNumber} - {notification.PCRB.Title}"; | ||||||
|  |  | ||||||
|  |             StringBuilder bodyBuilder = new(); | ||||||
|  |             bodyBuilder.Append($"{notification.Message} <br /> <br />"); | ||||||
|  |             bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=pcrb/{notification.PCRB.PlanNumber} to view the PCRB."); | ||||||
|  |  | ||||||
|  |             await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString()); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to send notification to originator, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyResponsiblePerson(PCRBActionItemNotification notification) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to notify responsible person"); | ||||||
|  |  | ||||||
|  |             if (notification is null) throw new ArgumentNullException("notification cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(notification.Message)) | ||||||
|  |                 throw new ArgumentException("message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             if (notification.ActionItem.ResponsiblePerson is null) | ||||||
|  |                 notification.ActionItem.ResponsiblePerson = await _userService.GetUserByUserId(notification.ActionItem.ResponsiblePersonID); | ||||||
|  |  | ||||||
|  |             List<MailAddress> toAddresses = new(); | ||||||
|  |             toAddresses.Add(new MailAddress(notification.ActionItem.ResponsiblePerson.Email)); | ||||||
|  |  | ||||||
|  |             List<MailAddress> ccAddresses = new(); | ||||||
|  |  | ||||||
|  |             string subject = $"[New Task] Mesa Fab Approval - PCRB# {notification.PCRB.PlanNumber} - {notification.PCRB.Title}"; | ||||||
|  |  | ||||||
|  |             StringBuilder bodyBuilder = new(); | ||||||
|  |             bodyBuilder.Append($"{notification.Message} <br /> <br />"); | ||||||
|  |             bodyBuilder.Append($"Click {_siteBaseUrl}/redirect?redirectPath=pcrb/{notification.PCRB.PlanNumber} to view the PCRB."); | ||||||
|  |  | ||||||
|  |             await _smtpService.SendEmail(toAddresses, ccAddresses, subject, bodyBuilder.ToString()); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to notify responsible person, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task SaveAttachmentInDb(IFormFile file, PCRBAttachment attachment) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation($"Attempting to save attachment to database"); | ||||||
|  |  | ||||||
|  |             if (file is null) throw new ArgumentNullException("File cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(attachment.Path)) throw new ArgumentException("Path cannot be null or empty"); | ||||||
|  |             if (attachment.PlanNumber <= 0) throw new ArgumentException($"{attachment.PlanNumber} is not a valid PCRB Plan#"); | ||||||
|  |  | ||||||
|  |             StringBuilder queryBuilder = new(); | ||||||
|  |             queryBuilder.Append("insert into CCAttachment (PlanNumber, FileName, UploadDateTime, Path, UploadedByID, Title, "); | ||||||
|  |             queryBuilder.Append($"Step) values ({attachment.PlanNumber}, '{file.FileName}', "); | ||||||
|  |             queryBuilder.Append($"'{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}', '{attachment.Path}', {attachment.UploadedByID}, "); | ||||||
|  |             queryBuilder.Append($"'{attachment.Title}', {attachment.Step});"); | ||||||
|  |  | ||||||
|  |             int rowsAffected = await _dalService.ExecuteAsync(queryBuilder.ToString()); | ||||||
|  |  | ||||||
|  |             if (rowsAffected <= 0) | ||||||
|  |                 throw new Exception("Unable to insert attachment in database"); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.LogError($"Unable to save file to DB, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										79
									
								
								MesaFabApproval.API/Services/SmtpService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								MesaFabApproval.API/Services/SmtpService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | |||||||
|  | using System.Net.Mail; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.API.Clients; | ||||||
|  | using MesaFabApproval.Models; | ||||||
|  |  | ||||||
|  | using Microsoft.IdentityModel.Tokens; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Services; | ||||||
|  |  | ||||||
|  | public interface ISmtpService { | ||||||
|  |     Task<bool> SendEmail(IEnumerable<MailAddress> recipients, IEnumerable<MailAddress> ccRecipients, string subject, string body); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class SmtpService : ISmtpService { | ||||||
|  |     private readonly ILogger<SmtpService> _logger; | ||||||
|  |     private readonly ISmtpClientWrapper _smtpClient; | ||||||
|  |     private readonly bool _shouldSendEmail; | ||||||
|  |  | ||||||
|  |     public SmtpService(ILogger<SmtpService> logger, ISmtpClientWrapper smtpClient, AppSettings appSettings) { | ||||||
|  |         _logger = logger ?? | ||||||
|  |             throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _smtpClient = smtpClient ?? | ||||||
|  |             throw new ArgumentNullException("SmtpClient not injected"); | ||||||
|  |         _shouldSendEmail = appSettings.ShouldSendEmail; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<bool> SendEmail(IEnumerable<MailAddress> recipients, | ||||||
|  |                                       IEnumerable<MailAddress> ccRecipients, | ||||||
|  |                                       string subject, | ||||||
|  |                                       string body) { | ||||||
|  |         if (recipients.IsNullOrEmpty()) throw new ArgumentNullException("recipients cannot be null or empty!"); | ||||||
|  |         if (ccRecipients is null) throw new ArgumentNullException("ccRecipients cannot be null!"); | ||||||
|  |         if (subject.IsNullOrEmpty()) throw new ArgumentNullException("subject cannot be null or empty!"); | ||||||
|  |         if (body.IsNullOrEmpty()) throw new ArgumentNullException("body cannot be null or empty!"); | ||||||
|  |  | ||||||
|  |         return await Task.Run(() => { | ||||||
|  |             int maxRetries = 3; | ||||||
|  |             int backoffSeconds = 30; | ||||||
|  |  | ||||||
|  |             bool messageWasSent = false; | ||||||
|  |  | ||||||
|  |             try { | ||||||
|  |                 if (_shouldSendEmail) { | ||||||
|  |                     int remainingRetries = maxRetries; | ||||||
|  |                     while (!messageWasSent && remainingRetries > 0) { | ||||||
|  |                         try { | ||||||
|  |                             Task.Delay((maxRetries - remainingRetries--) * backoffSeconds * 1000); | ||||||
|  |  | ||||||
|  |                             _logger.LogInformation($"Attempting to send notification. Remaining retries: {remainingRetries}"); | ||||||
|  |  | ||||||
|  |                             MailMessage msg = new MailMessage(); | ||||||
|  |                             msg.IsBodyHtml = true; | ||||||
|  |                             msg.From = new MailAddress("MesaFabApproval@infineon.com", "Mesa Fab Approval"); | ||||||
|  |                             msg.Sender = new MailAddress("MesaFabApproval@infineon.com", "Mesa Fab Approval"); | ||||||
|  |                             foreach (MailAddress recipient in recipients) msg.To.Add(recipient); | ||||||
|  |                             msg.Bcc.Add("chase.tucker@infineon.com"); | ||||||
|  |                             foreach (MailAddress ccRecipient in ccRecipients) msg.CC.Add(ccRecipient); | ||||||
|  |                             msg.Subject = subject; | ||||||
|  |                             msg.Body = body; | ||||||
|  |  | ||||||
|  |                             _smtpClient.Send(msg); | ||||||
|  |  | ||||||
|  |                             messageWasSent = true; | ||||||
|  |                         } catch (Exception ex) { | ||||||
|  |                             _logger.LogError($"Message not sent successfully. Exception: {ex.Message}"); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     _logger.LogInformation("Not sending email per local configuration"); | ||||||
|  |                     messageWasSent = true; | ||||||
|  |                 } | ||||||
|  |             } catch (Exception ex) { | ||||||
|  |                 _logger.LogError($"An exception occurred when attempting to send notification. Exception: {ex.Message}"); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return messageWasSent; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										147
									
								
								MesaFabApproval.API/Services/UserService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								MesaFabApproval.API/Services/UserService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,147 @@ | |||||||
|  | using System.Text; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  |  | ||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Services; | ||||||
|  |  | ||||||
|  | public interface IUserService { | ||||||
|  |     Task<IEnumerable<User>> GetAllActiveUsers(); | ||||||
|  |     Task<User> GetUserByLoginId(string loginId); | ||||||
|  |     Task<User> GetUserByUserId(int userId); | ||||||
|  |     Task<IEnumerable<int>> GetApproverUserIdsBySubRoleCategoryItem(string item); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class UserService : IUserService { | ||||||
|  |     private readonly ILogger<UserService> _logger; | ||||||
|  |     private readonly IDalService _dalService; | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |  | ||||||
|  |     public UserService(ILogger<UserService> logger, IDalService dalService, IMemoryCache cache) { | ||||||
|  |         _logger = logger ?? | ||||||
|  |             throw new ArgumentNullException("ILogger not injected"); | ||||||
|  |         _dalService = dalService ?? | ||||||
|  |             throw new ArgumentNullException("IDalService not injected"); | ||||||
|  |         _cache = cache ?? | ||||||
|  |             throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<User>> GetAllActiveUsers() { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get all active users"); | ||||||
|  |  | ||||||
|  |             IEnumerable<User>? allActiveUsers = _cache.Get<IEnumerable<User>>("allActiveUsers"); | ||||||
|  |  | ||||||
|  |             if (allActiveUsers is null) { | ||||||
|  |                 string sql = "select * from Users where IsActive = 1"; | ||||||
|  |  | ||||||
|  |                 allActiveUsers = (await _dalService.QueryAsync<User>(sql)).ToList(); | ||||||
|  |  | ||||||
|  |                 _cache.Set("allActiveUsers", allActiveUsers, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (allActiveUsers is null || allActiveUsers.Count() == 0) { | ||||||
|  |                 throw new Exception("No users found"); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return allActiveUsers; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             string errMsg = $"An exception occurred when attempting to get all users. Exception: {ex.Message}"; | ||||||
|  |             _logger.LogError(errMsg); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<User> GetUserByLoginId(string loginId) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get user by LoginId"); | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(loginId)) | ||||||
|  |                 throw new ArgumentException("LoginId cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             User? user = _cache.Get<User>($"userByLoginId{loginId}"); | ||||||
|  |  | ||||||
|  |             if (user is null) | ||||||
|  |                 user = _cache.Get<IEnumerable<User>>("allActiveUsers")?.FirstOrDefault(u => u.LoginID == loginId); | ||||||
|  |  | ||||||
|  |             if (user is null) { | ||||||
|  |                 string sql = $"select * from Users where LoginID = '{loginId}';"; | ||||||
|  |  | ||||||
|  |                 user = (await _dalService.QueryAsync<User>(sql)).FirstOrDefault(); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"userByLoginId{loginId}", user, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (user is null) throw new Exception($"No user found with LoginID {loginId}"); | ||||||
|  |  | ||||||
|  |             return user; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             string errMsg = $"An exception occurred when attempting to get user for LoginID {loginId}. Exception: {ex.Message}"; | ||||||
|  |             _logger.LogError(errMsg); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<User> GetUserByUserId(int userId) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get user by user ID"); | ||||||
|  |  | ||||||
|  |             if (userId <= 0) throw new ArgumentException($"{userId} is not a valid user ID"); | ||||||
|  |  | ||||||
|  |             User? user = _cache.Get<User>($"userByUserId{userId}"); | ||||||
|  |  | ||||||
|  |             if (user is null) | ||||||
|  |                 user = _cache.Get<IEnumerable<User>>("allActiveUsers")?.FirstOrDefault(u => u.UserID == userId); | ||||||
|  |  | ||||||
|  |             if (user is null) { | ||||||
|  |                 string sql = $"select * from Users where UserID = '{userId}';"; | ||||||
|  |  | ||||||
|  |                 user = (await _dalService.QueryAsync<User>(sql)).FirstOrDefault(); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"userByUserId{userId}", user, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (user is null) throw new Exception($"No user found with UserID {userId}"); | ||||||
|  |  | ||||||
|  |             return user; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             string errMsg = $"An exception occurred when attempting to get user for UserID {userId}. Exception: {ex.Message}"; | ||||||
|  |             _logger.LogError(errMsg); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<int>> GetApproverUserIdsBySubRoleCategoryItem(string item) { | ||||||
|  |         try { | ||||||
|  |             _logger.LogInformation("Attempting to get approver user IDs"); | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(item)) throw new ArgumentException("SubRoleCategoryItem cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             IEnumerable<int>? userIds = _cache.Get<IEnumerable<int>>($"approverUserIdsBySubRollCategory{item}"); | ||||||
|  |  | ||||||
|  |             if (userIds is null) { | ||||||
|  |                 StringBuilder queryBuilder = new(); | ||||||
|  |                 queryBuilder.Append("select us.UserID "); | ||||||
|  |                 queryBuilder.Append("from SubRole as sr "); | ||||||
|  |                 queryBuilder.Append("join UserSubRole as us on sr.SubRoleID=us.SubRoleID "); | ||||||
|  |                 queryBuilder.Append("join SubRoleCategory as sc on sr.SubRoleCategoryID=sc.SubRoleCategoryID "); | ||||||
|  |                 queryBuilder.Append($"where sc.SubRoleCategoryItem='{item}'"); | ||||||
|  |  | ||||||
|  |                 userIds = (await _dalService.QueryAsync<int>(queryBuilder.ToString())).ToList(); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"approverUserIdsBySubRollCategory{item}", userIds, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (userIds is null || userIds.Count() == 0) { | ||||||
|  |                 throw new Exception($"No users found for SubRoleCategoryItem {item}"); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return userIds; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             string errMsg = $"An exception occurred when attempting to get approver user IDs. Exception: {ex.Message}"; | ||||||
|  |             _logger.LogError(errMsg); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								MesaFabApproval.API/Utilities/FileUtilities.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								MesaFabApproval.API/Utilities/FileUtilities.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | |||||||
|  | using Microsoft.AspNetCore.Components.Forms; | ||||||
|  |  | ||||||
|  | using NLog; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.API.Utilities; | ||||||
|  |  | ||||||
|  | public class FileUtilities { | ||||||
|  |     private static readonly Logger _logger = NLog.LogManager.GetCurrentClassLogger(); | ||||||
|  |  | ||||||
|  |     public static async Task SaveFileToFileSystem(IFormFile file, string path) { | ||||||
|  |         try { | ||||||
|  |             _logger.Info($"Attempting to save file to file system"); | ||||||
|  |  | ||||||
|  |             if (file is null) throw new ArgumentNullException("File cannot be null"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Path cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             if (File.Exists(path)) throw new Exception($"A file already exists with name {file.FileName}"); | ||||||
|  |  | ||||||
|  |             string? directoryPath = Path.GetDirectoryName(path); | ||||||
|  |             if (!string.IsNullOrWhiteSpace(directoryPath)) | ||||||
|  |                 Directory.CreateDirectory(directoryPath); | ||||||
|  |  | ||||||
|  |             using (Stream stream = File.Create(path)) { | ||||||
|  |                 await file.CopyToAsync(stream); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _logger.Error($"Unable to save file to file system, because {ex.Message}"); | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								MesaFabApproval.API/appsettings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								MesaFabApproval.API/appsettings.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | { | ||||||
|  |   "AllowedHosts": "*" | ||||||
|  | } | ||||||
							
								
								
									
										33
									
								
								MesaFabApproval.API/nLog.config
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								MesaFabApproval.API/nLog.config
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8" ?> | ||||||
|  | <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" | ||||||
|  |       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  |       autoReload="true"> | ||||||
|  |  | ||||||
|  |     <extensions> | ||||||
|  |         <add assembly="NLog.Web.AspNetCore"/> | ||||||
|  |     </extensions> | ||||||
|  |      | ||||||
|  |     <targets> | ||||||
|  |         <target name="asyncLog" xsi:type="AsyncWrapper"> | ||||||
|  |             <target | ||||||
|  |                 name="appLog" | ||||||
|  |                 xsi:type="File" | ||||||
|  |                 fileName="d:\logs\MesaFabApproval.API\log.txt" | ||||||
|  |                 archiveFilename="d:\logs\MesaFabApproval.API\archive\log-${shortdate}.txt" | ||||||
|  |                 maxArchiveFiles="30" | ||||||
|  |                 archiveEvery="Day" | ||||||
|  |             /> | ||||||
|  |             <target | ||||||
|  |                 name="consoleLog" | ||||||
|  |                 xsi:type="Console" | ||||||
|  |             /> | ||||||
|  |         </target> | ||||||
|  |     </targets> | ||||||
|  |  | ||||||
|  |     <rules> | ||||||
|  |         <logger name="Microsoft.*" finalMinLevel="Warn" /> | ||||||
|  |         <logger name="Microsoft.AspNetCore.HttpLogging.*" finalMinLevel="Info" /> | ||||||
|  |         <logger name="System.Net.Http.HttpClient.*" finalMinLevel="Warn" /> | ||||||
|  |         <logger name="*" minlevel="Info" writeTo="consoleLog, appLog" /> | ||||||
|  |     </rules> | ||||||
|  | </nlog> | ||||||
							
								
								
									
										1
									
								
								MesaFabApproval.Client/.vscode/format-report.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								MesaFabApproval.Client/.vscode/format-report.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | [] | ||||||
							
								
								
									
										30
									
								
								MesaFabApproval.Client/.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								MesaFabApproval.Client/.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | { | ||||||
|  |     // Use IntelliSense to learn about possible attributes. | ||||||
|  |     // Hover to view descriptions of existing attributes. | ||||||
|  |     // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||||||
|  |     "version": "0.2.0", | ||||||
|  |     "configurations": [ | ||||||
|  |         { | ||||||
|  |             "name": ".NET Core Launch (console)", | ||||||
|  |             "type": "coreclr", | ||||||
|  |             "request": "launch", | ||||||
|  |             "preLaunchTask": "build", | ||||||
|  |             "program": "${workspaceFolder}/bin/Debug/net8.0/MesaFabApproval.API.dll", | ||||||
|  |             "args": [], | ||||||
|  |             "cwd": "${workspaceFolder}", | ||||||
|  |             "console": "integratedTerminal", | ||||||
|  |             "stopAtEntry": false | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "name": ".NET Core Attach", | ||||||
|  |             "type": "coreclr", | ||||||
|  |             "request": "attach" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "type": "node", | ||||||
|  |             "request": "launch", | ||||||
|  |             "name": "node Launch Current Opened File", | ||||||
|  |             "program": "${file}" | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								MesaFabApproval.Client/.vscode/mklink.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								MesaFabApproval.Client/.vscode/mklink.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | # mklink | ||||||
|  |  | ||||||
|  | ```bash 1731705389065 = 638673021890650000 = Fri Nov 15 2024 14:16:28 GMT-0700 (Mountain Standard Time) | ||||||
|  | mklink /J "L:\DevOps\Mesa_FI\MesaFabApproval\MesaFabApproval.API\.vscode\.UserSecrets" "C:\Users\phares\AppData\Roaming\Microsoft\UserSecrets\0b98e1f2-95ed-4edd-8149-58cce51ca059" | ||||||
|  | dotnet run --urls=https://localhost:7114/ -C Release | ||||||
|  | ``` | ||||||
							
								
								
									
										424
									
								
								MesaFabApproval.Client/.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								MesaFabApproval.Client/.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,424 @@ | |||||||
|  | { | ||||||
|  |   "[markdown]": { | ||||||
|  |     "editor.wordWrap": "off" | ||||||
|  |   }, | ||||||
|  |   "files.exclude": { | ||||||
|  |     "**/.git": false, | ||||||
|  |     "**/node_modules": true | ||||||
|  |   }, | ||||||
|  |   "files.watcherExclude": { | ||||||
|  |     "**/node_modules": true | ||||||
|  |   }, | ||||||
|  |   "cSpell.words": [ | ||||||
|  |     "abutton", | ||||||
|  |     "accessibilities", | ||||||
|  |     "accodingly", | ||||||
|  |     "acknowledgmentby", | ||||||
|  |     "Acks", | ||||||
|  |     "actionsheet", | ||||||
|  |     "Additonal", | ||||||
|  |     "Addtional", | ||||||
|  |     "againm", | ||||||
|  |     "agendaview", | ||||||
|  |     "Antlr", | ||||||
|  |     "Appover", | ||||||
|  |     "Appprrovers", | ||||||
|  |     "Approvalog", | ||||||
|  |     "Aprovers", | ||||||
|  |     "Aproverslist", | ||||||
|  |     "asax", | ||||||
|  |     "aspnetmvc", | ||||||
|  |     "Assignedto", | ||||||
|  |     "Atachments", | ||||||
|  |     "Attachemnt", | ||||||
|  |     "Attachemnts", | ||||||
|  |     "Attchment", | ||||||
|  |     "auditee", | ||||||
|  |     "Auditee", | ||||||
|  |     "Auditees", | ||||||
|  |     "automaically", | ||||||
|  |     "Autthorized", | ||||||
|  |     "beacuase", | ||||||
|  |     "beforeunload", | ||||||
|  |     "Belguim", | ||||||
|  |     "bfound", | ||||||
|  |     "bgcolor", | ||||||
|  |     "Bies", | ||||||
|  |     "binded", | ||||||
|  |     "blackbackground", | ||||||
|  |     "blackhover", | ||||||
|  |     "blackpressed", | ||||||
|  |     "blueenergy", | ||||||
|  |     "blueopal", | ||||||
|  |     "buttongroup", | ||||||
|  |     "BYMRB", | ||||||
|  |     "bytesgot", | ||||||
|  |     "CAID", | ||||||
|  |     "casection", | ||||||
|  |     "CAXXXX", | ||||||
|  |     "CCPCR", | ||||||
|  |     "CCPCRB", | ||||||
|  |     "cellspacing", | ||||||
|  |     "Cheeso's", | ||||||
|  |     "chkbx", | ||||||
|  |     "Clib", | ||||||
|  |     "colorpicker", | ||||||
|  |     "columnmenu", | ||||||
|  |     "columnsreorder", | ||||||
|  |     "columnsresize", | ||||||
|  |     "comming", | ||||||
|  |     "Containmen", | ||||||
|  |     "Copmments", | ||||||
|  |     "correctiv", | ||||||
|  |     "Correctivet", | ||||||
|  |     "Creat", | ||||||
|  |     "currentd", | ||||||
|  |     "Cyle", | ||||||
|  |     "dadada", | ||||||
|  |     "darkbluehover", | ||||||
|  |     "darkbluepressed", | ||||||
|  |     "darkred", | ||||||
|  |     "datafields", | ||||||
|  |     "datasource", | ||||||
|  |     "dataviz", | ||||||
|  |     "datepicker", | ||||||
|  |     "datetimepicker", | ||||||
|  |     "dayview", | ||||||
|  |     "Deletet", | ||||||
|  |     "Delgation", | ||||||
|  |     "DENITED", | ||||||
|  |     "Deparmtent", | ||||||
|  |     "departmentids", | ||||||
|  |     "Descirption", | ||||||
|  |     "devprog", | ||||||
|  |     "dfeffc", | ||||||
|  |     "Disp", | ||||||
|  |     "Dispo", | ||||||
|  |     "Dispoitio", | ||||||
|  |     "Dispos", | ||||||
|  |     "Dispositon", | ||||||
|  |     "Dispostion", | ||||||
|  |     "Dispostions", | ||||||
|  |     "dispotypevalidation", | ||||||
|  |     "Docbase", | ||||||
|  |     "Documentum", | ||||||
|  |     "Documetum", | ||||||
|  |     "dont", | ||||||
|  |     "downlaoded", | ||||||
|  |     "draganddrop", | ||||||
|  |     "dragcancel", | ||||||
|  |     "dropdownlist", | ||||||
|  |     "Eamils", | ||||||
|  |     "ECNPCRB", | ||||||
|  |     "Ecns", | ||||||
|  |     "edmx", | ||||||
|  |     "EECN", | ||||||
|  |     "emai", | ||||||
|  |     "emailparams", | ||||||
|  |     "Emergrncy", | ||||||
|  |     "energyblue", | ||||||
|  |     "Eran", | ||||||
|  |     "Esql", | ||||||
|  |     "ETECN", | ||||||
|  |     "EXCELOPENXML", | ||||||
|  |     "existinglocation", | ||||||
|  |     "Expando", | ||||||
|  |     "extrafield", | ||||||
|  |     "fadc", | ||||||
|  |     "fbec", | ||||||
|  |     "fcfdfd", | ||||||
|  |     "fdff", | ||||||
|  |     "fece", | ||||||
|  |     "feeebd", | ||||||
|  |     "ffdc", | ||||||
|  |     "ffdd", | ||||||
|  |     "fieldset", | ||||||
|  |     "FILIPE", | ||||||
|  |     "filtermenu", | ||||||
|  |     "Fldr", | ||||||
|  |     "flintstone", | ||||||
|  |     "FLOWLOCS", | ||||||
|  |     "FMEA", | ||||||
|  |     "ftplib", | ||||||
|  |     "FTPSPN", | ||||||
|  |     "GETDATE", | ||||||
|  |     "gitea", | ||||||
|  |     "globaldocudms", | ||||||
|  |     "glyphicons", | ||||||
|  |     "groupable", | ||||||
|  |     "Guids", | ||||||
|  |     "halflings", | ||||||
|  |     "Hexsize", | ||||||
|  |     "highcontrast", | ||||||
|  |     "Hmac", | ||||||
|  |     "holdsteps", | ||||||
|  |     "hostspecific", | ||||||
|  |     "icenium", | ||||||
|  |     "IECN", | ||||||
|  |     "imagebrowser", | ||||||
|  |     "IMRB", | ||||||
|  |     "Infineon", | ||||||
|  |     "Insertd", | ||||||
|  |     "inverseicons", | ||||||
|  |     "IPCRB", | ||||||
|  |     "ISADMIN", | ||||||
|  |     "islast", | ||||||
|  |     "ISNULL", | ||||||
|  |     "ITAR", | ||||||
|  |     "jquery", | ||||||
|  |     "jqueryval", | ||||||
|  |     "jqwidgets", | ||||||
|  |     "jqxbuttongroup", | ||||||
|  |     "jqxbuttons", | ||||||
|  |     "jqxcalendar", | ||||||
|  |     "jqxchart", | ||||||
|  |     "jqxcheckbox", | ||||||
|  |     "jqxcolorpicker", | ||||||
|  |     "jqxcombobox", | ||||||
|  |     "jqxcore", | ||||||
|  |     "jqxdata", | ||||||
|  |     "jqxdatatable", | ||||||
|  |     "jqxdatetimeinput", | ||||||
|  |     "jqxdocking", | ||||||
|  |     "jqxdockpanel", | ||||||
|  |     "jqxdragdrop", | ||||||
|  |     "jqxdropdownbutton", | ||||||
|  |     "jqxdropdownlist", | ||||||
|  |     "jqxexpander", | ||||||
|  |     "jqxgauge", | ||||||
|  |     "jqxgrid", | ||||||
|  |     "jqxinput", | ||||||
|  |     "jqxknockout", | ||||||
|  |     "jqxlistbox", | ||||||
|  |     "jqxlistmenu", | ||||||
|  |     "jqxmaskedinput", | ||||||
|  |     "jqxmenu", | ||||||
|  |     "jqxnavigationbar", | ||||||
|  |     "jqxnumberinput", | ||||||
|  |     "jqxpanel", | ||||||
|  |     "jqxpasswordinput", | ||||||
|  |     "jqxprogressbar", | ||||||
|  |     "jqxradiobutton", | ||||||
|  |     "jqxrangeselector", | ||||||
|  |     "jqxrating", | ||||||
|  |     "jqxresponse", | ||||||
|  |     "jqxscrollbar", | ||||||
|  |     "jqxscrollview", | ||||||
|  |     "jqxslider", | ||||||
|  |     "jqxsplitter", | ||||||
|  |     "jqxswitchbutton", | ||||||
|  |     "jqxtabs", | ||||||
|  |     "jqxtooltip", | ||||||
|  |     "jqxtouch", | ||||||
|  |     "jqxtree", | ||||||
|  |     "jqxtreegrid", | ||||||
|  |     "jqxtreemap", | ||||||
|  |     "jqxvalidator", | ||||||
|  |     "jqxwindow", | ||||||
|  |     "kendogridcustom", | ||||||
|  |     "kendoui", | ||||||
|  |     "labelelement", | ||||||
|  |     "labelledby", | ||||||
|  |     "Leanred", | ||||||
|  |     "lightgray", | ||||||
|  |     "linkbutton", | ||||||
|  |     "Linq", | ||||||
|  |     "Listdiv", | ||||||
|  |     "listview", | ||||||
|  |     "Lnks", | ||||||
|  |     "localfilename", | ||||||
|  |     "loclist", | ||||||
|  |     "logis", | ||||||
|  |     "logtext", | ||||||
|  |     "loopmis", | ||||||
|  |     "lotdispo", | ||||||
|  |     "LOTDISPSITION", | ||||||
|  |     "Lotfile", | ||||||
|  |     "lotlist", | ||||||
|  |     "lotstatusoption", | ||||||
|  |     "LTRIM", | ||||||
|  |     "MADUREIRA", | ||||||
|  |     "mailrelay", | ||||||
|  |     "MDTM", | ||||||
|  |     "meego", | ||||||
|  |     "meetingid", | ||||||
|  |     "menubutton", | ||||||
|  |     "mesafi", | ||||||
|  |     "metroblack", | ||||||
|  |     "metrodark", | ||||||
|  |     "miliseconds", | ||||||
|  |     "modalview", | ||||||
|  |     "modernizr", | ||||||
|  |     "Modernizr", | ||||||
|  |     "monthview", | ||||||
|  |     "MRBIs", | ||||||
|  |     "Mrbs", | ||||||
|  |     "msecs", | ||||||
|  |     "multipleextended", | ||||||
|  |     "Navigatable", | ||||||
|  |     "nbsp", | ||||||
|  |     "newbase", | ||||||
|  |     "newchange", | ||||||
|  |     "newdi", | ||||||
|  |     "newfilename", | ||||||
|  |     "newsource", | ||||||
|  |     "Newtonsoft", | ||||||
|  |     "notications", | ||||||
|  |     "Notifcation", | ||||||
|  |     "Notifyf", | ||||||
|  |     "NTLM", | ||||||
|  |     "Nullcc", | ||||||
|  |     "numerictextbox", | ||||||
|  |     "objdata", | ||||||
|  |     "OCAP", | ||||||
|  |     "occured", | ||||||
|  |     "odata", | ||||||
|  |     "oldfilename", | ||||||
|  |     "OLHOLD", | ||||||
|  |     "onclick", | ||||||
|  |     "onmousemove", | ||||||
|  |     "OPDESC", | ||||||
|  |     "OPENQUERY", | ||||||
|  |     "Oper", | ||||||
|  |     "operationslist", | ||||||
|  |     "Orginator", | ||||||
|  |     "Originatorname", | ||||||
|  |     "Ouellette", | ||||||
|  |     "Owin", | ||||||
|  |     "pageable", | ||||||
|  |     "Pageable", | ||||||
|  |     "panelbar", | ||||||
|  |     "parentid", | ||||||
|  |     "parminput", | ||||||
|  |     "parms", | ||||||
|  |     "Parms", | ||||||
|  |     "particula", | ||||||
|  |     "pasv", | ||||||
|  |     "PASV", | ||||||
|  |     "PATINDEX", | ||||||
|  |     "PCRB", | ||||||
|  |     "PCRBID", | ||||||
|  |     "pcrvalues", | ||||||
|  |     "pdbonly", | ||||||
|  |     "Preventitive", | ||||||
|  |     "preventivet", | ||||||
|  |     "Prevetative", | ||||||
|  |     "proces", | ||||||
|  |     "Processedl", | ||||||
|  |     "procs", | ||||||
|  |     "productfamilies", | ||||||
|  |     "progess", | ||||||
|  |     "progressbar", | ||||||
|  |     "qrcode", | ||||||
|  |     "Quanityt", | ||||||
|  |     "rangebar", | ||||||
|  |     "Recep", | ||||||
|  |     "Recepient", | ||||||
|  |     "recieved", | ||||||
|  |     "recordlock", | ||||||
|  |     "remotefilename", | ||||||
|  |     "reorderable", | ||||||
|  |     "reportform", | ||||||
|  |     "reportslist", | ||||||
|  |     "reportslistdiv", | ||||||
|  |     "Reqquired", | ||||||
|  |     "Reqs", | ||||||
|  |     "Requiest", | ||||||
|  |     "Responsibles", | ||||||
|  |     "RETR", | ||||||
|  |     "Revisioing", | ||||||
|  |     "Revisioned", | ||||||
|  |     "Revison", | ||||||
|  |     "rgba", | ||||||
|  |     "rkotian", | ||||||
|  |     "RNFR", | ||||||
|  |     "RNTO", | ||||||
|  |     "Roless", | ||||||
|  |     "roundbg", | ||||||
|  |     "RTRIM", | ||||||
|  |     "SAMDB", | ||||||
|  |     "scroller", | ||||||
|  |     "scrollview", | ||||||
|  |     "seleced", | ||||||
|  |     "selectionlog", | ||||||
|  |     "Selectpart", | ||||||
|  |     "sess", | ||||||
|  |     "Sfisharepoint", | ||||||
|  |     "shinyblack", | ||||||
|  |     "showpassword", | ||||||
|  |     "SIGNON", | ||||||
|  |     "simpleparser", | ||||||
|  |     "slddrw", | ||||||
|  |     "sldprt", | ||||||
|  |     "sortasc", | ||||||
|  |     "sortascbutton", | ||||||
|  |     "sortdesc", | ||||||
|  |     "sortdescbutton", | ||||||
|  |     "sortremove", | ||||||
|  |     "sparkline", | ||||||
|  |     "splitview", | ||||||
|  |     "SPNMRB", | ||||||
|  |     "SPNPDB", | ||||||
|  |     "SSRS", | ||||||
|  |     "Sssign", | ||||||
|  |     "Staus", | ||||||
|  |     "stylesheet", | ||||||
|  |     "Submited", | ||||||
|  |     "subrole", | ||||||
|  |     "subroles", | ||||||
|  |     "Succefully", | ||||||
|  |     "Succesfully", | ||||||
|  |     "sucessfully", | ||||||
|  |     "SURP", | ||||||
|  |     "Swashbuckle", | ||||||
|  |     "SWRN", | ||||||
|  |     "tabindex", | ||||||
|  |     "tabstrip", | ||||||
|  |     "Tahoma", | ||||||
|  |     "taskcompleted", | ||||||
|  |     "Tasklist", | ||||||
|  |     "Taveler", | ||||||
|  |     "TECN", | ||||||
|  |     "TECNs", | ||||||
|  |     "TEMIRWAP", | ||||||
|  |     "tempecd", | ||||||
|  |     "tempimplement", | ||||||
|  |     "templabel", | ||||||
|  |     "tempvalue", | ||||||
|  |     "TEMSA", | ||||||
|  |     "timepicker", | ||||||
|  |     "Tobe", | ||||||
|  |     "Toplevel", | ||||||
|  |     "Totrav", | ||||||
|  |     "trainingby", | ||||||
|  |     "Traininglist", | ||||||
|  |     "traininglistdiv", | ||||||
|  |     "transanction", | ||||||
|  |     "Trav", | ||||||
|  |     "Traveller", | ||||||
|  |     "Traverler", | ||||||
|  |     "TRAVLELER", | ||||||
|  |     "Travler", | ||||||
|  |     "TREEVIEW", | ||||||
|  |     "trigerred", | ||||||
|  |     "ttinclude", | ||||||
|  |     "Uhandled", | ||||||
|  |     "Updat", | ||||||
|  |     "Uplaod", | ||||||
|  |     "Upto", | ||||||
|  |     "userevents", | ||||||
|  |     "userids", | ||||||
|  |     "userlist", | ||||||
|  |     "Validatable", | ||||||
|  |     "valueelement", | ||||||
|  |     "Variabls", | ||||||
|  |     "Verdana", | ||||||
|  |     "vgrid", | ||||||
|  |     "viewmodel", | ||||||
|  |     "vsdoc", | ||||||
|  |     "whethere", | ||||||
|  |     "windowsphone", | ||||||
|  |     "Winsock", | ||||||
|  |     "worlflow" | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										121
									
								
								MesaFabApproval.Client/.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								MesaFabApproval.Client/.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,121 @@ | |||||||
|  | { | ||||||
|  |     "version": "2.0.0", | ||||||
|  |     "tasks": [ | ||||||
|  |         { | ||||||
|  |             "label": "User Secrets Init", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "user-secrets", | ||||||
|  |                 "-p", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client.csproj", | ||||||
|  |                 "init" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Format", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "format", | ||||||
|  |                 "--report", | ||||||
|  |                 ".vscode", | ||||||
|  |                 "--verbosity", | ||||||
|  |                 "detailed", | ||||||
|  |                 "--severity", | ||||||
|  |                 "warn" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Format-Whitespaces", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "format", | ||||||
|  |                 "whitespace" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "build", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "build", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "testDebug", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "test", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "testRelease", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "test", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary", | ||||||
|  |                 "-c", | ||||||
|  |                 "Release" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "publish", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "publish", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "watch", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "watch", | ||||||
|  |                 "run", | ||||||
|  |                 "--project", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client.csproj" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "label": "Publish AOT", | ||||||
|  |             "command": "dotnet", | ||||||
|  |             "type": "process", | ||||||
|  |             "args": [ | ||||||
|  |                 "publish", | ||||||
|  |                 "-r", | ||||||
|  |                 "win-x64", | ||||||
|  |                 "-c", | ||||||
|  |                 "Release", | ||||||
|  |                 "-p:PublishAot=true", | ||||||
|  |                 "${workspaceFolder}/MesaFabApproval.Client.csproj", | ||||||
|  |                 "/property:GenerateFullPaths=true", | ||||||
|  |                 "/consoleloggerparameters:NoSummary" | ||||||
|  |             ], | ||||||
|  |             "problemMatcher": "$msCompile" | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								MesaFabApproval.Client/App.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								MesaFabApproval.Client/App.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | |||||||
|  | <CascadingAuthenticationState> | ||||||
|  |     <Router AppAssembly="@typeof(App).Assembly"> | ||||||
|  |         <Found Context="routeData"> | ||||||
|  |             <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" > | ||||||
|  |                 <NotAuthorized> | ||||||
|  |                     @if (context.User.Identity?.IsAuthenticated != true) { | ||||||
|  |                         <RedirectToLogin /> | ||||||
|  |                     } else { | ||||||
|  |                         <p role="alert">You are not authorized to access this resource.</p> | ||||||
|  |                     } | ||||||
|  |                 </NotAuthorized> | ||||||
|  |                 <Authorizing> | ||||||
|  |                     <MudProgressCircular Color="Color.Tertiary" Indeterminate="true" /> | ||||||
|  |                     <div>Authorizing...</div> | ||||||
|  |                 </Authorizing> | ||||||
|  |             </AuthorizeRouteView> | ||||||
|  |             <FocusOnNavigate RouteData="@routeData" Selector="h1" /> | ||||||
|  |         </Found> | ||||||
|  |         <NotFound> | ||||||
|  |             <PageTitle>Not found</PageTitle> | ||||||
|  |             <LayoutView Layout="@typeof(MainLayout)"> | ||||||
|  |                 <p role="alert">Sorry, there's nothing at this address.</p> | ||||||
|  |             </LayoutView> | ||||||
|  |         </NotFound> | ||||||
|  |     </Router> | ||||||
|  | </CascadingAuthenticationState> | ||||||
							
								
								
									
										8
									
								
								MesaFabApproval.Client/GlobalSuppressions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								MesaFabApproval.Client/GlobalSuppressions.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | |||||||
|  | // This file is used by Code Analysis to maintain SuppressMessage | ||||||
|  | // attributes that are applied to this project. | ||||||
|  | // Project-level suppressions either have no target or are given | ||||||
|  | // a specific target and scoped to a namespace, type, member, etc. | ||||||
|  |  | ||||||
|  | using System.Diagnostics.CodeAnalysis; | ||||||
|  |  | ||||||
|  | [assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>", Scope = "member", Target = "~M:MesaFabApproval.Client.Services.AuthenticationService.AttemptLocalUserAuth~System.Threading.Tasks.Task{System.Security.Claims.ClaimsPrincipal}")] | ||||||
							
								
								
									
										124
									
								
								MesaFabApproval.Client/Layout/MainLayout.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								MesaFabApproval.Client/Layout/MainLayout.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,124 @@ | |||||||
|  | @using System.Text.Json | ||||||
|  | @using System.Text | ||||||
|  | @inherits LayoutComponentBase | ||||||
|  |  | ||||||
|  | @inject MesaFabApprovalAuthStateProvider authStateProvider | ||||||
|  | @inject IAuthenticationService authenticationService | ||||||
|  | @inject IConfiguration Configuration | ||||||
|  | @inject IMemoryCache cache | ||||||
|  | @inject IJSRuntime jsRuntime | ||||||
|  | @inject IHttpClientFactory httpClientFactory | ||||||
|  | @inject ISnackbar snackbar | ||||||
|  | @inject NavigationManager navManager | ||||||
|  |  | ||||||
|  | <MudThemeProvider /> | ||||||
|  | <MudDialogProvider /> | ||||||
|  | <MudSnackbarProvider /> | ||||||
|  | <MudPopoverProvider /> | ||||||
|  |  | ||||||
|  | <div style="height: 100vh;"> | ||||||
|  |     <MudLayout> | ||||||
|  |         <MudAppBar Elevation="1" Color="Color.Info"> | ||||||
|  |             <MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" /> | ||||||
|  |             <MudText Typo="Typo.h5" Class="ml-3">Mesa Fab Approval</MudText> | ||||||
|  |             @if (authStateProvider.CurrentUser is not null) { | ||||||
|  |                 <MudSpacer /> | ||||||
|  |                 <MudText Typo="Typo.h6" Class="mr-3">@authStateProvider.CurrentUser.FirstName @authStateProvider.CurrentUser.LastName</MudText> | ||||||
|  |                 <MudIconButton Variant="Variant.Filled" | ||||||
|  |                                Color="Color.Tertiary" | ||||||
|  |                                OnClick=Logout | ||||||
|  |                                Edge="Edge.End" | ||||||
|  |                                Icon="@Icons.Material.Filled.Logout" /> | ||||||
|  |             } | ||||||
|  |         </MudAppBar> | ||||||
|  |         <MudDrawer @bind-Open="_drawerOpen" ClipMode="DrawerClipMode.Always" Elevation="2"> | ||||||
|  |             <MudNavMenu Color="Color.Info" Bordered="true" Class="d-flex flex-column justify-center p-1 gap-1"> | ||||||
|  |                 <MudButton Variant="Variant.Filled" | ||||||
|  |                             Color="Color.Tertiary" | ||||||
|  |                             Href="@Configuration["OldFabApprovalUrl"]" | ||||||
|  |                             Target="_blank" | ||||||
|  |                             StartIcon="@Icons.Material.Filled.Home"> | ||||||
|  |                     Return to Main Site | ||||||
|  |                 </MudButton> | ||||||
|  |  | ||||||
|  |                 <MudDivider Class="my-1" /> | ||||||
|  |                 @if (authStateProvider.CurrentUser is not null) { | ||||||
|  |                     <MudNavGroup Title="Create New"> | ||||||
|  |                         <MudNavLink OnClick="@(() => GoTo("mrb/new"))">Create New MRB</MudNavLink> | ||||||
|  |                         <MudNavLink OnClick="@(() => GoTo("pcrb/new"))">Create New PCRB</MudNavLink> | ||||||
|  |                     </MudNavGroup> | ||||||
|  |                     <MudNavLink OnClick="@(() => GoTo(""))" Icon="@Icons.Material.Filled.Dashboard">Dashboard</MudNavLink> | ||||||
|  |                     <MudNavLink OnClick="@(() => GoTo("mrb/all"))" Icon="@Icons.Material.Filled.Ballot">MRB List</MudNavLink> | ||||||
|  |                     <MudNavLink OnClick="@(() => GoTo("pcrb/all"))" Icon="@Icons.Material.Filled.Ballot">PCRB List</MudNavLink> | ||||||
|  |                 } | ||||||
|  |             </MudNavMenu> | ||||||
|  |         </MudDrawer> | ||||||
|  |         <div style="display: flex; flex-flow: column; height: 100%;"> | ||||||
|  |             <MudMainContent Style="@($"background:#E0E0E0; flex-grow: 1;")"> | ||||||
|  |                 @Body | ||||||
|  |             </MudMainContent> | ||||||
|  |         </div> | ||||||
|  |     </MudLayout> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     bool _drawerOpen = true; | ||||||
|  |  | ||||||
|  |     void DrawerToggle() { | ||||||
|  |         _drawerOpen = !_drawerOpen; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Logout() { | ||||||
|  |         authStateProvider.Logout(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void GoTo(string page) { | ||||||
|  |         DrawerToggle(); | ||||||
|  |         cache.Set("redirectUrl", page); | ||||||
|  |         navManager.NavigateTo(page); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task GoToExternal(string url, string content) { | ||||||
|  |         IJSObjectReference windowModule = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "./js/OpenInNewWindow.js"); | ||||||
|  |         await windowModule.InvokeAsync<object>("OpenInNewWindow", url, content); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task GoToOldSite() { | ||||||
|  |         try { | ||||||
|  |             User? currentUser = authStateProvider.CurrentUser; | ||||||
|  |  | ||||||
|  |             AuthTokens? authTokens = await authenticationService.GetAuthTokens(); | ||||||
|  |  | ||||||
|  |             if (currentUser is null || authTokens is null) { | ||||||
|  |                 await authStateProvider.Logout(); | ||||||
|  |                 navManager.NavigateTo("login"); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             AuthAttempt authAttempt = new() { | ||||||
|  |                     LoginID = currentUser.LoginID, | ||||||
|  |                     AuthTokens = authTokens | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |             HttpClient httpClient = httpClientFactory.CreateClient("OldSite"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "Account/ExternalAuthSetup"); | ||||||
|  |  | ||||||
|  |             request.Content = new StringContent(JsonSerializer.Serialize(authAttempt), | ||||||
|  |                                                 Encoding.UTF8, | ||||||
|  |                                                 "application/json"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(request); | ||||||
|  |  | ||||||
|  |             if (httpResponseMessage.IsSuccessStatusCode) { | ||||||
|  |                 snackbar.Add("Old site auth setup successful", Severity.Success); | ||||||
|  |             } else { | ||||||
|  |                 snackbar.Add($"Old site auth setup failed, because {httpResponseMessage.ReasonPhrase}", Severity.Error); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             await GoToExternal($"{Configuration["OldFabApprovalUrl"]}", ""); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             snackbar.Add($"Unable to go to old site, because {ex.Message}", Severity.Error); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										77
									
								
								MesaFabApproval.Client/Layout/MainLayout.razor.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								MesaFabApproval.Client/Layout/MainLayout.razor.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,77 @@ | |||||||
|  | .page { | ||||||
|  |     position: relative; | ||||||
|  |     display: flex; | ||||||
|  |     flex-direction: column; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | main { | ||||||
|  |     flex: 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .sidebar { | ||||||
|  |     background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .top-row { | ||||||
|  |     background-color: #f7f7f7; | ||||||
|  |     border-bottom: 1px solid #d6d5d5; | ||||||
|  |     justify-content: flex-end; | ||||||
|  |     height: 3.5rem; | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |     .top-row ::deep a, .top-row ::deep .btn-link { | ||||||
|  |         white-space: nowrap; | ||||||
|  |         margin-left: 1.5rem; | ||||||
|  |         text-decoration: none; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { | ||||||
|  |         text-decoration: underline; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .top-row ::deep a:first-child { | ||||||
|  |         overflow: hidden; | ||||||
|  |         text-overflow: ellipsis; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | @media (max-width: 640.98px) { | ||||||
|  |     .top-row { | ||||||
|  |         justify-content: space-between; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .top-row ::deep a, .top-row ::deep .btn-link { | ||||||
|  |         margin-left: 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @media (min-width: 641px) { | ||||||
|  |     .page { | ||||||
|  |         flex-direction: row; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .sidebar { | ||||||
|  |         width: 250px; | ||||||
|  |         height: 100vh; | ||||||
|  |         position: sticky; | ||||||
|  |         top: 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .top-row { | ||||||
|  |         position: sticky; | ||||||
|  |         top: 0; | ||||||
|  |         z-index: 1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .top-row.auth ::deep a:first-child { | ||||||
|  |         flex: 1; | ||||||
|  |         text-align: right; | ||||||
|  |         width: 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .top-row, article { | ||||||
|  |         padding-left: 2rem !important; | ||||||
|  |         padding-right: 1.5rem !important; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										33
									
								
								MesaFabApproval.Client/MesaFabApproval.Client.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								MesaFabApproval.Client/MesaFabApproval.Client.csproj
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | |||||||
|  | <Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly"> | ||||||
|  |  | ||||||
|  |   <PropertyGroup> | ||||||
|  |     <TargetFramework>net8.0</TargetFramework> | ||||||
|  |     <Nullable>enable</Nullable> | ||||||
|  |     <ImplicitUsings>enable</ImplicitUsings> | ||||||
|  |   </PropertyGroup> | ||||||
|  |  | ||||||
|  |     <ItemGroup> | ||||||
|  |         <Watch Include="**\*.razor" /> | ||||||
|  |     </ItemGroup> | ||||||
|  |  | ||||||
|  |     <ItemGroup> | ||||||
|  |       <Watch Remove="Pages\Components\PCRBApproverForm.razor" /> | ||||||
|  |     </ItemGroup> | ||||||
|  |  | ||||||
|  |   <ItemGroup> | ||||||
|  |     <PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.8" /> | ||||||
|  |     <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.8" /> | ||||||
|  |     <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.8" PrivateAssets="all" /> | ||||||
|  |     <PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" /> | ||||||
|  |     <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" /> | ||||||
|  |     <PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="8.0.8" /> | ||||||
|  |     <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" /> | ||||||
|  |     <PackageReference Include="MudBlazor" Version="7.6.0" /> | ||||||
|  |     <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.1" /> | ||||||
|  |   </ItemGroup> | ||||||
|  |  | ||||||
|  |     <ItemGroup> | ||||||
|  |         <ProjectReference Include="..\MesaFabApproval.Shared\MesaFabApproval.Shared.csproj" /> | ||||||
|  |     </ItemGroup> | ||||||
|  |  | ||||||
|  | </Project> | ||||||
							
								
								
									
										65
									
								
								MesaFabApproval.Client/Pages/AuthenticatedRedirect.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								MesaFabApproval.Client/Pages/AuthenticatedRedirect.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | |||||||
|  | @page "/redirect" | ||||||
|  | @attribute [AllowAnonymous] | ||||||
|  | @inject MesaFabApprovalAuthStateProvider authStateProvider | ||||||
|  | @inject IAuthenticationService authService | ||||||
|  | @inject IUserService userService | ||||||
|  | @inject ISnackbar snackbar | ||||||
|  | @inject MesaFabApprovalAuthStateProvider authStateProvider | ||||||
|  | @inject NavigationManager navigationManager | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     private string? _jwt; | ||||||
|  |     private string? _refreshToken; | ||||||
|  |     private string? _redirectPath; | ||||||
|  |  | ||||||
|  |     protected override async Task OnParametersSetAsync() { | ||||||
|  |         try { | ||||||
|  |             Uri uri = navigationManager.ToAbsoluteUri(navigationManager.Uri); | ||||||
|  |  | ||||||
|  |             if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("jwt", out var jwt)) { | ||||||
|  |                 _jwt = System.Net.WebUtility.UrlDecode(jwt); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("refreshToken", out var refreshToken)) { | ||||||
|  |                 _refreshToken = System.Net.WebUtility.UrlDecode(refreshToken); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("redirectPath", out var redirectPath)) { | ||||||
|  |                 _redirectPath = redirectPath.ToString(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (!string.IsNullOrWhiteSpace(_jwt) && !string.IsNullOrWhiteSpace(_refreshToken)) { | ||||||
|  |                 await authService.SetTokens(_jwt, _refreshToken); | ||||||
|  |  | ||||||
|  |                 ClaimsPrincipal principal = authService.GetClaimsPrincipalFromJwt(_jwt); | ||||||
|  |  | ||||||
|  |                 string loginId = userService.GetLoginIdFromClaimsPrincipal(principal); | ||||||
|  |  | ||||||
|  |                 await authService.ClearCurrentUser(); | ||||||
|  |                 await authService.ClearTokens(); | ||||||
|  |  | ||||||
|  |                 await authService.SetLoginId(loginId); | ||||||
|  |                 await authService.SetTokens(_jwt, _refreshToken); | ||||||
|  |                 await authService.SetCurrentUser(null); | ||||||
|  |  | ||||||
|  |                 await authStateProvider.StateHasChanged(principal); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (authStateProvider.CurrentUser is not null && !string.IsNullOrWhiteSpace(_redirectPath)) { | ||||||
|  |                 navigationManager.NavigateTo(_redirectPath); | ||||||
|  |             } else { | ||||||
|  |                 await authStateProvider.Logout(); | ||||||
|  |  | ||||||
|  |                 if (!string.IsNullOrWhiteSpace(_redirectPath)) { | ||||||
|  |                     navigationManager.NavigateTo($"login/{_redirectPath}"); | ||||||
|  |                 } else { | ||||||
|  |                     navigationManager.NavigateTo("login"); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             snackbar.Add($"Redirect failed, because {ex.Message}", Severity.Error); | ||||||
|  |             navigationManager.NavigateTo("login"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								MesaFabApproval.Client/Pages/Components/Comments.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								MesaFabApproval.Client/Pages/Components/Comments.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | |||||||
|  | @inject ISnackbar snackbar | ||||||
|  |  | ||||||
|  | <MudDialog> | ||||||
|  |     <DialogContent> | ||||||
|  |         <MudPaper Class="m-2 p-2"> | ||||||
|  |             <MudForm @bind-Errors="@errors"> | ||||||
|  |                 <MudTextField T="string" | ||||||
|  |                     Label="Comments" | ||||||
|  |                     Required="true" | ||||||
|  |                     RequiredError="You must provide a comment" | ||||||
|  |                     @bind-Value="@comments" | ||||||
|  |                     @bind-Text="@comments" | ||||||
|  |                     Immediate="true" | ||||||
|  |                     AutoGrow | ||||||
|  |                     AutoFocus/> | ||||||
|  |             </MudForm> | ||||||
|  |         </MudPaper> | ||||||
|  |     </DialogContent> | ||||||
|  |     <DialogActions> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Color="Color.Tertiary" | ||||||
|  |                    Class="m1-auto" | ||||||
|  |                    OnClick=SubmitComments> | ||||||
|  |             @if (processing) { | ||||||
|  |                 <MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" /> | ||||||
|  |                 <MudText>Processing</MudText> | ||||||
|  |             } else { | ||||||
|  |                 <MudText>Ok</MudText> | ||||||
|  |             } | ||||||
|  |         </MudButton> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Class="grey text-black m1-auto" | ||||||
|  |                    OnClick=Cancel> | ||||||
|  |             Cancel | ||||||
|  |         </MudButton> | ||||||
|  |     </DialogActions> | ||||||
|  | </MudDialog> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     [CascadingParameter] MudDialogInstance MudDialog { get; set; } | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public string comments { get; set; } = ""; | ||||||
|  |  | ||||||
|  |     private string[] errors = { }; | ||||||
|  |  | ||||||
|  |     private bool processing = false; | ||||||
|  |  | ||||||
|  |     protected override void OnParametersSet() { | ||||||
|  |         comments = string.Empty; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void SubmitComments() { | ||||||
|  |         processing = true; | ||||||
|  |         try { | ||||||
|  |             if (string.IsNullOrWhiteSpace(comments) || comments.Length < 5) | ||||||
|  |                 throw new Exception("Comments must be at least five characters long"); | ||||||
|  |  | ||||||
|  |             MudDialog.Close(DialogResult.Ok(comments)); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             snackbar.Add(ex.Message, Severity.Error); | ||||||
|  |         } | ||||||
|  |         processing = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void Cancel() { | ||||||
|  |         MudDialog.Close(DialogResult.Cancel()); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,115 @@ | |||||||
|  | @inject ISnackbar snackbar | ||||||
|  | @inject IMRBService mrbService | ||||||
|  | @inject MesaFabApprovalAuthStateProvider authStateProvider | ||||||
|  |  | ||||||
|  | <MudDialog> | ||||||
|  |     <DialogContent> | ||||||
|  |         <MudPaper Class="m-2 p-2"> | ||||||
|  |             <MudForm @bind-Errors="@errors"> | ||||||
|  |                 <MudTextField T="string" | ||||||
|  |                     Label="Comments" | ||||||
|  |                     Required="true" | ||||||
|  |                     RequiredError="You must provide a comment" | ||||||
|  |                     @bind-Value="@comments" | ||||||
|  |                     @bind-Text="@comments" | ||||||
|  |                     Immediate="true" | ||||||
|  |                     AutoGrow | ||||||
|  |                     AutoFocus/> | ||||||
|  |                 <MudFileUpload T="IReadOnlyList<IBrowserFile>" OnFilesChanged="AddAttachments"> | ||||||
|  |                     <ActivatorContent> | ||||||
|  |                         <MudButton Variant="Variant.Filled" | ||||||
|  |                                    Color="Color.Tertiary" | ||||||
|  |                                    style="margin: auto;" | ||||||
|  |                                    StartIcon="@Icons.Material.Filled.AttachFile"> | ||||||
|  |                             @if (attachmentUploadInProcess) { | ||||||
|  |                                 <MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" /> | ||||||
|  |                                 <MudText>Processing</MudText> | ||||||
|  |                             } else { | ||||||
|  |                                 <MudText>Upload Supporting Document</MudText> | ||||||
|  |                             } | ||||||
|  |                         </MudButton> | ||||||
|  |                     </ActivatorContent> | ||||||
|  |                 </MudFileUpload> | ||||||
|  |             </MudForm> | ||||||
|  |         </MudPaper> | ||||||
|  |     </DialogContent> | ||||||
|  |     <DialogActions> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Color="Color.Tertiary" | ||||||
|  |                    Class="m1-auto" | ||||||
|  |                    OnClick=SubmitComments> | ||||||
|  |             @if (processing) { | ||||||
|  |                 <MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" /> | ||||||
|  |                 <MudText>Processing</MudText> | ||||||
|  |             } else { | ||||||
|  |                 <MudText>Ok</MudText> | ||||||
|  |             } | ||||||
|  |         </MudButton> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Class="grey text-black m1-auto" | ||||||
|  |                    OnClick=Cancel> | ||||||
|  |             Cancel | ||||||
|  |         </MudButton> | ||||||
|  |     </DialogActions> | ||||||
|  | </MudDialog> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     [CascadingParameter] MudDialogInstance MudDialog { get; set; } | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public string comments { get; set; } = ""; | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public int actionId { get; set; } = 0; | ||||||
|  |  | ||||||
|  |     private string[] errors = { }; | ||||||
|  |  | ||||||
|  |     private bool processing = false; | ||||||
|  |     private bool attachmentUploadInProcess = false; | ||||||
|  |  | ||||||
|  |     protected override void OnParametersSet() { | ||||||
|  |         comments = string.Empty; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void SubmitComments() { | ||||||
|  |         processing = true; | ||||||
|  |         try { | ||||||
|  |             if (string.IsNullOrWhiteSpace(comments) || comments.Length < 5) | ||||||
|  |                 throw new Exception("Comments must be at least five characters long"); | ||||||
|  |  | ||||||
|  |             MudDialog.Close(DialogResult.Ok(comments)); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             snackbar.Add(ex.Message, Severity.Error); | ||||||
|  |         } | ||||||
|  |         processing = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void Cancel() { | ||||||
|  |         MudDialog.Close(DialogResult.Cancel()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task AddAttachments(InputFileChangeEventArgs args) { | ||||||
|  |         attachmentUploadInProcess = true; | ||||||
|  |         try { | ||||||
|  |             if (actionId <= 0) | ||||||
|  |                 throw new Exception($"{actionId} is not a valid MRB action ID"); | ||||||
|  |  | ||||||
|  |             IReadOnlyList<IBrowserFile> attachments = args.GetMultipleFiles(); | ||||||
|  |  | ||||||
|  |             if (authStateProvider.CurrentUser is not null) { | ||||||
|  |                 await mrbService.UploadActionAttachments(attachments, actionId); | ||||||
|  |  | ||||||
|  |                 await mrbService.GetAllActionAttachmentsForMRB(actionId, true); | ||||||
|  |  | ||||||
|  |                 attachmentUploadInProcess = false; | ||||||
|  |  | ||||||
|  |                 snackbar.Add("Attachments successfully uploaded", Severity.Success); | ||||||
|  |  | ||||||
|  |                 StateHasChanged(); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             attachmentUploadInProcess = false; | ||||||
|  |             snackbar.Add($"Unable to upload attachments, because {ex.Message}", Severity.Error); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										327
									
								
								MesaFabApproval.Client/Pages/Components/MRBActionForm.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								MesaFabApproval.Client/Pages/Components/MRBActionForm.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,327 @@ | |||||||
|  | @inject IMRBService mrbService | ||||||
|  | @inject ISnackbar snackbar | ||||||
|  | @inject ICustomerService customerService | ||||||
|  |  | ||||||
|  | <MudDialog> | ||||||
|  |     <DialogContent> | ||||||
|  |         <MudPaper Class="m-2 p-2"> | ||||||
|  |             <MudForm @bind-Errors="@errors"> | ||||||
|  |                 <MudSelect T="string" | ||||||
|  |                            Label="Action" | ||||||
|  |                            Disabled="@(!string.IsNullOrWhiteSpace(mrbAction.Action))" | ||||||
|  |                            Required="true" | ||||||
|  |                            RequiredError="You must select an action!" | ||||||
|  |                            @bind-Value="@mrbAction.Action" | ||||||
|  |                            Text="@mrbAction.Action"> | ||||||
|  |                     <MudSelectItem Value="@("Block")" /> | ||||||
|  |                     <MudSelectItem Value="@("Convert")" /> | ||||||
|  |                     <MudSelectItem Value="@("Recall")" /> | ||||||
|  |                     <MudSelectItem Value="@("Scrap")" /> | ||||||
|  |                     <MudSelectItem Value="@("Unblock")" /> | ||||||
|  |                     <MudSelectItem Value="@("Waiver")" /> | ||||||
|  |                 </MudSelect> | ||||||
|  |                 @if (mrbAction.Action.Equals("Convert", StringComparison.InvariantCultureIgnoreCase)) { | ||||||
|  |                     <MudSelect T="string" | ||||||
|  |                                Label="Convert From Customer" | ||||||
|  |                                Required | ||||||
|  |                                Variant="Variant.Outlined" | ||||||
|  |                                AnchorOrigin="Origin.BottomCenter" | ||||||
|  |                                @bind-Value=convertFromCustomer | ||||||
|  |                                Text="@convertFromCustomer"> | ||||||
|  |                         @foreach (string customer in customerNames) { | ||||||
|  |                             <MudSelectItem Value="@(customer)" /> | ||||||
|  |                         } | ||||||
|  |                     </MudSelect> | ||||||
|  |                     <MudTextField @bind-Value="@convertFromPart" | ||||||
|  |                                   Label="Convert From Part Number" | ||||||
|  |                                   Required | ||||||
|  |                                   RequiredError="Part number required!" | ||||||
|  |                                   Text="@convertFromPart" /> | ||||||
|  |                     <MudSelect T="string" | ||||||
|  |                                Label="Convert To Customer" | ||||||
|  |                                Required | ||||||
|  |                                Variant="Variant.Outlined" | ||||||
|  |                                AnchorOrigin="Origin.BottomCenter" | ||||||
|  |                                @bind-Value=convertToCustomer | ||||||
|  |                                Text="@convertToCustomer"> | ||||||
|  |                         @foreach (string customer in customerNames) { | ||||||
|  |                             <MudSelectItem Value="@(customer)" /> | ||||||
|  |                         } | ||||||
|  |                     </MudSelect> | ||||||
|  |                     <MudTextField @bind-Value="@convertToPart" | ||||||
|  |                                   Label="Convert To Part Number" | ||||||
|  |                                   Required | ||||||
|  |                                   RequiredError="Part number required!" | ||||||
|  |                                   Text="@convertToPart" /> | ||||||
|  |                 } else { | ||||||
|  |                     <MudSelect T="string" | ||||||
|  |                                Label="Affected Customer" | ||||||
|  |                                Required | ||||||
|  |                                Variant="Variant.Outlined" | ||||||
|  |                                AnchorOrigin="Origin.BottomCenter" | ||||||
|  |                                @bind-Value=mrbAction.Customer | ||||||
|  |                                Text="@mrbAction.Customer"> | ||||||
|  |                         @foreach (string customer in customerNames) { | ||||||
|  |                             <MudSelectItem Value="@(customer)" /> | ||||||
|  |                         } | ||||||
|  |                     </MudSelect> | ||||||
|  |                     <MudAutocomplete T="string" | ||||||
|  |                                      Label="Part Number" | ||||||
|  |                                      Variant="Variant.Outlined" | ||||||
|  |                                      AnchorOrigin="Origin.BottomCenter" | ||||||
|  |                                      @bind-Value=mrbAction.PartNumber | ||||||
|  |                                      Text="@mrbAction.PartNumber" | ||||||
|  |                                      SearchFunc="@PartNumberSearch" | ||||||
|  |                                      ResetValueOnEmptyText | ||||||
|  |                                      CoerceText /> | ||||||
|  |                 } | ||||||
|  |                 <MudTextField T="int" | ||||||
|  |                               InputType="@InputType.Number" | ||||||
|  |                               Label="Qty" | ||||||
|  |                               Required="true" | ||||||
|  |                               RequiredError="You must supply a quantity!" | ||||||
|  |                               @bind-Value=mrbAction.Quantity | ||||||
|  |                               Text="@mrbAction.Quantity.ToString()" /> | ||||||
|  |                 <MudAutocomplete T="string" | ||||||
|  |                                  Label="Batch Number / Lot Number" | ||||||
|  |                                  Variant="Variant.Outlined" | ||||||
|  |                                  AnchorOrigin="Origin.BottomCenter" | ||||||
|  |                                  @bind-Value=mrbAction.LotNumber | ||||||
|  |                                  Text="@mrbAction.LotNumber" | ||||||
|  |                                  SearchFunc="@LotNumberSearch" | ||||||
|  |                                  ResetValueOnEmptyText | ||||||
|  |                                  CoerceText /> | ||||||
|  |                 @if (mrbAction.Action.Equals("Scrap")) { | ||||||
|  |                     <MudSelect T="string" | ||||||
|  |                                Label="Justification" | ||||||
|  |                                Required | ||||||
|  |                                RequiredError="Justification required!" | ||||||
|  |                                Variant="Variant.Outlined" | ||||||
|  |                                AnchorOrigin="Origin.BottomCenter" | ||||||
|  |                                @bind-Value=mrbAction.Justification | ||||||
|  |                                Text="@mrbAction.Justification"> | ||||||
|  |                         <MudSelectItem Value="@("Obsolete")" /> | ||||||
|  |                         <MudSelectItem Value="@("Aged Material")" /> | ||||||
|  |                         <MudSelectItem Value="@("Out of Specification")" /> | ||||||
|  |                     </MudSelect> | ||||||
|  |                 } | ||||||
|  |             </MudForm> | ||||||
|  |         </MudPaper> | ||||||
|  |     </DialogContent> | ||||||
|  |     <DialogActions> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Color="Color.Tertiary" | ||||||
|  |                    Class="m1-auto" | ||||||
|  |                    OnClick=SaveMRBAction> | ||||||
|  |             @if (processingSave) { | ||||||
|  |                 <MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" /> | ||||||
|  |                 <MudText>Processing</MudText> | ||||||
|  |             } else { | ||||||
|  |                 <MudText>Save</MudText> | ||||||
|  |             } | ||||||
|  |         </MudButton> | ||||||
|  |         @if (mrbAction is not null && mrbAction.ActionID > 0) { | ||||||
|  |             <MudButton Variant="Variant.Filled" | ||||||
|  |                        Color="Color.Secondary" | ||||||
|  |                        Disabled="@(mrbAction is null || (mrbAction is not null && mrbAction.ActionID <= 0))" | ||||||
|  |                        Class="m1-auto" | ||||||
|  |                        OnClick=DeleteMRBAction> | ||||||
|  |                 @if (processingDelete) { | ||||||
|  |                     <MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" /> | ||||||
|  |                     <MudText>Processing</MudText> | ||||||
|  |                 } else { | ||||||
|  |                     <MudText>Delete</MudText> | ||||||
|  |                 } | ||||||
|  |             </MudButton> | ||||||
|  |         } | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Class="grey text-black m1-auto" | ||||||
|  |                    OnClick=Cancel> | ||||||
|  |             Cancel | ||||||
|  |         </MudButton> | ||||||
|  |     </DialogActions> | ||||||
|  | </MudDialog> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     [CascadingParameter] MudDialogInstance MudDialog { get; set; } | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public MRBAction mrbAction { get; set; } | ||||||
|  |  | ||||||
|  |     private IEnumerable<MRBAction>? actions = null; | ||||||
|  |  | ||||||
|  |     private MRBAction lastAction = null; | ||||||
|  |  | ||||||
|  |     private IEnumerable<string> customerNames = new List<string>(); | ||||||
|  |  | ||||||
|  |     private string convertFromCustomer = string.Empty; | ||||||
|  |     private string convertFromPart = string.Empty; | ||||||
|  |     private string convertToCustomer = string.Empty; | ||||||
|  |     private string convertToPart = string.Empty; | ||||||
|  |  | ||||||
|  |     private bool isVisible { get; set; } | ||||||
|  |     private string[] errors = { }; | ||||||
|  |     private bool processingSave = false; | ||||||
|  |     private bool processingDelete = false; | ||||||
|  |  | ||||||
|  |     protected override async Task OnParametersSetAsync() { | ||||||
|  |         isVisible = true; | ||||||
|  |  | ||||||
|  |         if (mrbAction is null) { | ||||||
|  |             snackbar.Add("MRB action cannot be null", Severity.Warning); | ||||||
|  |             MudDialog.Cancel(); | ||||||
|  |         } else { | ||||||
|  |             actions = (await mrbService.GetMRBActionsForMRB(mrbAction.MRBNumber, false)).OrderByDescending(a => a.ActionID); | ||||||
|  |  | ||||||
|  |             if (actions is not null && actions.Count() > 0) { | ||||||
|  |                 if (string.IsNullOrWhiteSpace(mrbAction.Action)) | ||||||
|  |                     mrbAction.Action = actions.First().Action; | ||||||
|  |                 if (string.IsNullOrWhiteSpace(mrbAction.Customer)) | ||||||
|  |                     mrbAction.Customer = actions.First().Customer; | ||||||
|  |                 if (string.IsNullOrWhiteSpace(mrbAction.LotNumber)) | ||||||
|  |                     mrbAction.LotNumber = actions.First().LotNumber; | ||||||
|  |                 if (string.IsNullOrWhiteSpace(mrbAction.PartNumber)) | ||||||
|  |                     mrbAction.PartNumber = actions.First().PartNumber; | ||||||
|  |                 if (string.IsNullOrWhiteSpace(mrbAction.Justification)) | ||||||
|  |                     mrbAction.Justification = actions.First().Justification; | ||||||
|  |                 if (mrbAction.Quantity == 0) | ||||||
|  |                     mrbAction.Quantity = actions.First().Quantity; | ||||||
|  |  | ||||||
|  |                 if (mrbAction.Action.Equals("Convert", StringComparison.InvariantCultureIgnoreCase)) { | ||||||
|  |                     string[] convertFrom = actions.First().ConvertFrom.Split(" "); | ||||||
|  |                     if (convertFrom.Length > 1) { | ||||||
|  |                         convertFromCustomer = convertFrom[0]; | ||||||
|  |                         foreach (string partStr in convertFrom.Skip(1)) | ||||||
|  |                             convertFromPart += partStr; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     string[] convertTo = actions.First().ConvertTo.Split(" "); | ||||||
|  |                     if (convertTo.Length > 1) { | ||||||
|  |                         convertToCustomer = convertTo[0]; | ||||||
|  |                         foreach (string partStr in convertTo.Skip(1)) | ||||||
|  |                             convertToPart += partStr; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (customerNames is null || customerNames.Count() <= 0) | ||||||
|  |             customerNames = await customerService.GetAllCustomerNames(); | ||||||
|  |  | ||||||
|  |         StateHasChanged(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private bool FormIsValid() { | ||||||
|  |         bool actionIsValid = mrbAction.Action.Equals("Block") || mrbAction.Action.Equals("Convert") || | ||||||
|  |             mrbAction.Action.Equals("Other") || mrbAction.Action.Equals("Recall") || mrbAction.Action.Equals("Scrap") || | ||||||
|  |             mrbAction.Action.Equals("Unblock") || mrbAction.Action.Equals("Waiver"); | ||||||
|  |         actionIsValid = actionIsValid && !string.IsNullOrWhiteSpace(mrbAction.Customer) && | ||||||
|  |             !string.IsNullOrWhiteSpace(mrbAction.PartNumber) && | ||||||
|  |             !string.IsNullOrWhiteSpace(mrbAction.LotNumber); | ||||||
|  |         actionIsValid = actionIsValid && mrbAction.Quantity > 0; | ||||||
|  |  | ||||||
|  |         if (mrbAction.Action.Equals("Convert", StringComparison.InvariantCultureIgnoreCase)) { | ||||||
|  |             actionIsValid = actionIsValid && !string.IsNullOrWhiteSpace(convertFromCustomer) && | ||||||
|  |                 !string.IsNullOrWhiteSpace(convertFromPart) && | ||||||
|  |                 !string.IsNullOrWhiteSpace(convertToCustomer) && | ||||||
|  |                 !string.IsNullOrWhiteSpace(convertToPart); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (mrbAction.Action.Equals("Scrap", StringComparison.InvariantCultureIgnoreCase)) | ||||||
|  |             actionIsValid = actionIsValid && !string.IsNullOrWhiteSpace(mrbAction.Justification); | ||||||
|  |  | ||||||
|  |         return actionIsValid; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async void SaveMRBAction() { | ||||||
|  |         processingSave = true; | ||||||
|  |         try { | ||||||
|  |             if (!FormIsValid()) throw new Exception("You must complete the form before saving!"); | ||||||
|  |  | ||||||
|  |             if (mrbAction.Action.Equals("Convert", StringComparison.InvariantCultureIgnoreCase)) { | ||||||
|  |                 mrbAction.ConvertFrom = $"{convertFromCustomer} {convertFromPart}"; | ||||||
|  |                 mrbAction.ConvertTo = $"{convertToCustomer} {convertToPart}"; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (mrbAction.MRBNumber > 0) { | ||||||
|  |                 if (mrbAction.ActionID <= 0) { | ||||||
|  |                     await mrbService.CreateMRBAction(mrbAction); | ||||||
|  |                     snackbar.Add("MRB action created", Severity.Success); | ||||||
|  |                 } else { | ||||||
|  |                     await mrbService.UpdateMRBAction(mrbAction); | ||||||
|  |                     snackbar.Add("MRB action updated", Severity.Success); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 actions = (await mrbService.GetMRBActionsForMRB(mrbAction.MRBNumber, true)).OrderByDescending(a => a.ActionID); | ||||||
|  |             } else { | ||||||
|  |                 snackbar.Add("MRB action saved", Severity.Success); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             StateHasChanged(); | ||||||
|  |  | ||||||
|  |             MudDialog.Close(DialogResult.Ok(mrbAction)); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             snackbar.Add(ex.Message, Severity.Error); | ||||||
|  |         } | ||||||
|  |         processingSave = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async void DeleteMRBAction() { | ||||||
|  |         processingDelete = true; | ||||||
|  |         try { | ||||||
|  |             if (mrbAction is null) throw new Exception("MRB action cannot be null!"); | ||||||
|  |             if (mrbAction.ActionID <= 0) | ||||||
|  |                 throw new Exception("You cannot delete an action before creating it!"); | ||||||
|  |             if (mrbAction.MRBNumber <= 0) | ||||||
|  |                 throw new Exception("Invalid MRB number!"); | ||||||
|  |  | ||||||
|  |             await mrbService.DeleteMRBAction(mrbAction); | ||||||
|  |             snackbar.Add("MRB action successfully deleted", Severity.Success); | ||||||
|  |  | ||||||
|  |             StateHasChanged(); | ||||||
|  |  | ||||||
|  |             MudDialog.Close(DialogResult.Ok<MRBAction>(null)); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             snackbar.Add(ex.Message, Severity.Error); | ||||||
|  |         } | ||||||
|  |         processingDelete = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void Cancel() { | ||||||
|  |         MudDialog.Cancel(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task<IEnumerable<string>> PartNumberSearch(string value, CancellationToken token) { | ||||||
|  |         if (actions is null) return new List<string> { value }; | ||||||
|  |  | ||||||
|  |         if (string.IsNullOrWhiteSpace(value)) return new string[0]; | ||||||
|  |  | ||||||
|  |         HashSet<string> partNumbers = new(); | ||||||
|  |  | ||||||
|  |         partNumbers.Add(value); | ||||||
|  |  | ||||||
|  |         foreach (MRBAction action in actions) { | ||||||
|  |             if (action.PartNumber.Contains(value, StringComparison.InvariantCultureIgnoreCase)) | ||||||
|  |                 partNumbers.Add(action.PartNumber); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return partNumbers; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task<IEnumerable<string>> LotNumberSearch(string value, CancellationToken token) { | ||||||
|  |         if (actions is null) return new List<string> { value }; | ||||||
|  |  | ||||||
|  |         if (string.IsNullOrWhiteSpace(value)) return new string[0]; | ||||||
|  |  | ||||||
|  |         HashSet<string> lotNumbers = new(); | ||||||
|  |  | ||||||
|  |         lotNumbers.Add(value); | ||||||
|  |  | ||||||
|  |         foreach (MRBAction action in actions) { | ||||||
|  |             if (action.LotNumber.Contains(value, StringComparison.InvariantCultureIgnoreCase)) | ||||||
|  |                 lotNumbers.Add(action.LotNumber); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return lotNumbers; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,111 @@ | |||||||
|  | @inject IApprovalService approvalService | ||||||
|  | @inject ISnackbar snackbar | ||||||
|  | @inject MesaFabApprovalAuthStateProvider authStateProvider | ||||||
|  |  | ||||||
|  | <MudDialog> | ||||||
|  |     <DialogContent> | ||||||
|  |         @if (availableApprovers is not null) { | ||||||
|  |             <MudPaper Class="m-2 p-2"> | ||||||
|  |                 <MudSelect T="User" | ||||||
|  |                            Label="Select a User" | ||||||
|  |                            Required | ||||||
|  |                            Variant="Variant.Outlined" | ||||||
|  |                            AnchorOrigin="Origin.BottomCenter" | ||||||
|  |                            @bind-Value=selectedUser | ||||||
|  |                            Text="@(selectedUser is null ? "" : selectedUser.GetFullName())"> | ||||||
|  |                     @foreach (User user in availableApprovers) { | ||||||
|  |                         <MudSelectItem Value="@user"> | ||||||
|  |                             @user.GetFullName() | ||||||
|  |                         </MudSelectItem> | ||||||
|  |                     } | ||||||
|  |                 </MudSelect> | ||||||
|  |             </MudPaper> | ||||||
|  |         } | ||||||
|  |     </DialogContent> | ||||||
|  |     <DialogActions> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Color="Color.Tertiary" | ||||||
|  |                    Class="m1-auto" | ||||||
|  |                    OnClick=Submit> | ||||||
|  |             <MudText>Submit</MudText> | ||||||
|  |         </MudButton> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Color="Color.Secondary" | ||||||
|  |                    Class="m1-auto" | ||||||
|  |                    OnClick=Cancel> | ||||||
|  |             <MudText>Cancel</MudText> | ||||||
|  |         </MudButton> | ||||||
|  |     </DialogActions> | ||||||
|  | </MudDialog> | ||||||
|  |  | ||||||
|  | <MudOverlay Visible=processing DarkBackground="true" AutoClose="false"> | ||||||
|  |     <MudProgressCircular Color="Color.Info" Size="Size.Medium" Indeterminate="true" /> | ||||||
|  | </MudOverlay> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     [CascadingParameter] MudDialogInstance MudDialog { get; set; } | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public User selectedUser { get; set; } | ||||||
|  |  | ||||||
|  |     private bool processing = false; | ||||||
|  |  | ||||||
|  |     private HashSet<User> availableApprovers = new(); | ||||||
|  |  | ||||||
|  |     protected override async Task OnInitializedAsync() { | ||||||
|  |         try { | ||||||
|  |             processing = true; | ||||||
|  |  | ||||||
|  |             string roleName = "QA_PRE_APPROVAL"; | ||||||
|  |             string subRoleName = "QA_PRE_APPROVAL"; | ||||||
|  |  | ||||||
|  |             IEnumerable<User> qaApprovers = await GetApprovalGroupMembersForRoleAndSubRole(roleName, subRoleName); | ||||||
|  |  | ||||||
|  |             foreach (User approver in qaApprovers) | ||||||
|  |                 availableApprovers.Add(approver); | ||||||
|  |  | ||||||
|  |             roleName = "MRB Approver"; | ||||||
|  |             subRoleName = "MRBApprover"; | ||||||
|  |  | ||||||
|  |             IEnumerable<User> mrbApprovers = await GetApprovalGroupMembersForRoleAndSubRole(roleName, subRoleName); | ||||||
|  |  | ||||||
|  |             foreach (User approver in mrbApprovers) | ||||||
|  |                 availableApprovers.Add(approver); | ||||||
|  |  | ||||||
|  |             selectedUser = availableApprovers.First(); | ||||||
|  |  | ||||||
|  |             processing = false; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             processing = false; | ||||||
|  |             snackbar.Add($"Unable to get all approvers, because {ex.Message}", Severity.Error); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void Submit() { | ||||||
|  |         MudDialog.Close(DialogResult.Ok(selectedUser)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void Cancel() { | ||||||
|  |         MudDialog.Close(DialogResult.Cancel()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task<IEnumerable<User>> GetApprovalGroupMembersForRoleAndSubRole(string roleName, string subRoleName) { | ||||||
|  |         HashSet<User> members = new(); | ||||||
|  |  | ||||||
|  |         int roleId = await approvalService.GetRoleIdForRoleName(roleName); | ||||||
|  |  | ||||||
|  |         if (roleId <= 0) throw new Exception($"could not find {roleName} role ID"); | ||||||
|  |  | ||||||
|  |         IEnumerable<SubRole> subRoles = await approvalService.GetSubRolesForSubRoleName(subRoleName, roleId); | ||||||
|  |  | ||||||
|  |         foreach (SubRole subRole in subRoles) { | ||||||
|  |             IEnumerable<User> subRoleMembers = await approvalService.GetApprovalGroupMembers(subRole.SubRoleID); | ||||||
|  |  | ||||||
|  |             foreach (User member in subRoleMembers) { | ||||||
|  |                 members.Add(member); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return members; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										151
									
								
								MesaFabApproval.Client/Pages/Components/PCR3DocumentForm.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								MesaFabApproval.Client/Pages/Components/PCR3DocumentForm.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,151 @@ | |||||||
|  | @inject MesaFabApprovalAuthStateProvider authStateProvider | ||||||
|  | @inject NavigationManager navigationManager | ||||||
|  | @inject IPCRBService pcrbService | ||||||
|  | @inject IUserService userService | ||||||
|  | @inject IECNService ecnService | ||||||
|  | @inject ISnackbar snackbar | ||||||
|  |  | ||||||
|  | <MudDialog> | ||||||
|  |     <DialogContent> | ||||||
|  |         <MudPaper Class="m-2 p-2"> | ||||||
|  |             <MudForm @bind-Errors="@errors"> | ||||||
|  |                 <MudTextField T="string" | ||||||
|  |                               Label="Document Type" | ||||||
|  |                               @bind-Value="@document.DocType" | ||||||
|  |                               @bind-Text="@document.DocType" | ||||||
|  |                               Disabled | ||||||
|  |                               AutoGrow /> | ||||||
|  |                 <MudTextField Label="Document Numbers - Rev. & Title" | ||||||
|  |                               @bind-Value="@document.DocNumbers" | ||||||
|  |                               @bind-Text="@document.DocNumbers" | ||||||
|  |                               Immediate | ||||||
|  |                               AutoGrow | ||||||
|  |                               AutoFocus /> | ||||||
|  |                 @if (DocNumberIsNA()) { | ||||||
|  |                     <MudTextField Label="Comments" | ||||||
|  |                                   @bind-Value="@document.Comment" | ||||||
|  |                                   @bind-Text="@document.Comment" | ||||||
|  |                                   Required | ||||||
|  |                                   RequiredError="You must provide a comment" | ||||||
|  |                                   Immediate | ||||||
|  |                                   AutoGrow /> | ||||||
|  |                 } else { | ||||||
|  |                     <MudTextField @bind-Value="@document.ECNNumber" | ||||||
|  |                                   Required | ||||||
|  |                                   RequiredError="You must provide a valid ECN#" | ||||||
|  |                                   Clearable | ||||||
|  |                                   Variant="Variant.Outlined" | ||||||
|  |                                   InputType="@InputType.Number" | ||||||
|  |                                   Validation="@(new Func<int, Task<string>>(ECNNoIsValid))" | ||||||
|  |                                   Label="ECN#" | ||||||
|  |                                   Immediate | ||||||
|  |                                   AutoGrow /> | ||||||
|  |                 } | ||||||
|  |                 <MudCheckBox Label="Complete" | ||||||
|  |                              Color="Color.Tertiary" | ||||||
|  |                              @bind-Value=complete | ||||||
|  |                              LabelPosition="LabelPosition.Start" /> | ||||||
|  |             </MudForm> | ||||||
|  |         </MudPaper> | ||||||
|  |     </DialogContent> | ||||||
|  |     <DialogActions> | ||||||
|  |         @if ((DocNumberIsNA() && !string.IsNullOrWhiteSpace(document.Comment)) ||  | ||||||
|  |              (!DocNumberIsNA() && ecnNoIsValid)) { | ||||||
|  |             <MudButton Variant="Variant.Filled" | ||||||
|  |                        Color="Color.Tertiary" | ||||||
|  |                        Class="m1-auto" | ||||||
|  |                        OnClick=Save> | ||||||
|  |                 @if (saveInProcess) { | ||||||
|  |                     <MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" /> | ||||||
|  |                     <MudText>Processing</MudText> | ||||||
|  |                 } else { | ||||||
|  |                     <MudText>Save</MudText> | ||||||
|  |                 } | ||||||
|  |             </MudButton> | ||||||
|  |         } | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Class="grey text-black m1-auto" | ||||||
|  |                    OnClick=Cancel> | ||||||
|  |             Cancel | ||||||
|  |         </MudButton> | ||||||
|  |     </DialogActions> | ||||||
|  | </MudDialog> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     [CascadingParameter]  | ||||||
|  |     MudDialogInstance MudDialog { get; set; } | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public required PCR3Document document { get; set; } | ||||||
|  |  | ||||||
|  |     private string[] errors = { }; | ||||||
|  |  | ||||||
|  |     private bool complete = false; | ||||||
|  |  | ||||||
|  |     private bool saveInProcess = false; | ||||||
|  |  | ||||||
|  |     private bool ecnNoIsValid = true; | ||||||
|  |  | ||||||
|  |     protected override async Task OnParametersSetAsync() { | ||||||
|  |         complete = document.CompletedByID > 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task Save() { | ||||||
|  |         saveInProcess = true; | ||||||
|  |         try { | ||||||
|  |             if (authStateProvider.CurrentUser is null) { | ||||||
|  |                 await authStateProvider.Logout(); | ||||||
|  |                 navigationManager.NavigateTo("login"); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (!complete) { | ||||||
|  |                 document.CompletedByID = 0; | ||||||
|  |                 document.CompletedBy = null; | ||||||
|  |                 document.CompletedDate = DateTimeUtilities.MAX_DT; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (complete && document.CompletedByID <= 0) { | ||||||
|  |                 document.CompletedByID = authStateProvider.CurrentUser.UserID; | ||||||
|  |                 document.CompletedBy = authStateProvider.CurrentUser; | ||||||
|  |                 document.CompletedDate = DateTime.Now; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (!DocNumberIsNA() && !ecnNoIsValid)  | ||||||
|  |                 throw new Exception($"{document.ECNNumber} is not a valid ECN#"); | ||||||
|  |             if (DocNumberIsNA() && string.IsNullOrWhiteSpace(document.Comment)) | ||||||
|  |                 throw new Exception("you must provide a comment"); | ||||||
|  |  | ||||||
|  |             await pcrbService.UpdatePCR3Document(document); | ||||||
|  |  | ||||||
|  |             await pcrbService.GetPCR3DocumentsForPlanNumber(document.PlanNumber, true); | ||||||
|  |  | ||||||
|  |             saveInProcess = false; | ||||||
|  |  | ||||||
|  |             MudDialog.Close(DialogResult.Ok(document)); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             saveInProcess = false; | ||||||
|  |             snackbar.Add($"Unable to save document, because {ex.Message}", Severity.Error); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void Cancel() { | ||||||
|  |         MudDialog.Close(DialogResult.Cancel()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private bool DocNumberIsNA() { | ||||||
|  |         if (document.DocNumbers.ToLower().Equals("na") || | ||||||
|  |             document.DocNumbers.ToLower().Equals("n/a")) { | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task<string> ECNNoIsValid(int ecnNumber) { | ||||||
|  |         string? result = await ecnService.ECNNumberIsValidStr(ecnNumber); | ||||||
|  |         if (result is null) ecnNoIsValid = true; | ||||||
|  |         else ecnNoIsValid = false; | ||||||
|  |         StateHasChanged(); | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										201
									
								
								MesaFabApproval.Client/Pages/Components/PCRBActionItemForm.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								MesaFabApproval.Client/Pages/Components/PCRBActionItemForm.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,201 @@ | |||||||
|  | @inject MesaFabApprovalAuthStateProvider authStateProvider | ||||||
|  | @inject NavigationManager navigationManager | ||||||
|  | @inject IPCRBService pcrbService | ||||||
|  | @inject IUserService userService | ||||||
|  | @inject ISnackbar snackbar | ||||||
|  |  | ||||||
|  | <MudDialog> | ||||||
|  |     <DialogContent> | ||||||
|  |         <MudPaper Class="m-2 p-2"> | ||||||
|  |             <MudForm @bind-Errors="@errors"> | ||||||
|  |                 <MudTextField T="string" | ||||||
|  |                               Label="Action" | ||||||
|  |                               Required | ||||||
|  |                               RequiredError="Enter action item" | ||||||
|  |                               @bind-Value="@name" | ||||||
|  |                               @bind-Text="@name" | ||||||
|  |                               Immediate | ||||||
|  |                               Clearable | ||||||
|  |                               AutoGrow | ||||||
|  |                               AutoFocus /> | ||||||
|  |                 <MudCheckBox Label="Gating" | ||||||
|  |                              Color="Color.Tertiary" | ||||||
|  |                              @bind-Value=gating | ||||||
|  |                              LabelPosition="LabelPosition.Start" /> | ||||||
|  |                 <MudCheckBox Label="Closed" | ||||||
|  |                              Color="Color.Tertiary" | ||||||
|  |                              @bind-Value="@closedStatus" | ||||||
|  |                              LabelPosition="LabelPosition.Start" /> | ||||||
|  |                 @if (closedStatus) { | ||||||
|  |                     <MudDatePicker Label="Closed Date" | ||||||
|  |                                    Color="Color.Tertiary" | ||||||
|  |                                    @bind-Date="@closedDate" | ||||||
|  |                                    Clearable | ||||||
|  |                                    MinDate="@DateTimeUtilities.MIN_DT" | ||||||
|  |                                    MaxDate="@DateTimeUtilities.MAX_DT" | ||||||
|  |                                    Placeholder="Select a closed date" /> | ||||||
|  |                 } | ||||||
|  |                 <MudSelect T="User" | ||||||
|  |                            Label="Responsible Person" | ||||||
|  |                            Variant="Variant.Outlined" | ||||||
|  |                            Required | ||||||
|  |                            RequiredError="You must select a responsible person" | ||||||
|  |                            Clearable | ||||||
|  |                            AnchorOrigin="Origin.BottomCenter" | ||||||
|  |                            ToStringFunc="@UserToNameConverter" | ||||||
|  |                            @bind-Value=@responsiblePerson> | ||||||
|  |                     @foreach (User user in allActiveUsers.OrderBy(u => u.FirstName)) { | ||||||
|  |                         <MudSelectItem T="User" Value="@(user)" /> | ||||||
|  |                     } | ||||||
|  |                 </MudSelect> | ||||||
|  |             </MudForm> | ||||||
|  |         </MudPaper> | ||||||
|  |     </DialogContent> | ||||||
|  |     <DialogActions> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Color="Color.Tertiary" | ||||||
|  |                    Class="m1-auto" | ||||||
|  |                    OnClick=Save> | ||||||
|  |             @if (saveActionItemInProcess) { | ||||||
|  |                 <MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" /> | ||||||
|  |                 <MudText>Processing</MudText> | ||||||
|  |             } else { | ||||||
|  |                 <MudText>Submit</MudText> | ||||||
|  |             } | ||||||
|  |         </MudButton> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Class="grey text-black m1-auto" | ||||||
|  |                    OnClick=Cancel> | ||||||
|  |             Cancel | ||||||
|  |         </MudButton> | ||||||
|  |     </DialogActions> | ||||||
|  | </MudDialog> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     [CascadingParameter]  | ||||||
|  |     MudDialogInstance MudDialog { get; set; } | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public int planNumber { get; set; } = 0; | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public int step { get; set; } = 0; | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public PCRBActionItem? actionItem { get; set; } = null; | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public IEnumerable<User> allActiveUsers { get; set; } | ||||||
|  |  | ||||||
|  |     private string[] errors = { }; | ||||||
|  |  | ||||||
|  |     private string name = ""; | ||||||
|  |     private bool gating = false; | ||||||
|  |     private DateTime? closedDate = DateTimeUtilities.MAX_DT; | ||||||
|  |     private bool closedStatus = false; | ||||||
|  |     private User? responsiblePerson = null; | ||||||
|  |  | ||||||
|  |     private bool saveActionItemInProcess = false; | ||||||
|  |  | ||||||
|  |     protected override async Task OnParametersSetAsync() { | ||||||
|  |         if (authStateProvider.CurrentUser is null) { | ||||||
|  |             await authStateProvider.Logout(); | ||||||
|  |             navigationManager.NavigateTo("login"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (planNumber <= 0) { | ||||||
|  |             snackbar.Add($"{planNumber} is not a valid PCRB plan#", Severity.Error); | ||||||
|  |             MudDialog.Close(DialogResult.Cancel()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (allActiveUsers is null || allActiveUsers.Count() <= 0) | ||||||
|  |             allActiveUsers = await userService.GetAllActiveUsers(); | ||||||
|  |  | ||||||
|  |         if (actionItem is not null) { | ||||||
|  |             name = actionItem.Name; | ||||||
|  |             gating = actionItem.Gating; | ||||||
|  |             closedStatus = actionItem.ClosedStatus; | ||||||
|  |             closedDate = actionItem.ClosedDate; | ||||||
|  |             if (closedDate.Equals(DateTimeUtilities.MAX_DT)) { | ||||||
|  |                 closedDate = DateTime.Now; | ||||||
|  |             } | ||||||
|  |             if (actionItem.ResponsiblePersonID > 0) { | ||||||
|  |                 if (actionItem.ResponsiblePerson is not null) responsiblePerson = actionItem.ResponsiblePerson; | ||||||
|  |                 else responsiblePerson = await userService.GetUserByUserId(actionItem.ResponsiblePersonID); | ||||||
|  |                 actionItem.ResponsiblePerson = responsiblePerson; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             name = ""; | ||||||
|  |             gating = false; | ||||||
|  |             closedStatus = false; | ||||||
|  |             closedDate = DateTime.Now; | ||||||
|  |             responsiblePerson = null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task Save() { | ||||||
|  |         saveActionItemInProcess = true; | ||||||
|  |         try { | ||||||
|  |             if (authStateProvider.CurrentUser is null) { | ||||||
|  |                 await authStateProvider.Logout(); | ||||||
|  |                 navigationManager.NavigateTo("login"); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(name)) throw new Exception("name missing"); | ||||||
|  |  | ||||||
|  |             if (actionItem is null) { | ||||||
|  |                 actionItem = new() { | ||||||
|  |                     Name = name, | ||||||
|  |                     UploadedBy = authStateProvider.CurrentUser, | ||||||
|  |                     UploadedByID = authStateProvider.CurrentUser.UserID, | ||||||
|  |                     PlanNumber = planNumber, | ||||||
|  |                     Step = step, | ||||||
|  |                     Gating = gating, | ||||||
|  |                     ClosedStatus = closedStatus, | ||||||
|  |                     ResponsiblePerson = responsiblePerson, | ||||||
|  |                     ResponsiblePersonID = responsiblePerson.UserID, | ||||||
|  |                     ClosedDate = closedDate, | ||||||
|  |                     ClosedBy = closedDate is null || closedDate >= DateTimeUtilities.MAX_DT ? null : authStateProvider.CurrentUser, | ||||||
|  |                     ClosedByID = closedStatus ? authStateProvider.CurrentUser.UserID : 0 | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 if (actionItem.ClosedStatus == false) { | ||||||
|  |                     actionItem.ClosedDate = DateTimeUtilities.MAX_DT; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 await pcrbService.CreateNewActionItem(actionItem); | ||||||
|  |             } else { | ||||||
|  |                 actionItem.Name = name; | ||||||
|  |                 actionItem.Gating = gating; | ||||||
|  |                 actionItem.ClosedStatus = closedStatus; | ||||||
|  |                 actionItem.ClosedDate = closedDate; | ||||||
|  |                 if (closedStatus) { | ||||||
|  |                     actionItem.ClosedBy = authStateProvider.CurrentUser; | ||||||
|  |                     actionItem.ClosedByID = authStateProvider.CurrentUser.UserID; | ||||||
|  |                 } else { | ||||||
|  |                     actionItem.ClosedDate = DateTimeUtilities.MAX_DT; | ||||||
|  |                 } | ||||||
|  |                 actionItem.ResponsiblePerson = responsiblePerson; | ||||||
|  |                 if (responsiblePerson is not null) | ||||||
|  |                     actionItem.ResponsiblePersonID = responsiblePerson.UserID; | ||||||
|  |  | ||||||
|  |                 await pcrbService.UpdateActionItem(actionItem); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             saveActionItemInProcess = false; | ||||||
|  |  | ||||||
|  |             MudDialog.Close(DialogResult.Ok(actionItem)); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             saveActionItemInProcess = false; | ||||||
|  |             snackbar.Add($"Unable to save action item, because {ex.Message}", Severity.Error); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void Cancel() { | ||||||
|  |         MudDialog.Close(DialogResult.Cancel()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private Func<User, string> UserToNameConverter = u => u is null ? string.Empty : u.GetFullName(); | ||||||
|  |  | ||||||
|  |     private Func<PCRBAttachment, string> AttachmentToFileNameConverter = a => a is null ? "" : a.FileName; | ||||||
|  | } | ||||||
							
								
								
									
										250
									
								
								MesaFabApproval.Client/Pages/Components/PCRBApproverForm.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								MesaFabApproval.Client/Pages/Components/PCRBApproverForm.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,250 @@ | |||||||
|  | @inject MesaFabApprovalAuthStateProvider authStateProvider | ||||||
|  | @inject NavigationManager navigationManager | ||||||
|  | @inject IPCRBService pcrbService | ||||||
|  | @inject IUserService userService | ||||||
|  | @inject IApprovalService approvalService | ||||||
|  | @inject ISnackbar snackbar | ||||||
|  |  | ||||||
|  | <MudDialog> | ||||||
|  |     <DialogContent> | ||||||
|  |         <MudPaper Class="m-2 p-2"> | ||||||
|  |             <MudForm @bind-Errors="@errors"> | ||||||
|  |                 <MudSelect T="string" | ||||||
|  |                               Label="Job Title" | ||||||
|  |                               Required | ||||||
|  |                               RequiredError="You must provide a job title" | ||||||
|  |                               ValueChanged="@SelectedJobTitleChanged" | ||||||
|  |                               @bind-Text="@selectedJobTitle" | ||||||
|  |                               Immediate | ||||||
|  |                               Disabled="@(approval is not null && !string.IsNullOrWhiteSpace(selectedJobTitle))" | ||||||
|  |                               Clearable | ||||||
|  |                               AutoFocus > | ||||||
|  |                     @foreach (string jt in availableJobTitles) { | ||||||
|  |                         <MudSelectItem Value="@jt">@jt</MudSelectItem> | ||||||
|  |                     } | ||||||
|  |                 </MudSelect> | ||||||
|  |                 <MudSelect T="User" | ||||||
|  |                            Label="Select a User" | ||||||
|  |                            Required | ||||||
|  |                            Clearable | ||||||
|  |                            Disabled="@(string.IsNullOrWhiteSpace(selectedJobTitle))" | ||||||
|  |                            Variant="Variant.Outlined" | ||||||
|  |                            AnchorOrigin="Origin.BottomCenter" | ||||||
|  |                            @bind-Value=selectedUser | ||||||
|  |                            ToStringFunc="@UserToNameConverter"> | ||||||
|  |                     @foreach (User user in availableUsers) { | ||||||
|  |                         <MudSelectItem Value="@user">@user.GetFullName()</MudSelectItem> | ||||||
|  |                     } | ||||||
|  |                 </MudSelect> | ||||||
|  |             </MudForm> | ||||||
|  |         </MudPaper> | ||||||
|  |     </DialogContent> | ||||||
|  |     <DialogActions> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Color="Color.Tertiary" | ||||||
|  |                    Class="m1-auto" | ||||||
|  |                    OnClick=Save> | ||||||
|  |             @if (saveAttendeeInProcess) { | ||||||
|  |                 <MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" /> | ||||||
|  |                 <MudText>Processing</MudText> | ||||||
|  |             } else { | ||||||
|  |                 <MudText>Submit</MudText> | ||||||
|  |             } | ||||||
|  |         </MudButton> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Class="grey text-black m1-auto" | ||||||
|  |                    OnClick=Cancel> | ||||||
|  |             Cancel | ||||||
|  |         </MudButton> | ||||||
|  |     </DialogActions> | ||||||
|  | </MudDialog> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     [CascadingParameter]  | ||||||
|  |     MudDialogInstance MudDialog { get; set; } | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public int planNumber { get; set; } = 0; | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public int step { get; set; } = 0; | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public Approval? approval { get; set; } = null; | ||||||
|  |  | ||||||
|  |     private HashSet<string> availableJobTitles = new(); | ||||||
|  |  | ||||||
|  |     private Dictionary<string, SubRole> jobTitleToSubRoleMap = new(); | ||||||
|  |  | ||||||
|  |     private Dictionary<string, IEnumerable<User>> jobTitleToAvailableUsersMap = new(); | ||||||
|  |  | ||||||
|  |     private HashSet<User> availableUsers = new(); | ||||||
|  |  | ||||||
|  |     private string[] errors = { }; | ||||||
|  |  | ||||||
|  |     private string selectedJobTitle = ""; | ||||||
|  |     private User? selectedUser = null; | ||||||
|  |  | ||||||
|  |     private bool saveAttendeeInProcess = false; | ||||||
|  |  | ||||||
|  |     protected override async Task OnParametersSetAsync() { | ||||||
|  |         if (authStateProvider.CurrentUser is null) { | ||||||
|  |             await authStateProvider.Logout(); | ||||||
|  |             navigationManager.NavigateTo("login"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (planNumber <= 0) { | ||||||
|  |             snackbar.Add($"{planNumber} is not a valid PCRB plan#", Severity.Error); | ||||||
|  |             MudDialog.Close(DialogResult.Cancel()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         await GetAttendees(); | ||||||
|  |  | ||||||
|  |         if (approval is not null) { | ||||||
|  |             selectedJobTitle = approval.RoleName; | ||||||
|  |             if (approval.UserID > 0) { | ||||||
|  |                 if (approval.User is not null) { | ||||||
|  |                     selectedUser = approval.User; | ||||||
|  |                 } else { | ||||||
|  |                     selectedUser = await userService.GetUserByUserId(approval.UserID); | ||||||
|  |                     approval.User = selectedUser; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             SelectedJobTitleChanged(selectedJobTitle); | ||||||
|  |         } else { | ||||||
|  |             selectedJobTitle = ""; | ||||||
|  |             selectedUser = null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task Save() { | ||||||
|  |         saveAttendeeInProcess = true; | ||||||
|  |         try { | ||||||
|  |             if (authStateProvider.CurrentUser is null) { | ||||||
|  |                 await authStateProvider.Logout(); | ||||||
|  |                 navigationManager.NavigateTo("login"); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(selectedJobTitle)) throw new Exception("job title missing"); | ||||||
|  |             if (selectedUser is null) throw new Exception("attendee not selected"); | ||||||
|  |  | ||||||
|  |             PCRB pcrb = await pcrbService.GetPCRBByPlanNumber(planNumber, false); | ||||||
|  |  | ||||||
|  |             if (approval is null) { | ||||||
|  |                 jobTitleToSubRoleMap.TryGetValue($"{selectedJobTitle}{selectedUser.UserID}", out SubRole? subRole); | ||||||
|  |  | ||||||
|  |                 if (subRole is null) throw new Exception($"no approval role found for job title {selectedJobTitle}"); | ||||||
|  |  | ||||||
|  |                 approval = new() { | ||||||
|  |                     RoleName = subRole.SubRoleCategoryItem, | ||||||
|  |                     SubRole = subRole.SubRoleName, | ||||||
|  |                     SubRoleID = subRole.SubRoleID, | ||||||
|  |                     IssueID = planNumber, | ||||||
|  |                     Step = step, | ||||||
|  |                     User = selectedUser, | ||||||
|  |                     UserID = selectedUser.UserID, | ||||||
|  |                     AssignedDate = DateTimeUtilities.MIN_DT | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 await approvalService.CreateApproval(approval); | ||||||
|  |             } else { | ||||||
|  |                 int originalUserId = approval.UserID; | ||||||
|  |  | ||||||
|  |                 approval.UserID = selectedUser.UserID; | ||||||
|  |                 approval.User = selectedUser; | ||||||
|  |  | ||||||
|  |                 if (originalUserId != approval.UserID) { | ||||||
|  |                     if (approval.AssignedDate > DateTimeUtilities.MIN_DT) | ||||||
|  |                         approval.AssignedDate = DateTime.Now; | ||||||
|  |                     approval.NotifyDate = DateTimeUtilities.MIN_DT; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 await approvalService.UpdateApproval(approval); | ||||||
|  |  | ||||||
|  |                 if (originalUserId != approval.UserID) | ||||||
|  |                     await pcrbService.NotifyNewApprovals(pcrb); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             saveAttendeeInProcess = false; | ||||||
|  |  | ||||||
|  |             MudDialog.Close(DialogResult.Ok(approval)); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             saveAttendeeInProcess = false; | ||||||
|  |             snackbar.Add($"Unable to save attendee, because {ex.Message}", Severity.Error); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void Cancel() { | ||||||
|  |         MudDialog.Close(DialogResult.Cancel()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private Func<User, string> UserToNameConverter = u => u is null ? string.Empty : u.GetFullName(); | ||||||
|  |  | ||||||
|  |     private async Task GetAttendees() { | ||||||
|  |         int roleId = await approvalService.GetRoleIdForRoleName("Module Manager"); | ||||||
|  |  | ||||||
|  |         if (roleId <= 0) throw new Exception($"could not find Director role ID"); | ||||||
|  |  | ||||||
|  |         availableJobTitles.Clear(); | ||||||
|  |         jobTitleToAvailableUsersMap.Clear(); | ||||||
|  |         jobTitleToSubRoleMap.Clear(); | ||||||
|  |  | ||||||
|  |         IEnumerable<SubRole> subRoles = await approvalService.GetSubRolesForSubRoleName("MMSubRole", roleId); | ||||||
|  |  | ||||||
|  |         HashSet<string> defaultSubRoleCategoryItems = new() { "Si Production", "Si Engineering", "Quality" }; | ||||||
|  |         HashSet<string> unusedSubRoleCategoryItems = new() { "GaN Engineering", "GaN Operations", "Integration" }; | ||||||
|  |         foreach (SubRole subRole in subRoles) { | ||||||
|  |             if (approval is null) { | ||||||
|  |                 if (!defaultSubRoleCategoryItems.Contains(subRole.SubRoleCategoryItem) &&  | ||||||
|  |                     !unusedSubRoleCategoryItems.Contains(subRole.SubRoleCategoryItem)) { | ||||||
|  |                     availableJobTitles.Add(subRole.SubRoleCategoryItem); | ||||||
|  |  | ||||||
|  |                     IEnumerable<User> subRoleMembers = await approvalService.GetApprovalGroupMembers(subRole.SubRoleID); | ||||||
|  |  | ||||||
|  |                     jobTitleToAvailableUsersMap.Add(subRole.SubRoleCategoryItem, subRoleMembers); | ||||||
|  |  | ||||||
|  |                     foreach (User member in subRoleMembers) { | ||||||
|  |                         jobTitleToSubRoleMap.Add($"{subRole.SubRoleCategoryItem}{member.UserID}", subRole); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 if (!unusedSubRoleCategoryItems.Contains(subRole.SubRoleCategoryItem)) { | ||||||
|  |                     IEnumerable<User> subRoleMembers = await approvalService.GetApprovalGroupMembers(subRole.SubRoleID); | ||||||
|  |  | ||||||
|  |                     jobTitleToAvailableUsersMap.Add(subRole.SubRoleCategoryItem, subRoleMembers); | ||||||
|  |  | ||||||
|  |                     foreach (User member in subRoleMembers) | ||||||
|  |                         availableUsers.Add(member); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void SelectedJobTitleChanged(string jobTitle) { | ||||||
|  |         selectedJobTitle = jobTitle; | ||||||
|  |  | ||||||
|  |         selectedUser = null; | ||||||
|  |  | ||||||
|  |         availableUsers.Clear(); | ||||||
|  |  | ||||||
|  |         if (approval is null) { | ||||||
|  |             if (jobTitleToAvailableUsersMap.TryGetValue(jobTitle, out IEnumerable<User>? jobTitleMembers)) { | ||||||
|  |                 if (jobTitleMembers is not null) { | ||||||
|  |                     foreach (User member in jobTitleMembers) | ||||||
|  |                         availableUsers.Add(member); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             foreach (IEnumerable<User> memberList in jobTitleToAvailableUsersMap.Values) { | ||||||
|  |                 if (memberList is not null) { | ||||||
|  |                     foreach(User member in memberList) { | ||||||
|  |                         availableUsers.Add(member); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         StateHasChanged(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										140
									
								
								MesaFabApproval.Client/Pages/Components/PCRBAttachmentForm.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								MesaFabApproval.Client/Pages/Components/PCRBAttachmentForm.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,140 @@ | |||||||
|  | @inject MesaFabApprovalAuthStateProvider authStateProvider | ||||||
|  | @inject NavigationManager navigationManager | ||||||
|  | @inject IPCRBService pcrbService | ||||||
|  | @inject ISnackbar snackbar | ||||||
|  |  | ||||||
|  | <MudDialog> | ||||||
|  |     <DialogContent> | ||||||
|  |         <MudPaper Class="m-2 p-2"> | ||||||
|  |             <MudForm @bind-Errors="@errors"> | ||||||
|  |                 <MudTextField T="string" | ||||||
|  |                               Label="File Name" | ||||||
|  |                               Disabled | ||||||
|  |                               Immediate | ||||||
|  |                               @bind-Value="@fileName" | ||||||
|  |                               @bind-Text="@fileName" | ||||||
|  |                               AutoGrow /> | ||||||
|  |                 <MudFileUpload T="IBrowserFile"  | ||||||
|  |                                FilesChanged="AddFile" | ||||||
|  |                                Required | ||||||
|  |                                Disabled="@(!string.IsNullOrWhiteSpace(fileName))" | ||||||
|  |                                RequiredError="You must select a file"> | ||||||
|  |                     <ActivatorContent> | ||||||
|  |                         <MudButton Variant="Variant.Filled" | ||||||
|  |                                    Color="Color.Tertiary" | ||||||
|  |                                    style="margin: auto;" | ||||||
|  |                                    StartIcon="@Icons.Material.Filled.AttachFile"> | ||||||
|  |                             @if (addFileInProcess) { | ||||||
|  |                                 <MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" /> | ||||||
|  |                                 <MudText>Processing</MudText> | ||||||
|  |                             } else { | ||||||
|  |                                 <MudText>Add File</MudText> | ||||||
|  |                             } | ||||||
|  |                         </MudButton> | ||||||
|  |                     </ActivatorContent> | ||||||
|  |                 </MudFileUpload> | ||||||
|  |             </MudForm> | ||||||
|  |         </MudPaper> | ||||||
|  |     </DialogContent> | ||||||
|  |     <DialogActions> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Color="Color.Tertiary" | ||||||
|  |                    Class="m1-auto" | ||||||
|  |                    OnClick=Submit> | ||||||
|  |             @if (processing) { | ||||||
|  |                 <MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" /> | ||||||
|  |                 <MudText>Processing</MudText> | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 <MudText>Submit</MudText> | ||||||
|  |             } | ||||||
|  |         </MudButton> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Class="grey text-black m1-auto" | ||||||
|  |                    OnClick=Cancel> | ||||||
|  |             Cancel | ||||||
|  |         </MudButton> | ||||||
|  |     </DialogActions> | ||||||
|  | </MudDialog> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     [CascadingParameter] MudDialogInstance MudDialog { get; set; } | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public int planNumber { get; set; } = 0; | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public int step { get; set; } = 0; | ||||||
|  |  | ||||||
|  |     private string[] errors = { }; | ||||||
|  |  | ||||||
|  |     private string fileName = ""; | ||||||
|  |  | ||||||
|  |     private IBrowserFile? file = null; | ||||||
|  |  | ||||||
|  |     private bool addFileInProcess = false; | ||||||
|  |     private bool processing = false; | ||||||
|  |  | ||||||
|  |     protected override async Task OnParametersSetAsync() { | ||||||
|  |         if (planNumber <= 0) { | ||||||
|  |             snackbar.Add($"{planNumber} is not a valid PCRB plan#", Severity.Error); | ||||||
|  |             MudDialog.Close(DialogResult.Cancel()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (step <= 0) { | ||||||
|  |             snackbar.Add($"{step} is not a valid PCRB stage#", Severity.Error); | ||||||
|  |             MudDialog.Close(DialogResult.Cancel()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (authStateProvider.CurrentUser is null) { | ||||||
|  |             await authStateProvider.Logout(); | ||||||
|  |             navigationManager.NavigateTo("login"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void AddFile(IBrowserFile newFile) { | ||||||
|  |         addFileInProcess = true; | ||||||
|  |         file = newFile; | ||||||
|  |         fileName = newFile.Name; | ||||||
|  |         addFileInProcess = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task Submit() { | ||||||
|  |         processing = true; | ||||||
|  |         try { | ||||||
|  |             if (authStateProvider.CurrentUser is null) { | ||||||
|  |                 await authStateProvider.Logout(); | ||||||
|  |                 navigationManager.NavigateTo("login"); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (string.IsNullOrWhiteSpace(fileName)) | ||||||
|  |                 throw new Exception("file name missing"); | ||||||
|  |  | ||||||
|  |             if (file is null) | ||||||
|  |                 throw new Exception("file is missing"); | ||||||
|  |  | ||||||
|  |             PCRBAttachment attachment = new() { | ||||||
|  |                 Step = step, | ||||||
|  |                 UploadDateTime = DateTime.Now, | ||||||
|  |                 UploadedByID = authStateProvider.CurrentUser.UserID, | ||||||
|  |                 PlanNumber = planNumber, | ||||||
|  |                 File = file, | ||||||
|  |                 FileName = fileName | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             await pcrbService.UploadAttachment(attachment); | ||||||
|  |  | ||||||
|  |             processing = false; | ||||||
|  |  | ||||||
|  |             MudDialog.Close(DialogResult.Ok(attachment)); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             snackbar.Add($"Unable to save document, because {ex.Message}", Severity.Error); | ||||||
|  |             processing = false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void Cancel() { | ||||||
|  |         MudDialog.Close(DialogResult.Cancel()); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | @attribute [AllowAnonymous] | ||||||
|  | @inject NavigationManager Navigation | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     protected override void OnInitialized() { | ||||||
|  |         Navigation.NavigateTo("login"); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										74
									
								
								MesaFabApproval.Client/Pages/Components/UserSelector.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								MesaFabApproval.Client/Pages/Components/UserSelector.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,74 @@ | |||||||
|  | @inject IUserService userService | ||||||
|  | @inject ISnackbar snackbar | ||||||
|  | @inject MesaFabApprovalAuthStateProvider authStateProvider | ||||||
|  |  | ||||||
|  | <MudDialog> | ||||||
|  |     <DialogContent> | ||||||
|  |         @if (allUsers is not null) { | ||||||
|  |             <MudPaper Class="p-2"> | ||||||
|  |                 <MudSelect T="User" | ||||||
|  |                            Label="Select a User" | ||||||
|  |                            Required | ||||||
|  |                            Variant="Variant.Outlined" | ||||||
|  |                            AnchorOrigin="Origin.BottomCenter" | ||||||
|  |                            @bind-Value=selectedUser | ||||||
|  |                            Text="@(selectedUser is null ? "" : selectedUser.GetFullName())"> | ||||||
|  |                     @foreach (User user in allUsers) { | ||||||
|  |                         <MudSelectItem Value="@user"> | ||||||
|  |                             @user.GetFullName() | ||||||
|  |                         </MudSelectItem> | ||||||
|  |                     } | ||||||
|  |                 </MudSelect> | ||||||
|  |             </MudPaper> | ||||||
|  |         } | ||||||
|  |     </DialogContent> | ||||||
|  |     <DialogActions> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Color="Color.Tertiary" | ||||||
|  |                    Class="m1-auto" | ||||||
|  |                    OnClick=Submit> | ||||||
|  |             <MudText>Submit</MudText> | ||||||
|  |         </MudButton> | ||||||
|  |         <MudButton Variant="Variant.Filled" | ||||||
|  |                    Color="Color.Secondary" | ||||||
|  |                    Class="m1-auto" | ||||||
|  |                    OnClick=Cancel> | ||||||
|  |             <MudText>Cancel</MudText> | ||||||
|  |         </MudButton> | ||||||
|  |     </DialogActions> | ||||||
|  | </MudDialog> | ||||||
|  |  | ||||||
|  | <MudOverlay Visible=processing DarkBackground="true" AutoClose="false"> | ||||||
|  |     <MudProgressCircular Color="Color.Info" Size="Size.Medium" Indeterminate="true" /> | ||||||
|  | </MudOverlay> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     [CascadingParameter] MudDialogInstance MudDialog { get; set; } | ||||||
|  |  | ||||||
|  |     [Parameter] | ||||||
|  |     public User selectedUser { get; set; } | ||||||
|  |  | ||||||
|  |     private bool processing = false; | ||||||
|  |  | ||||||
|  |     private IEnumerable<User> allUsers = new List<User>(); | ||||||
|  |  | ||||||
|  |     protected override async Task OnInitializedAsync() { | ||||||
|  |         try { | ||||||
|  |             processing = true; | ||||||
|  |             selectedUser = authStateProvider.CurrentUser; | ||||||
|  |             allUsers = await userService.GetAllActiveUsers(); | ||||||
|  |             processing = false; | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             processing = false; | ||||||
|  |             snackbar.Add($"Unable to get all users, because {ex.Message}", Severity.Error); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void Submit() { | ||||||
|  |         MudDialog.Close(DialogResult.Ok(selectedUser)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void Cancel() { | ||||||
|  |         MudDialog.Close(DialogResult.Cancel()); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										363
									
								
								MesaFabApproval.Client/Pages/Dashboard.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								MesaFabApproval.Client/Pages/Dashboard.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,363 @@ | |||||||
|  | @page "/" | ||||||
|  | @page "/Dashboard" | ||||||
|  | @inject IConfiguration Configuration | ||||||
|  | @inject MesaFabApprovalAuthStateProvider stateProvider | ||||||
|  | @inject IApprovalService approvalService | ||||||
|  | @inject IMemoryCache cache | ||||||
|  | @inject NavigationManager navigationManager | ||||||
|  | @inject ISnackbar snackbar | ||||||
|  | @inject IMRBService mrbService | ||||||
|  | @inject IPCRBService pcrbService | ||||||
|  | @inject IECNService ecnService | ||||||
|  | @inject ICAService caService | ||||||
|  | @inject IJSRuntime jsRuntime | ||||||
|  |  | ||||||
|  | <PageTitle>Dashboard</PageTitle> | ||||||
|  |  | ||||||
|  | <MudPaper Class="p-2 m-2"> | ||||||
|  |     <MudText Typo="Typo.h3" Align="Align.Center">Dashboard</MudText> | ||||||
|  | </MudPaper> | ||||||
|  |  | ||||||
|  | <MudPaper Class="p-2 m-2"> | ||||||
|  |     <MudTabs Class="p-2" Rounded Centered Color="Color.Info" MinimumTabWidth="50%"> | ||||||
|  |         <MudTabPanel Text="My Active Approvals" Style="min-width:50%; text-align: center;"> | ||||||
|  |             @if (stateProvider.CurrentUser is not null && approvalList is not null && !myApprovalsProcessing) { | ||||||
|  |                 <MudPaper Outlined="true" | ||||||
|  |                           Class="p-2 m-2 d-flex flex-column justify-center"> | ||||||
|  |                     <MudText Typo="Typo.h4" Align="Align.Center">My Active Approvals</MudText> | ||||||
|  |                     <MudDivider DividerType="DividerType.Middle" Class="my-2" /> | ||||||
|  |                     <MudTable Items="@approvalList" | ||||||
|  |                               Class="m-2" | ||||||
|  |                               Striped | ||||||
|  |                               SortLabel="Sort by"> | ||||||
|  |                         <HeaderContent> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel SortBy="new Func<Approval,object>(x=>x.IssueID)"> | ||||||
|  |                                     Issue ID | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel SortBy="new Func<Approval,object>(x=>x.SubRoleCategoryItem)"> | ||||||
|  |                                     Role | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<Approval,object>(x=>x.AssignedDate)"> | ||||||
|  |                                     Assigned Date | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel SortBy="new Func<Approval,object>(x=>x.Step)"> | ||||||
|  |                                     Step | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                         </HeaderContent> | ||||||
|  |                         <RowTemplate> | ||||||
|  |                             <MudTd DataLabel="Issue ID"> | ||||||
|  |                                 @if (context.IssueID > 0) { | ||||||
|  |                                     <MudLink OnClick="@(() => FollowLink(context.IssueID))">@context.IssueID</MudLink> | ||||||
|  |                                 } | ||||||
|  |                             </MudTd> | ||||||
|  |                             <MudTd DataLabel="Role">@context.SubRoleCategoryItem</MudTd> | ||||||
|  |                             <MudTd DataLabel="Assigned Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.AssignedDate)</MudTd> | ||||||
|  |                             <MudTd DataLabel="Step">@context.Step</MudTd> | ||||||
|  |                         </RowTemplate> | ||||||
|  |                         <PagerContent> | ||||||
|  |                             <MudTablePager /> | ||||||
|  |                         </PagerContent> | ||||||
|  |                     </MudTable> | ||||||
|  |                 </MudPaper> | ||||||
|  |             } else { | ||||||
|  |                 <MudOverlay Visible DarkBackground="true" AutoClose="false"> | ||||||
|  |                     <MudText Align="Align.Center" Typo="Typo.h3">Processing</MudText> | ||||||
|  |                     <MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" /> | ||||||
|  |                 </MudOverlay> | ||||||
|  |             } | ||||||
|  |         </MudTabPanel> | ||||||
|  |         <MudTabPanel Text="My MRBs" Style="min-width:50%; text-align: center;"> | ||||||
|  |             @if (stateProvider.CurrentUser is not null && myMRBs is not null && !myMrbsProcessing) { | ||||||
|  |                 <MudPaper Outlined="true" | ||||||
|  |                           Class="p-2 m-2 d-flex flex-column justify-center"> | ||||||
|  |                     <MudText Typo="Typo.h4" Align="Align.Center">My MRBs</MudText> | ||||||
|  |                     <MudDivider DividerType="DividerType.Middle" Class="my-2" /> | ||||||
|  |                     <MudTable Items="@myMRBs" | ||||||
|  |                               Class="m-2" | ||||||
|  |                               Striped | ||||||
|  |                               SortLabel="Sort by" | ||||||
|  |                               Filter="new Func<MRB, bool>(FilterFuncForMRBTable)"> | ||||||
|  |                         <ToolBarContent> | ||||||
|  |                             <MudSpacer /> | ||||||
|  |                             <MudTextField @bind-Value="mrbSearchString" | ||||||
|  |                                           Placeholder="Search" | ||||||
|  |                                           Immediate | ||||||
|  |                                           Adornment="Adornment.Start" | ||||||
|  |                                           AdornmentIcon="@Icons.Material.Filled.Search" | ||||||
|  |                                           IconSize="Size.Medium" | ||||||
|  |                                           Class="mt-0" /> | ||||||
|  |                         </ToolBarContent> | ||||||
|  |                         <HeaderContent> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<MRB,object>(x=>x.MRBNumber)"> | ||||||
|  |                                     MRB# | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.Title)"> | ||||||
|  |                                     Title | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.SubmittedDate)"> | ||||||
|  |                                     Submitted Date | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.ApprovalDate)"> | ||||||
|  |                                     Approval Date | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.CancelDate)"> | ||||||
|  |                                     Cancel Date | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.CloseDate)"> | ||||||
|  |                                     Completed Date | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                         </HeaderContent> | ||||||
|  |                         <RowTemplate> | ||||||
|  |                             <MudTd DataLabel="MRB#"> | ||||||
|  |                                 <MudLink OnClick="@(() => GoTo($"mrb/{context.MRBNumber}"))">@context.MRBNumber</MudLink> | ||||||
|  |                             </MudTd> | ||||||
|  |                             <MudTd DataLabel="Title">@context.Title</MudTd> | ||||||
|  |                             <MudTd DataLabel="Submitted Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.SubmittedDate)</MudTd> | ||||||
|  |                             <MudTd DataLabel="Approval Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.ApprovalDate)</MudTd> | ||||||
|  |                             <MudTd DataLabel="Cancel Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.CancelDate)</MudTd> | ||||||
|  |                             <MudTd DataLabel="Completed Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.CloseDate)</MudTd> | ||||||
|  |                         </RowTemplate> | ||||||
|  |                         <PagerContent> | ||||||
|  |                             <MudTablePager /> | ||||||
|  |                         </PagerContent> | ||||||
|  |                     </MudTable> | ||||||
|  |                 </MudPaper> | ||||||
|  |             } else { | ||||||
|  |                 <MudOverlay Visible DarkBackground="true" AutoClose="false"> | ||||||
|  |                     <MudText Align="Align.Center" Typo="Typo.h3">Processing</MudText> | ||||||
|  |                     <MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" /> | ||||||
|  |                 </MudOverlay> | ||||||
|  |             } | ||||||
|  |         </MudTabPanel> | ||||||
|  |         <MudTabPanel Text="My PCRBs" Style="min-width:50%; text-align: center;"> | ||||||
|  |             @if (stateProvider.CurrentUser is not null && myPCRBs is not null && !myPcrbsProcessing) { | ||||||
|  |                 <MudPaper Outlined="true" | ||||||
|  |                           Class="p-2 m-2 d-flex flex-column justify-center"> | ||||||
|  |                     <MudText Typo="Typo.h4" Align="Align.Center">My PCRBs</MudText> | ||||||
|  |                     <MudDivider DividerType="DividerType.Middle" Class="my-2" /> | ||||||
|  |                     <MudTable Items="@myPCRBs" | ||||||
|  |                               Class="m-2" | ||||||
|  |                               Striped | ||||||
|  |                               SortLabel="Sort by" | ||||||
|  |                               Filter="new Func<PCRB, bool>(FilterFuncForPCRBTable)"> | ||||||
|  |                         <ToolBarContent> | ||||||
|  |                             <MudSpacer /> | ||||||
|  |                             <MudTextField @bind-Value="pcrbSearchString" | ||||||
|  |                                           Placeholder="Search" | ||||||
|  |                                           Adornment="Adornment.Start" | ||||||
|  |                                           Immediate | ||||||
|  |                                           AdornmentIcon="@Icons.Material.Filled.Search" | ||||||
|  |                                           IconSize="Size.Medium" | ||||||
|  |                                           Class="mt-0" /> | ||||||
|  |                         </ToolBarContent> | ||||||
|  |                         <HeaderContent> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<PCRB,object>(x=>x.PlanNumber)"> | ||||||
|  |                                     PCRB# | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.Title)"> | ||||||
|  |                                     Title | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.CurrentStep)"> | ||||||
|  |                                     Current Step | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.InsertTimeStamp)"> | ||||||
|  |                                     Submitted Date | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.LastUpdateDate)"> | ||||||
|  |                                     Last Updated | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                             <MudTh> | ||||||
|  |                                 <MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.ClosedDate)"> | ||||||
|  |                                     Completed Date | ||||||
|  |                                 </MudTableSortLabel> | ||||||
|  |                             </MudTh> | ||||||
|  |                         </HeaderContent> | ||||||
|  |                         <RowTemplate> | ||||||
|  |                             <MudTd DataLabel="PCRB#"> | ||||||
|  |                                 <MudLink OnClick="@(() => GoTo($"pcrb/{context.PlanNumber}"))">@context.PlanNumber</MudLink> | ||||||
|  |                             </MudTd> | ||||||
|  |                             <MudTd DataLabel="Title">@context.Title</MudTd> | ||||||
|  |                             <MudTd DataLabel="Current Step">@(GetCurrentPCRBStep(context.CurrentStep))</MudTd> | ||||||
|  |                             <MudTd DataLabel="Submitted Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.InsertTimeStamp)</MudTd> | ||||||
|  |                             <MudTd DataLabel="Last Updated">@DateTimeUtilities.GetDateAsStringMinDefault(context.LastUpdateDate)</MudTd> | ||||||
|  |                             <MudTd DataLabel="Completed Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.ClosedDate)</MudTd> | ||||||
|  |                         </RowTemplate> | ||||||
|  |                         <PagerContent> | ||||||
|  |                             <MudTablePager /> | ||||||
|  |                         </PagerContent> | ||||||
|  |                     </MudTable> | ||||||
|  |                 </MudPaper> | ||||||
|  |             } else { | ||||||
|  |                 <MudOverlay Visible DarkBackground="true" AutoClose="false"> | ||||||
|  |                     <MudText Align="Align.Center" Typo="Typo.h3">Processing</MudText> | ||||||
|  |                     <MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" /> | ||||||
|  |                 </MudOverlay> | ||||||
|  |             } | ||||||
|  |         </MudTabPanel> | ||||||
|  |     </MudTabs> | ||||||
|  | </MudPaper> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     private IEnumerable<Approval> approvalList = new List<Approval>(); | ||||||
|  |     private IEnumerable<MRB> myMRBs = new List<MRB>(); | ||||||
|  |     private IEnumerable<PCRB> myPCRBs = new List<PCRB>(); | ||||||
|  |  | ||||||
|  |     private IEnumerable<int> ecnNumbers = new HashSet<int>(); | ||||||
|  |     private IEnumerable<int> caNumbers = new HashSet<int>(); | ||||||
|  |     private IEnumerable<int> mrbNumbers = new HashSet<int>(); | ||||||
|  |     private IEnumerable<int> pcrbNumbers = new HashSet<int>(); | ||||||
|  |  | ||||||
|  |     private bool myApprovalsProcessing = false; | ||||||
|  |     private bool myMrbsProcessing = false; | ||||||
|  |     private bool myPcrbsProcessing = false; | ||||||
|  |  | ||||||
|  |     private string mrbSearchString = ""; | ||||||
|  |     private string pcrbSearchString = ""; | ||||||
|  |  | ||||||
|  |     protected async override Task OnParametersSetAsync() { | ||||||
|  |         try { | ||||||
|  |             if (stateProvider.CurrentUser is not null) { | ||||||
|  |                 myApprovalsProcessing = true; | ||||||
|  |                 approvalList = (await approvalService.GetApprovalsForUserId(stateProvider.CurrentUser.UserID, true)) | ||||||
|  |                     .Where(a => a.CompletedDate > DateTime.Now && a.ItemStatus == 0) | ||||||
|  |                     .ToList() | ||||||
|  |                     .OrderByDescending(x => x.AssignedDate); | ||||||
|  |                 myApprovalsProcessing = false; | ||||||
|  |  | ||||||
|  |                 myMrbsProcessing = true; | ||||||
|  |                 myMRBs = (await mrbService.GetAllMRBs(false)).Where(m => m.OriginatorID == stateProvider.CurrentUser.UserID) | ||||||
|  |                     .ToList() | ||||||
|  |                     .OrderByDescending(x => x.SubmittedDate); | ||||||
|  |                 myMrbsProcessing = false; | ||||||
|  |  | ||||||
|  |                 myPcrbsProcessing = true; | ||||||
|  |                 myPCRBs = (await pcrbService.GetAllPCRBs(false)).Where(p => p.OwnerID == stateProvider.CurrentUser.UserID) | ||||||
|  |                     .ToList() | ||||||
|  |                     .OrderByDescending(p => p.InsertTimeStamp); | ||||||
|  |                 myPcrbsProcessing = false; | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             myApprovalsProcessing = false; | ||||||
|  |             myMrbsProcessing = false; | ||||||
|  |             myPcrbsProcessing = false; | ||||||
|  |             snackbar.Add($"Unable to load the dashboard, because {ex.Message}", Severity.Error); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task FollowLink(int issueId) { | ||||||
|  |         HashSet<Task> tasks = new(); | ||||||
|  |  | ||||||
|  |         bool isEcn = false; | ||||||
|  |         bool isCa = false; | ||||||
|  |         bool isMrb = false; | ||||||
|  |         bool isPcrb = false; | ||||||
|  |         if (ecnNumbers.Contains(issueId)) | ||||||
|  |             isEcn = true; | ||||||
|  |         if (caNumbers.Contains(issueId)) | ||||||
|  |             isCa = true; | ||||||
|  |         if (mrbNumbers.Contains(issueId)) | ||||||
|  |             isMrb = true; | ||||||
|  |         if (pcrbNumbers.Contains(issueId)) | ||||||
|  |             isPcrb = true; | ||||||
|  |  | ||||||
|  |         if (!isEcn && !isCa && !isMrb) { | ||||||
|  |             Task<bool> isEcnTask = ecnService.ECNNumberIsValid(issueId); | ||||||
|  |             tasks.Add(isEcnTask); | ||||||
|  |  | ||||||
|  |             Task<bool> isCaTask = caService.CANumberIsValid(issueId); | ||||||
|  |             tasks.Add(isCaTask); | ||||||
|  |  | ||||||
|  |             Task<bool> isMrbTask = mrbService.NumberIsValid(issueId); | ||||||
|  |             tasks.Add(isMrbTask); | ||||||
|  |  | ||||||
|  |             Task<bool> isPcrbTask = pcrbService.IdIsValid(issueId); | ||||||
|  |             tasks.Add(isPcrbTask); | ||||||
|  |  | ||||||
|  |             await Task.WhenAll(tasks); | ||||||
|  |  | ||||||
|  |             if (isEcnTask.Result) { | ||||||
|  |                 isEcn = true; | ||||||
|  |             } else if (isCaTask.Result) { | ||||||
|  |                 isCa = true; | ||||||
|  |             } else if (isMrbTask.Result) { | ||||||
|  |                 isMrb = true; | ||||||
|  |             } else if (isPcrbTask.Result) { | ||||||
|  |                 isPcrb = true; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (isEcn) await GoToExternal($"{Configuration["OldFabApprovalUrl"]}/ECN/Edit?IssueID={issueId}", ""); | ||||||
|  |         if (isCa) await GoToExternal($"{Configuration["OldFabApprovalUrl"]}/CorrectiveAction/Edit?IssueID={issueId}", ""); | ||||||
|  |         if (isMrb) GoTo($"mrb/{issueId}"); | ||||||
|  |         if (isPcrb) GoTo($"pcrb/{issueId}"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void GoTo(string page) { | ||||||
|  |         cache.Set("redirectUrl", page); | ||||||
|  |         navigationManager.NavigateTo("/" + page); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task GoToExternal(string url, string content) { | ||||||
|  |         IJSObjectReference windowModule = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "./js/OpenInNewWindow.js"); | ||||||
|  |         await windowModule.InvokeAsync<object>("OpenInNewWindow", url, content); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private bool FilterFuncForMRBTable(MRB mrb) => MRBFilterFunc(mrb, mrbSearchString); | ||||||
|  |  | ||||||
|  |     private bool MRBFilterFunc(MRB mrb, string searchString) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(searchString)) | ||||||
|  |             return true; | ||||||
|  |         if (mrb.Title.ToLower().Contains(searchString.Trim().ToLower())) | ||||||
|  |             return true; | ||||||
|  |         if (mrb.MRBNumber.ToString().Contains(searchString.Trim())) | ||||||
|  |             return true; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private bool FilterFuncForPCRBTable(PCRB pcrb) => PCRBFilterFunc(pcrb, pcrbSearchString); | ||||||
|  |  | ||||||
|  |     private bool PCRBFilterFunc(PCRB pcrb, string searchString) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(searchString)) | ||||||
|  |             return true; | ||||||
|  |         if (pcrb.Title.ToLower().Contains(searchString.Trim().ToLower())) | ||||||
|  |             return true; | ||||||
|  |         if (pcrb.PlanNumber.ToString().Contains(searchString.Trim())) | ||||||
|  |             return true; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private string GetCurrentPCRBStep(int step) { | ||||||
|  |         if (step < 0 || step > (PCRB.Stages.Length - 1)) return string.Empty; | ||||||
|  |         else return PCRB.Stages[step]; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										113
									
								
								MesaFabApproval.Client/Pages/Login.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								MesaFabApproval.Client/Pages/Login.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,113 @@ | |||||||
|  | @page "/login" | ||||||
|  | @page "/login/{redirectUrl}" | ||||||
|  | @page "/login/{redirectUrl}/{redirectUrlSub}" | ||||||
|  | @attribute [AllowAnonymous] | ||||||
|  | @inject MesaFabApprovalAuthStateProvider authStateProvider | ||||||
|  | @inject NavigationManager navManager | ||||||
|  | @inject ISnackbar snackbar | ||||||
|  |  | ||||||
|  | <MudPaper Class="p-2 m-2"> | ||||||
|  |     <MudText Typo="Typo.h3" Align="Align.Center">Login</MudText> | ||||||
|  | </MudPaper> | ||||||
|  |  | ||||||
|  | <MudPaper Class="p-2 m-2"> | ||||||
|  |     <MudForm @bind-IsValid="@success" @bind-Errors="@errors"> | ||||||
|  |         <MudTextField T="string" | ||||||
|  |                       Label="Windows Username" | ||||||
|  |                       Required="true" | ||||||
|  |                       RequiredError="Username is required!" | ||||||
|  |                       Variant="Variant.Outlined" | ||||||
|  |                       @bind-Value=username  | ||||||
|  |                       Class="m-1" | ||||||
|  |                       Immediate="true" | ||||||
|  |                       AutoFocus | ||||||
|  |                       OnKeyDown=SubmitIfEnter /> | ||||||
|  |         <MudTextField T="string" | ||||||
|  |                       Label="Windows Password" | ||||||
|  |                       Required="true" | ||||||
|  |                       RequiredError="Password is required!" | ||||||
|  |                       Variant="Variant.Outlined" | ||||||
|  |                       @bind-Value=password | ||||||
|  |                       InputType="InputType.Password" | ||||||
|  |                       Class="m-1" | ||||||
|  |                       Immediate="true"  | ||||||
|  |                       OnKeyDown=SubmitIfEnter /> | ||||||
|  |         <MudButton  | ||||||
|  |             Variant="Variant.Filled" | ||||||
|  |             Color="Color.Tertiary" | ||||||
|  |             Disabled="@(!success)" | ||||||
|  |             Class="m-1" | ||||||
|  |             OnClick=SubmitLogin > | ||||||
|  |             @if (processing) { | ||||||
|  |                 <MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" /> | ||||||
|  |                 <MudText>Processing</MudText> | ||||||
|  |             } else { | ||||||
|  |                 <MudText>Log In</MudText> | ||||||
|  |             } | ||||||
|  |         </MudButton> | ||||||
|  |         <MudDivider /> | ||||||
|  |         @* <MudButton | ||||||
|  |             Variant="Variant.Filled" | ||||||
|  |             Color="Color.Tertiary" | ||||||
|  |             Class="m-1" | ||||||
|  |             OnClick="LoginLocal" > | ||||||
|  |         @if (processingLocal) { | ||||||
|  |             <MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" /> | ||||||
|  |             <MudText>Processing</MudText> | ||||||
|  |         } else { | ||||||
|  |             <MudText>Log In (SSO)</MudText> | ||||||
|  |         } | ||||||
|  |         </MudButton> *@ | ||||||
|  |     </MudForm> | ||||||
|  | </MudPaper> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     [Parameter] | ||||||
|  |     public string? redirectUrl { get; set; } | ||||||
|  |     [Parameter] | ||||||
|  |     public string? redirectUrlSub { get; set; } | ||||||
|  |     private bool success; | ||||||
|  |     private bool processing = false; | ||||||
|  |     private bool processingLocal = false; | ||||||
|  |     private string[] errors = { }; | ||||||
|  |     private string? username; | ||||||
|  |     private string? password; | ||||||
|  |  | ||||||
|  |     private async Task SubmitLogin() { | ||||||
|  |         processing = true; | ||||||
|  |         if (string.IsNullOrWhiteSpace(username)) snackbar.Add("Username is required!", Severity.Error); | ||||||
|  |         else if (string.IsNullOrWhiteSpace(password)) snackbar.Add("Password is required!", Severity.Error); | ||||||
|  |         else { | ||||||
|  |             await authStateProvider.LoginAsync(username, password); | ||||||
|  |             if (!string.IsNullOrWhiteSpace(redirectUrl) && !string.IsNullOrWhiteSpace(redirectUrlSub)) { | ||||||
|  |                 navManager.NavigateTo($"{redirectUrl}/{redirectUrlSub}"); | ||||||
|  |             } else if (!string.IsNullOrWhiteSpace(redirectUrl)) { | ||||||
|  |                 navManager.NavigateTo(redirectUrl); | ||||||
|  |             } else { | ||||||
|  |                 navManager.NavigateTo("dashboard"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         processing = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task SubmitIfEnter(KeyboardEventArgs e) { | ||||||
|  |         if (e.Key == "Enter" && success) { | ||||||
|  |             SubmitLogin(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private async Task LoginLocal() { | ||||||
|  |         processingLocal = true; | ||||||
|  |  | ||||||
|  |         await authStateProvider.LoginLocal(); | ||||||
|  |         if (!string.IsNullOrWhiteSpace(redirectUrl) && !string.IsNullOrWhiteSpace(redirectUrlSub)) { | ||||||
|  |             navManager.NavigateTo($"{redirectUrl}/{redirectUrlSub}"); | ||||||
|  |         } else if (!string.IsNullOrWhiteSpace(redirectUrl)) { | ||||||
|  |             navManager.NavigateTo(redirectUrl); | ||||||
|  |         } else { | ||||||
|  |             navManager.NavigateTo("dashboard"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         processingLocal = false; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										119
									
								
								MesaFabApproval.Client/Pages/MRBAll.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								MesaFabApproval.Client/Pages/MRBAll.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,119 @@ | |||||||
|  | @page "/mrb/all" | ||||||
|  | @using System.Globalization | ||||||
|  | @inject IMRBService mrbService | ||||||
|  | @inject ISnackbar snackbar | ||||||
|  | @inject IMemoryCache cache | ||||||
|  | @inject NavigationManager navigationManager | ||||||
|  |  | ||||||
|  | <PageTitle>MRB</PageTitle> | ||||||
|  |  | ||||||
|  | <MudPaper Class="p-2 m-2"> | ||||||
|  |     <MudText Typo="Typo.h3" Align="Align.Center">MRB List</MudText> | ||||||
|  | </MudPaper> | ||||||
|  |  | ||||||
|  | @if (allMrbs is not null && allMrbs.Count() > 0) { | ||||||
|  |     <MudTable Items="@allMrbs" | ||||||
|  |               Class="m-2" | ||||||
|  |               Striped="true" | ||||||
|  |               Filter="new Func<MRB,bool>(FilterFuncForTable)" | ||||||
|  |               SortLabel="Sort By" | ||||||
|  |               Hover="true"> | ||||||
|  |         <ToolBarContent> | ||||||
|  |             <MudSpacer /> | ||||||
|  |             <MudTextField @bind-Value="searchString" | ||||||
|  |                           Placeholder="Search" | ||||||
|  |                           Adornment="Adornment.Start" | ||||||
|  |                           AdornmentIcon="@Icons.Material.Filled.Search" | ||||||
|  |                           IconSize="Size.Medium" | ||||||
|  |                           Class="mt-0" /> | ||||||
|  |         </ToolBarContent> | ||||||
|  |         <HeaderContent> | ||||||
|  |             <MudTh> | ||||||
|  |                 <MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<MRB,object>(x=>x.MRBNumber)"> | ||||||
|  |                     MRB# | ||||||
|  |                 </MudTableSortLabel> | ||||||
|  |             </MudTh> | ||||||
|  |             <MudTh> | ||||||
|  |                 <MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.Title)"> | ||||||
|  |                     Title | ||||||
|  |                 </MudTableSortLabel> | ||||||
|  |             </MudTh> | ||||||
|  |             <MudTh> | ||||||
|  |                 <MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.OriginatorName)"> | ||||||
|  |                     Originator | ||||||
|  |                 </MudTableSortLabel> | ||||||
|  |             </MudTh> | ||||||
|  |             <MudTh> | ||||||
|  |                 <MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.SubmittedDate)"> | ||||||
|  |                     Submitted Date | ||||||
|  |                 </MudTableSortLabel> | ||||||
|  |             </MudTh> | ||||||
|  |             <MudTh> | ||||||
|  |                 <MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.ApprovalDate)"> | ||||||
|  |                     Approval Date | ||||||
|  |                 </MudTableSortLabel> | ||||||
|  |             </MudTh> | ||||||
|  |             <MudTh> | ||||||
|  |                 <MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.CloseDate)"> | ||||||
|  |                     Closed Date | ||||||
|  |                 </MudTableSortLabel> | ||||||
|  |             </MudTh> | ||||||
|  |         </HeaderContent> | ||||||
|  |         <RowTemplate> | ||||||
|  |             <MudTd DataLabel="MRB#"> | ||||||
|  |                 <MudLink OnClick="@(() => GoTo($"mrb/{context.MRBNumber}"))">@context.MRBNumber</MudLink> | ||||||
|  |             </MudTd> | ||||||
|  |             <MudTd DataLabel="Title">@context.Title</MudTd> | ||||||
|  |             <MudTd DataLabel="Originator">@context.OriginatorName</MudTd> | ||||||
|  |             <MudTd DataLabel="Submitted Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.SubmittedDate)</MudTd> | ||||||
|  |             <MudTd DataLabel="Approval Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.ApprovalDate)</MudTd> | ||||||
|  |             <MudTd DataLabel="Closed Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.CloseDate)</MudTd> | ||||||
|  |         </RowTemplate> | ||||||
|  |         <PagerContent> | ||||||
|  |             <MudTablePager /> | ||||||
|  |         </PagerContent> | ||||||
|  |     </MudTable> | ||||||
|  | } | ||||||
|  |  | ||||||
|  | <MudOverlay @bind-Visible=inProcess DarkBackground="true" AutoClose="false"> | ||||||
|  |     <MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" /> | ||||||
|  | </MudOverlay> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     private bool inProcess = false; | ||||||
|  |     private string searchString = ""; | ||||||
|  |     private IEnumerable<MRB> allMrbs = new List<MRB>(); | ||||||
|  |  | ||||||
|  |     protected override async Task OnParametersSetAsync() { | ||||||
|  |         inProcess = true; | ||||||
|  |         try { | ||||||
|  |             if (mrbService is null) { | ||||||
|  |                 throw new Exception("MRB service not injected!"); | ||||||
|  |             } else { | ||||||
|  |                 allMrbs = await mrbService.GetAllMRBs(false); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             snackbar.Add(ex.Message, Severity.Error); | ||||||
|  |         } | ||||||
|  |         inProcess = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private bool FilterFuncForTable(MRB mrb) => FilterFunc(mrb, searchString); | ||||||
|  |  | ||||||
|  |     private bool FilterFunc(MRB mrb, string searchString) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(searchString)) | ||||||
|  |             return true; | ||||||
|  |         if (mrb.Title.ToLower().Contains(searchString.Trim().ToLower())) | ||||||
|  |             return true; | ||||||
|  |         if (mrb.OriginatorName.ToLower().Contains(searchString.Trim().ToLower())) | ||||||
|  |             return true; | ||||||
|  |         if (mrb.MRBNumber.ToString().Contains(searchString.Trim())) | ||||||
|  |             return true; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void GoTo(string page) { | ||||||
|  |         cache.Set("redirectUrl", page); | ||||||
|  |         navigationManager.NavigateTo(page); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										1736
									
								
								MesaFabApproval.Client/Pages/MRBSingle.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1736
									
								
								MesaFabApproval.Client/Pages/MRBSingle.razor
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										126
									
								
								MesaFabApproval.Client/Pages/PCRBAll.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								MesaFabApproval.Client/Pages/PCRBAll.razor
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,126 @@ | |||||||
|  | @page "/pcrb/all" | ||||||
|  | @using System.Globalization | ||||||
|  | @inject IPCRBService pcrbService | ||||||
|  | @inject ISnackbar snackbar | ||||||
|  | @inject IMemoryCache cache | ||||||
|  | @inject NavigationManager navigationManager | ||||||
|  |  | ||||||
|  | <PageTitle>PCRB</PageTitle> | ||||||
|  |  | ||||||
|  | <MudPaper Class="p-2 m-2"> | ||||||
|  |     <MudText Typo="Typo.h3" Align="Align.Center">PCRB List</MudText> | ||||||
|  | </MudPaper> | ||||||
|  |  | ||||||
|  | @if (allPCRBs is not null && allPCRBs.Count() > 0) { | ||||||
|  |     <MudTable Items="@allPCRBs" | ||||||
|  |               Class="m-2" | ||||||
|  |               Striped="true" | ||||||
|  |               Filter="new Func<PCRB,bool>(FilterFuncForTable)" | ||||||
|  |               SortLabel="Sort By" | ||||||
|  |               Hover="true"> | ||||||
|  |         <ToolBarContent> | ||||||
|  |             <MudSpacer /> | ||||||
|  |             <MudTextField @bind-Value="searchString" | ||||||
|  |                           Placeholder="Search" | ||||||
|  |                           Adornment="Adornment.Start" | ||||||
|  |                           AdornmentIcon="@Icons.Material.Filled.Search" | ||||||
|  |                           IconSize="Size.Medium" | ||||||
|  |                           Class="mt-0" /> | ||||||
|  |         </ToolBarContent> | ||||||
|  |         <HeaderContent> | ||||||
|  |             <MudTh> | ||||||
|  |                 <MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<PCRB,object>(x=>x.PlanNumber)"> | ||||||
|  |                     Change# | ||||||
|  |                 </MudTableSortLabel> | ||||||
|  |             </MudTh> | ||||||
|  |             <MudTh> | ||||||
|  |                 <MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.Title)"> | ||||||
|  |                     Title | ||||||
|  |                 </MudTableSortLabel> | ||||||
|  |             </MudTh> | ||||||
|  |             <MudTh> | ||||||
|  |                 <MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.OwnerName)"> | ||||||
|  |                     Owner | ||||||
|  |                 </MudTableSortLabel> | ||||||
|  |             </MudTh> | ||||||
|  |             <MudTh>Stage</MudTh> | ||||||
|  |             <MudTh> | ||||||
|  |                 <MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.InsertTimeStamp)"> | ||||||
|  |                     Submitted Date | ||||||
|  |                 </MudTableSortLabel> | ||||||
|  |             </MudTh> | ||||||
|  |             <MudTh> | ||||||
|  |                 <MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.LastUpdateDate)"> | ||||||
|  |                     Last Updated | ||||||
|  |                 </MudTableSortLabel> | ||||||
|  |             </MudTh> | ||||||
|  |             <MudTh> | ||||||
|  |                 <MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.ClosedDate)"> | ||||||
|  |                     Closed Date | ||||||
|  |                 </MudTableSortLabel> | ||||||
|  |             </MudTh> | ||||||
|  |         </HeaderContent> | ||||||
|  |         <RowTemplate> | ||||||
|  |             <MudTd DataLabel="Plan#"> | ||||||
|  |                 <MudLink OnClick="@(() => GoTo($"pcrb/{context.PlanNumber.ToString()}"))">@context.PlanNumber</MudLink> | ||||||
|  |             </MudTd> | ||||||
|  |             <MudTd DataLabel="Title">@context.Title</MudTd> | ||||||
|  |             <MudTd DataLabel="Owner">@context.OwnerName</MudTd> | ||||||
|  |             <MudTd DataLabel="Stage">@(GetStageName(context.CurrentStep))</MudTd> | ||||||
|  |             <MudTd DataLabel="Submitted Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.InsertTimeStamp)</MudTd> | ||||||
|  |             <MudTd DataLabel="Last Updated">@DateTimeUtilities.GetDateAsStringMinDefault(context.LastUpdateDate)</MudTd> | ||||||
|  |             <MudTd DataLabel="Closed Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.ClosedDate)</MudTd> | ||||||
|  |         </RowTemplate> | ||||||
|  |         <PagerContent> | ||||||
|  |             <MudTablePager /> | ||||||
|  |         </PagerContent> | ||||||
|  |     </MudTable> | ||||||
|  | } | ||||||
|  |  | ||||||
|  | <MudOverlay @bind-Visible=inProcess DarkBackground="true" AutoClose="false"> | ||||||
|  |     <MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" /> | ||||||
|  | </MudOverlay> | ||||||
|  |  | ||||||
|  | @code { | ||||||
|  |     private bool inProcess = false; | ||||||
|  |     private string searchString = ""; | ||||||
|  |     private IEnumerable<PCRB> allPCRBs = new List<PCRB>(); | ||||||
|  |  | ||||||
|  |     protected override async Task OnParametersSetAsync() { | ||||||
|  |         inProcess = true; | ||||||
|  |         try { | ||||||
|  |             if (pcrbService is null) { | ||||||
|  |                 throw new Exception("PCRB service not injected!"); | ||||||
|  |             } else { | ||||||
|  |                 allPCRBs = await pcrbService.GetAllPCRBs(false); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             snackbar.Add(ex.Message, Severity.Error); | ||||||
|  |         } | ||||||
|  |         inProcess = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private bool FilterFuncForTable(PCRB pcrb) => FilterFunc(pcrb, searchString); | ||||||
|  |  | ||||||
|  |     private bool FilterFunc(PCRB pcrb, string searchString) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(searchString)) | ||||||
|  |             return true; | ||||||
|  |         if (pcrb.Title.ToLower().Contains(searchString.Trim().ToLower())) | ||||||
|  |             return true; | ||||||
|  |         if (pcrb.OwnerName.ToLower().Contains(searchString.Trim().ToLower())) | ||||||
|  |             return true; | ||||||
|  |         if (pcrb.PlanNumber.ToString().Contains(searchString.Trim())) | ||||||
|  |             return true; | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void GoTo(string page) { | ||||||
|  |         cache.Set("redirectUrl", page); | ||||||
|  |         navigationManager.NavigateTo(page); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private string GetStageName(int step) { | ||||||
|  |         if (step >= PCRB.Stages.Length || step < 0) return ""; | ||||||
|  |         return PCRB.Stages[step]; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										1771
									
								
								MesaFabApproval.Client/Pages/PCRBSingle.razor
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1771
									
								
								MesaFabApproval.Client/Pages/PCRBSingle.razor
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										73
									
								
								MesaFabApproval.Client/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								MesaFabApproval.Client/Program.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,73 @@ | |||||||
|  | using MesaFabApproval.Client; | ||||||
|  | using MesaFabApproval.Client.Utilities; | ||||||
|  |  | ||||||
|  | using Microsoft.AspNetCore.Components.Web; | ||||||
|  | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; | ||||||
|  |  | ||||||
|  | using MudBlazor.Services; | ||||||
|  | using MesaFabApproval.Client.Services; | ||||||
|  | using Microsoft.AspNetCore.Components.Authorization; | ||||||
|  | using System.Net.Http.Headers; | ||||||
|  | using MudBlazor; | ||||||
|  |  | ||||||
|  | WebAssemblyHostBuilder builder = WebAssemblyHostBuilder.CreateDefault(args); | ||||||
|  |  | ||||||
|  | string _apiBaseUrl = builder.Configuration["FabApprovalApiBaseUrl"] ?? | ||||||
|  |     throw new NullReferenceException("FabApprovalApiBaseUrl not found in config"); | ||||||
|  |  | ||||||
|  | string _oldSiteUrl = builder.Configuration["OldFabApprovalUrl"] ?? | ||||||
|  |     throw new NullReferenceException("OldFabApprovalUrl not found in config"); | ||||||
|  |  | ||||||
|  | builder.Services.AddTransient<ApiHttpClientHandler>(); | ||||||
|  |  | ||||||
|  | builder.Services | ||||||
|  |     .AddHttpClient("API_Handler", client => { | ||||||
|  |         client.BaseAddress = new Uri(_apiBaseUrl); | ||||||
|  |         client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*")); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | builder.Services | ||||||
|  |     .AddHttpClient("API", client => { | ||||||
|  |         client.BaseAddress = new Uri(_apiBaseUrl); | ||||||
|  |         client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*")); | ||||||
|  |     }) | ||||||
|  |     .AddHttpMessageHandler<ApiHttpClientHandler>(); | ||||||
|  |  | ||||||
|  | builder.Services | ||||||
|  |     .AddHttpClient("OldSite", client => { | ||||||
|  |         client.BaseAddress = new Uri(_oldSiteUrl); | ||||||
|  |         client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*")); | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  | builder.Services.AddMemoryCache(); | ||||||
|  |  | ||||||
|  | builder.Services.AddMudServices(config => { | ||||||
|  |     config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomCenter; | ||||||
|  |     config.SnackbarConfiguration.PreventDuplicates = true; | ||||||
|  |     config.SnackbarConfiguration.MaxDisplayedSnackbars = 5; | ||||||
|  |     config.SnackbarConfiguration.SnackbarVariant = Variant.Filled; | ||||||
|  |     config.SnackbarConfiguration.ShowCloseIcon = true; | ||||||
|  |     config.SnackbarConfiguration.VisibleStateDuration = 7000; | ||||||
|  |     config.SnackbarConfiguration.HideTransitionDuration = 500; | ||||||
|  |     config.SnackbarConfiguration.ShowTransitionDuration = 500; | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | builder.Services.AddScoped<ILocalStorageService, LocalStorageService>(); | ||||||
|  | builder.Services.AddScoped<IAuthenticationService, AuthenticationService>(); | ||||||
|  | builder.Services.AddScoped<ICustomerService, CustomerService>(); | ||||||
|  | builder.Services.AddScoped<IUserService, UserService>(); | ||||||
|  | builder.Services.AddScoped<IECNService, ECNService>(); | ||||||
|  | builder.Services.AddScoped<ICAService, CAService>(); | ||||||
|  | builder.Services.AddScoped<IPCRBService, PCRBService>(); | ||||||
|  | builder.Services.AddScoped<IMRBService, MRBService>(); | ||||||
|  | builder.Services.AddScoped<IApprovalService, ApprovalService>(); | ||||||
|  | builder.Services.AddScoped<MesaFabApprovalAuthStateProvider>(); | ||||||
|  | builder.Services.AddScoped<AuthenticationStateProvider>(sp => | ||||||
|  |     sp.GetRequiredService<MesaFabApprovalAuthStateProvider>()); | ||||||
|  |  | ||||||
|  | builder.Services.AddAuthorizationCore(); | ||||||
|  |  | ||||||
|  | builder.RootComponents.Add<App>("#app"); | ||||||
|  | builder.RootComponents.Add<HeadOutlet>("head::after"); | ||||||
|  |  | ||||||
|  | await builder.Build().RunAsync(); | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <!-- | ||||||
|  | https://go.microsoft.com/fwlink/?LinkID=208121. | ||||||
|  | --> | ||||||
|  | <Project> | ||||||
|  |   <PropertyGroup> | ||||||
|  |     <DeleteExistingFiles>true</DeleteExistingFiles> | ||||||
|  |     <ExcludeApp_Data>false</ExcludeApp_Data> | ||||||
|  |     <LaunchSiteAfterPublish>true</LaunchSiteAfterPublish> | ||||||
|  |     <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration> | ||||||
|  |     <LastUsedPlatform>Any CPU</LastUsedPlatform> | ||||||
|  |     <PublishProvider>FileSystem</PublishProvider> | ||||||
|  |     <PublishUrl>bin\Release\net8.0\browser-wasm\publish\</PublishUrl> | ||||||
|  |     <WebPublishMethod>FileSystem</WebPublishMethod> | ||||||
|  |     <_TargetId>Folder</_TargetId> | ||||||
|  |     <SiteUrlToLaunchAfterPublish /> | ||||||
|  |     <TargetFramework>net8.0</TargetFramework> | ||||||
|  |     <RuntimeIdentifier>browser-wasm</RuntimeIdentifier> | ||||||
|  |     <ProjectGuid>34d52f44-a81f-4247-8180-16e204824a07</ProjectGuid> | ||||||
|  |     <SelfContained>true</SelfContained> | ||||||
|  |   </PropertyGroup> | ||||||
|  | </Project> | ||||||
							
								
								
									
										300
									
								
								MesaFabApproval.Client/Services/ApprovalService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								MesaFabApproval.Client/Services/ApprovalService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,300 @@ | |||||||
|  | using System.Text; | ||||||
|  | using System.Text.Json; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  |  | ||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.Client.Services; | ||||||
|  |  | ||||||
|  | public interface IApprovalService { | ||||||
|  |     Task<int> GetRoleIdForRoleName(string roleName); | ||||||
|  |     Task<IEnumerable<SubRole>> GetSubRolesForSubRoleName(string subRoleName, int roleId); | ||||||
|  |     Task<IEnumerable<User>> GetApprovalGroupMembers(int subRoleId); | ||||||
|  |     Task CreateApproval(Approval approval); | ||||||
|  |     Task UpdateApproval(Approval approval); | ||||||
|  |     Task Approve(Approval approval); | ||||||
|  |     Task Deny(Approval approval); | ||||||
|  |     Task<IEnumerable<Approval>> GetApprovalsForIssueId(int issueId, bool bypassCache); | ||||||
|  |     Task<IEnumerable<Approval>> GetApprovalsForUserId(int userId, bool bypassCache); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class ApprovalService : IApprovalService { | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly IHttpClientFactory _httpClientFactory; | ||||||
|  |  | ||||||
|  |     public ApprovalService(IMemoryCache cache, IHttpClientFactory httpClientFactory) { | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _httpClientFactory = httpClientFactory ?? | ||||||
|  |             throw new ArgumentNullException("IHttpClientFactory not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task CreateApproval(Approval approval) { | ||||||
|  |         if (approval is null) throw new ArgumentNullException("approval cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, "approval"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(approval), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) { | ||||||
|  |             throw new Exception($"Unable to create approval, because {responseMessage.ReasonPhrase}"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         await GetApprovalsForIssueId(approval.IssueID, true); | ||||||
|  |         await GetApprovalsForUserId(approval.UserID, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<Approval>> GetApprovalsForIssueId(int issueId, bool bypassCache) { | ||||||
|  |         if (issueId <= 0) throw new ArgumentException($"{issueId} is not a valid issue ID"); | ||||||
|  |          | ||||||
|  |         IEnumerable<Approval>? approvals = null; | ||||||
|  |  | ||||||
|  |         if (!bypassCache) | ||||||
|  |             approvals = _cache.Get<IEnumerable<Approval>>($"approvals{issueId}"); | ||||||
|  |  | ||||||
|  |         if (approvals is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/issue?issueId={issueId}&bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 approvals = JsonSerializer.Deserialize<IEnumerable<Approval>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     throw new Exception("Unable to parse approvals from API response"); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"approvals{issueId}", approvals, DateTimeOffset.Now.AddMinutes(15)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"Unable to get approvals, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         foreach (Approval approval in approvals) { | ||||||
|  |             if (approval.ItemStatus < 0) | ||||||
|  |                 approval.StatusMessage = "Denied"; | ||||||
|  |             if (approval.ItemStatus == 0) | ||||||
|  |                 approval.StatusMessage = "Assigned"; | ||||||
|  |             if (approval.ItemStatus > 0) | ||||||
|  |                 approval.StatusMessage = "Approved"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return approvals; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<Approval>> GetApprovalsForUserId(int userId, bool bypassCache) { | ||||||
|  |         if (userId <= 0) throw new ArgumentException($"{userId} is not a valid user ID"); | ||||||
|  |  | ||||||
|  |         IEnumerable<Approval>? approvals = null; | ||||||
|  |  | ||||||
|  |         if (!bypassCache) approvals = _cache.Get<IEnumerable<Approval>>($"approvals{userId}"); | ||||||
|  |  | ||||||
|  |         if (approvals is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/user?userId={userId}&bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 approvals = JsonSerializer.Deserialize<IEnumerable<Approval>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     throw new Exception("Unable to parse approvals from API response"); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"approvals{userId}", approvals, DateTimeOffset.Now.AddMinutes(15)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"Unable to get approvals, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         foreach (Approval approval in approvals) { | ||||||
|  |             if (approval.ItemStatus < 0) | ||||||
|  |                 approval.StatusMessage = "Denied"; | ||||||
|  |             if (approval.ItemStatus == 0) | ||||||
|  |                 approval.StatusMessage = "Assigned"; | ||||||
|  |             if (approval.ItemStatus > 0) | ||||||
|  |                 approval.StatusMessage = "Approved"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return approvals; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdateApproval(Approval approval) { | ||||||
|  |         if (approval is null) throw new ArgumentNullException("approval cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Put, "approval"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(approval), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) { | ||||||
|  |             throw new Exception($"Unable to update approval, because {responseMessage.ReasonPhrase}"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         await GetApprovalsForIssueId(approval.IssueID, true); | ||||||
|  |         await GetApprovalsForUserId(approval.UserID, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task Approve(Approval approval) { | ||||||
|  |         if (approval is null) throw new ArgumentNullException("approval cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Put, "approval/approve"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(approval), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) { | ||||||
|  |             throw new Exception($"Approval failed, because {responseMessage.ReasonPhrase}"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         await GetApprovalsForIssueId(approval.IssueID, true); | ||||||
|  |         await GetApprovalsForUserId(approval.UserID, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task Deny(Approval approval) { | ||||||
|  |         if (approval is null) throw new ArgumentNullException("approval cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Put, "approval/deny"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(approval), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) { | ||||||
|  |             throw new Exception($"Denial failed, because {responseMessage.ReasonPhrase}"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<int> GetRoleIdForRoleName(string roleName) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(roleName)) throw new ArgumentException("role name cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         int roleId = _cache.Get<int>($"roleId{roleName}"); | ||||||
|  |  | ||||||
|  |         if (roleId <= 0) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/roleId?roleName={roleName}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 roleId = JsonSerializer.Deserialize<int>(responseContent, jsonSerializerOptions); | ||||||
|  |  | ||||||
|  |                 if (roleId <= 0) | ||||||
|  |                     throw new Exception($"unable to find role ID for {roleName}"); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"roleId{roleName}", roleId, DateTimeOffset.Now.AddMinutes(15)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"Unable to get role ID, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return roleId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<SubRole>> GetSubRolesForSubRoleName(string subRoleName, int roleId) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(subRoleName)) throw new ArgumentException("role name cannot be null or empty"); | ||||||
|  |         if (roleId <= 0) throw new ArgumentException($"{roleId} is not a valid role ID"); | ||||||
|  |  | ||||||
|  |         IEnumerable<SubRole>? subRoles = _cache.Get<IEnumerable<SubRole>>($"subRoles{subRoleName}"); | ||||||
|  |  | ||||||
|  |         if (subRoles is null || subRoles.Count() <= 0) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/subRoles?subRoleName={subRoleName}&roleId={roleId}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 subRoles = JsonSerializer.Deserialize<IEnumerable<SubRole>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     throw new Exception("Unable to parse sub roles from API response"); | ||||||
|  |  | ||||||
|  |                 if (subRoles is not null && subRoles.Count() > 0) { | ||||||
|  |                     _cache.Set($"subRoles{subRoleName}", subRoles, DateTimeOffset.Now.AddMinutes(15)); | ||||||
|  |                 } else { | ||||||
|  |                     throw new Exception($"unable to find sub roles for {subRoleName}"); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"Unable to get sub roles, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return subRoles; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<User>> GetApprovalGroupMembers(int subRoleId) { | ||||||
|  |         if (subRoleId <= 0) throw new ArgumentException($"{subRoleId} is not a valid sub role ID"); | ||||||
|  |  | ||||||
|  |         IEnumerable<User>? members = _cache.Get<IEnumerable<User>>($"approvalMembers{subRoleId}"); | ||||||
|  |  | ||||||
|  |         if (members is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/members?subRoleId={subRoleId}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 members = JsonSerializer.Deserialize<IEnumerable<User>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     throw new Exception("Unable to parse users from API response"); | ||||||
|  |  | ||||||
|  |                 if (members is null || members.Count() <= 0) | ||||||
|  |                     throw new Exception($"unable to find group members for sub role {subRoleId}"); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"approvalMembers{subRoleId}", members, DateTimeOffset.Now.AddMinutes(2)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"Unable to get group members, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return members; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										232
									
								
								MesaFabApproval.Client/Services/AuthenticationService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								MesaFabApproval.Client/Services/AuthenticationService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,232 @@ | |||||||
|  | using System.IdentityModel.Tokens.Jwt; | ||||||
|  | using System.Security.Claims; | ||||||
|  | using System.Security.Principal; | ||||||
|  | using System.Text; | ||||||
|  | using System.Text.Json; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  |  | ||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.Client.Services; | ||||||
|  |  | ||||||
|  | public interface IAuthenticationService { | ||||||
|  |     Task<ClaimsPrincipal> SendAuthenticationRequest(string loginId,  string password); | ||||||
|  |     Task<ClaimsPrincipal> AttemptLocalUserAuth(); | ||||||
|  |     Task<ClaimsPrincipal> FetchAuthState(); | ||||||
|  |     Task ClearTokens(); | ||||||
|  |     Task ClearCurrentUser(); | ||||||
|  |     Task SetTokens(string jwt, string refreshToken); | ||||||
|  |     Task SetLoginId(string loginId); | ||||||
|  |     Task SetCurrentUser(User user); | ||||||
|  |     Task<User> GetCurrentUser(); | ||||||
|  |     Task<AuthTokens> GetAuthTokens(); | ||||||
|  |     Task<string> GetLoginId(); | ||||||
|  |     ClaimsPrincipal GetClaimsPrincipalFromJwt(string jwt); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class AuthenticationService : IAuthenticationService { | ||||||
|  |     private readonly ILocalStorageService _localStorageService; | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly IHttpClientFactory _httpClientFactory; | ||||||
|  |  | ||||||
|  |     public AuthenticationService(ILocalStorageService localStorageService, | ||||||
|  |                                  IMemoryCache cache, | ||||||
|  |                                  IHttpClientFactory httpClientFactory) { | ||||||
|  |         _localStorageService = localStorageService ?? | ||||||
|  |             throw new ArgumentNullException("ILocalStorageService not injected"); | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException("IHttpClientFactory not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<ClaimsPrincipal> SendAuthenticationRequest(string loginId, string password) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(loginId)) throw new ArgumentException("loginId cannot be null or empty"); | ||||||
|  |         if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("password cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         AuthAttempt authAttempt = new() {  | ||||||
|  |             LoginID = loginId, | ||||||
|  |             Password = password | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "auth/login"); | ||||||
|  |  | ||||||
|  |         request.Content = new StringContent(JsonSerializer.Serialize(authAttempt), | ||||||
|  |                                             Encoding.UTF8, | ||||||
|  |                                             "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(request); | ||||||
|  |  | ||||||
|  |         if (httpResponseMessage.IsSuccessStatusCode) { | ||||||
|  |             string responseContent = await httpResponseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |             JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                 PropertyNameCaseInsensitive = true | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             LoginResult loginResult = JsonSerializer.Deserialize<LoginResult>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                 throw new Exception("Unable to parse login result from API response"); | ||||||
|  |  | ||||||
|  |             if (!loginResult.IsAuthenticated) throw new Exception($"User with Login ID {loginId} not authorized"); | ||||||
|  |  | ||||||
|  |             await SetLoginId(loginId); | ||||||
|  |  | ||||||
|  |             await SetTokens(loginResult.AuthTokens.JwtToken, loginResult.AuthTokens.RefreshToken); | ||||||
|  |  | ||||||
|  |             await SetCurrentUser(loginResult.User); | ||||||
|  |  | ||||||
|  |             ClaimsPrincipal principal = GetClaimsPrincipalFromJwt(loginResult.AuthTokens.JwtToken); | ||||||
|  |  | ||||||
|  |             return principal; | ||||||
|  |         } else { | ||||||
|  |             throw new Exception($"Login API request failed for {loginId}, because {httpResponseMessage.ReasonPhrase}"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<ClaimsPrincipal> AttemptLocalUserAuth() { | ||||||
|  |         WindowsIdentity? user = WindowsIdentity.GetCurrent(); | ||||||
|  |  | ||||||
|  |         if (user is null) | ||||||
|  |             throw new Exception("no authenticated user found"); | ||||||
|  |  | ||||||
|  |         if (!user.IsAuthenticated) | ||||||
|  |             throw new Exception("you are not authenticated"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "auth/login/localWindows"); | ||||||
|  |  | ||||||
|  |         request.Content = new StringContent(JsonSerializer.Serialize(user), | ||||||
|  |                                             Encoding.UTF8, | ||||||
|  |                                             "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(request); | ||||||
|  |  | ||||||
|  |         if (httpResponseMessage.IsSuccessStatusCode) { | ||||||
|  |             string responseContent = await httpResponseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |             JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                 PropertyNameCaseInsensitive = true | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             LoginResult loginResult = JsonSerializer.Deserialize<LoginResult>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                 throw new Exception("Unable to parse login result from API response"); | ||||||
|  |  | ||||||
|  |             if (!loginResult.IsAuthenticated) throw new Exception($"User with Login ID {user.Name} not authorized"); | ||||||
|  |  | ||||||
|  |             await SetLoginId(loginResult.User.LoginID); | ||||||
|  |  | ||||||
|  |             await SetTokens(loginResult.AuthTokens.JwtToken, loginResult.AuthTokens.RefreshToken); | ||||||
|  |  | ||||||
|  |             await SetCurrentUser(loginResult.User); | ||||||
|  |  | ||||||
|  |             ClaimsPrincipal principal = GetClaimsPrincipalFromJwt(loginResult.AuthTokens.JwtToken); | ||||||
|  |  | ||||||
|  |             return principal; | ||||||
|  |         } else { | ||||||
|  |             throw new Exception($"Login API request failed for {user.Name}, because {httpResponseMessage.ReasonPhrase}"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<ClaimsPrincipal> FetchAuthState() { | ||||||
|  |         string? jwt = _cache.Get<string>("MesaFabApprovalJwt"); | ||||||
|  |  | ||||||
|  |         if (jwt is null) jwt = await _localStorageService.GetItem("MesaFabApprovalJwt"); | ||||||
|  |  | ||||||
|  |         if (jwt is null) throw new Exception("Unable to find JWT"); | ||||||
|  |  | ||||||
|  |         ClaimsPrincipal principal = GetClaimsPrincipalFromJwt(jwt); | ||||||
|  |  | ||||||
|  |         return principal; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task ClearTokens() { | ||||||
|  |         _cache.Remove("MesaFabApprovalJwt"); | ||||||
|  |         await _localStorageService.RemoveItem("MesaFabApprovalJwt"); | ||||||
|  |         _cache.Remove("MesaFabApprovalRefreshToken"); | ||||||
|  |         await _localStorageService.RemoveItem("MesaFabApprovalRefreshToken"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task SetTokens(string jwt, string refreshToken) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(jwt)) throw new ArgumentNullException("JWT cannot be null or empty"); | ||||||
|  |         if (string.IsNullOrWhiteSpace(refreshToken)) throw new ArgumentNullException("Refresh token cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         _cache.Set<string>("MesaFabApprovalJwt", jwt); | ||||||
|  |         await _localStorageService.AddItem("MesaFabApprovalJwt", jwt); | ||||||
|  |         _cache.Set<string>("MesaFabApprovalRefreshToken", refreshToken); | ||||||
|  |         await _localStorageService.AddItem("MesaFabApprovalRefreshToken", refreshToken); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task SetLoginId(string loginId) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(loginId)) throw new ArgumentNullException("LoginId cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         _cache.Set<string>("MesaFabApprovalUserId", loginId); | ||||||
|  |         await _localStorageService.AddItem("MesaFabApprovalUserId", loginId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task SetCurrentUser(User? user) { | ||||||
|  |         _cache.Set<User>("MesaFabApprovalCurrentUser", user); | ||||||
|  |         await _localStorageService.AddItem<User>("MesaFabApprovalCurrentUser", user); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task ClearCurrentUser() { | ||||||
|  |         _cache.Remove("MesaFabApprovalCurrentUser"); | ||||||
|  |         await _localStorageService.RemoveItem("MesaFabApprovalCurrentUser"); | ||||||
|  |         _cache.Remove("MesaFabApprovalUserId"); | ||||||
|  |         await _localStorageService.RemoveItem("MesaFabApprovalUserId"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<User> GetCurrentUser() { | ||||||
|  |         User? currentUser = null; | ||||||
|  |  | ||||||
|  |         currentUser = _cache.Get<User>("MesaFabApprovalCurrentUser"); | ||||||
|  |  | ||||||
|  |         if (currentUser is null) | ||||||
|  |             currentUser = await _localStorageService.GetItem<User>("MesaFabApprovalCurrentUser"); | ||||||
|  |  | ||||||
|  |         return currentUser; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<AuthTokens> GetAuthTokens() { | ||||||
|  |         AuthTokens? authTokens = null; | ||||||
|  |  | ||||||
|  |         string? jwt = _cache.Get<string>("MesaFabApprovalJwt"); | ||||||
|  |         if (jwt is null) jwt = await _localStorageService.GetItem("MesaFabApprovalJwt"); | ||||||
|  |  | ||||||
|  |         string? refreshToken = _cache.Get<string>("MesaFabApprovalRefreshToken"); | ||||||
|  |         if (refreshToken is null) refreshToken = await _localStorageService.GetItem("MesaFabApprovalRefreshToken"); | ||||||
|  |  | ||||||
|  |         if (!string.IsNullOrWhiteSpace(jwt) && !string.IsNullOrWhiteSpace(refreshToken)) { | ||||||
|  |             authTokens = new() {  | ||||||
|  |                 JwtToken = jwt, | ||||||
|  |                 RefreshToken = refreshToken | ||||||
|  |             }; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return authTokens; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<string> GetLoginId() { | ||||||
|  |         string? loginId = _cache.Get<string>("MesaFabApprovalUserId"); | ||||||
|  |         if (loginId is null) loginId = await _localStorageService.GetItem("MesaFabApprovalUserId"); | ||||||
|  |  | ||||||
|  |         return loginId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public ClaimsPrincipal GetClaimsPrincipalFromJwt(string jwt) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(jwt)) throw new ArgumentException("JWT cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler(); | ||||||
|  |  | ||||||
|  |         if (!tokenHandler.CanReadToken(jwt)) { | ||||||
|  |             throw new Exception("Unable to parse JWT from API"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         JwtSecurityToken jwtSecurityToken = tokenHandler.ReadJwtToken(jwt); | ||||||
|  |          | ||||||
|  |         ClaimsIdentity identity = new ClaimsIdentity(jwtSecurityToken.Claims, "MesaFabApprovalWasm"); | ||||||
|  |  | ||||||
|  |         return new(identity); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										44
									
								
								MesaFabApproval.Client/Services/CAService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								MesaFabApproval.Client/Services/CAService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | using System.Text.Json; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.Client.Services; | ||||||
|  |  | ||||||
|  | public interface ICAService { | ||||||
|  |     Task<bool> CANumberIsValid(int number); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class CAService : ICAService { | ||||||
|  |     private readonly IHttpClientFactory _httpClientFactory; | ||||||
|  |  | ||||||
|  |     public CAService(IHttpClientFactory httpClientFactory) { | ||||||
|  |         _httpClientFactory = httpClientFactory ?? | ||||||
|  |             throw new ArgumentNullException("IHttpClientFactory not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<bool> CANumberIsValid(int number) { | ||||||
|  |         if (number <= 0) return false; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"ca/isValidCANumber?number={number}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 bool isValid = JsonSerializer.Deserialize<bool>(responseContent, jsonSerializerOptions); | ||||||
|  |  | ||||||
|  |                 return isValid; | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             throw new Exception($"Unable to determine if {number} is a valid CA#, because {ex.Message}"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										51
									
								
								MesaFabApproval.Client/Services/CustomerService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								MesaFabApproval.Client/Services/CustomerService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | using System.Text.Json; | ||||||
|  |  | ||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.Client.Services; | ||||||
|  |  | ||||||
|  | public interface ICustomerService { | ||||||
|  |     Task<IEnumerable<string>> GetAllCustomerNames(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class CustomerService : ICustomerService { | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly IHttpClientFactory _httpClientFactory; | ||||||
|  |  | ||||||
|  |     public CustomerService(IMemoryCache cache, IHttpClientFactory httpClientFactory) { | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _httpClientFactory = httpClientFactory ?? | ||||||
|  |             throw new ArgumentNullException("IHttpClientFactory not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<string>> GetAllCustomerNames() { | ||||||
|  |         IEnumerable<string>? allCustomerNames = null; | ||||||
|  |  | ||||||
|  |         allCustomerNames = _cache.Get<IEnumerable<string>>("allCustomerNames"); | ||||||
|  |  | ||||||
|  |         if (allCustomerNames is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"customer/all"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 allCustomerNames = JsonSerializer.Deserialize<IEnumerable<string>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     throw new Exception("Unable to parse names from API response"); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"allCustomerNames", allCustomerNames, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"Unable to get all customer names, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return allCustomerNames; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										52
									
								
								MesaFabApproval.Client/Services/ECNService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								MesaFabApproval.Client/Services/ECNService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | |||||||
|  | using System.Text.Json; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.Client.Services; | ||||||
|  |  | ||||||
|  | public interface IECNService { | ||||||
|  |     Task<string> ECNNumberIsValidStr(int ecnNumber); | ||||||
|  |     Task<bool> ECNNumberIsValid(int number); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class ECNService : IECNService { | ||||||
|  |     private readonly IHttpClientFactory _httpClientFactory; | ||||||
|  |  | ||||||
|  |     public ECNService(IHttpClientFactory httpClientFactory) { | ||||||
|  |         _httpClientFactory = httpClientFactory ?? | ||||||
|  |             throw new ArgumentNullException("IHttpClientFactory not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<string> ECNNumberIsValidStr(int ecnNumber) { | ||||||
|  |         if (ecnNumber <= 0 || !await ECNNumberIsValid(ecnNumber)) | ||||||
|  |             return $"{ecnNumber} is not a valid ECN#"; | ||||||
|  |  | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<bool> ECNNumberIsValid(int number) { | ||||||
|  |         if (number <= 0) return false; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"ecn/isValidEcnNumber?number={number}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 bool isValid = JsonSerializer.Deserialize<bool>(responseContent, jsonSerializerOptions); | ||||||
|  |  | ||||||
|  |                 return isValid; | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             throw new Exception($"Unable to determine if {number} is a valid ECN#, because {ex.Message}"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								MesaFabApproval.Client/Services/LocalStorageService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								MesaFabApproval.Client/Services/LocalStorageService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | using System.Text.Json; | ||||||
|  | using System.Text.Json.Serialization; | ||||||
|  |  | ||||||
|  | using Microsoft.JSInterop; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.Client.Services; | ||||||
|  |  | ||||||
|  | public interface ILocalStorageService { | ||||||
|  |     Task AddItem(string key, string value); | ||||||
|  |     Task AddItem<T>(string key, T value); | ||||||
|  |     Task RemoveItem(string key); | ||||||
|  |     Task<string> GetItem(string key); | ||||||
|  |     Task<T?> GetItem<T>(string key); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class LocalStorageService : ILocalStorageService { | ||||||
|  |     private readonly IJSRuntime _jsRuntime; | ||||||
|  |  | ||||||
|  |     public LocalStorageService(IJSRuntime jsRuntime) { | ||||||
|  |         _jsRuntime = jsRuntime; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task AddItem(string key, string value) { | ||||||
|  |         await _jsRuntime.InvokeVoidAsync("localStorage.setItem", key, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task AddItem<T>(string key, T value) { | ||||||
|  |         string item = JsonSerializer.Serialize(value); | ||||||
|  |         await _jsRuntime.InvokeVoidAsync("localStorage.setItem", key, item); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task RemoveItem(string key) { | ||||||
|  |         await _jsRuntime.InvokeVoidAsync("localStorage.removeItem", key); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<string> GetItem(string key) { | ||||||
|  |         return await _jsRuntime.InvokeAsync<string>("localStorage.getItem", key); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<T?> GetItem<T>(string key) { | ||||||
|  |         string item = await _jsRuntime.InvokeAsync<string>("localStorage.getItem", key); | ||||||
|  |  | ||||||
|  |         JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |             PropertyNameCaseInsensitive = true | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         return JsonSerializer.Deserialize<T>(item, jsonSerializerOptions); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										755
									
								
								MesaFabApproval.Client/Services/MRBService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										755
									
								
								MesaFabApproval.Client/Services/MRBService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,755 @@ | |||||||
|  | using System.Net.Http.Headers; | ||||||
|  | using System.Text; | ||||||
|  | using System.Text.Json; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  | using MesaFabApproval.Shared.Utilities; | ||||||
|  |  | ||||||
|  | using Microsoft.AspNetCore.Components.Forms; | ||||||
|  | using Microsoft.AspNetCore.StaticFiles; | ||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | using MudBlazor; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.Client.Services; | ||||||
|  |  | ||||||
|  | public interface IMRBService { | ||||||
|  |     Task<IEnumerable<MRB>> GetAllMRBs(bool bypassCache); | ||||||
|  |     Task<MRB> GetMRBById(int id, bool bypassCache = false); | ||||||
|  |     Task<MRB> GetMRBByTitle(string title, bool bypassCache); | ||||||
|  |     Task CreateNewMRB(MRB mrb); | ||||||
|  |     Task RecallMRB(MRB mrb, User recallUser); | ||||||
|  |     Task DeleteMRB(int mrbNumber); | ||||||
|  |     Task UpdateMRB(MRB mrb); | ||||||
|  |     Task SubmitForApproval(MRB mrb); | ||||||
|  |     Task GenerateActionTasks(MRB mrb, MRBAction action); | ||||||
|  |     Task CreateMRBAction(MRBAction mrbAction); | ||||||
|  |     Task<IEnumerable<MRBAction>> GetMRBActionsForMRB(int mrbNumber, bool bypassCache); | ||||||
|  |     Task UpdateMRBAction(MRBAction mrbAction); | ||||||
|  |     Task DeleteMRBAction(MRBAction mrbAction); | ||||||
|  |     Task UploadAttachments(IEnumerable<IBrowserFile> files, int mrbNumber); | ||||||
|  |     Task UploadActionAttachments(IEnumerable<IBrowserFile> files, int actionId); | ||||||
|  |     Task<IEnumerable<MRBAttachment>> GetAllAttachmentsForMRB(int mrbNumber, bool bypassCache); | ||||||
|  |     Task<IEnumerable<MRBActionAttachment>> GetAllActionAttachmentsForMRB(int mrbNumber, bool bypassCache); | ||||||
|  |     Task DeleteAttachment(MRBAttachment attachment); | ||||||
|  |     Task NotifyNewApprovals(MRB mrb); | ||||||
|  |     Task NotifyApprovers(MRBNotification notification); | ||||||
|  |     Task NotifyOriginator(MRBNotification notification); | ||||||
|  |     Task NotifyQAPreApprover(MRBNotification notification); | ||||||
|  |     Task<bool> NumberIsValid(int number); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class MRBService : IMRBService { | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly IHttpClientFactory _httpClientFactory; | ||||||
|  |     private readonly ISnackbar _snackbar; | ||||||
|  |     private readonly IUserService _userService; | ||||||
|  |     private readonly IApprovalService _approvalService; | ||||||
|  |  | ||||||
|  |     public MRBService(IMemoryCache cache, | ||||||
|  |                       IHttpClientFactory httpClientFactory, | ||||||
|  |                       ISnackbar snackbar, | ||||||
|  |                       IUserService userService, | ||||||
|  |                       IApprovalService approvalService) { | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException("IHttpClientFactory not injected"); | ||||||
|  |         _snackbar = snackbar ?? throw new ArgumentNullException("ISnackbar not injected"); | ||||||
|  |         _userService = userService ?? throw new ArgumentNullException("IUserService not injected"); | ||||||
|  |         _approvalService = approvalService ?? throw new ArgumentNullException("IApprovalService not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task CreateNewMRB(MRB mrb) { | ||||||
|  |         if (mrb is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, "mrb/new"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(mrb), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) { | ||||||
|  |             throw new Exception($"Unable to generate new MRB, because {responseMessage.ReasonPhrase}"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         mrb = await GetMRBByTitle(mrb.Title, true); | ||||||
|  |  | ||||||
|  |         _cache.Set($"mrb{mrb.MRBNumber}", mrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |         _cache.Set($"mrb{mrb.Title}", mrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |  | ||||||
|  |         IEnumerable<MRB>? allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs"); | ||||||
|  |         if (allMrbs is not null) { | ||||||
|  |             List<MRB> mrbList = allMrbs.ToList(); | ||||||
|  |             mrbList.Add(mrb); | ||||||
|  |             _cache.Set("allMrbs", mrbList); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task RecallMRB(MRB mrb, User recallUser) { | ||||||
|  |         if (mrb is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |         if (mrb.StageNo < 1) throw new ArgumentException("MRB already in Draft stage"); | ||||||
|  |         if (mrb.StageNo >= 4) throw new Exception("you cannot recall a completed MRB"); | ||||||
|  |  | ||||||
|  |         mrb.StageNo = 0; | ||||||
|  |         mrb.SubmittedDate = DateTimeUtilities.MIN_DT; | ||||||
|  |         mrb.ApprovalDate = DateTimeUtilities.MAX_DT; | ||||||
|  |         mrb.CloseDate = DateTimeUtilities.MAX_DT; | ||||||
|  |         await UpdateMRB(mrb); | ||||||
|  |  | ||||||
|  |         IEnumerable<Approval> approvals = await _approvalService.GetApprovalsForIssueId(mrb.MRBNumber, false); | ||||||
|  |  | ||||||
|  |         foreach (Approval approval in approvals) { | ||||||
|  |             if (approval.CompletedDate >= DateTimeUtilities.MAX_DT) { | ||||||
|  |                 string comment = $"Recalled by {recallUser.GetFullName()}."; | ||||||
|  |                 approval.Comments = comment; | ||||||
|  |  | ||||||
|  |                 approval.CompletedDate = DateTime.Now; | ||||||
|  |                 approval.ItemStatus = -1; | ||||||
|  |  | ||||||
|  |                 await _approvalService.UpdateApproval(approval); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         string message = $"MRB# {mrb.MRBNumber} [{mrb.Title}] has been recalled by {recallUser.GetFullName()}."; | ||||||
|  |         MRBNotification notification = new() { Message = message, MRB = mrb }; | ||||||
|  |  | ||||||
|  |         await NotifyApprovers(notification); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeleteMRB(int mrbNumber) { | ||||||
|  |         if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Delete, $"mrb/delete?mrbNumber={mrbNumber}"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) { | ||||||
|  |             throw new Exception($"Unable to delete MRB# {mrbNumber}, because {responseMessage.ReasonPhrase}"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         IEnumerable<MRB> allMRBs = await GetAllMRBs(true); | ||||||
|  |         _cache.Set("allMrbs", allMRBs); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<MRB>> GetAllMRBs(bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             IEnumerable<MRB>? allMRBs = null; | ||||||
|  |             if (!bypassCache) allMRBs = _cache.Get<IEnumerable<MRB>>("allMrbs"); | ||||||
|  |  | ||||||
|  |             if (allMRBs is null) { | ||||||
|  |                 HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |                 HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/all?bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |                 HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |                 if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                     string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                     JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                         PropertyNameCaseInsensitive = true | ||||||
|  |                     }; | ||||||
|  |  | ||||||
|  |                     allMRBs = JsonSerializer.Deserialize<IEnumerable<MRB>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                         throw new Exception("Unable to parse MRBs from API response"); | ||||||
|  |  | ||||||
|  |                     _cache.Set($"allMrbs", allMRBs, DateTimeOffset.Now.AddMinutes(15)); | ||||||
|  |                 } else { | ||||||
|  |                     throw new Exception($"Unable to get all MRBs, because {responseMessage.ReasonPhrase}"); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return allMRBs; | ||||||
|  |         } catch (Exception) { | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<bool> NumberIsValid(int number) { | ||||||
|  |         try { | ||||||
|  |             if (number <= 0) return false; | ||||||
|  |  | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/numberIsValid?number={number}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 bool isValid = JsonSerializer.Deserialize<bool>(responseContent, jsonSerializerOptions); | ||||||
|  |  | ||||||
|  |                 return isValid; | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             throw new Exception($"Unable to determine if {number} is a valid MRB#, because {ex.Message}"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<MRB> GetMRBById(int id, bool bypassCache=false) { | ||||||
|  |         if (id <= 0) throw new ArgumentException($"Invalid MRB number: {id}"); | ||||||
|  |  | ||||||
|  |         MRB? mrb = null; | ||||||
|  |         if (!bypassCache) | ||||||
|  |             mrb = _cache.Get<MRB>($"mrb{id}"); | ||||||
|  |  | ||||||
|  |         if (mrb is null && !bypassCache) mrb = _cache.Get<IEnumerable<MRB>>("allMrbs")?.FirstOrDefault(m => m.MRBNumber == id); | ||||||
|  |  | ||||||
|  |         if (mrb is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/getById?id={id}&bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 mrb = JsonSerializer.Deserialize<MRB>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     throw new Exception("Unable to parse MRB from API response"); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"mrb{mrb.MRBNumber}", mrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"Unable to get MRB by Id, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return mrb; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<MRB> GetMRBByTitle(string title, bool bypassCache) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Title cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         MRB? mrb = null; | ||||||
|  |         if (!bypassCache) mrb = _cache.Get<MRB>($"mrb{title}"); | ||||||
|  |  | ||||||
|  |         if (mrb is null && !bypassCache)  | ||||||
|  |             mrb = _cache.Get<IEnumerable<MRB>>("allMrbs")?.FirstOrDefault(m => m.Title.Equals(title)); | ||||||
|  |  | ||||||
|  |         if (mrb is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/getByTitle?title={title}&bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 mrb = JsonSerializer.Deserialize<MRB>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     throw new Exception("Unable to parse MRB from API response"); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"mrb{mrb.Title}", mrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"Unable to get MRB by title, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return mrb; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdateMRB(MRB mrb) { | ||||||
|  |         if (mrb is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Put, $"mrb"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(mrb), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) { | ||||||
|  |             throw new Exception($"Unable to update MRB, because {responseMessage.ReasonPhrase}"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         _cache.Set($"mrb{mrb.MRBNumber}", mrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |         _cache.Set($"mrb{mrb.Title}", mrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |  | ||||||
|  |         IEnumerable<MRB>? allMrbs = _cache.Get<IEnumerable<MRB>>("allMrbs"); | ||||||
|  |         if (allMrbs is not null) { | ||||||
|  |             List<MRB> mrbList = allMrbs.ToList(); | ||||||
|  |             mrbList.RemoveAll(m => m.MRBNumber == mrb.MRBNumber); | ||||||
|  |             mrbList.Add(mrb); | ||||||
|  |             _cache.Set("allMrbs", mrbList); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task CreateMRBAction(MRBAction mrbAction) { | ||||||
|  |         if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, "mrbAction"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(mrbAction), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception($"Unable to create new MRB action, because {responseMessage.ReasonPhrase}"); | ||||||
|  |  | ||||||
|  |         await GetMRBActionsForMRB(mrbAction.MRBNumber, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<MRBAction>> GetMRBActionsForMRB(int mrbNumber, bool bypassCache) { | ||||||
|  |         if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#"); | ||||||
|  |  | ||||||
|  |         IEnumerable<MRBAction>? mrbActions = null; | ||||||
|  |         if (!bypassCache) | ||||||
|  |             mrbActions = _cache.Get<IEnumerable<MRBAction>>($"mrbActions{mrbNumber}"); | ||||||
|  |  | ||||||
|  |         if (mrbActions is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrbAction?mrbNumber={mrbNumber}&bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 mrbActions = JsonSerializer.Deserialize<IEnumerable<MRBAction>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     new List<MRBAction>(); | ||||||
|  |  | ||||||
|  |                 if (mrbActions.Count() > 0) | ||||||
|  |                     _cache.Set($"mrbActions{mrbNumber}", mrbActions, DateTimeOffset.Now.AddMinutes(5)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"Unable to get MRB {mrbNumber} actions, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return mrbActions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdateMRBAction(MRBAction mrbAction) { | ||||||
|  |         if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Put, $"mrbAction"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(mrbAction), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) { | ||||||
|  |             throw new Exception($"Unable to update MRB action, because {responseMessage.ReasonPhrase}"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         IEnumerable<MRBAction>? mrbActions = _cache.Get<IEnumerable<MRBAction>>($"mrbActions{mrbAction.MRBNumber}"); | ||||||
|  |         if (mrbActions is not null) { | ||||||
|  |             List<MRBAction> mrbActionList = mrbActions.ToList(); | ||||||
|  |             mrbActionList.RemoveAll(a => a.ActionID == mrbAction.ActionID); | ||||||
|  |             mrbActionList.Add(mrbAction); | ||||||
|  |             _cache.Set($"mrbActions{mrbAction.MRBNumber}", mrbActionList, DateTimeOffset.Now.AddMinutes(5)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeleteMRBAction(MRBAction mrbAction) { | ||||||
|  |         if (mrbAction is null) throw new ArgumentNullException("MRB action cannot be null"); | ||||||
|  |         if (mrbAction.ActionID <= 0) throw new ArgumentException($"{mrbAction.ActionID} is not a valid MRBActionID"); | ||||||
|  |         if (mrbAction.MRBNumber <= 0) throw new ArgumentException($"{mrbAction.MRBNumber} is not a valid MRBNumber"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         string route = $"mrbAction?mrbActionID={mrbAction.ActionID}&mrbNumber={mrbAction.MRBNumber}"; | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Delete, route); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception($"Unable to delete MRB action {mrbAction.ActionID}"); | ||||||
|  |  | ||||||
|  |         IEnumerable<MRBAction>? mrbActions = _cache.Get<IEnumerable<MRBAction>>($"mrbActions{mrbAction.MRBNumber}"); | ||||||
|  |         if (mrbActions is not null) { | ||||||
|  |             List<MRBAction> mrbActionList = mrbActions.ToList(); | ||||||
|  |             mrbActionList.RemoveAll(a => a.ActionID == mrbAction.ActionID); | ||||||
|  |             _cache.Set($"mrbActions{mrbAction.MRBNumber}", mrbActionList, DateTimeOffset.Now.AddMinutes(5)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UploadAttachments(IEnumerable<IBrowserFile> files, int mrbNumber) { | ||||||
|  |         if (files is null) throw new ArgumentNullException("Files cannot be null"); | ||||||
|  |         if (files.Count() <= 0) throw new ArgumentException("Files cannot be empty"); | ||||||
|  |         if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB number"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"mrb/attach?mrbNumber={mrbNumber}"); | ||||||
|  |  | ||||||
|  |         using MultipartFormDataContent content = new MultipartFormDataContent(); | ||||||
|  |  | ||||||
|  |         foreach (IBrowserFile file in files) { | ||||||
|  |             try { | ||||||
|  |                 long maxFileSize = 1024L * 1024L * 1024L * 2L; | ||||||
|  |                 StreamContent fileContent = new StreamContent(file.OpenReadStream(maxFileSize)); | ||||||
|  |  | ||||||
|  |                 FileExtensionContentTypeProvider contentTypeProvider = new FileExtensionContentTypeProvider(); | ||||||
|  |  | ||||||
|  |                 const string defaultContentType = "application/octet-stream"; | ||||||
|  |  | ||||||
|  |                 if (!contentTypeProvider.TryGetContentType(file.Name, out string? contentType)) { | ||||||
|  |                     contentType = defaultContentType; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType); | ||||||
|  |  | ||||||
|  |                 content.Add(content: fileContent, name: "\"files\"", fileName: file.Name); | ||||||
|  |             } catch (Exception ex) { | ||||||
|  |                 _snackbar.Add($"File {file.Name} not saved, because {ex.Message}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         requestMessage.Content = content; | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception($"Unable to save attachments, because {responseMessage.ReasonPhrase}"); | ||||||
|  |  | ||||||
|  |         string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |         JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |             PropertyNameCaseInsensitive = true | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         IEnumerable<UploadResult> results = JsonSerializer.Deserialize<IEnumerable<UploadResult>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |             new List<UploadResult>(); | ||||||
|  |  | ||||||
|  |         foreach (UploadResult result in results) { | ||||||
|  |             if (result.UploadSuccessful) { | ||||||
|  |                 _snackbar.Add($"{result.FileName} successfully uploaded", Severity.Success); | ||||||
|  |             } else { | ||||||
|  |                 _snackbar.Add($"{result.FileName} not uploaded, because {result.Error}", Severity.Error); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         await GetAllAttachmentsForMRB(mrbNumber, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UploadActionAttachments(IEnumerable<IBrowserFile> files, int actionId) { | ||||||
|  |         if (files is null) throw new ArgumentNullException("Files cannot be null"); | ||||||
|  |         if (files.Count() <= 0) throw new ArgumentException("Files cannot be empty"); | ||||||
|  |         if (actionId <= 0) throw new ArgumentException($"{actionId} is not a valid MRB action ID"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"mrb/action/attach?actionId={actionId}"); | ||||||
|  |  | ||||||
|  |         using MultipartFormDataContent content = new MultipartFormDataContent(); | ||||||
|  |  | ||||||
|  |         foreach (IBrowserFile file in files) { | ||||||
|  |             try { | ||||||
|  |                 long maxFileSize = 1024L * 1024L * 1024L * 2L; | ||||||
|  |                 StreamContent fileContent = new StreamContent(file.OpenReadStream(maxFileSize)); | ||||||
|  |  | ||||||
|  |                 FileExtensionContentTypeProvider contentTypeProvider = new FileExtensionContentTypeProvider(); | ||||||
|  |  | ||||||
|  |                 const string defaultContentType = "application/octet-stream"; | ||||||
|  |  | ||||||
|  |                 if (!contentTypeProvider.TryGetContentType(file.Name, out string? contentType)) { | ||||||
|  |                     contentType = defaultContentType; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType); | ||||||
|  |  | ||||||
|  |                 content.Add(content: fileContent, name: "\"files\"", fileName: file.Name); | ||||||
|  |             } catch (Exception ex) { | ||||||
|  |                 _snackbar.Add($"File {file.Name} not saved, because {ex.Message}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         requestMessage.Content = content; | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception($"Unable to save action attachments, because {responseMessage.ReasonPhrase}"); | ||||||
|  |  | ||||||
|  |         string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |         JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |             PropertyNameCaseInsensitive = true | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         IEnumerable<UploadResult> results = JsonSerializer.Deserialize<IEnumerable<UploadResult>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |             new List<UploadResult>(); | ||||||
|  |  | ||||||
|  |         foreach (UploadResult result in results) { | ||||||
|  |             if (result.UploadSuccessful) { | ||||||
|  |                 _snackbar.Add($"{result.FileName} successfully uploaded", Severity.Success); | ||||||
|  |             } else { | ||||||
|  |                 _snackbar.Add($"{result.FileName} not uploaded, because {result.Error}", Severity.Error); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         await GetAllAttachmentsForMRB(actionId, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<MRBAttachment>> GetAllAttachmentsForMRB(int mrbNumber, bool bypassCache) { | ||||||
|  |         if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#"); | ||||||
|  |  | ||||||
|  |         IEnumerable<MRBAttachment>? mrbAttachments = null; | ||||||
|  |         if (!bypassCache) | ||||||
|  |             mrbAttachments = _cache.Get<IEnumerable<MRBAttachment>>($"mrbAttachments{mrbNumber}"); | ||||||
|  |  | ||||||
|  |         if (mrbAttachments is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/attachments?mrbNumber={mrbNumber}&bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 mrbAttachments = JsonSerializer.Deserialize<IEnumerable<MRBAttachment>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     new List<MRBAttachment>(); | ||||||
|  |  | ||||||
|  |                 if (mrbAttachments.Count() > 0) | ||||||
|  |                     _cache.Set($"mrbAttachments{mrbNumber}", mrbAttachments, DateTimeOffset.Now.AddMinutes(5)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"Unable to get MRB {mrbNumber} attachments, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return mrbAttachments; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<MRBActionAttachment>> GetAllActionAttachmentsForMRB(int mrbNumber, bool bypassCache) { | ||||||
|  |         if (mrbNumber <= 0) throw new ArgumentException($"{mrbNumber} is not a valid MRB#"); | ||||||
|  |  | ||||||
|  |         IEnumerable<MRBActionAttachment>? actionAttachments = null; | ||||||
|  |         if (!bypassCache) | ||||||
|  |             actionAttachments = _cache.Get<IEnumerable<MRBActionAttachment>>($"mrbActionAttachments{mrbNumber}"); | ||||||
|  |  | ||||||
|  |         if (actionAttachments is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"mrb/action/attachments?mrbNumber={mrbNumber}&bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 actionAttachments = JsonSerializer.Deserialize<IEnumerable<MRBActionAttachment>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     new List<MRBActionAttachment>(); | ||||||
|  |  | ||||||
|  |                 if (actionAttachments.Count() > 0) | ||||||
|  |                     _cache.Set($"mrbActionAttachments{mrbNumber}", actionAttachments, DateTimeOffset.Now.AddMinutes(5)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"Unable to get MRB {mrbNumber} action attachments, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return actionAttachments; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeleteAttachment(MRBAttachment attachment) { | ||||||
|  |         if (attachment is null) throw new ArgumentNullException("MRB attachment cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Delete, "mrb/attach"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(attachment), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception($"Unable to delete MRB attachment"); | ||||||
|  |  | ||||||
|  |         IEnumerable<MRBAttachment>? mrbAttachments = _cache.Get<IEnumerable<MRBAttachment>>($"mrbAttachments{attachment.MRBNumber}"); | ||||||
|  |         if (mrbAttachments is not null) { | ||||||
|  |             List<MRBAttachment> mrbAttachmentList = mrbAttachments.ToList(); | ||||||
|  |             mrbAttachmentList.RemoveAll(a => a.AttachmentID == attachment.AttachmentID); | ||||||
|  |             _cache.Set($"mrbAttachments{attachment.MRBNumber}", mrbAttachmentList, DateTimeOffset.Now.AddMinutes(5)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task SubmitForApproval(MRB mrb) { | ||||||
|  |         if (mrb is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |  | ||||||
|  |         string roleName = "QA_PRE_APPROVAL"; | ||||||
|  |         string subRoleName = "QA_PRE_APPROVAL"; | ||||||
|  |  | ||||||
|  |         if (mrb.StageNo > 1) { | ||||||
|  |             roleName = "MRB Approver"; | ||||||
|  |             subRoleName = "MRBApprover"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         int roleId = await _approvalService.GetRoleIdForRoleName(roleName); | ||||||
|  |  | ||||||
|  |         if (roleId <= 0) throw new Exception($"could not find {roleName} role ID"); | ||||||
|  |  | ||||||
|  |         IEnumerable<SubRole> subRoles = await _approvalService.GetSubRolesForSubRoleName(subRoleName, roleId); | ||||||
|  |  | ||||||
|  |         foreach (SubRole subRole in subRoles) { | ||||||
|  |             IEnumerable<User> members = await _approvalService.GetApprovalGroupMembers(subRole.SubRoleID); | ||||||
|  |  | ||||||
|  |             foreach (User member in members) { | ||||||
|  |                 Approval approval = new() { | ||||||
|  |                     IssueID = mrb.MRBNumber, | ||||||
|  |                     RoleName = roleName, | ||||||
|  |                     SubRole = subRole.SubRoleName, | ||||||
|  |                     UserID = member.UserID, | ||||||
|  |                     SubRoleID = subRole.SubRoleID, | ||||||
|  |                     AssignedDate = DateTime.Now, | ||||||
|  |                     Step = mrb.StageNo | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 await _approvalService.CreateApproval(approval); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task GenerateActionTasks(MRB mrb, MRBAction action) { | ||||||
|  |         if (mrb is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |         if (action is null) throw new ArgumentNullException("MRBAction cannot be null"); | ||||||
|  |  | ||||||
|  |         string roleName = "MRB Actions"; | ||||||
|  |         string subRoleName = "MRBActions"; | ||||||
|  |  | ||||||
|  |         int roleId = await _approvalService.GetRoleIdForRoleName(roleName); | ||||||
|  |  | ||||||
|  |         if (roleId <= 0) throw new Exception($"could not find {roleName} role ID"); | ||||||
|  |  | ||||||
|  |         IEnumerable<SubRole> subRoles = await _approvalService.GetSubRolesForSubRoleName(subRoleName, roleId); | ||||||
|  |  | ||||||
|  |         foreach (SubRole subRole in subRoles) { | ||||||
|  |             IEnumerable<User> members = await _approvalService.GetApprovalGroupMembers(subRole.SubRoleID); | ||||||
|  |  | ||||||
|  |             foreach (User member in members) { | ||||||
|  |                 Approval approval = new() { | ||||||
|  |                     IssueID = action.MRBNumber, | ||||||
|  |                     RoleName = roleName, | ||||||
|  |                     SubRole = subRole.SubRoleName, | ||||||
|  |                     UserID = member.UserID, | ||||||
|  |                     SubRoleID = subRole.SubRoleID, | ||||||
|  |                     AssignedDate = DateTime.Now, | ||||||
|  |                     Step = mrb.StageNo, | ||||||
|  |                     SubRoleCategoryItem = subRole.SubRoleCategoryItem, | ||||||
|  |                     TaskID = action.ActionID | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 await _approvalService.CreateApproval(approval); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyNewApprovals(MRB mrb) { | ||||||
|  |         if (mrb is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"mrb/notify/new-approvals"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(mrb), | ||||||
|  |                                                     Encoding.UTF8, | ||||||
|  |                                                     "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception($"Unable to notify new MRB approvers, because {responseMessage.ReasonPhrase}"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyApprovers(MRBNotification notification) { | ||||||
|  |         if (notification is null) throw new ArgumentNullException("notification cannot be null"); | ||||||
|  |         if (notification.MRB is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |         if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"mrb/notify/approvers"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(notification), | ||||||
|  |                                                     Encoding.UTF8, | ||||||
|  |                                                     "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception($"Unable to notify MRB approvers, because {responseMessage.ReasonPhrase}"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyOriginator(MRBNotification notification) { | ||||||
|  |         if (notification is null) throw new ArgumentNullException("notification cannot be null"); | ||||||
|  |         if (notification.MRB is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |         if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"mrb/notify/originator"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(notification), | ||||||
|  |                                                     Encoding.UTF8, | ||||||
|  |                                                     "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception($"Unable to notify MRB originator, because {responseMessage.ReasonPhrase}"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyQAPreApprover(MRBNotification notification) { | ||||||
|  |         if (notification is null) throw new ArgumentNullException("notification cannot be null"); | ||||||
|  |         if (notification.MRB is null) throw new ArgumentNullException("MRB cannot be null"); | ||||||
|  |         if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"mrb/notify/qa-pre-approver"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(notification), | ||||||
|  |                                                     Encoding.UTF8, | ||||||
|  |                                                     "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception($"Unable to notify QA pre approver, because {responseMessage.ReasonPhrase}"); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,111 @@ | |||||||
|  | using System.Security.Claims; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  |  | ||||||
|  | using Microsoft.AspNetCore.Components.Authorization; | ||||||
|  |  | ||||||
|  | using MudBlazor; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.Client.Services; | ||||||
|  |  | ||||||
|  | public class MesaFabApprovalAuthStateProvider : AuthenticationStateProvider, IDisposable { | ||||||
|  |     private readonly IAuthenticationService _authService; | ||||||
|  |     private readonly IUserService _userService; | ||||||
|  |     private readonly ISnackbar _snackbar; | ||||||
|  |  | ||||||
|  |     public User? CurrentUser { get; private set; } | ||||||
|  |  | ||||||
|  |     public MesaFabApprovalAuthStateProvider(IAuthenticationService authService, | ||||||
|  |                                             ISnackbar snackbar, | ||||||
|  |                                             IUserService userService) { | ||||||
|  |         _authService = authService ?? | ||||||
|  |             throw new ArgumentNullException("IAuthenticationService not injected"); | ||||||
|  |         _snackbar = snackbar ?? | ||||||
|  |             throw new ArgumentNullException("ISnackbar not injected"); | ||||||
|  |         _userService = userService ?? | ||||||
|  |             throw new ArgumentNullException("IUserService not injected"); | ||||||
|  |         AuthenticationStateChanged += OnAuthenticationStateChangedAsync; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public override async Task<AuthenticationState> GetAuthenticationStateAsync() { | ||||||
|  |         ClaimsPrincipal principal = new(); | ||||||
|  |         try { | ||||||
|  |             principal = await _authService.FetchAuthState(); | ||||||
|  |  | ||||||
|  |             CurrentUser = await _authService.GetCurrentUser(); | ||||||
|  |  | ||||||
|  |             return new(principal); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             return new(new ClaimsPrincipal()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task StateHasChanged(ClaimsPrincipal principal) { | ||||||
|  |         if (principal is null) throw new ArgumentNullException("ClaimsPrincipal cannot be null"); | ||||||
|  |  | ||||||
|  |         CurrentUser = await _authService.GetCurrentUser(); | ||||||
|  |  | ||||||
|  |         NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal))); | ||||||
|  |  | ||||||
|  |         if (CurrentUser is null) { | ||||||
|  |             string loginId = _userService.GetLoginIdFromClaimsPrincipal(principal); | ||||||
|  |  | ||||||
|  |             User? user = await _userService.GetUserByLoginId(loginId); | ||||||
|  |  | ||||||
|  |             await _authService.SetCurrentUser(user); | ||||||
|  |  | ||||||
|  |             NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal))); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task LoginAsync(string loginId, string password) { | ||||||
|  |         try { | ||||||
|  |             if (string.IsNullOrWhiteSpace(loginId)) throw new ArgumentException("LoginId cannot be null or empty"); | ||||||
|  |             if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("Password cannot be null or empty"); | ||||||
|  |  | ||||||
|  |             ClaimsPrincipal principal = await _authService.SendAuthenticationRequest(loginId, password); | ||||||
|  |  | ||||||
|  |             CurrentUser = await _authService.GetCurrentUser(); | ||||||
|  |  | ||||||
|  |             NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal))); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _snackbar.Add(ex.Message, Severity.Error); | ||||||
|  |             NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(new()))); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task LoginLocal() { | ||||||
|  |         try { | ||||||
|  |             ClaimsPrincipal principal = await _authService.AttemptLocalUserAuth(); | ||||||
|  |  | ||||||
|  |             CurrentUser = await _authService.GetCurrentUser(); | ||||||
|  |  | ||||||
|  |             NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal))); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _snackbar.Add(ex.Message, Severity.Error); | ||||||
|  |             NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(new()))); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task Logout() { | ||||||
|  |         CurrentUser = null; | ||||||
|  |         await _authService.ClearTokens(); | ||||||
|  |         await _authService.ClearCurrentUser(); | ||||||
|  |         NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(new()))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public void Dispose() => AuthenticationStateChanged -= OnAuthenticationStateChangedAsync; | ||||||
|  |  | ||||||
|  |     private async void OnAuthenticationStateChangedAsync(Task<AuthenticationState> task) { | ||||||
|  |         try { | ||||||
|  |             AuthenticationState authenticationState = await task; | ||||||
|  |             if (authenticationState is not null) { | ||||||
|  |                 ClaimsPrincipal principal = await _authService.FetchAuthState(); | ||||||
|  |                  | ||||||
|  |                 CurrentUser = await _authService.GetCurrentUser(); | ||||||
|  |             } | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             // _snackbar.Add($"Unable to fetch authentication state, because {ex.Message}", Severity.Error); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										767
									
								
								MesaFabApproval.Client/Services/PCRBService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										767
									
								
								MesaFabApproval.Client/Services/PCRBService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,767 @@ | |||||||
|  | using System.Net.Http.Headers; | ||||||
|  | using System.Text; | ||||||
|  | using System.Text.Json; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  |  | ||||||
|  | using Microsoft.AspNetCore.Components.Forms; | ||||||
|  | using Microsoft.AspNetCore.StaticFiles; | ||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | using MudBlazor; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.Client.Services; | ||||||
|  |  | ||||||
|  | public interface IPCRBService { | ||||||
|  |     Task<string> IdIsValid(string id); | ||||||
|  |     Task<bool> IdIsValid(int id); | ||||||
|  |     Task<IEnumerable<PCRB>> GetAllPCRBs(bool bypassCache); | ||||||
|  |     Task CreateNewPCRB(PCRB pcrb); | ||||||
|  |     Task<PCRB> GetPCRBByPlanNumber(int planNumber, bool bypassCache); | ||||||
|  |     Task<PCRB> GetPCRBByTitle(string title, bool bypassCache); | ||||||
|  |     Task UpdatePCRB(PCRB pcrb); | ||||||
|  |     Task DeletePCRB(int planNumber); | ||||||
|  |     Task UploadAttachment(PCRBAttachment attachment); | ||||||
|  |     Task<IEnumerable<PCRBAttachment>> GetAttachmentsByPlanNumber(int planNumber, bool bypassCache); | ||||||
|  |     Task UpdateAttachment(PCRBAttachment attachment); | ||||||
|  |     Task DeleteAttachment(PCRBAttachment attachment); | ||||||
|  |     Task CreateNewActionItem(PCRBActionItem actionItem); | ||||||
|  |     Task UpdateActionItem(PCRBActionItem actionItem); | ||||||
|  |     Task DeleteActionItem(int id); | ||||||
|  |     Task<IEnumerable<PCRBActionItem>> GetActionItemsForPlanNumber(int planNumber, bool bypassCache); | ||||||
|  |     Task CreateNewAttendee(PCRBAttendee attendee); | ||||||
|  |     Task UpdateAttendee(PCRBAttendee attendee); | ||||||
|  |     Task DeleteAttendee(int id); | ||||||
|  |     Task<IEnumerable<PCRBAttendee>> GetAttendeesByPlanNumber(int planNumber, bool bypassCache); | ||||||
|  |     Task CreatePCR3Document(PCR3Document document); | ||||||
|  |     Task UpdatePCR3Document(PCR3Document document); | ||||||
|  |     Task<IEnumerable<PCR3Document>> GetPCR3DocumentsForPlanNumber(int planNumber, bool bypassCache); | ||||||
|  |     Task NotifyNewApprovals(PCRB pcrb); | ||||||
|  |     Task NotifyApprovers(PCRBNotification notification); | ||||||
|  |     Task NotifyOriginator(PCRBNotification notification); | ||||||
|  |     Task NotifyResponsiblePerson(PCRBActionItemNotification notification); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class PCRBService : IPCRBService { | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly IHttpClientFactory _httpClientFactory; | ||||||
|  |     private readonly ISnackbar _snackbar; | ||||||
|  |     private readonly IUserService _userService; | ||||||
|  |  | ||||||
|  |     public PCRBService(IMemoryCache cache, | ||||||
|  |                        IHttpClientFactory httpClientFactory, | ||||||
|  |                        ISnackbar snackbar, | ||||||
|  |                        IUserService userService) { | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException("IHttpClientFactory not injected"); | ||||||
|  |         _snackbar = snackbar ?? throw new ArgumentNullException("ISnackbar not injected"); | ||||||
|  |         _userService = userService ?? throw new ArgumentNullException("IUserService not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<string> IdIsValid(string id) { | ||||||
|  |         bool isMatch = true; | ||||||
|  |         if (string.IsNullOrWhiteSpace(id)) isMatch = false; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/getByPlanNumber?planNumber={id}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 PCRB? pcrb = JsonSerializer.Deserialize<PCRB>(responseContent, jsonSerializerOptions); | ||||||
|  |  | ||||||
|  |                 if (pcrb is null) isMatch = false; | ||||||
|  |             } else { | ||||||
|  |                 isMatch = false; | ||||||
|  |             } | ||||||
|  |         } catch (Exception) { | ||||||
|  |             isMatch = false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!isMatch) return $"{id} is not a valid PCRB#"; | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<bool> IdIsValid(int id) { | ||||||
|  |         bool isMatch = true; | ||||||
|  |         if (id <= 0) isMatch = false; | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/getByPlanNumber?planNumber={id}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 PCRB? pcrb = JsonSerializer.Deserialize<PCRB>(responseContent, jsonSerializerOptions); | ||||||
|  |  | ||||||
|  |                 if (pcrb is null) isMatch = false; | ||||||
|  |             } else { | ||||||
|  |                 isMatch = false; | ||||||
|  |             } | ||||||
|  |         } catch (Exception) { | ||||||
|  |             isMatch = false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return isMatch; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<PCRB>> GetAllPCRBs(bool bypassCache) { | ||||||
|  |         try { | ||||||
|  |             IEnumerable<PCRB>? allPCRBs = null; | ||||||
|  |             if (!bypassCache) allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs"); | ||||||
|  |  | ||||||
|  |             if (allPCRBs is null) { | ||||||
|  |                 HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |                 HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/all?bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |                 HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |                 if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                     string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                     JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                         PropertyNameCaseInsensitive = true | ||||||
|  |                     }; | ||||||
|  |  | ||||||
|  |                     allPCRBs = JsonSerializer.Deserialize<IEnumerable<PCRB>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                         throw new Exception("Unable to parse PCRBs from API response"); | ||||||
|  |  | ||||||
|  |                     _cache.Set($"allPCRBs", allPCRBs, DateTimeOffset.Now.AddMinutes(15)); | ||||||
|  |                 } else { | ||||||
|  |                     throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return allPCRBs; | ||||||
|  |         } catch (Exception) { | ||||||
|  |             throw; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task CreateNewPCRB(PCRB pcrb) { | ||||||
|  |         if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(pcrb), | ||||||
|  |                                                Encoding.UTF8, | ||||||
|  |                                                "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |  | ||||||
|  |         PCRB newPCRB = await GetPCRBByTitle(pcrb.Title, true); | ||||||
|  |  | ||||||
|  |         _cache.Set($"pcrb{pcrb.PlanNumber}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |         _cache.Set($"pcrb{pcrb.Title}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |  | ||||||
|  |         IEnumerable<PCRB>? allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs"); | ||||||
|  |         if (allPCRBs is not null) { | ||||||
|  |             List<PCRB> pcrbList = allPCRBs.ToList(); | ||||||
|  |             pcrbList.Add(newPCRB); | ||||||
|  |             _cache.Set("allPCRBs", pcrbList); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<PCRB> GetPCRBByPlanNumber(int planNumber, bool bypassCache) { | ||||||
|  |         if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB plan #"); | ||||||
|  |  | ||||||
|  |         PCRB? pcrb = null; | ||||||
|  |         if (!bypassCache) pcrb = _cache.Get<PCRB>($"pcrb{planNumber}"); | ||||||
|  |  | ||||||
|  |         if (pcrb is null && !bypassCache) | ||||||
|  |             pcrb = _cache.Get<IEnumerable<PCRB>>("allPCRBs")?.FirstOrDefault(m => m.PlanNumber == planNumber); | ||||||
|  |  | ||||||
|  |         if (pcrb is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = | ||||||
|  |                 new(HttpMethod.Get, $"pcrb/getByPlanNumber?planNumber={planNumber}&bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |                 throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |  | ||||||
|  |             string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |             JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                 PropertyNameCaseInsensitive = true | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             pcrb = JsonSerializer.Deserialize<PCRB>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                 throw new Exception("unable to parse PCRB from API response"); | ||||||
|  |  | ||||||
|  |             _cache.Set($"pcrb{pcrb.PlanNumber}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             _cache.Set($"pcrb{pcrb.Title}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |  | ||||||
|  |             if (bypassCache) { | ||||||
|  |                 IEnumerable<PCRB>? allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs"); | ||||||
|  |                 if (allPCRBs is not null) { | ||||||
|  |                     List<PCRB> pcrbList = allPCRBs.ToList(); | ||||||
|  |                     pcrbList.RemoveAll(p => p.PlanNumber == planNumber); | ||||||
|  |                     pcrbList.Add(pcrb); | ||||||
|  |                     _cache.Set("allPCRBs", pcrbList); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return pcrb; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<PCRB> GetPCRBByTitle(string title, bool bypassCache) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(title)) throw new ArgumentNullException("title cannot be null"); | ||||||
|  |  | ||||||
|  |         PCRB? pcrb = null; | ||||||
|  |         if (!bypassCache) pcrb = _cache.Get<PCRB>($"pcrb{title}"); | ||||||
|  |  | ||||||
|  |         if (pcrb is null && !bypassCache)  | ||||||
|  |             pcrb = _cache.Get<IEnumerable<PCRB>>("allPCRBs")?.FirstOrDefault(m => m.Title.Equals(title)); | ||||||
|  |  | ||||||
|  |         if (pcrb is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage =  | ||||||
|  |                 new(HttpMethod.Get, $"pcrb/getByTitle?title={title}&bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |                 throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |  | ||||||
|  |             string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |             JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                 PropertyNameCaseInsensitive = true | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             pcrb = JsonSerializer.Deserialize<PCRB>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                 throw new Exception("unable to parse PCRB from API response"); | ||||||
|  |  | ||||||
|  |             _cache.Set($"pcrb{pcrb.Title}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             _cache.Set($"pcrb{pcrb.PlanNumber}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |  | ||||||
|  |             if (bypassCache) { | ||||||
|  |                 IEnumerable<PCRB>? allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs"); | ||||||
|  |                 if (allPCRBs is not null) { | ||||||
|  |                     List<PCRB> pcrbList = allPCRBs.ToList(); | ||||||
|  |                     pcrbList.RemoveAll(p => p.PlanNumber == pcrb.PlanNumber); | ||||||
|  |                     pcrbList.Add(pcrb); | ||||||
|  |                     _cache.Set("allPCRBs", pcrbList); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return pcrb; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdatePCRB(PCRB pcrb) { | ||||||
|  |         if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Put, $"pcrb"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(pcrb), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |  | ||||||
|  |         _cache.Set($"pcrb{pcrb.PlanNumber}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |         _cache.Set($"pcrb{pcrb.Title}", pcrb, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |  | ||||||
|  |         IEnumerable<PCRB>? allPCRBs = _cache.Get<IEnumerable<PCRB>>("allPCRBs"); | ||||||
|  |         if (allPCRBs is not null) { | ||||||
|  |             List<PCRB> pcrbList = allPCRBs.ToList(); | ||||||
|  |             pcrbList.RemoveAll(m => m.PlanNumber == pcrb.PlanNumber); | ||||||
|  |             pcrbList.Add(pcrb); | ||||||
|  |             _cache.Set("allPCRBs", pcrbList); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeletePCRB(int planNumber) { | ||||||
|  |         if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB plan #"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Delete, $"pcrb?planNumber={planNumber}"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |  | ||||||
|  |         IEnumerable<PCRB> allPCRBs = await GetAllPCRBs(true); | ||||||
|  |         _cache.Set("allPCRBs", allPCRBs); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UploadAttachment(PCRBAttachment attachment) { | ||||||
|  |         if (attachment is null) throw new ArgumentNullException("attachment cannot be null"); | ||||||
|  |         if (attachment.File is null) throw new ArgumentNullException("file cannot be null"); | ||||||
|  |         if (attachment.File.Size <= 0) throw new ArgumentException("file size must be greater than zero"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/attachment"); | ||||||
|  |  | ||||||
|  |         using MultipartFormDataContent content = new MultipartFormDataContent(); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             long maxFileSize = 1024L * 1024L * 1024L * 2L; | ||||||
|  |             StreamContent fileContent = new StreamContent(attachment.File.OpenReadStream(maxFileSize)); | ||||||
|  |  | ||||||
|  |             FileExtensionContentTypeProvider contentTypeProvider = new FileExtensionContentTypeProvider(); | ||||||
|  |  | ||||||
|  |             const string defaultContentType = "application/octet-stream"; | ||||||
|  |  | ||||||
|  |             if (!contentTypeProvider.TryGetContentType(attachment.File.Name, out string? contentType)) { | ||||||
|  |                 contentType = defaultContentType; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType); | ||||||
|  |  | ||||||
|  |             content.Add(content: fileContent, name: "\"file\"", fileName: attachment.File.Name); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             _snackbar.Add(ex.Message); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         content.Add(new StringContent(attachment.PlanNumber.ToString()), "PlanNumber"); | ||||||
|  |         content.Add(new StringContent(attachment.FileName), "FileName"); | ||||||
|  |         content.Add(new StringContent(attachment.UploadedByID.ToString()), "UploadedByID"); | ||||||
|  |         content.Add(new StringContent(attachment.Title), "Title"); | ||||||
|  |         content.Add(new StringContent(attachment.UploadDateTime.ToString("yyyy-MM-dd HH:mm:ss")), "UploadDateTime"); | ||||||
|  |         content.Add(new StringContent(attachment.Step.ToString()), "Step"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = content; | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |  | ||||||
|  |         await GetAttachmentsByPlanNumber(attachment.PlanNumber, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<PCRBAttachment>> GetAttachmentsByPlanNumber(int planNumber, bool bypassCache) { | ||||||
|  |         if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB Plan#"); | ||||||
|  |  | ||||||
|  |         IEnumerable<PCRBAttachment>? attachments = null; | ||||||
|  |         if (!bypassCache) | ||||||
|  |             attachments = _cache.Get<IEnumerable<PCRBAttachment>>($"pcrbAttachments{planNumber}"); | ||||||
|  |  | ||||||
|  |         if (attachments is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/attachments?planNumber={planNumber}&bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 attachments = JsonSerializer.Deserialize<IEnumerable<PCRBAttachment>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     new List<PCRBAttachment>(); | ||||||
|  |  | ||||||
|  |                 if (attachments.Count() > 0) { | ||||||
|  |                     foreach (PCRBAttachment attachment in attachments) { | ||||||
|  |                         attachment.UploadedBy = await _userService.GetUserByUserId(attachment.UploadedByID); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     _cache.Set($"pcrbAttachments{planNumber}", attachments, DateTimeOffset.Now.AddMinutes(5)); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return attachments; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdateAttachment(PCRBAttachment attachment) { | ||||||
|  |         if (attachment is null) throw new ArgumentNullException("attachment cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Put, $"pcrb/attachment"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(attachment), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeleteAttachment(PCRBAttachment attachment) { | ||||||
|  |         if (attachment is null) throw new ArgumentNullException("attachment cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Delete, $"pcrb/attachment"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(attachment), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task CreateNewActionItem(PCRBActionItem actionItem) { | ||||||
|  |         if (actionItem is null) throw new ArgumentNullException("action item cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/actionItem"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(actionItem), | ||||||
|  |                                                Encoding.UTF8, | ||||||
|  |                                                "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |  | ||||||
|  |         await GetActionItemsForPlanNumber(actionItem.PlanNumber, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdateActionItem(PCRBActionItem actionItem) { | ||||||
|  |         if (actionItem is null) throw new ArgumentNullException("action item cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Put, $"pcrb/actionItem"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(actionItem), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeleteActionItem(int id) { | ||||||
|  |         if (id <= 0) throw new ArgumentException($"{id} is not a valid PCRB action item ID"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Delete, $"pcrb/actionItem?id={id}"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<PCRBActionItem>> GetActionItemsForPlanNumber(int planNumber, bool bypassCache) { | ||||||
|  |         if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB Plan#"); | ||||||
|  |  | ||||||
|  |         IEnumerable<PCRBActionItem>? actionItems = null; | ||||||
|  |         if (!bypassCache) | ||||||
|  |             actionItems = _cache.Get<IEnumerable<PCRBActionItem>>($"pcrbActionItems{planNumber}"); | ||||||
|  |  | ||||||
|  |         if (actionItems is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/actionItems?planNumber={planNumber}&bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 actionItems = JsonSerializer.Deserialize<IEnumerable<PCRBActionItem>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     new List<PCRBActionItem>(); | ||||||
|  |  | ||||||
|  |                 if (actionItems.Count() > 0) { | ||||||
|  |                     foreach (PCRBActionItem actionItem in actionItems) { | ||||||
|  |                         actionItem.UploadedBy = await _userService.GetUserByUserId(actionItem.UploadedByID); | ||||||
|  |                         if (actionItem.ResponsiblePersonID > 0) | ||||||
|  |                             actionItem.ResponsiblePerson = await _userService.GetUserByUserId(actionItem.ResponsiblePersonID); | ||||||
|  |                         if (actionItem.ClosedByID > 0) | ||||||
|  |                             actionItem.ClosedBy = await _userService.GetUserByUserId(actionItem.ClosedByID); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     _cache.Set($"pcrbActionItems{planNumber}", actionItems, DateTimeOffset.Now.AddMinutes(5)); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return actionItems; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task CreateNewAttendee(PCRBAttendee attendee) { | ||||||
|  |         if (attendee is null) throw new ArgumentNullException("attendee cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/attendee"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(attendee), | ||||||
|  |                                                Encoding.UTF8, | ||||||
|  |                                                "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |  | ||||||
|  |         await GetAttendeesByPlanNumber(attendee.PlanNumber, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdateAttendee(PCRBAttendee attendee) { | ||||||
|  |         if (attendee is null) throw new ArgumentNullException("attendee cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Put, $"pcrb/attendee"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(attendee), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task DeleteAttendee(int id) { | ||||||
|  |         if (id <= 0) throw new ArgumentException($"{id} is not a valid PCRB attendee ID"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Delete, $"pcrb/attendee?id={id}"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<PCRBAttendee>> GetAttendeesByPlanNumber(int planNumber, bool bypassCache) { | ||||||
|  |         if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB Plan#"); | ||||||
|  |  | ||||||
|  |         IEnumerable<PCRBAttendee>? attendees = null; | ||||||
|  |         if (!bypassCache) | ||||||
|  |             attendees = _cache.Get<IEnumerable<PCRBAttendee>>($"pcrbAttendees{planNumber}"); | ||||||
|  |  | ||||||
|  |         if (attendees is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/attendees?planNumber={planNumber}&bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 attendees = JsonSerializer.Deserialize<IEnumerable<PCRBAttendee>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     new List<PCRBAttendee>(); | ||||||
|  |  | ||||||
|  |                 if (attendees.Count() > 0) { | ||||||
|  |                     foreach (PCRBAttendee attendee in attendees) | ||||||
|  |                         attendee.Attendee = await _userService.GetUserByUserId(attendee.AttendeeID); | ||||||
|  |  | ||||||
|  |                     _cache.Set($"pcrbAttendees{planNumber}", attendees, DateTimeOffset.Now.AddMinutes(5)); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return attendees; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task CreatePCR3Document(PCR3Document document) { | ||||||
|  |         if (document is null) throw new ArgumentNullException("document cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/pcr3Document"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(document), | ||||||
|  |                                                Encoding.UTF8, | ||||||
|  |                                                "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |  | ||||||
|  |         await GetPCR3DocumentsForPlanNumber(document.PlanNumber, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task UpdatePCR3Document(PCR3Document document) { | ||||||
|  |         if (document is null) throw new ArgumentNullException("document cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Put, $"pcrb/pcr3Document"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(document), | ||||||
|  |                                                    Encoding.UTF8, | ||||||
|  |                                                    "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<PCR3Document>> GetPCR3DocumentsForPlanNumber(int planNumber, bool bypassCache) { | ||||||
|  |         if (planNumber <= 0) throw new ArgumentException($"{planNumber} is not a valid PCRB Plan#"); | ||||||
|  |  | ||||||
|  |         IEnumerable<PCR3Document>? documents = null; | ||||||
|  |         if (!bypassCache) | ||||||
|  |             documents = _cache.Get<IEnumerable<PCR3Document>>($"pcr3Documents{planNumber}"); | ||||||
|  |  | ||||||
|  |         if (documents is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"pcrb/pcr3Documents?planNumber={planNumber}&bypassCache={bypassCache}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 documents = JsonSerializer.Deserialize<IEnumerable<PCR3Document>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     new List<PCR3Document>(); | ||||||
|  |  | ||||||
|  |                 if (documents.Count() > 0) { | ||||||
|  |                     foreach (PCR3Document document in documents) { | ||||||
|  |                         if (document.CompletedByID > 0) | ||||||
|  |                             document.CompletedBy = await _userService.GetUserByUserId(document.CompletedByID); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     _cache.Set($"pcr3Documents{planNumber}", documents, DateTimeOffset.Now.AddMinutes(5)); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception(responseMessage.ReasonPhrase); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return documents; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyNewApprovals(PCRB pcrb) { | ||||||
|  |         if (pcrb is null) throw new ArgumentNullException("PCRB cannot be null"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/notify/new-approvals"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(pcrb), | ||||||
|  |                                                     Encoding.UTF8, | ||||||
|  |                                                     "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception($"Unable to notify new PCRB approvers, because {responseMessage.ReasonPhrase}"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyApprovers(PCRBNotification notification) { | ||||||
|  |         if (notification is null) throw new ArgumentNullException("notification cannot be null"); | ||||||
|  |         if (notification.PCRB is null) throw new ArgumentNullException("PCRB cannot be null"); | ||||||
|  |         if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/notify/approvers"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(notification), | ||||||
|  |                                                     Encoding.UTF8, | ||||||
|  |                                                     "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception($"Unable to notify PCRB approvers, because {responseMessage.ReasonPhrase}"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyOriginator(PCRBNotification notification) { | ||||||
|  |         if (notification is null) throw new ArgumentNullException("notification cannot be null"); | ||||||
|  |         if (notification.PCRB is null) throw new ArgumentNullException("PCRB cannot be null"); | ||||||
|  |         if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/notify/originator"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(notification), | ||||||
|  |                                                     Encoding.UTF8, | ||||||
|  |                                                     "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception($"Unable to notify PCRB originator, because {responseMessage.ReasonPhrase}"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task NotifyResponsiblePerson(PCRBActionItemNotification notification) { | ||||||
|  |         if (notification is null) throw new ArgumentNullException("notification cannot be null"); | ||||||
|  |         if (string.IsNullOrWhiteSpace(notification.Message)) throw new ArgumentException("message cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |         HttpRequestMessage requestMessage = new(HttpMethod.Post, $"pcrb/notify/responsiblePerson"); | ||||||
|  |  | ||||||
|  |         requestMessage.Content = new StringContent(JsonSerializer.Serialize(notification), | ||||||
|  |                                                     Encoding.UTF8, | ||||||
|  |                                                     "application/json"); | ||||||
|  |  | ||||||
|  |         HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |         if (!responseMessage.IsSuccessStatusCode) | ||||||
|  |             throw new Exception($"Unable to notify PCRB responsible person, because {responseMessage.ReasonPhrase}"); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										208
									
								
								MesaFabApproval.Client/Services/UserService.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								MesaFabApproval.Client/Services/UserService.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,208 @@ | |||||||
|  | using System.Security.Claims; | ||||||
|  | using System.Text.Json; | ||||||
|  |  | ||||||
|  | using MesaFabApproval.Shared.Models; | ||||||
|  |  | ||||||
|  | using Microsoft.AspNetCore.Components.WebAssembly.Http; | ||||||
|  | using Microsoft.Extensions.Caching.Memory; | ||||||
|  |  | ||||||
|  | namespace MesaFabApproval.Client.Services; | ||||||
|  |  | ||||||
|  | public interface IUserService { | ||||||
|  |     ClaimsPrincipal GetClaimsPrincipalFromUser(User user); | ||||||
|  |     string GetLoginIdFromClaimsPrincipal(ClaimsPrincipal claimsPrincipal); | ||||||
|  |     Task<User> GetUserFromClaimsPrincipal(ClaimsPrincipal claimsPrincipal); | ||||||
|  |     Task<User> GetUserByUserId(int userId); | ||||||
|  |     Task<User> GetUserByLoginId(string loginId); | ||||||
|  |     Task<IEnumerable<User>> GetAllActiveUsers(); | ||||||
|  |     Task<IEnumerable<int>> GetApproverUserIdsBySubRoleCategoryItem(string item); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | public class UserService : IUserService { | ||||||
|  |     private readonly IMemoryCache _cache; | ||||||
|  |     private readonly IHttpClientFactory _httpClientFactory; | ||||||
|  |  | ||||||
|  |     public UserService(IMemoryCache cache, IHttpClientFactory httpClientFactory) { | ||||||
|  |         _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); | ||||||
|  |         _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException("IHttpClientFactory not injected"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public ClaimsPrincipal GetClaimsPrincipalFromUser(User user) { | ||||||
|  |         if (user is null) throw new ArgumentNullException("user cannot be null"); | ||||||
|  |  | ||||||
|  |         List<Claim> claims = new() { | ||||||
|  |             new Claim(nameof(user.LoginID), user.LoginID) | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         if (user.IsManager) claims.Add(new Claim(ClaimTypes.Role, "manager")); | ||||||
|  |         if (user.IsAdmin) claims.Add(new Claim(ClaimTypes.Role, "admin")); | ||||||
|  |  | ||||||
|  |         ClaimsIdentity identity = new ClaimsIdentity(claims, "MesaFabApprovalWasm"); | ||||||
|  |  | ||||||
|  |         return new ClaimsPrincipal(identity); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<User> GetUserByUserId(int userId) { | ||||||
|  |         if (userId <= 0) throw new ArgumentException($"{userId} is not a valid user ID"); | ||||||
|  |  | ||||||
|  |         User? user = _cache.Get<User>($"user{userId}"); | ||||||
|  |  | ||||||
|  |         if (user is null) | ||||||
|  |             user = _cache.Get<IEnumerable<User>>("allActiveUsers")?.FirstOrDefault(u => u.UserID == userId); | ||||||
|  |  | ||||||
|  |         if (user is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"user/userId?userId={userId}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 user = JsonSerializer.Deserialize<User>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     throw new Exception("Unable to parse user from API response"); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"user{userId}", user, DateTimeOffset.Now.AddDays(1)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"GetUserByUserId failed for user {userId}, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (user is null) throw new Exception($"User for userId {userId} not found"); | ||||||
|  |  | ||||||
|  |         return user; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<User> GetUserByLoginId(string loginId) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(loginId)) | ||||||
|  |             throw new ArgumentNullException("loginId cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         User? user = _cache.Get<User>($"user{loginId}"); | ||||||
|  |  | ||||||
|  |         if (user is null) | ||||||
|  |             user = _cache.Get<IEnumerable<User>>("allActiveUsers")?.FirstOrDefault(u => u.LoginID == loginId); | ||||||
|  |  | ||||||
|  |         if (user is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"user/loginId?loginId={loginId}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 user = JsonSerializer.Deserialize<User>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     throw new Exception("Unable to parse user from API response"); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"user{loginId}", user, DateTimeOffset.Now.AddDays(1)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"GetUserByLoginId failed for {loginId}, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (user is null) throw new Exception($"User for loginId {loginId} not found"); | ||||||
|  |  | ||||||
|  |         return user; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<User>> GetAllActiveUsers() { | ||||||
|  |         IEnumerable<User>? activeUsers = _cache.Get<IEnumerable<User>>("allActiveUsers"); | ||||||
|  |  | ||||||
|  |         if (activeUsers is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"users/active"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 activeUsers = JsonSerializer.Deserialize<IEnumerable<User>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     throw new Exception("Unable to parse user from API response"); | ||||||
|  |  | ||||||
|  |                 _cache.Set("allActiveUsers", activeUsers, DateTimeOffset.Now.AddHours(1)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"Cannot get all active users, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (activeUsers is null) | ||||||
|  |             throw new Exception("unable to fetch all active users"); | ||||||
|  |  | ||||||
|  |         return activeUsers; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public string GetLoginIdFromClaimsPrincipal(ClaimsPrincipal principal) { | ||||||
|  |         if (principal is null) throw new ArgumentNullException("Principal cannot be null"); | ||||||
|  |  | ||||||
|  |         Claim loginIdClaim = principal.FindFirst("LoginID") ?? | ||||||
|  |             throw new Exception("LoginID claim not found in principal"); | ||||||
|  |  | ||||||
|  |         string loginId = loginIdClaim.Value; | ||||||
|  |  | ||||||
|  |         return loginId; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<User> GetUserFromClaimsPrincipal(ClaimsPrincipal claimsPrincipal) { | ||||||
|  |         if (claimsPrincipal is null) throw new ArgumentNullException("ClaimsPrincipal cannot be null"); | ||||||
|  |  | ||||||
|  |         Claim loginIdClaim = claimsPrincipal.FindFirst("LoginID") ?? | ||||||
|  |             throw new Exception("LoginID claim not found in principal"); | ||||||
|  |  | ||||||
|  |         string loginId = loginIdClaim.Value ?? | ||||||
|  |             throw new Exception("LoginID claim value is null"); | ||||||
|  |  | ||||||
|  |         User user = await GetUserByLoginId(loginId) ?? | ||||||
|  |             throw new Exception($"User for loginId {loginId} not found"); | ||||||
|  |  | ||||||
|  |         return user; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<IEnumerable<int>> GetApproverUserIdsBySubRoleCategoryItem(string item) { | ||||||
|  |         if (string.IsNullOrWhiteSpace(item)) throw new ArgumentException("SubRoleCategoryItem cannot be null or empty"); | ||||||
|  |  | ||||||
|  |         IEnumerable<int>? approverUserIds = _cache.Get<IEnumerable<int>>($"approvers{item}"); | ||||||
|  |  | ||||||
|  |         if (approverUserIds is null) { | ||||||
|  |             HttpClient httpClient = _httpClientFactory.CreateClient("API"); | ||||||
|  |  | ||||||
|  |             HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approver?subRoleCategoryItem={item}"); | ||||||
|  |  | ||||||
|  |             HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); | ||||||
|  |  | ||||||
|  |             if (responseMessage.IsSuccessStatusCode) { | ||||||
|  |                 string responseContent = await responseMessage.Content.ReadAsStringAsync(); | ||||||
|  |  | ||||||
|  |                 JsonSerializerOptions jsonSerializerOptions = new() { | ||||||
|  |                     PropertyNameCaseInsensitive = true | ||||||
|  |                 }; | ||||||
|  |  | ||||||
|  |                 approverUserIds = JsonSerializer.Deserialize<IEnumerable<int>>(responseContent, jsonSerializerOptions) ?? | ||||||
|  |                     throw new Exception("Unable to parse user from API response"); | ||||||
|  |  | ||||||
|  |                 _cache.Set($"approvers{item}", approverUserIds, DateTimeOffset.Now.AddDays(1)); | ||||||
|  |             } else { | ||||||
|  |                 throw new Exception($"Unable to get approvers for SubRoleCategoryItem {item}, because {responseMessage.ReasonPhrase}"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (approverUserIds is null) throw new Exception($"Approvers for SubRoleCategoryItem {item} not found"); | ||||||
|  |  | ||||||
|  |         return approverUserIds; | ||||||
|  |     } | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	