diff --git a/backend/core/forms.py b/backend/core/forms.py index 6108ae4..ad26651 100644 --- a/backend/core/forms.py +++ b/backend/core/forms.py @@ -10,11 +10,40 @@ class OrganizationForm(forms.ModelForm): 'network_infrastructure', 'remote_workforce_percentage', 'third_party_vendor_access', 'internal_software_development', 'geographic_scope', 'customer_base', 'customer_type', 'product_portfolio', 'supplier_base', 'it_infrastructure', 'intellectual_property', - 'sensitive_data', 'integration_level' + 'sensitive_data','sensitive_data_types', 'integration_level', 'ip_value', 'change_rate', 'threat_actors' ] widgets = { 'compliance_frameworks': forms.CheckboxSelectMultiple(), 'it_infrastructure': forms.CheckboxSelectMultiple(), 'intellectual_property': forms.CheckboxSelectMultiple(), 'sensitive_data': forms.CheckboxSelectMultiple(), + 'threat_actors': forms.CheckboxSelectMultiple(), + 'sensitive_data_types': forms.CheckboxSelectMultiple(), } + + def clean(self): + cleaned_data = super().clean() + + # Handle compliance_frameworks "Other" + frameworks = cleaned_data.get('compliance_frameworks', []) + other_framework = self.data.get('compliance_frameworks_other', '').strip() + if 'other' in frameworks and other_framework: + frameworks = [fw for fw in frameworks if fw != 'other'] + frameworks.append(other_framework) + cleaned_data['compliance_frameworks'] = frameworks + + # Handle industry_sector "Other" + sector = cleaned_data.get('industry_sector') + sector_other = self.data.get('industry_sector_other', '').strip() + if sector == 'other' and sector_other: + cleaned_data['industry_sector'] = sector_other + + # Handle sensitive_data_types + types = cleaned_data.get('sensitive_data_types') or [] + other_type = self.data.get('sensitive_data_types_other', '').strip() + if 'other' in types and other_type: + types = [t for t in types if t != 'other'] + types.append(other_type) + cleaned_data['sensitive_data_types'] = types + + return cleaned_data diff --git a/backend/core/migrations/0010_organization_change_rate_organization_ip_value_and_more.py b/backend/core/migrations/0010_organization_change_rate_organization_ip_value_and_more.py new file mode 100644 index 0000000..1a22c73 --- /dev/null +++ b/backend/core/migrations/0010_organization_change_rate_organization_ip_value_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 5.1.3 on 2025-04-23 15:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0009_documentriskcontrol_likelihood_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='organization', + name='change_rate', + field=models.CharField(blank=True, max_length=20, null=True), + ), + migrations.AddField( + model_name='organization', + name='ip_value', + field=models.CharField(blank=True, max_length=20, null=True), + ), + migrations.AddField( + model_name='organization', + name='threat_actors', + field=models.JSONField(blank=True, null=True), + ), + migrations.AlterField( + model_name='organization', + name='it_dependency', + field=models.CharField(help_text='On a scale from 1-10, how dependent is your business operations on technology?', max_length=255), + ), + ] diff --git a/backend/core/migrations/0011_alter_organization_data_sensitivity.py b/backend/core/migrations/0011_alter_organization_data_sensitivity.py new file mode 100644 index 0000000..5aaa257 --- /dev/null +++ b/backend/core/migrations/0011_alter_organization_data_sensitivity.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.3 on 2025-04-23 15:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0010_organization_change_rate_organization_ip_value_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='organization', + name='data_sensitivity', + field=models.CharField(blank=True, help_text='...', max_length=20, null=True), + ), + ] diff --git a/backend/core/migrations/0012_organization_sensitive_data_types.py b/backend/core/migrations/0012_organization_sensitive_data_types.py new file mode 100644 index 0000000..be891a0 --- /dev/null +++ b/backend/core/migrations/0012_organization_sensitive_data_types.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.3 on 2025-04-23 15:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0011_alter_organization_data_sensitivity'), + ] + + operations = [ + migrations.AddField( + model_name='organization', + name='sensitive_data_types', + field=models.JSONField(blank=True, help_text='What type of sensitive data does your organization handle?', null=True), + ), + ] diff --git a/backend/core/migrations/0013_alter_organization_change_rate_and_more.py b/backend/core/migrations/0013_alter_organization_change_rate_and_more.py new file mode 100644 index 0000000..a43ce1d --- /dev/null +++ b/backend/core/migrations/0013_alter_organization_change_rate_and_more.py @@ -0,0 +1,40 @@ +# Generated by Django 5.1.3 on 2025-04-23 17:08 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0012_organization_sensitive_data_types'), + ] + + operations = [ + migrations.AlterField( + model_name='organization', + name='change_rate', + field=models.CharField(blank=True, help_text='How frequently does your organization undergo significant technology or business changes?', max_length=20, null=True), + ), + migrations.AlterField( + model_name='organization', + name='data_sensitivity', + field=models.CharField(default=django.utils.timezone.now, help_text='Overall Sensitivity Level of Data Processed: Subjective rating of the value and impact of the data your organization processes.', max_length=20), + preserve_default=False, + ), + migrations.AlterField( + model_name='organization', + name='ip_value', + field=models.CharField(blank=True, help_text="Intellectual Property (IP) Value: Select best description of IP's importance to the business model.", max_length=20, null=True), + ), + migrations.AlterField( + model_name='organization', + name='network_infrastructure', + field=models.CharField(blank=True, help_text="What best describes your organization's network infrastructure model?", max_length=20, null=True), + ), + migrations.AlterField( + model_name='organization', + name='threat_actors', + field=models.JSONField(blank=True, help_text='Which types of threat actors are most relevant to your organization (e.g., cybercriminals, insiders, nation-states)?', null=True), + ), + ] diff --git a/backend/core/models.py b/backend/core/models.py index bfdd03f..0a38687 100644 --- a/backend/core/models.py +++ b/backend/core/models.py @@ -51,9 +51,8 @@ class Organization(models.Model): critical_applications = models.CharField(max_length=20, help_text="How many critical business applications do your employees use daily?") compliance_frameworks = models.JSONField(help_text="Which regulatory frameworks is your organization required to comply with?") # Stores selected compliance frameworks as a list industry_sector = models.CharField(max_length=255,help_text="What is your primary industry sector?") - it_dependency = models.IntegerField(help_text="On a scale from 1-10, how dependent is your business operations on technology?") - data_sensitivity = models.CharField(max_length=20, help_text="What level of sensitive data does your organization process?") - network_infrastructure = models.CharField(max_length=20, help_text="What best describes your organization's network infrastructure model?") + it_dependency = models.CharField(max_length=255, help_text="On a scale from 1-10, how dependent is your business operations on technology?") + data_sensitivity = models.CharField(max_length=20, help_text="Overall Sensitivity Level of Data Processed: Subjective rating of the value and impact of the data your organization processes.") remote_workforce_percentage = models.CharField(max_length=20, help_text="What percentage of your workforce operates remotely?") third_party_vendor_access = models.CharField(max_length=20, help_text="How many third-party vendors have access to your systems?") internal_software_development = models.CharField(max_length=20, help_text="What is the extent of your internal software development activities?") @@ -66,7 +65,11 @@ class Organization(models.Model): intellectual_property = models.JSONField(null=True, blank=True, help_text="How does your organization protect and manage intellectual property?") # Stores selected IP protection types as a list sensitive_data = models.JSONField(null=True, blank=True, help_text="What type of sensitive data does your organization handle?") # Stores selected sensitive data types as a list integration_level = models.CharField(max_length=20, null=True, blank=True, help_text="How integrated are your critical business systems?") - + network_infrastructure = models.CharField(max_length=20, null=True, blank=True, help_text="What best describes your organization's network infrastructure model?") + ip_value = models.CharField(max_length=20, null=True, blank=True, help_text="Intellectual Property (IP) Value: Select best description of IP's importance to the business model.") + change_rate = models.CharField(max_length=20, null=True, blank=True, help_text="How frequently does your organization undergo significant technology or business changes?") + threat_actors = models.JSONField(null=True, blank=True, help_text="Which types of threat actors are most relevant to your organization (e.g., cybercriminals, insiders, nation-states)?") + sensitive_data_types = models.JSONField(null=True, blank=True, help_text="What type of sensitive data does your organization handle?") risks = models.ManyToManyField('Risk', related_name='organizations', blank=True) def __str__(self): diff --git a/backend/core/static/js/formHandling.js b/backend/core/static/js/formHandling.js index 1adef60..05d8c47 100644 --- a/backend/core/static/js/formHandling.js +++ b/backend/core/static/js/formHandling.js @@ -2,6 +2,18 @@ document.addEventListener('DOMContentLoaded', (event) => { const form = document.querySelector('form'); const formElements = form.elements; + const instructionsModal = new bootstrap.Modal(document.getElementById('instructionsModal')); + instructionsModal.show(); + + document.getElementById('startModalBtn').addEventListener('click', function() { + hideNavElementsAndQuestions(); + document.currentQuestion = 0; + showQuestion('q0'); + setButtonVisiblity('next', true); + setButtonVisiblity('back', true); + setNextButtonAvailability(); + }); + // Load saved form state /* loadFormState(formElements); @@ -76,24 +88,32 @@ function setNextButtonAvailability() { const submitButton = document.getElementById('submit'); // check if any input in the current question is checked, or filled in case it is a text input let nextEnabled = false; - const inputs = currentQuestion.querySelectorAll('input, select, textarea'); - for (let input of inputs) { - // if the input is not visible, skip it - if (input.checkVisibility() === false) { - continue; + if (document.currentQuestion === 0) { + const name = document.getElementById('name'); + const email = document.getElementById('email'); + if (name && email && name.value.trim() && email.value.trim()) { + nextEnabled = true; } - if (input.type === 'checkbox' || input.type === 'radio') { - if (input.checked) { - nextEnabled = true; - break; + } else { + const inputs = currentQuestion.querySelectorAll('input, select, textarea'); + for (let input of inputs) { + if (input.checkVisibility() === false){ + continue; } - } else { - if (input.value) { - nextEnabled = true; - break; + if (input.type === 'checkbox' || input.type === 'radio') { + if (input.checked) { + nextEnabled = true; + break; + } + } else { + if (input.value) { + nextEnabled = true; + break; + } } } } + nextButton.disabled = !nextEnabled; submitButton.disabled = !nextEnabled; } diff --git a/backend/core/templates/signup.html b/backend/core/templates/signup.html index 946d712..5a5b334 100644 --- a/backend/core/templates/signup.html +++ b/backend/core/templates/signup.html @@ -9,55 +9,57 @@