Skip to content

Commit

Permalink
Auto-start a particular project (#1640)
Browse files Browse the repository at this point in the history
* [WIP] Auto-start a particular project

Enable the auto-starting of a particular project, e.g.,
start a project without having to visit the compliance app
store.

Eventually, start a project and launch the first question.

* Rename auto start app variables

* Finish project auto start, auto start question, redirect actions

Complete work on automatically starting a project defined in
by a System Setting.

Allow the auto start system setting to define the project template
(e.g. compliance app) to use and even the module to automatically
start.

Also add new question actions to redirect to project page
or project component after answering a question.

TO DO:
- Add error handling (e.g., missing/incorrect project)
- Add tests

* Bump VERSION

Co-authored-by: Greg Elin <Greg Elin>
Co-authored-by: Greg Elin <greg.elin@govready.com>
  • Loading branch information
gregelin and govreadydeploy committed Aug 8, 2021
1 parent 878e328 commit 72a8846
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 10 deletions.
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
GovReady-Q Release Notes
========================

v0.9.8-dev (August xx, 2021)
----------------------------

**Developer changes**

* Support autostart of a project, taking user to first question of a project when starting a new project.


v0.9.7 (August 06, 2021)
------------------------
Expand Down Expand Up @@ -36,6 +43,7 @@ v0.9.6 (July 15, 2021)
* Added a Select/Deselect button for component comparison choice.
* Add accordion to assessment page to provide information on getting data from Wazuh.
* Add form to Assessments page to collect Wazuh information.
* Support auto start of project via global System Setting.

**Bug fixes**

Expand All @@ -46,13 +54,15 @@ v0.9.6 (July 15, 2021)
* Add custom Django command to batch import legacy control implementation statements from legacy SSPs Excel spreadsheet exports. Currently supports CSAM.
* Added missing unit test for portfolio project endpoint.
* Add `sec_srvc.SecurityService` class to represent a security service from which data could be collected.
* Add SystemSettings `auto_start_project` to permit the automatic start of a particular project and automatic start of a question.
* Add questions actions to redirect to project home page or project components.

**Data changes**

* Set all `StatementTypeEnum.<LABEL>.value` to `StatementTypeEnum.<LABEL>.name` in order for relevant label/term to show up in Django database admin interface.
* Create baselines for CMMC catalog.
* Fisma impact level is now represented as Security Sensitivity level following OSCAL's schema.

* Add JSONfield `value` to SystemSettings model to support specific detail values.

v0.9.5 (June 23, 2021)
----------------------
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.9.7
v0.9.8-dev
20 changes: 19 additions & 1 deletion guidedmodules/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,6 @@ def redirect_to():
messages.add_message(request, messages.INFO,
f'I\'ve updated the system and project name.')


# Process element actions
# -----------------------------------
# Only two actions are currently supported:
Expand Down Expand Up @@ -602,6 +601,25 @@ def redirect_to():
messages.add_message(request, messages.INFO,
f'I\'ve deleted "{producer_element.name}" and its {smts_assigned_count} control implementation statements from the system.')

# Process project actions
# -----------------------------------
if a_obj == 'project':

# Get all elements assigned role specified in the action
# elements_with_role = Element.objects.filter(element_type="system_element").filter(roles__role=a_filter)

# Add elements matching role to the selected components of a system
if a_verb == "view_project":

if a_filter == "project":
# Redirect to the project's home page.
response = JsonResponse({ "status": "ok", "redirect": project.get_absolute_url() })
return response

if a_filter == "components":
# Redirect to the new project's components.
response = JsonResponse({ "status": "ok", "redirect": f"/systems/{system_id}/components/selected" })
return response

# Form a JSON response to the AJAX request and indicate the
# URL to redirect to, to load the next question.
Expand Down
57 changes: 57 additions & 0 deletions siteapp/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,63 @@ def apps_catalog(request):
# If user is superuser, enable creating new apps
authoring_tool_enabled = request.user.has_perm('guidedmodules.change_module')

# Auto start a project if set in database
# Temporarily pretend values set in development
# TODO: Maybe refactor! This code is close duplicate to what is in `apps_catalog_item` POST section
if "start" in request.GET and request.GET["start"]=="true" and SystemSettings.objects.filter(setting="auto_start_project").exists():
setting_asp = SystemSettings.objects.get(setting="auto_start_project")
if setting_asp.active:
source_slug = setting_asp.details.get('source_slug', None)
app_name = setting_asp.details.get('app_name', None)
module = setting_asp.details.get('module', None)

# can user start the app?
# Is this a module the user has access to? The app store
# does some authz based on the organization.
from guidedmodules.models import AppSource
catalog, _ = filter_app_catalog(get_compliance_apps_catalog_for_user(request.user), request)
for app_catalog_info in catalog:
if app_catalog_info["key"] == source_slug + "/" + app_name:
# We found it.
break
else:
raise Http404()

# Start the most recent version of the app.
appver = app_catalog_info["versions"][0]
from guidedmodules.app_loading import ModuleDefinitionError
organization = Organization.objects.first() # temporary
folder = None
task = None
q = None
# Get portfolio project should be included in.
if request.GET.get("portfolio"):
portfolio = Portfolio.objects.get(id=request.GET.get("portfolio"))
else:
if not request.user.default_portfolio:
request.user.create_default_portfolio_if_missing()
portfolio = request.user.default_portfolio
try:
project = start_app(appver, organization, request.user, folder, task, q, portfolio)
except ModuleDefinitionError as e:
error = str(e)

if module:
# Can the user create a task within this project?
if not project.can_start_task(request.user):
return HttpResponseForbidden()

# Create the new subtask.
question_key = list(project.root_task.get_answers().answertuples)[0]
task = project.root_task.get_or_create_subtask(request.user, question_key)

# Redirect.
url = task.get_absolute_url()
return HttpResponseRedirect(url)

# Redirect to the new project.
return HttpResponseRedirect(project.get_absolute_url())

return render(request, "app-store.html", {
"apps": catalog_by_category,
"filter_description": filter_description,
Expand Down
4 changes: 2 additions & 2 deletions system_settings/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
from .models import SystemSettings, Classification, Sitename

class SystemSettingsAdmin(admin.ModelAdmin):
list_display = ('setting', 'active')
fields = ('setting', 'active')
list_display = ('setting', 'active', 'details')
fields = ('setting', 'active', 'details')

admin.site.register(SystemSettings, SystemSettingsAdmin)

Expand Down
23 changes: 23 additions & 0 deletions system_settings/migrations/0010_auto_20210713_1031.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 3.2.4 on 2021-07-13 10:31

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('system_settings', '0009_sitename'),
]

operations = [
migrations.AddField(
model_name='systemsettings',
name='details',
field=models.JSONField(blank=True, help_text='Value objects of System Setting in JSON', null=True),
),
migrations.AlterField(
model_name='systemsettings',
name='setting',
field=models.CharField(help_text='Name of System Setting', max_length=200, unique=True),
),
]
10 changes: 7 additions & 3 deletions system_settings/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.db import models
from jsonfield import JSONField

# This is just a bare minimum for demo. Needs to be elaborated upon. Classified intentionally left out because it has complicated implications.

Expand All @@ -24,13 +25,12 @@ class Sitename(models.Model):
def __str__(self):
return f'{self.sitename}'


class SystemSettings(models.Model):
"""Model for various system settings for install of GovReady"""

setting = models.CharField(max_length=200, unique=True)
setting = models.CharField(max_length=200, unique=True, help_text="Name of System Setting")
active = models.BooleanField(default=False)

details = models.JSONField(blank=True, null=True, help_text="Value objects of System Setting in JSON")

def __str__(self):
return self.setting
Expand All @@ -50,3 +50,7 @@ def enable_experimental_oscal(cls):
@classmethod
def enable_experimental_evidence(cls):
return cls.objects.get(setting="enable_experimental_evidence").active

@classmethod
def enable_auto_start_project(cls):
return cls.objects.get(setting="auto_start_project").active
2 changes: 1 addition & 1 deletion templates/navbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<span class="glyphicon glyphicon-plus"></span>
</a>
<ul class="dropdown-menu">
<li><a id="" href="{% url 'store' %}">Start a new project&hellip;</a></li>
<li><a id="" href="{% url 'store' %}?start=true">Start a new project&hellip;</a></li>
<li class="dropdown-item-text small text-muted nav-dropdown-item-text">Begin a project from the assessment library. You will be able to choose any available assessment.
</li>
<li><a href="/portfolios/new" id="">Create a portfolio&hellip;</a></li>
Expand Down
2 changes: 1 addition & 1 deletion templates/projects.html
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
<div class="container">

<div class="project-main">
<a id="new-project" href="{% url 'store' %}" class=" btn btn-success">Start a project</a>
<a id="new-project" href="{% url 'store' %}?start=true" class=" btn btn-success">Start a project</a>
</div>

<h2 class="">Projects</h2>
Expand Down

0 comments on commit 72a8846

Please sign in to comment.