Compare commits
34 Commits
1.1.0
...
8d071c68df
Author | SHA1 | Date | |
---|---|---|---|
8d071c68df | |||
3b1691ff62 | |||
a77c43d213 | |||
086959b431 | |||
3f117f9d83 | |||
6a23845a4f | |||
b9c6d04e04 | |||
32c0027ecf | |||
dae52e8646 | |||
890a5651a0 | |||
4cb37f8347 | |||
a2010b9517 | |||
c95736ce14 | |||
b46c61954c | |||
afe4266600 | |||
0c8d1c8da1 | |||
eac998b5cc | |||
5914782252 | |||
73d875c4ac | |||
8f439f0675 | |||
0f102c6aaf | |||
4852c6caeb | |||
3fffba2eba | |||
a1293984ea | |||
4876db50c1 | |||
425cc066af | |||
1086f517fa | |||
2fdbf87ddd | |||
86228836c7 | |||
a6e6c948a5 | |||
dcdfa8feb7 | |||
8388d2e695 | |||
29f269050f | |||
93c4fc2009 |
2
.cz.yaml
2
.cz.yaml
@ -17,5 +17,5 @@ commitizen:
|
||||
prerelease_offset: 1
|
||||
tag_format: $version
|
||||
update_changelog_on_bump: false
|
||||
version: 1.1.0
|
||||
version: 1.0.0-b14
|
||||
version_scheme: semver
|
||||
|
11
.github/workflows/ci.yaml
vendored
11
.github/workflows/ci.yaml
vendored
@ -16,17 +16,6 @@ env:
|
||||
jobs:
|
||||
|
||||
|
||||
mkdocs:
|
||||
name: 'MKDocs'
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
statuses: write
|
||||
checks: write
|
||||
actions: write
|
||||
uses: nofusscomputing/action_mkdocs/.github/workflows/reusable_mkdocs.yaml@development
|
||||
|
||||
|
||||
docker:
|
||||
name: 'Docker'
|
||||
uses: nofusscomputing/action_docker/.github/workflows/docker.yaml@development
|
||||
|
82
CHANGELOG.md
82
CHANGELOG.md
@ -1,85 +1,3 @@
|
||||
## 1.1.0 (2024-08-23)
|
||||
|
||||
### feat
|
||||
|
||||
- **itim**: Dont attempt to apply cluster type config if no type specified.
|
||||
- **itim**: Service config rendered as part of cluster config
|
||||
- **itim**: dont force config key, validate when it's required
|
||||
- **itim**: Services assignable to cluster
|
||||
- **itim**: Ability to add configuration to cluster type
|
||||
- **itim**: Ability to add external link to cluster
|
||||
- **itim**: Ability to add and configure Cluster Types
|
||||
- **itim**: Add cluster to history save
|
||||
- **itim**: prevent cluster from setting itself as parent
|
||||
- **itim**: Ability to add and configure cluster
|
||||
- **itam**: Track if device is virtual
|
||||
- **api**: Endpoint to fetch user permissions
|
||||
- **development**: Add function to filter permissions to those used by centurion
|
||||
- **development**: Add new template tag `choice_ids` for string list casting
|
||||
- **development**: Render `model_name_plural` as part of back button
|
||||
- **development**: add to form field `model_name_plural`
|
||||
- **development**: render heading if section included
|
||||
- **base**: create detail view templates
|
||||
- **itam**: Render Service Config with device config
|
||||
- **itam**: Display deployed services for devices
|
||||
- **itim**: Prevent circular service dependencies
|
||||
- **itim**: Port number validation to check for valid port numbers
|
||||
- **itim**: Prevent Service template from being assigned as dependent service
|
||||
- **itim**: Add service template support
|
||||
- **itim**: Ports for service management
|
||||
- **itim**: Service Management
|
||||
- **assistance**: Filter KB articles to target user
|
||||
- **assistance**: Add date picker to date fields for KB articles
|
||||
- **assistance**: Dont display expired articles for "view" users
|
||||
- **base**: add code highlighting to markdown
|
||||
- **assistance**: Categorised Knowledge base articles
|
||||
- **itim**: Add menu entry
|
||||
- **itam**: Ability to add device configuration
|
||||
- **settings**: New model to allow adding templated links to devices and software
|
||||
|
||||
### Fixes
|
||||
|
||||
- **settings**: return the rendering of external links to models
|
||||
- **core**: Ensure when saving history json is correctly formatted
|
||||
- **itim**: Fix name typo in Add Service button
|
||||
- Ensure tenancy models have `Meta.verbose_name_plural` attribute
|
||||
- **base**: Use correct url for back button
|
||||
- **itim**: ensure that the service template config is also rendered as part of device config
|
||||
- **itim**: dont render link if no device
|
||||
- **itim**: Dont show self within service dependencies
|
||||
- **assistance**: Only return distinct values when limiting KB articles
|
||||
|
||||
### Refactoring
|
||||
|
||||
- **itim**: Add Cluster type to index page
|
||||
- **itam**: Knowledge Base now uses details template
|
||||
- **itam**: Device Type now uses details template
|
||||
- **itam**: Operating System now uses details template
|
||||
- **itim**: Service Port now uses details template
|
||||
- **itam**: Device Model now uses details template
|
||||
- **config_management**: Config Groups now uses details template
|
||||
- **itam**: Software Categories now uses details template
|
||||
- **itam**: manufacturer now uses details template
|
||||
- **itam**: software now uses details template
|
||||
- **itam**: device now use details template
|
||||
- **itim**: services now use details template
|
||||
|
||||
### Tests
|
||||
|
||||
- **itim**: Cluster Types unit tests
|
||||
- **itim**: Cluster unit tests
|
||||
- **itam**: Correct Device Type Model permissions test to use "change" view
|
||||
- **itam**: Correct Operating System Model permissions test to use "change" view
|
||||
- **config_management**: Correct Device Model permissions test to use "change" view
|
||||
- **config_management**: Correct Config Group permissions test to use "change" view
|
||||
- **itam**: Correct Software Category permissions test to use "change" view
|
||||
- **core**: Correct manufacturer permissions test to use "change" view
|
||||
- **itam**: Correct software permissions test to use "change" view
|
||||
- **model**: test for checking if Meta sub-class has variable verbose_name_plural
|
||||
- **external_link**: add tests
|
||||
|
||||
## 1.0.0 (2024-08-23)
|
||||
|
||||
## 1.0.0-b14 (2024-08-12)
|
||||
|
||||
### Fixes
|
||||
|
@ -1,13 +1,13 @@
|
||||
from django import forms
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.db.models import Q
|
||||
from django.forms import inlineformset_factory
|
||||
|
||||
from app import settings
|
||||
|
||||
from .team_users import TeamUsersForm, TeamUsers
|
||||
|
||||
from access.models import Team
|
||||
from access.functions import permissions
|
||||
|
||||
from app import settings
|
||||
|
||||
from core.forms.common import CommonModelForm
|
||||
|
||||
@ -66,4 +66,38 @@ class TeamForm(CommonModelForm):
|
||||
|
||||
self.fields['permissions'].widget.attrs = {'style': "height: 200px;"}
|
||||
|
||||
self.fields['permissions'].queryset = permissions.permission_queryset()
|
||||
apps = [
|
||||
'access',
|
||||
'assistance',
|
||||
'config_management',
|
||||
'core',
|
||||
'django_celery_results',
|
||||
'itam',
|
||||
'settings',
|
||||
]
|
||||
|
||||
exclude_models = [
|
||||
'appsettings',
|
||||
'chordcounter',
|
||||
'groupresult',
|
||||
'organization'
|
||||
'settings',
|
||||
'usersettings',
|
||||
]
|
||||
|
||||
exclude_permissions = [
|
||||
'add_organization',
|
||||
'add_taskresult',
|
||||
'change_organization',
|
||||
'change_taskresult',
|
||||
'delete_organization',
|
||||
'delete_taskresult',
|
||||
]
|
||||
|
||||
self.fields['permissions'].queryset = Permission.objects.filter(
|
||||
content_type__app_label__in=apps,
|
||||
).exclude(
|
||||
content_type__model__in=exclude_models
|
||||
).exclude(
|
||||
codename__in = exclude_permissions
|
||||
)
|
||||
|
@ -1,45 +0,0 @@
|
||||
from django.contrib.auth.models import Permission
|
||||
|
||||
def permission_queryset():
|
||||
"""Filter Permissions to those used within the application
|
||||
|
||||
Returns:
|
||||
list: Filtered queryset that only contains the used permissions
|
||||
"""
|
||||
|
||||
apps = [
|
||||
'access',
|
||||
'assistance',
|
||||
'config_management',
|
||||
'core',
|
||||
'django_celery_results',
|
||||
'itam',
|
||||
'itim',
|
||||
'settings',
|
||||
]
|
||||
|
||||
exclude_models = [
|
||||
'appsettings',
|
||||
'chordcounter',
|
||||
'groupresult',
|
||||
'organization'
|
||||
'settings',
|
||||
'usersettings',
|
||||
]
|
||||
|
||||
exclude_permissions = [
|
||||
'add_organization',
|
||||
'add_taskresult',
|
||||
'change_organization',
|
||||
'change_taskresult',
|
||||
'delete_organization',
|
||||
'delete_taskresult',
|
||||
]
|
||||
|
||||
return Permission.objects.filter(
|
||||
content_type__app_label__in=apps,
|
||||
).exclude(
|
||||
content_type__model__in=exclude_models
|
||||
).exclude(
|
||||
codename__in = exclude_permissions
|
||||
)
|
@ -5,9 +5,6 @@ from rest_framework.urlpatterns import format_suffix_patterns
|
||||
|
||||
from .views import access, config, index
|
||||
|
||||
from api.views.settings import permissions
|
||||
from api.views.settings import index as settings
|
||||
|
||||
from .views.itam import software, config as itam_config
|
||||
from .views.itam.device import DeviceViewSet
|
||||
from .views.itam import inventory
|
||||
@ -39,9 +36,6 @@ urlpatterns = [
|
||||
path("organization/<int:organization_id>/team/<int:group_ptr_id>/permissions", access.TeamPermissionDetail.as_view(), name='_api_team_permission'),
|
||||
path("organization/team/", access.TeamList.as_view(), name='_api_teams'),
|
||||
|
||||
path("settings", settings.View.as_view(), name='_settings'),
|
||||
path("settings/permissions", permissions.View.as_view(), name='_settings_permissions'),
|
||||
|
||||
]
|
||||
|
||||
urlpatterns = format_suffix_patterns(urlpatterns)
|
||||
|
@ -1,20 +1,15 @@
|
||||
# from django.contrib.auth.mixins import PermissionRequiredMixin, LoginRequiredMixin
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from rest_framework import generics, permissions, routers, viewsets
|
||||
from rest_framework.decorators import api_view
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.reverse import reverse
|
||||
|
||||
|
||||
|
||||
class Index(viewsets.ViewSet):
|
||||
|
||||
permission_classes = [
|
||||
IsAuthenticated,
|
||||
]
|
||||
|
||||
# permission_required = 'access.view_organization'
|
||||
|
||||
def get_view_name(self):
|
||||
return "API Index"
|
||||
@ -34,7 +29,6 @@ class Index(viewsets.ViewSet):
|
||||
"devices": reverse("API:device-list", request=request),
|
||||
"config_groups": reverse("API:_api_config_groups", request=request),
|
||||
"organizations": reverse("API:_api_orgs", request=request),
|
||||
"settings": reverse('API:_settings', request=request),
|
||||
"software": reverse("API:software-list", request=request),
|
||||
}
|
||||
)
|
||||
|
@ -1,47 +0,0 @@
|
||||
from django.contrib.auth.models import Permission
|
||||
|
||||
from drf_spectacular.utils import extend_schema, OpenApiResponse
|
||||
|
||||
from rest_framework import views
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.reverse import reverse
|
||||
|
||||
from core.http.common import Http
|
||||
|
||||
|
||||
|
||||
class View(views.APIView):
|
||||
|
||||
permission_classes = [
|
||||
IsAuthenticated,
|
||||
]
|
||||
|
||||
|
||||
@extend_schema(
|
||||
summary = "Settings Index Page",
|
||||
description = """This endpoint provides the available settings as available via the API.
|
||||
""",
|
||||
|
||||
methods=["GET"],
|
||||
parameters = None,
|
||||
tags = ['settings',],
|
||||
responses = {
|
||||
200: OpenApiResponse(description='Inventory upload successful'),
|
||||
401: OpenApiResponse(description='User Not logged in'),
|
||||
500: OpenApiResponse(description='Exception occured. View server logs for the Stack Trace'),
|
||||
}
|
||||
)
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
||||
status = Http.Status.OK
|
||||
|
||||
response_data: dict = {
|
||||
"permissions": reverse('API:_settings_permissions', request=request)
|
||||
}
|
||||
|
||||
return Response(data=response_data,status=status)
|
||||
|
||||
|
||||
def get_view_name(self):
|
||||
return "Settings"
|
@ -1,67 +0,0 @@
|
||||
from drf_spectacular.utils import extend_schema, OpenApiResponse
|
||||
|
||||
from rest_framework import views
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
|
||||
from access.functions import permissions
|
||||
|
||||
from core.http.common import Http
|
||||
|
||||
|
||||
|
||||
class View(views.APIView):
|
||||
|
||||
permission_classes = [
|
||||
IsAuthenticated,
|
||||
]
|
||||
|
||||
|
||||
@extend_schema(
|
||||
summary = "Fetch available permissions",
|
||||
description = """This endpoint provides a list of permissions that are available within
|
||||
Centurion ERP. The format of each permission is `<app name>.<permission>_<model>`.
|
||||
|
||||
This endpoint is available to **all** authenticated users.
|
||||
""",
|
||||
|
||||
methods=["GET"],
|
||||
parameters = None,
|
||||
tags = ['settings',],
|
||||
responses = {
|
||||
200: OpenApiResponse(description='Inventory upload successful'),
|
||||
401: OpenApiResponse(description='User Not logged in'),
|
||||
500: OpenApiResponse(description='Exception occured. View server logs for the Stack Trace'),
|
||||
}
|
||||
)
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
||||
status = Http.Status.OK
|
||||
|
||||
response_data: list = []
|
||||
|
||||
try:
|
||||
|
||||
for permission in permissions.permission_queryset():
|
||||
|
||||
response_data += [ str(f"{permission.content_type.app_label}.{permission.codename}") ]
|
||||
|
||||
except PermissionDenied as e:
|
||||
|
||||
status = Http.Status.FORBIDDEN
|
||||
response_data = ''
|
||||
|
||||
|
||||
except Exception as e:
|
||||
|
||||
print(f'An error occured{e}')
|
||||
|
||||
status = Http.Status.SERVER_ERROR
|
||||
response_data = 'Unknown Server Error occured'
|
||||
|
||||
|
||||
return Response(data=response_data,status=status)
|
||||
|
||||
|
||||
def get_view_name(self):
|
||||
return "Permissions"
|
@ -1,8 +1,6 @@
|
||||
import importlib
|
||||
import pytest
|
||||
import unittest
|
||||
|
||||
|
||||
from access.models import TenancyObject
|
||||
from access.tests.abstract.tenancy_object import TenancyObject as TenancyObjectTestCases
|
||||
|
||||
@ -42,40 +40,6 @@ class TenancyModel(
|
||||
""" Model to test """
|
||||
|
||||
|
||||
def test_field_exists_verbose_name_plural(self):
|
||||
"""Test for existance of field in `<model>.Meta`
|
||||
|
||||
Field is required for `templates/detail.html.js`
|
||||
|
||||
Attribute `verbose_name_plural` must be defined in `Meta` class.
|
||||
"""
|
||||
|
||||
assert 'verbose_name_plural' in self.model._meta.original_attrs
|
||||
|
||||
|
||||
def test_field_not_empty_verbose_name_plural(self):
|
||||
"""Test field `<model>.Meta` is not empty
|
||||
|
||||
Field is required for `templates/detail.html.js`
|
||||
|
||||
Attribute `verbose_name_plural` must be defined in `Meta` class.
|
||||
"""
|
||||
|
||||
assert self.model._meta.original_attrs['verbose_name_plural'] is not None
|
||||
|
||||
|
||||
def test_field_type_verbose_name_plural(self):
|
||||
"""Test field `<model>.Meta` is not empty
|
||||
|
||||
Field is required for `templates/detail.html.js`
|
||||
|
||||
Attribute `verbose_name_plural` must be of type str.
|
||||
"""
|
||||
|
||||
assert type(self.model._meta.original_attrs['verbose_name_plural']) is str
|
||||
|
||||
|
||||
|
||||
|
||||
class ModelAdd(
|
||||
AddView
|
||||
|
@ -1,6 +1,5 @@
|
||||
|
||||
from django import forms
|
||||
from django.urls import reverse
|
||||
from django.forms import ValidationError
|
||||
|
||||
from app import settings
|
||||
@ -64,84 +63,3 @@ class KnowledgeBaseForm(CommonModelForm):
|
||||
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
|
||||
class DetailForm(KnowledgeBaseForm):
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'title',
|
||||
'category',
|
||||
'responsible_user',
|
||||
'organization',
|
||||
'is_global',
|
||||
'c_created',
|
||||
'c_modified',
|
||||
],
|
||||
"right": [
|
||||
'release_date',
|
||||
'expiry_date',
|
||||
'target_user',
|
||||
'target_team',
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "single",
|
||||
"name": "Summary",
|
||||
"fields": [
|
||||
'summary',
|
||||
],
|
||||
"markdown": [
|
||||
'summary',
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "single",
|
||||
"name": "Content",
|
||||
"fields": [
|
||||
'content',
|
||||
],
|
||||
"markdown": [
|
||||
'content',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"notes": {
|
||||
"name": "Notes",
|
||||
"slug": "notes",
|
||||
"sections": []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('Assistance:_knowledge_base_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('Assistance:Knowledge Base')
|
||||
|
@ -1,40 +1,232 @@
|
||||
{% extends 'detail.html.j2' %}
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% block tabs %}
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<div id="details" class="content-tab">
|
||||
<script>
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
function openCity(evt, cityName) {
|
||||
var i, tabcontent, tablinks;
|
||||
|
||||
tabcontent = document.getElementsByClassName("tabcontent");
|
||||
for (i = 0; i < tabcontent.length; i++) {
|
||||
tabcontent[i].style.display = "none";
|
||||
}
|
||||
|
||||
tablinks = document.getElementsByClassName("tablinks");
|
||||
for (i = 0; i < tablinks.length; i++) {
|
||||
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||
}
|
||||
|
||||
document.getElementById(cityName).style.display = "block";
|
||||
evt.currentTarget.className += " active";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
.detail-view-field {
|
||||
display:unset;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0px 20px 40px 20px;
|
||||
|
||||
}
|
||||
|
||||
.detail-view-field label {
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
width: 200px;
|
||||
margin: 10px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
}
|
||||
|
||||
.detail-view-field span {
|
||||
display: inline-block;
|
||||
width: 340px;
|
||||
margin: 10px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
}
|
||||
|
||||
pre {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
</style>
|
||||
<div class="tab">
|
||||
<button
|
||||
onclick="window.location='{% url 'Assistance:Knowledge Base' %}';"
|
||||
style="vertical-align: middle; padding: auto; margin: 0px">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="25px" viewBox="0 -960 960 960" width="25px"
|
||||
style="vertical-align: middle; margin: 0px; padding: 0px border: none; " fill="#6a6e73">
|
||||
<path
|
||||
d="m313-480 155 156q11 11 11.5 27.5T468-268q-11 11-28 11t-28-11L228-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T468-692q11 11 11 28t-11 28L313-480Zm264 0 155 156q11 11 11.5 27.5T732-268q-11 11-28 11t-28-11L492-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T732-692q11 11 11 28t-11 28L577-480Z" />
|
||||
</svg>Back to Articles</button>
|
||||
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Details')">Details</button>
|
||||
{% if perms.assistance.change_knowledgebase %}
|
||||
<button class="tablinks" onclick="openCity(event, 'Notes')">Notes</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<div id="Details" class="tabcontent">
|
||||
{% if perms.assistance.change_knowledgebase %}
|
||||
<h3>Details</h3>
|
||||
|
||||
{% csrf_token %}
|
||||
|
||||
|
||||
<div style="align-items:flex-start; align-content: center; display: flexbox; width: 100%">
|
||||
|
||||
<div style="display: inline; width: 40%; margin: 30px;">
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.title.label }}</label>
|
||||
<span>{{ form.title.value }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.category.label }}</label>
|
||||
<span>
|
||||
{% if kb.category %}
|
||||
<a href="{% url 'Settings:_knowledge_base_category_view' kb.category.id %}">{{ kb.category }}</a>
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.responsible_user.label }}</label>
|
||||
<span>
|
||||
{% if form.responsible_user.value %}
|
||||
{{ kb.responsible_user }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.organization.label }}</label>
|
||||
<span>
|
||||
{% if form.organization.value %}
|
||||
{{ kb.organization }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
{% if perms.assistance.change_knowledgebase %}
|
||||
<div id="notes" class="content-tab">
|
||||
</div>
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.notes %}
|
||||
<div style="display: inline; width: 40%; margin: 30px; text-align: left;">
|
||||
|
||||
{{ notes_form }}
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.release_date.label }}</label>
|
||||
<span>
|
||||
{% if form.release_date.value %}
|
||||
{{ form.release_date.value }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<input type="submit" name="{{notes_form.prefix}}" value="Submit" />
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.expiry_date.label }}</label>
|
||||
<span>
|
||||
{% if form.expiry_date.value %}
|
||||
{{ form.expiry_date.value }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="comments">
|
||||
{% if notes %}
|
||||
{% for note in notes%}
|
||||
{% include 'note.html.j2' %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.target_user.label }}</label>
|
||||
<span>
|
||||
{% if form.target_user.value %}
|
||||
{{ kb.target_user }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.target_team.label }}</label>
|
||||
<span>
|
||||
{% if form.target_team.value %}
|
||||
{{ form.target_team.value }} {{ kb.target_team }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<input type="button" value="Edit" onclick="window.location='{% url 'Assistance:_knowledge_base_change' kb.id %}';">
|
||||
{% endif %}
|
||||
|
||||
{% if form.summary.value %}
|
||||
<div style="display: block; width: 100%;">
|
||||
<h3>Summary</h3>
|
||||
{{ form.summary.value | safe }}
|
||||
<br>
|
||||
<hr />
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div style="display: block; width: 100%;">
|
||||
<h3>Content</h3>
|
||||
<hr />
|
||||
<br>
|
||||
{{ form.content.value | markdown | safe }}
|
||||
<br>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<script>
|
||||
document.getElementById("defaultOpen").click();
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
{% if perms.assistance.change_knowledgebase %}
|
||||
<div id="Notes" class="tabcontent">
|
||||
<h3>
|
||||
Notes
|
||||
</h3>
|
||||
{{ notes_form }}
|
||||
<input type="submit" name="{{notes_form.prefix}}" value="Submit" />
|
||||
<div class="comments">
|
||||
{% if notes %}
|
||||
{% for note in notes %}
|
||||
{% include 'note.html.j2' %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
@ -7,7 +7,7 @@ from django.utils.decorators import method_decorator
|
||||
|
||||
from access.models import TeamUsers
|
||||
|
||||
from assistance.forms.knowledge_base import DetailForm, KnowledgeBaseForm
|
||||
from assistance.forms.knowledge_base import KnowledgeBaseForm
|
||||
from assistance.models.knowledge_base import KnowledgeBase
|
||||
|
||||
from core.forms.comment import AddNoteForm
|
||||
@ -139,7 +139,7 @@ class View(ChangeView):
|
||||
|
||||
context_object_name = "kb"
|
||||
|
||||
form_class = DetailForm
|
||||
form_class = KnowledgeBaseForm
|
||||
|
||||
model = KnowledgeBase
|
||||
|
||||
@ -168,7 +168,7 @@ class View(ChangeView):
|
||||
return context
|
||||
|
||||
|
||||
# @method_decorator(auth_decorator.permission_required("assistance.change_knowledgebase", raise_exception=True))
|
||||
@method_decorator(auth_decorator.permission_required("assistance.change_knowledgebase", raise_exception=True))
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
item = KnowledgeBase.objects.get(pk=self.kwargs['pk'])
|
||||
|
@ -1,7 +1,4 @@
|
||||
from django import forms
|
||||
from django.urls import reverse
|
||||
|
||||
from app import settings
|
||||
from django.db.models import Q
|
||||
|
||||
from config_management.models.groups import ConfigGroups
|
||||
|
||||
@ -35,89 +32,3 @@ class ConfigGroupForm(CommonModelForm):
|
||||
).exclude(
|
||||
id=int(kwargs['instance'].id)
|
||||
)
|
||||
|
||||
|
||||
|
||||
class DetailForm(ConfigGroupForm):
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'name',
|
||||
'parent',
|
||||
'is_global',
|
||||
'organization',
|
||||
'c_created',
|
||||
'c_modified',
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "single",
|
||||
"fields": [
|
||||
'config',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"child_groups": {
|
||||
"name": "Child Groups",
|
||||
"slug": "child_groups",
|
||||
"sections": []
|
||||
},
|
||||
"hosts": {
|
||||
"name": "Hosts",
|
||||
"slug": "hosts",
|
||||
"sections": []
|
||||
},
|
||||
"software": {
|
||||
"name": "Software",
|
||||
"slug": "software",
|
||||
"sections": []
|
||||
},
|
||||
"configuration": {
|
||||
"name": "Configuration",
|
||||
"slug": "configuration",
|
||||
"sections": []
|
||||
},
|
||||
"notes": {
|
||||
"name": "Notes",
|
||||
"slug": "notes",
|
||||
"sections": []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('Config Management:_group_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('Config Management:Groups')
|
||||
|
||||
|
@ -1,21 +0,0 @@
|
||||
# Generated by Django 5.0.7 on 2024-08-17 08:05
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('config_management', '0002_configgrouphosts_configgroupsoftware'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='configgroups',
|
||||
options={'verbose_name_plural': 'Config Groups'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='configgroupsoftware',
|
||||
options={'ordering': ['-action', 'software'], 'verbose_name_plural': 'Config Group Softwares'},
|
||||
),
|
||||
]
|
@ -35,12 +35,6 @@ class GroupsCommonFields(TenancyObject, models.Model):
|
||||
|
||||
class ConfigGroups(GroupsCommonFields, SaveHistory):
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
verbose_name_plural = 'Config Groups'
|
||||
|
||||
|
||||
reserved_config_keys: list = [
|
||||
'software'
|
||||
]
|
||||
@ -270,8 +264,6 @@ class ConfigGroupSoftware(GroupsCommonFields, SaveHistory):
|
||||
'software'
|
||||
]
|
||||
|
||||
verbose_name_plural = 'Config Group Softwares'
|
||||
|
||||
|
||||
config_group = models.ForeignKey(
|
||||
ConfigGroups,
|
||||
|
@ -1,180 +1,47 @@
|
||||
{% extends 'detail.html.j2' %}
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
{% block content %}
|
||||
|
||||
<script>
|
||||
|
||||
{% block tabs %}
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
function openCity(evt, cityName) {
|
||||
var i, tabcontent, tablinks;
|
||||
|
||||
<div id="details" class="content-tab">
|
||||
tabcontent = document.getElementsByClassName("tabcontent");
|
||||
for (i = 0; i < tabcontent.length; i++) {
|
||||
tabcontent[i].style.display = "none";
|
||||
}
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
tablinks = document.getElementsByClassName("tablinks");
|
||||
for (i = 0; i < tablinks.length; i++) {
|
||||
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||
}
|
||||
|
||||
document.getElementById(cityName).style.display = "block";
|
||||
evt.currentTarget.className += " active";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="tab">
|
||||
<button
|
||||
onclick="window.location='{% if group.parent %}{% url 'Config Management:_group_view' pk=group.parent.id %}{% else %}{% url 'Config Management:Groups' %}{% endif %}';"
|
||||
style="vertical-align: middle; padding: auto; margin: 0px">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="25px" viewBox="0 -960 960 960" width="25px"
|
||||
style="vertical-align: middle; margin: 0px; padding: 0px border: none; " fill="#6a6e73">
|
||||
<path
|
||||
d="m313-480 155 156q11 11 11.5 27.5T468-268q-11 11-28 11t-28-11L228-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T468-692q11 11 11 28t-11 28L313-480Zm264 0 155 156q11 11 11.5 27.5T732-268q-11 11-28 11t-28-11L492-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T732-692q11 11 11 28t-11 28L577-480Z" />
|
||||
</svg>Back to {% if group.parent %}Parent{% else %}Groups{% endif %}</button>
|
||||
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Details')">Details</button>
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Children')">Child Groups</button>
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Hosts')">Hosts</button>
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Software')">Software</button>
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Configuration')">Configuration</button>
|
||||
<button class="tablinks" onclick="openCity(event, 'Notes')">Notes</button>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="child_groups" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.child_groups %}
|
||||
|
||||
<input type="button" value="Add Child Group" onclick="window.location='{% url 'Config Management:_group_add_child' group.id %}';">
|
||||
|
||||
<table class="data">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Sub-Groups</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
{% if child_groups %}
|
||||
{% for group in child_groups %}
|
||||
<tr>
|
||||
<td><a href="{% url 'Config Management:_group_view' pk=group.id %}">{{ group.name }}</a></td>
|
||||
<td>{{ group.count_children }}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4">Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="hosts" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.hosts %}
|
||||
|
||||
<input type="button" value="Add Host" onclick="window.location='{% url 'Config Management:_group_add_host' group.id %}';">
|
||||
|
||||
<table class="data">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Organization</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
{% if config_group_hosts %}
|
||||
{% for host in config_group_hosts %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_device_view' pk=host.host.id %}">{{ host.host }}</a></td>
|
||||
<td>{{ host.host.organization }}</td>
|
||||
<td><a href="{% url 'Config Management:_group_delete_host' group_id=group.id pk=host.id %}">Delete</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="3">Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="software" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.software %}
|
||||
|
||||
<input type="button" value="Add Software Action" onclick="window.location='{% url 'Config Management:_group_software_add' model_pk %}';">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Category</th>
|
||||
<th>Action</th>
|
||||
<th>Desired Version</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
{% if softwares %}
|
||||
{% for software in softwares %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_software_view' pk=software.software_id %}">{{ software.software }}</a></td>
|
||||
<td>{{ software.software.category }}</td>
|
||||
<td>
|
||||
{% url 'Config Management:_group_software_change' group_id=group.id pk=software.id as icon_link %}
|
||||
{% if software.get_action_display == 'Install' %}
|
||||
{% include 'icons/success_text.html.j2' with icon_text=software.get_action_display icon_link=icon_link %}
|
||||
{% elif software.get_action_display == 'Remove'%}
|
||||
{% include 'icons/cross_text.html.j2' with icon_text=software.get_action_display %}
|
||||
{% else %}
|
||||
{% include 'icons/add_link.html.j2' with icon_text='Add' %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if software.version %}
|
||||
{{ software.version }}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<td colspan="5">Nothing Found</td>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="configuration" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.configuration %}
|
||||
|
||||
<div>
|
||||
<textarea cols="90" rows="30" readonly>{{ config }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="notes" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.notes %}
|
||||
|
||||
{{ notes_form }}
|
||||
<input type="submit" name="{{notes_form.prefix}}" value="Submit" />
|
||||
<div class="comments">
|
||||
{% if notes %}
|
||||
{% for note in notes%}
|
||||
{% include 'note.html.j2' %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% block contents %}
|
||||
|
||||
|
||||
<form method="post">
|
||||
<div id="Details" class="tabcontent">
|
||||
<h3>Details</h3>
|
||||
@ -193,6 +60,28 @@
|
||||
<div id="Children" class="tabcontent">
|
||||
<h3>Child Groups</h3>
|
||||
|
||||
<input type="button" value="Add Child Group" onclick="window.location='{% url 'Config Management:_group_add_child' group.id %}';">
|
||||
|
||||
<table class="data">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Sub-Groups</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
{% if child_groups %}
|
||||
{% for group in child_groups %}
|
||||
<tr>
|
||||
<td><a href="{% url 'Config Management:_group_view' pk=group.id %}">{{ group.name }}</a></td>
|
||||
<td>{{ group.count_children }}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4">Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
@ -201,6 +90,28 @@
|
||||
Hosts
|
||||
</h3>
|
||||
|
||||
<input type="button" value="Add Host" onclick="window.location='{% url 'Config Management:_group_add_host' group.id %}';">
|
||||
|
||||
<table class="data">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Organization</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
{% if config_group_hosts %}
|
||||
{% for host in config_group_hosts %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_device_view' pk=host.host.id %}">{{ host.host }}</a></td>
|
||||
<td>{{ host.host.organization }}</td>
|
||||
<td><a href="{% url 'Config Management:_group_delete_host' group_id=group.id pk=host.id %}">Delete</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="3">Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
@ -209,11 +120,52 @@
|
||||
Software
|
||||
</h3>
|
||||
|
||||
<input type="button" value="Add Software Action" onclick="window.location='{% url 'Config Management:_group_software_add' model_pk %}';">
|
||||
<table>
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Category</th>
|
||||
<th>Action</th>
|
||||
<th>Desired Version</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
{% if softwares %}
|
||||
{% for software in softwares %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_software_view' pk=software.software_id %}">{{ software.software }}</a></td>
|
||||
<td>{{ software.software.category }}</td>
|
||||
<td>
|
||||
{% url 'Config Management:_group_software_change' group_id=group.id pk=software.id as icon_link %}
|
||||
{% if software.get_action_display == 'Install' %}
|
||||
{% include 'icons/success_text.html.j2' with icon_text=software.get_action_display icon_link=icon_link %}
|
||||
{% elif software.get_action_display == 'Remove'%}
|
||||
{% include 'icons/cross_text.html.j2' with icon_text=software.get_action_display %}
|
||||
{% else %}
|
||||
{% include 'icons/add_link.html.j2' with icon_text='Add' %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if software.version %}
|
||||
{{ software.version }}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<td colspan="5">Nothing Found</td>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="Configuration" class="tabcontent">
|
||||
<h3>Configuration</h3>
|
||||
|
||||
<div>
|
||||
<textarea cols="90" rows="30" readonly>{{ config }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="Notes" class="tabcontent">
|
||||
|
@ -27,7 +27,7 @@ class ConfigGroupPermissions(TestCase, ModelPermissions):
|
||||
|
||||
url_name_add = '_group_add'
|
||||
|
||||
url_name_change = '_group_change'
|
||||
url_name_change = '_group_view'
|
||||
|
||||
url_name_delete = '_group_delete'
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django.urls import path
|
||||
|
||||
from config_management.views.groups.groups import GroupIndexView, GroupAdd, GroupChange, GroupDelete, GroupView, GroupHostAdd, GroupHostDelete
|
||||
from config_management.views.groups.groups import GroupIndexView, GroupAdd, GroupDelete, GroupView, GroupHostAdd, GroupHostDelete
|
||||
from config_management.views.groups.software import GroupSoftwareAdd, GroupSoftwareChange, GroupSoftwareDelete
|
||||
|
||||
app_name = "Config Management"
|
||||
@ -9,7 +9,6 @@ urlpatterns = [
|
||||
path('group', GroupIndexView.as_view(), name='Groups'),
|
||||
path('group/add', GroupAdd.as_view(), name='_group_add'),
|
||||
path('group/<int:pk>', GroupView.as_view(), name='_group_view'),
|
||||
path('group/<int:pk>/edit', GroupChange.as_view(), name='_group_change'),
|
||||
|
||||
path('group/<int:pk>/child', GroupAdd.as_view(), name='_group_add_child'),
|
||||
path('group/<int:pk>/delete', GroupDelete.as_view(), name='_group_delete'),
|
||||
|
@ -13,7 +13,7 @@ from itam.models.device import Device
|
||||
from settings.models.user_settings import UserSettings
|
||||
|
||||
from config_management.forms.group_hosts import ConfigGroupHostsForm
|
||||
from config_management.forms.group.group import ConfigGroupForm, DetailForm
|
||||
from config_management.forms.group.group import ConfigGroupForm
|
||||
from config_management.models.groups import ConfigGroups, ConfigGroupHosts, ConfigGroupSoftware
|
||||
|
||||
|
||||
@ -102,7 +102,7 @@ class GroupAdd(AddView):
|
||||
|
||||
|
||||
|
||||
class GroupChange(ChangeView):
|
||||
class GroupView(ChangeView):
|
||||
|
||||
context_object_name = "group"
|
||||
|
||||
@ -110,38 +110,9 @@ class GroupChange(ChangeView):
|
||||
|
||||
model = ConfigGroups
|
||||
|
||||
permission_required = [
|
||||
'config_management.change_configgroups',
|
||||
]
|
||||
|
||||
template_name = 'form.html.j2'
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = self.object.name
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('Config Management:_group_view', args=(self.kwargs['pk'],))
|
||||
|
||||
|
||||
|
||||
class GroupView(ChangeView):
|
||||
|
||||
context_object_name = "group"
|
||||
|
||||
form_class = DetailForm
|
||||
|
||||
model = ConfigGroups
|
||||
|
||||
permission_required = [
|
||||
'config_management.view_configgroups',
|
||||
'config_management.change_configgroups',
|
||||
]
|
||||
|
||||
template_name = 'config_management/group.html.j2'
|
||||
|
@ -98,7 +98,3 @@ class CommonModelForm(forms.ModelForm):
|
||||
|
|
||||
Q(manager=user)
|
||||
)
|
||||
|
||||
if hasattr(self, 'instance'):
|
||||
|
||||
self.model_name_plural = self.instance._meta.verbose_name_plural
|
||||
|
@ -1,7 +1,4 @@
|
||||
from django import forms
|
||||
from django.urls import reverse
|
||||
|
||||
from app import settings
|
||||
|
||||
from core.forms.common import CommonModelForm
|
||||
from core.models.manufacturer import Manufacturer
|
||||
@ -27,64 +24,3 @@ class ManufacturerForm(
|
||||
]
|
||||
|
||||
model = Manufacturer
|
||||
|
||||
|
||||
|
||||
class DetailForm(ManufacturerForm):
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'name',
|
||||
'slug',
|
||||
'organization',
|
||||
'is_global',
|
||||
'c_created',
|
||||
'c_modified',
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
# "notes": {
|
||||
# "name": "Notes",
|
||||
# "slug": "notes",
|
||||
# "sections": []
|
||||
# }
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('Settings:_manufacturer_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('Settings:_manufacturers')
|
||||
|
||||
|
||||
|
@ -1,21 +0,0 @@
|
||||
# Generated by Django 5.0.7 on 2024-08-17 08:05
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0002_notes'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='manufacturer',
|
||||
options={'ordering': ['name'], 'verbose_name_plural': 'Manufacturers'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='notes',
|
||||
options={'ordering': ['-created'], 'verbose_name_plural': 'Notes'},
|
||||
),
|
||||
]
|
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.0.7 on 2024-08-17 08:05
|
||||
# Generated by Django 5.0.7 on 2024-07-21 02:35
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
@ -7,7 +7,7 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0003_alter_manufacturer_options_alter_notes_options'),
|
||||
('core', '0002_notes'),
|
||||
('itim', '0001_initial'),
|
||||
]
|
||||
|
@ -41,18 +41,6 @@ class SaveHistory(models.Model):
|
||||
|
||||
value = bool(before[entry])
|
||||
|
||||
elif (
|
||||
"{" in str(after[entry])
|
||||
and
|
||||
"}" in str(after[entry])
|
||||
) or (
|
||||
"[" in str(after[entry])
|
||||
and
|
||||
"]" in str(after[entry])
|
||||
):
|
||||
|
||||
value = str(after[entry]).replace("'", '\"')
|
||||
|
||||
else:
|
||||
|
||||
value = str(before[entry])
|
||||
@ -74,18 +62,6 @@ class SaveHistory(models.Model):
|
||||
|
||||
value = bool(after[entry])
|
||||
|
||||
elif (
|
||||
"{" in str(after[entry])
|
||||
and
|
||||
"}" in str(after[entry])
|
||||
) or (
|
||||
"[" in str(after[entry])
|
||||
and
|
||||
"]" in str(after[entry])
|
||||
):
|
||||
|
||||
value = str(after[entry]).replace("'", '\"')
|
||||
|
||||
else:
|
||||
|
||||
value = str(after[entry])
|
||||
|
@ -34,9 +34,6 @@ class Manufacturer(TenancyObject, ManufacturerCommonFields, SaveHistory):
|
||||
'name'
|
||||
]
|
||||
|
||||
verbose_name_plural = 'Manufacturers'
|
||||
|
||||
|
||||
name = models.CharField(
|
||||
blank = False,
|
||||
max_length = 50,
|
||||
|
@ -46,9 +46,6 @@ class Notes(NotesCommonFields):
|
||||
'-created'
|
||||
]
|
||||
|
||||
verbose_name_plural = 'Notes'
|
||||
|
||||
|
||||
|
||||
note = models.TextField(
|
||||
verbose_name = 'Note',
|
||||
|
@ -1,34 +0,0 @@
|
||||
{% extends 'detail.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
|
||||
{% block tabs %}
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<div id="details" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="notes" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.notes %}
|
||||
|
||||
{{ notes_form }}
|
||||
<input type="submit" name="{{notes_form.prefix}}" value="Submit" />
|
||||
<div class="comments">
|
||||
{% if notes %}
|
||||
{% for note in notes%}
|
||||
{% include 'note.html.j2' %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
@ -1,64 +0,0 @@
|
||||
from django import template
|
||||
from django.template.defaultfilters import stringfilter
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter()
|
||||
@stringfilter
|
||||
def choice_ids(value):
|
||||
"""Convert choice field value to list
|
||||
|
||||
Provide from `{{ field.field.choices }}` the `field.value` and have it converted to a loop
|
||||
|
||||
Args:
|
||||
value (string): for field that has `field.field.choices`, provide `field.value`
|
||||
|
||||
Returns:
|
||||
list: `field.value` casted to a useable list
|
||||
"""
|
||||
|
||||
if value == 'None':
|
||||
|
||||
return ''
|
||||
|
||||
alist: list = []
|
||||
|
||||
if '[' in value:
|
||||
|
||||
value = str(value).replace('[', '').replace(']', '')
|
||||
|
||||
if ',' in value:
|
||||
|
||||
for item in value.split(','):
|
||||
|
||||
try:
|
||||
|
||||
alist += [ int(item) ]
|
||||
|
||||
except:
|
||||
|
||||
alist += [ str(item) ]
|
||||
|
||||
else:
|
||||
|
||||
try:
|
||||
|
||||
alist += [ int(item) ]
|
||||
|
||||
except:
|
||||
|
||||
alist += [ str(item) ]
|
||||
|
||||
else:
|
||||
|
||||
try:
|
||||
|
||||
alist += [ int(value) ]
|
||||
|
||||
except:
|
||||
|
||||
alist += [ str(value) ]
|
||||
|
||||
return alist
|
@ -26,7 +26,7 @@ class ManufacturerPermissions(TestCase, ModelPermissions):
|
||||
|
||||
url_name_add = '_manufacturer_add'
|
||||
|
||||
url_name_change = '_manufacturer_change'
|
||||
url_name_change = '_manufacturer_view'
|
||||
|
||||
url_name_delete = '_manufacturer_delete'
|
||||
|
||||
|
@ -83,11 +83,7 @@ class ChangeView(View, generic.UpdateView):
|
||||
context['open_tab'] = None
|
||||
|
||||
|
||||
if self.model._meta.model_name == 'cluster':
|
||||
|
||||
external_links_query = ExternalLink.objects.filter(cluster=True)
|
||||
|
||||
elif self.model._meta.model_name == 'device':
|
||||
if self.model._meta.model_name == 'device':
|
||||
|
||||
external_links_query = ExternalLink.objects.filter(devices=True)
|
||||
|
||||
|
@ -47,18 +47,6 @@ class View(OrganizationPermission, generic.View):
|
||||
|
||||
match self.kwargs['model_name']:
|
||||
|
||||
case 'cluster':
|
||||
|
||||
from itim.models.clusters import Cluster
|
||||
|
||||
self.model = Cluster
|
||||
|
||||
case 'clustertype':
|
||||
|
||||
from itim.models.clusters import ClusterType
|
||||
|
||||
self.model = ClusterType
|
||||
|
||||
case 'configgroups':
|
||||
|
||||
self.model = ConfigGroups
|
||||
|
@ -1,5 +1,5 @@
|
||||
from django import forms
|
||||
from django.urls import reverse
|
||||
from django.db.models import Q
|
||||
|
||||
from app import settings
|
||||
|
||||
@ -22,78 +22,16 @@ class DeviceForm(CommonModelForm):
|
||||
'uuid',
|
||||
'device_type',
|
||||
'organization',
|
||||
'is_virtual',
|
||||
'model_notes',
|
||||
'config',
|
||||
]
|
||||
|
||||
|
||||
|
||||
class DetailForm(DeviceForm):
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'name',
|
||||
'device_model',
|
||||
'serial_number',
|
||||
'uuid',
|
||||
'device_type',
|
||||
'organization',
|
||||
'c_created',
|
||||
'c_modified',
|
||||
'lastinventory',
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
'is_virtual',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"software": {
|
||||
"name": "Software",
|
||||
"slug": "software",
|
||||
"sections": []
|
||||
},
|
||||
"notes": {
|
||||
"name": "Notes",
|
||||
"slug": "notes",
|
||||
"sections": []
|
||||
},
|
||||
"config_management": {
|
||||
"name": "Config Management",
|
||||
"slug": "config_management",
|
||||
"sections": []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
self.fields['lastinventory'] = forms.DateTimeField(
|
||||
if hasattr(kwargs['instance'], 'inventorydate'):
|
||||
self.fields['lastinventory'] = forms.DateTimeField(
|
||||
label="Last Inventory Date",
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
initial=kwargs['instance'].inventorydate,
|
||||
@ -101,8 +39,5 @@ class DetailForm(DeviceForm):
|
||||
required=False,
|
||||
)
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('ITAM:_device_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('ITAM:Devices')
|
||||
# for key in self.fields.keys():
|
||||
# self.fields[key].widget.attrs['disabled'] = True
|
||||
|
@ -1,7 +1,4 @@
|
||||
from django import forms
|
||||
from django.urls import reverse
|
||||
|
||||
from app import settings
|
||||
from django.db.models import Q
|
||||
|
||||
from core.forms.common import CommonModelForm
|
||||
|
||||
@ -30,62 +27,3 @@ class DeviceModelForm(
|
||||
]
|
||||
|
||||
model = DeviceModel
|
||||
|
||||
|
||||
|
||||
class DetailForm(DeviceModelForm):
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'name',
|
||||
'slug',
|
||||
'manufacturer',
|
||||
'organization',
|
||||
'is_global',
|
||||
'c_created',
|
||||
'c_modified',
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
# "notes": {
|
||||
# "name": "Notes",
|
||||
# "slug": "notes",
|
||||
# "sections": []
|
||||
# },
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('Settings:_device_model_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('Settings:_device_models')
|
||||
|
@ -1,7 +1,4 @@
|
||||
from django import forms
|
||||
from django.urls import reverse
|
||||
|
||||
from app import settings
|
||||
from django.db.models import Q
|
||||
|
||||
from core.forms.common import CommonModelForm
|
||||
|
||||
@ -29,61 +26,3 @@ class DeviceTypeForm(
|
||||
]
|
||||
|
||||
model = DeviceType
|
||||
|
||||
|
||||
|
||||
class DetailForm(DeviceTypeForm):
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'name',
|
||||
'slug',
|
||||
'organization',
|
||||
'is_global',
|
||||
'c_created',
|
||||
'c_modified',
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
# "notes": {
|
||||
# "name": "Notes",
|
||||
# "slug": "notes",
|
||||
# "sections": []
|
||||
# }
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('Settings:_device_type_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('Settings:_device_types')
|
||||
|
@ -1,5 +1,5 @@
|
||||
from django import forms
|
||||
from django.urls import reverse
|
||||
from django.db.models import Q
|
||||
|
||||
from app import settings
|
||||
|
||||
@ -9,7 +9,7 @@ from itam.models.operating_system import OperatingSystem
|
||||
|
||||
|
||||
|
||||
class OperatingSystemForm(CommonModelForm):
|
||||
class OperatingSystemFormCommon(CommonModelForm):
|
||||
|
||||
class Meta:
|
||||
|
||||
@ -27,99 +27,27 @@ class OperatingSystemForm(CommonModelForm):
|
||||
|
||||
|
||||
|
||||
# class Update(OperatingSystemFormCommon):
|
||||
|
||||
|
||||
# def __init__(self, *args, **kwargs):
|
||||
# super().__init__(*args, **kwargs)
|
||||
|
||||
# self.fields['_created'] = forms.DateTimeField(
|
||||
# label="Created",
|
||||
# input_formats=settings.DATETIME_FORMAT,
|
||||
# initial=kwargs['instance'].created,
|
||||
# disabled=True
|
||||
# )
|
||||
|
||||
# self.fields['_modified'] = forms.DateTimeField(
|
||||
# label="Modified",
|
||||
# input_formats=settings.DATETIME_FORMAT,
|
||||
# initial=kwargs['instance'].modified,
|
||||
# disabled=True
|
||||
# )
|
||||
|
||||
|
||||
# if kwargs['instance'].is_global:
|
||||
|
||||
# self.fields['is_global'].widget.attrs['disabled'] = True
|
||||
|
||||
|
||||
class DetailForm(OperatingSystemForm):
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'name',
|
||||
'publisher',
|
||||
'serial_number',
|
||||
'organization',
|
||||
'c_created',
|
||||
'c_modified',
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"versions": {
|
||||
"name": "Versions",
|
||||
"slug": "versions",
|
||||
"sections": []
|
||||
},
|
||||
"licences": {
|
||||
"name": "Licences",
|
||||
"slug": "licences",
|
||||
"sections": []
|
||||
},
|
||||
"installations": {
|
||||
"name": "Installations",
|
||||
"slug": "installations",
|
||||
"sections": []
|
||||
},
|
||||
"notes": {
|
||||
"name": "Notes",
|
||||
"slug": "notes",
|
||||
"sections": []
|
||||
}
|
||||
}
|
||||
class Update(OperatingSystemFormCommon):
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
self.fields['_created'] = forms.DateTimeField(
|
||||
label="Created",
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
initial=kwargs['instance'].created,
|
||||
disabled=True
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
self.fields['_modified'] = forms.DateTimeField(
|
||||
label="Modified",
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
initial=kwargs['instance'].modified,
|
||||
disabled=True
|
||||
)
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('ITAM:_operating_system_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('ITAM:Operating Systems')
|
||||
if kwargs['instance'].is_global:
|
||||
|
||||
self.fields['is_global'].widget.attrs['disabled'] = True
|
||||
|
@ -1,8 +1,4 @@
|
||||
from django import forms
|
||||
from django.db.models import Q
|
||||
from django.urls import reverse
|
||||
|
||||
from app import settings
|
||||
|
||||
from core.forms.common import CommonModelForm
|
||||
|
||||
@ -15,108 +11,22 @@ class SoftwareForm(CommonModelForm):
|
||||
class Meta:
|
||||
model = Software
|
||||
fields = [
|
||||
'name',
|
||||
"name",
|
||||
'publisher',
|
||||
'slug',
|
||||
'id',
|
||||
'organization',
|
||||
'is_global',
|
||||
'category',
|
||||
'model_notes',
|
||||
]
|
||||
|
||||
|
||||
class SoftwareChange(SoftwareForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if not self.instance.is_global:
|
||||
|
||||
|
||||
self.fields['is_global'] = forms.BooleanField(
|
||||
label = 'Is Global',
|
||||
initial = self.instance.is_global
|
||||
)
|
||||
|
||||
self.fields['organization'] = forms.CharField(
|
||||
label = 'Organization',
|
||||
initial = self.instance.organization
|
||||
)
|
||||
|
||||
|
||||
class DetailForm(SoftwareForm):
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'name',
|
||||
'publisher',
|
||||
'slug',
|
||||
'organization',
|
||||
'is_global',
|
||||
'category',
|
||||
'c_created',
|
||||
'c_modified',
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"versions": {
|
||||
"name": "Versions",
|
||||
"slug": "versions",
|
||||
"sections": []
|
||||
},
|
||||
"licences": {
|
||||
"name": "Licences",
|
||||
"slug": "licences",
|
||||
"sections": []
|
||||
},
|
||||
"notes": {
|
||||
"name": "Notes",
|
||||
"slug": "notes",
|
||||
"sections": []
|
||||
},
|
||||
"installations": {
|
||||
"name": "Installations",
|
||||
"slug": "installations",
|
||||
"sections": []
|
||||
}
|
||||
}
|
||||
class SoftwareFormUpdate(SoftwareForm):
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
self.fields[ 'organization' ] = forms.CharField(
|
||||
label = 'Organization',
|
||||
initial = self.instance.organization
|
||||
)
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('ITAM:_software_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('ITAM:Software')
|
||||
self.fields['is_global'].widget.attrs['disabled'] = True
|
||||
|
@ -1,7 +1,4 @@
|
||||
from django import forms
|
||||
from django.urls import reverse
|
||||
|
||||
from app import settings
|
||||
from django.db.models import Q
|
||||
|
||||
from core.forms.common import CommonModelForm
|
||||
|
||||
@ -28,61 +25,3 @@ class SoftwareCategoryForm(
|
||||
]
|
||||
|
||||
model = SoftwareCategory
|
||||
|
||||
|
||||
|
||||
class DetailForm(SoftwareCategoryForm):
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'name',
|
||||
'slug',
|
||||
'organization',
|
||||
'is_global',
|
||||
'c_created',
|
||||
'c_modified',
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
# "notes": {
|
||||
# "name": "Notes",
|
||||
# "slug": "notes",
|
||||
# "sections": []
|
||||
# },
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('Settings:_software_category_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('Settings:_software_categories')
|
||||
|
@ -1,69 +0,0 @@
|
||||
# Generated by Django 5.0.7 on 2024-08-17 08:05
|
||||
|
||||
import itam.models.device
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('itam', '0002_device_config'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='device',
|
||||
options={'verbose_name_plural': 'Devices'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='devicemodel',
|
||||
options={'ordering': ['manufacturer', 'name'], 'verbose_name_plural': 'Device Models'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='deviceoperatingsystem',
|
||||
options={'verbose_name_plural': 'Device Operating Systems'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='devicesoftware',
|
||||
options={'ordering': ['-action', 'software'], 'verbose_name_plural': 'Device Softwares'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='devicetype',
|
||||
options={'verbose_name_plural': 'Device Types'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='operatingsystem',
|
||||
options={'verbose_name_plural': 'Operating Systems'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='operatingsystemversion',
|
||||
options={'verbose_name_plural': 'Operating System Versions'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='software',
|
||||
options={'verbose_name_plural': 'Softwares'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='softwarecategory',
|
||||
options={'verbose_name_plural': 'Software Categories'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='softwareversion',
|
||||
options={'verbose_name_plural': 'Software Versions'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='is_virtual',
|
||||
field=models.BooleanField(blank=True, default=False, help_text='Is this device a virtual machine', verbose_name='Is Virtual'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='device',
|
||||
name='name',
|
||||
field=models.CharField(max_length=50, unique=True, validators=[itam.models.device.Device.validate_hostname_format]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='device',
|
||||
name='uuid',
|
||||
field=models.CharField(blank=True, default=None, help_text='System GUID/UUID.', max_length=50, null=True, unique=True, validators=[itam.models.device.Device.validate_uuid_format], verbose_name='UUID'),
|
||||
),
|
||||
]
|
@ -25,11 +25,6 @@ from settings.models.app_settings import AppSettings
|
||||
class DeviceType(DeviceCommonFieldsName, SaveHistory):
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
verbose_name_plural = 'Device Types'
|
||||
|
||||
|
||||
def clean(self):
|
||||
|
||||
app_settings = AppSettings.objects.get(owner_organization=None)
|
||||
@ -49,11 +44,6 @@ class DeviceType(DeviceCommonFieldsName, SaveHistory):
|
||||
class Device(DeviceCommonFieldsName, SaveHistory):
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
verbose_name_plural = 'Devices'
|
||||
|
||||
|
||||
reserved_config_keys: list = [
|
||||
'software'
|
||||
]
|
||||
@ -152,15 +142,6 @@ class Device(DeviceCommonFieldsName, SaveHistory):
|
||||
blank = True,
|
||||
)
|
||||
|
||||
is_virtual = models.BooleanField(
|
||||
blank = True,
|
||||
default = False,
|
||||
help_text = 'Is this device a virtual machine',
|
||||
null = False,
|
||||
verbose_name = 'Is Virtual',
|
||||
)
|
||||
|
||||
|
||||
def save(
|
||||
self, force_insert=False, force_update=False, using=None, update_fields=None
|
||||
):
|
||||
@ -327,9 +308,6 @@ class DeviceSoftware(DeviceCommonFields, SaveHistory):
|
||||
'software'
|
||||
]
|
||||
|
||||
verbose_name_plural = 'Device Softwares'
|
||||
|
||||
|
||||
|
||||
class Actions(models.TextChoices):
|
||||
INSTALL = '1', 'Install'
|
||||
@ -405,12 +383,6 @@ class DeviceSoftware(DeviceCommonFields, SaveHistory):
|
||||
|
||||
class DeviceOperatingSystem(DeviceCommonFields, SaveHistory):
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
verbose_name_plural = 'Device Operating Systems'
|
||||
|
||||
|
||||
device = models.ForeignKey(
|
||||
Device,
|
||||
on_delete = models.CASCADE,
|
||||
|
@ -20,9 +20,6 @@ class DeviceModel(DeviceCommonFieldsName, SaveHistory):
|
||||
'name',
|
||||
]
|
||||
|
||||
verbose_name_plural = 'Device Models'
|
||||
|
||||
|
||||
manufacturer = models.ForeignKey(
|
||||
Manufacturer,
|
||||
on_delete=models.CASCADE,
|
||||
|
@ -42,12 +42,6 @@ class OperatingSystemFieldsName(OperatingSystemCommonFields):
|
||||
|
||||
class OperatingSystem(OperatingSystemFieldsName, SaveHistory):
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
verbose_name_plural = 'Operating Systems'
|
||||
|
||||
|
||||
publisher = models.ForeignKey(
|
||||
Manufacturer,
|
||||
on_delete=models.CASCADE,
|
||||
@ -63,12 +57,6 @@ class OperatingSystem(OperatingSystemFieldsName, SaveHistory):
|
||||
|
||||
class OperatingSystemVersion(OperatingSystemCommonFields, SaveHistory):
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
verbose_name_plural = 'Operating System Versions'
|
||||
|
||||
|
||||
operating_system = models.ForeignKey(
|
||||
OperatingSystem,
|
||||
on_delete=models.CASCADE,
|
||||
|
@ -37,12 +37,6 @@ class SoftwareCommonFields(TenancyObject, models.Model):
|
||||
class SoftwareCategory(SoftwareCommonFields, SaveHistory):
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
verbose_name_plural = 'Software Categories'
|
||||
|
||||
|
||||
|
||||
def clean(self):
|
||||
|
||||
app_settings = AppSettings.objects.get(owner_organization=None)
|
||||
@ -61,12 +55,6 @@ class SoftwareCategory(SoftwareCommonFields, SaveHistory):
|
||||
|
||||
class Software(SoftwareCommonFields, SaveHistory):
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
verbose_name_plural = 'Softwares'
|
||||
|
||||
|
||||
publisher = models.ForeignKey(
|
||||
Manufacturer,
|
||||
on_delete=models.CASCADE,
|
||||
@ -103,12 +91,6 @@ class Software(SoftwareCommonFields, SaveHistory):
|
||||
|
||||
class SoftwareVersion(SoftwareCommonFields, SaveHistory):
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
verbose_name_plural = 'Software Versions'
|
||||
|
||||
|
||||
software = models.ForeignKey(
|
||||
Software,
|
||||
on_delete=models.CASCADE,
|
||||
|
@ -1,26 +1,189 @@
|
||||
{% extends 'detail.html.j2' %}
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
{% block title %}{{ device.name }}{% endblock %}
|
||||
|
||||
{% block tabs %}
|
||||
{% block content %}
|
||||
|
||||
<script>
|
||||
|
||||
function openCity(evt, cityName) {
|
||||
// Declare all variables
|
||||
var i, tabcontent, tablinks;
|
||||
|
||||
// Get all elements with class="tabcontent" and hide them
|
||||
tabcontent = document.getElementsByClassName("tabcontent");
|
||||
for (i = 0; i < tabcontent.length; i++) {
|
||||
tabcontent[i].style.display = "none";
|
||||
}
|
||||
|
||||
// Get all elements with class="tablinks" and remove the class "active"
|
||||
tablinks = document.getElementsByClassName("tablinks");
|
||||
for (i = 0; i < tablinks.length; i++) {
|
||||
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||
}
|
||||
|
||||
// Show the current tab, and add an "active" class to the button that opened the tab
|
||||
document.getElementById(cityName).style.display = "block";
|
||||
evt.currentTarget.className += " active";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="tab">
|
||||
<button onclick="window.location='{% url 'ITAM:Devices' %}';"
|
||||
style="vertical-align: middle; padding: auto; margin: 0px">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="25px" viewBox="0 -960 960 960" width="25px"
|
||||
style="vertical-align: middle; margin: 0px; padding: 0px border: none; " fill="#6a6e73">
|
||||
<path d="m313-480 155 156q11 11 11.5 27.5T468-268q-11 11-28 11t-28-11L228-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T468-692q11 11 11 28t-11 28L313-480Zm264 0 155 156q11 11 11.5 27.5T732-268q-11 11-28 11t-28-11L492-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T732-692q11 11 11 28t-11 28L577-480Z" />
|
||||
</svg> Back to Devices</button>
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Details')">Details</button>
|
||||
<button id="SoftwareOpen" class="tablinks" onclick="openCity(event, 'Software')">Software</button>
|
||||
<button id="NotesOpen" class="tablinks" onclick="openCity(event, 'Notes')">Notes</button>
|
||||
<button id="ConfigManagementOpen" class="tablinks" onclick="openCity(event, 'ConfigManagement')">Config Management</button>
|
||||
<!-- <button class="tablinks" onclick="openCity(event, 'Installations')">Installations</button> -->
|
||||
</div>
|
||||
<style>
|
||||
|
||||
.detail-view-field {
|
||||
display:unset;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0px 20px 40px 20px;
|
||||
|
||||
}
|
||||
|
||||
.detail-view-field label {
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
width: 200px;
|
||||
margin: 10px;
|
||||
/*padding: 10px;*/
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
}
|
||||
|
||||
.detail-view-field span {
|
||||
display: inline-block;
|
||||
width: 340px;
|
||||
margin: 10px;
|
||||
/*padding: 10px;*/
|
||||
border-bottom: 1px solid #ccc;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
}
|
||||
</style>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<div id="details" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
|
||||
<hr />
|
||||
<div id="Details" class="tabcontent">
|
||||
<h3>
|
||||
Details
|
||||
{% for external_link in external_links %}
|
||||
<span style="font-weight: normal; float: right;">{% include 'icons/external_link.html.j2' with external_link=external_link %}</span>
|
||||
{% endfor %}
|
||||
</h3>
|
||||
<div style="align-items:flex-start; align-content: center; display: flexbox; width: 100%">
|
||||
|
||||
<div style="display: inline; width: 40%; margin: 30px;">
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.name.label }}</label>
|
||||
<span>{{ form.name.value }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.device_model.label }}</label>
|
||||
<span>
|
||||
{% if device.device_model %}
|
||||
{{ device.device_model }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.serial_number.label }}</label>
|
||||
<span>
|
||||
{% if form.serial_number.value %}
|
||||
{{ form.serial_number.value }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.uuid.label }}</label>
|
||||
<span>
|
||||
{% if form.uuid.value %}
|
||||
{{ form.uuid.value }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.device_type.label }}</label>
|
||||
<span>
|
||||
{% if device.device_type %}
|
||||
{{ device.device_type }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.organization.label }}</label>
|
||||
<span>{{ device.organization }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.lastinventory.label }}</label>
|
||||
<span>
|
||||
{% if form.lastinventory.value %}
|
||||
{{ form.lastinventory.value }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="display: inline; width: 40%; margin: 30px; text-align: left;">
|
||||
<div>
|
||||
<label style="font-weight: bold; width: 100%; border-bottom: 1px solid #ccc; display: block; text-align: inherit;">{{ form.model_notes.label }}</label>
|
||||
|
||||
<div style="display: inline-block; text-align: left;">
|
||||
{% if form.model_notes.value %}
|
||||
{{ form.model_notes.value | markdown | safe }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<input type="button" value="Edit" onclick="window.location='{% url 'ITAM:_device_change' device.id %}';">
|
||||
|
||||
<div style="display: block; width: 100%;">
|
||||
<h3>Operating System</h3>
|
||||
<br>
|
||||
{{ operating_system.as_p }}
|
||||
<input type="submit" name="{{ operating_system.prefix }}" value="Submit" />
|
||||
<input type="submit" name="{{operating_system.prefix}}" value="Submit" />
|
||||
</div>
|
||||
|
||||
|
||||
<div style="display: block; width: 100%;">
|
||||
<h3>Dependent Services</h3>
|
||||
<table>
|
||||
@ -41,8 +204,7 @@
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="display: block; width: 100%;">
|
||||
<h3>Device Config</h3>
|
||||
@ -50,15 +212,19 @@
|
||||
<textarea cols="90" rows="30" readonly>{{ device.config }}</textarea>
|
||||
</div>
|
||||
|
||||
<input type="button" value="Edit" onclick="window.location='{% url 'ITAM:_device_change' device.id %}';">
|
||||
{% if not tab %}
|
||||
<script>
|
||||
// Get the element with id="defaultOpen" and click on it
|
||||
document.getElementById("defaultOpen").click();
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id="software" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.software %}
|
||||
|
||||
<div id="Software" class="tabcontent">
|
||||
<h3>Software</h3>
|
||||
<hr>
|
||||
Installed Software: {{ installed_software }}
|
||||
<input type="button" value="Add Software Action" onclick="window.location='{% url 'ITAM:_device_software_add' device.id %}';">
|
||||
@ -134,14 +300,19 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% if tab == 'software' %}
|
||||
<script>
|
||||
// Get the element with id="defaultOpen" and click on it
|
||||
document.getElementById("SoftwareOpen").click();
|
||||
</script>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id="notes" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.notes %}
|
||||
|
||||
<div id="Notes" class="tabcontent">
|
||||
<h3>
|
||||
Notes
|
||||
</h3>
|
||||
{{ notes_form }}
|
||||
<input type="submit" name="{{notes_form.prefix}}" value="Submit" />
|
||||
<div class="comments">
|
||||
@ -152,14 +323,17 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% if tab == 'notes' %}
|
||||
<script>
|
||||
// Get the element with id="defaultOpen" and click on it
|
||||
document.getElementById("NotesOpen").click();
|
||||
</script>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id="config_management" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.config_management %}
|
||||
|
||||
<div id="ConfigManagement" class="tabcontent">
|
||||
<h3>Configuration Management</h3>
|
||||
<div>
|
||||
<textarea cols="90" rows="30" readonly>{{ config }}</textarea>
|
||||
</div>
|
||||
@ -186,6 +360,13 @@
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
{% if tab == 'configmanagement' %}
|
||||
<script>
|
||||
// Get the element with id="defaultOpen" and click on it
|
||||
document.getElementById("ConfigManagementOpen").click();
|
||||
</script>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
@ -1,34 +0,0 @@
|
||||
{% extends 'detail.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
|
||||
{% block tabs %}
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<div id="details" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="notes" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.notes %}
|
||||
|
||||
{{ notes_form }}
|
||||
<input type="submit" name="{{notes_form.prefix}}" value="Submit" />
|
||||
<div class="comments">
|
||||
{% if notes %}
|
||||
{% for note in notes%}
|
||||
{% include 'note.html.j2' %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
@ -1,36 +0,0 @@
|
||||
{% extends 'detail.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
|
||||
{% block tabs %}
|
||||
<form action="" method="post">
|
||||
|
||||
{% csrf_token %}
|
||||
|
||||
<div id="details" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="notes" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.notes %}
|
||||
|
||||
{{ notes_form }}
|
||||
<input type="submit" name="{{notes_form.prefix}}" value="Submit" />
|
||||
<div class="comments">
|
||||
{% if notes %}
|
||||
{% for note in notes%}
|
||||
{% include 'note.html.j2' %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
@ -1,116 +1,118 @@
|
||||
{% extends 'detail.html.j2' %}
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
{% block title %}{{ operating_system.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% block tabs %}
|
||||
<form action="" method="post">
|
||||
<script>
|
||||
|
||||
function openCity(evt, cityName) {
|
||||
|
||||
var i, tabcontent, tablinks;
|
||||
|
||||
tabcontent = document.getElementsByClassName("tabcontent");
|
||||
for (i = 0; i < tabcontent.length; i++) {
|
||||
tabcontent[i].style.display = "none";
|
||||
}
|
||||
|
||||
tablinks = document.getElementsByClassName("tablinks");
|
||||
for (i = 0; i < tablinks.length; i++) {
|
||||
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||
}
|
||||
|
||||
document.getElementById(cityName).style.display = "block";
|
||||
evt.currentTarget.className += " active";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="tab">
|
||||
<button onclick="window.location='{% url 'ITAM:Operating Systems' %}';" style="vertical-align: middle; padding: auto; margin: 0px">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="25px" viewBox="0 -960 960 960" width="25px" style="vertical-align: middle; margin: 0px; padding: 0px border: none; " fill="#6a6e73">
|
||||
<path d="m313-480 155 156q11 11 11.5 27.5T468-268q-11 11-28 11t-28-11L228-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T468-692q11 11 11 28t-11 28L313-480Zm264 0 155 156q11 11 11.5 27.5T732-268q-11 11-28 11t-28-11L492-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T732-692q11 11 11 28t-11 28L577-480Z"/>
|
||||
</svg> Back to Operating Systems</button>
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Details')">Details</button>
|
||||
<button class="tablinks" onclick="openCity(event, 'Versions')">Versions</button>
|
||||
<button class="tablinks" onclick="openCity(event, 'Licences')">Licences</button>
|
||||
<button class="tablinks" onclick="openCity(event, 'Notes')">Notes</button>
|
||||
<button class="tablinks" onclick="openCity(event, 'Installations')">Installations</button>
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<div id="Details" class="tabcontent">
|
||||
<h3>Details</h3>
|
||||
|
||||
{% csrf_token %}
|
||||
{{ form }}
|
||||
<br>
|
||||
<input type="submit" value="Submit">
|
||||
|
||||
<div id="details" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
<script>
|
||||
document.getElementById("defaultOpen").click();
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="versions" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.versions %}
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Version</th>
|
||||
<th>Installations</th>
|
||||
<th>Vulnerable</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
{% for version in operating_system_versions %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_operating_system_version_view' operating_system_id=operating_system.id pk=version.id %}">{{ version.name }}</a></td>
|
||||
<td>{% if version.installs == 0%}-{% else %}{{ version.installs }}{% endif %}</td>
|
||||
<td> </td>
|
||||
<td><a href="{% url 'ITAM:_operating_system_version_delete' operating_system_id=operating_system.id pk=version.id %}">DELETE</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<div id="Versions" class="tabcontent">
|
||||
<h3>Versions</h3>
|
||||
<input type="button" value="New Operating System Version" onclick="window.location='{% url 'ITAM:_operating_system_version_add' pk=operating_system.id %}';">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Version</th>
|
||||
<th>Installations</th>
|
||||
<th>Vulnerable</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
{% for version in operating_system_versions %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_operating_system_version_view' operating_system_id=operating_system.id pk=version.id %}">{{ version.name }}</a></td>
|
||||
<td>{% if version.installs == 0%}-{% else %}{{ version.installs }}{% endif %}</td>
|
||||
<td> </td>
|
||||
<td><a href="{% url 'ITAM:_operating_system_version_delete' operating_system_id=operating_system.id pk=version.id %}">DELETE</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="licences" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.licences %}
|
||||
|
||||
{% include 'icons/issue_link.html.j2' with issue=4 %}
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Available</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>GPL-3</td>
|
||||
<td>Open Source</td>
|
||||
<td>1 / 5</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MIT</td>
|
||||
<td>Open Source</td>
|
||||
<td>Unlimited</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Windows Device</td>
|
||||
<td>CAL</td>
|
||||
<td>11 / 15</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div id="Licences" class="tabcontent">
|
||||
<h3>Licences</h3>
|
||||
{% include 'icons/issue_link.html.j2' with issue=4 %}
|
||||
<table>
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Available</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>GPL-3</td>
|
||||
<td>Open Source</td>
|
||||
<td>1 / 5</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MIT</td>
|
||||
<td>Open Source</td>
|
||||
<td>Unlimited</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Windows Device</td>
|
||||
<td>CAL</td>
|
||||
<td>11 / 15</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="installations" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.installations %}
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Device</th>
|
||||
<th>Organization</th>
|
||||
<th>Version</th>
|
||||
<th title="Date Software Installed">Installed</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
{% for install in installs %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_device_view' pk=install.device_id %}">{{ install.device }}</a></td>
|
||||
<td>{{ install.organization }}</td>
|
||||
<td>{{ install.version }}</td>
|
||||
<td>
|
||||
{% if install.installdate %}
|
||||
{{ install.installdate }}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="notes" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.notes %}
|
||||
|
||||
<div id="Notes" class="tabcontent">
|
||||
<h3>
|
||||
Notes
|
||||
</h3>
|
||||
{{ notes_form }}
|
||||
<input type="submit" name="{{notes_form.prefix}}" value="Submit" />
|
||||
<div class="comments">
|
||||
@ -121,8 +123,36 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="Installations" class="tabcontent">
|
||||
<h3>Installations</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<th>Device</th>
|
||||
<th>Organization</th>
|
||||
<th>Version</th>
|
||||
<th title="Date Software Installed">Installed</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
{% for install in installs %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_device_view' pk=install.device_id %}">{{ install.device }}</a></td>
|
||||
<td>{{ install.organization }}</td>
|
||||
<td>{{ install.version }}</td>
|
||||
<td>
|
||||
{% if install.installdate %}
|
||||
{{ install.installdate }}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
@ -1,85 +1,123 @@
|
||||
{% extends 'detail.html.j2' %}
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
{% block title %}{{ software.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% block tabs %}
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<div id="details" class="content-tab">
|
||||
<script>
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
function openCity(evt, cityName) {
|
||||
// Declare all variables
|
||||
var i, tabcontent, tablinks;
|
||||
|
||||
// Get all elements with class="tabcontent" and hide them
|
||||
tabcontent = document.getElementsByClassName("tabcontent");
|
||||
for (i = 0; i < tabcontent.length; i++) {
|
||||
tabcontent[i].style.display = "none";
|
||||
}
|
||||
|
||||
// Get all elements with class="tablinks" and remove the class "active"
|
||||
tablinks = document.getElementsByClassName("tablinks");
|
||||
for (i = 0; i < tablinks.length; i++) {
|
||||
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||
}
|
||||
|
||||
// Show the current tab, and add an "active" class to the button that opened the tab
|
||||
document.getElementById(cityName).style.display = "block";
|
||||
evt.currentTarget.className += " active";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="tab">
|
||||
<button onclick="window.location='{% url 'ITAM:Software' %}';" style="vertical-align: middle; padding: auto; margin: 0px">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="25px" viewBox="0 -960 960 960" width="25px" style="vertical-align: middle; margin: 0px; padding: 0px border: none; " fill="#6a6e73">
|
||||
<path d="m313-480 155 156q11 11 11.5 27.5T468-268q-11 11-28 11t-28-11L228-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T468-692q11 11 11 28t-11 28L313-480Zm264 0 155 156q11 11 11.5 27.5T732-268q-11 11-28 11t-28-11L492-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T732-692q11 11 11 28t-11 28L577-480Z"/>
|
||||
</svg> Back to Software</button>
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Details')">Details</button>
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Versions')">Versions</button>
|
||||
<button class="tablinks" onclick="openCity(event, 'Licences')">Licences</button>
|
||||
<button class="tablinks" onclick="openCity(event, 'Notes')">Notes</button>
|
||||
<button class="tablinks" onclick="openCity(event, 'Installations')">Installations</button>
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<div id="Details" class="tabcontent">
|
||||
<h3>
|
||||
Details
|
||||
{% for external_link in external_links %}
|
||||
<span style="font-weight: normal; float: right;">{% include 'icons/external_link.html.j2' with external_link=external_link %}</span>
|
||||
{% endfor %}
|
||||
</h3>
|
||||
{% csrf_token %}
|
||||
{{ form }}
|
||||
<br>
|
||||
<input type="submit" value="Submit">
|
||||
|
||||
<script>
|
||||
// Get the element with id="defaultOpen" and click on it
|
||||
document.getElementById("defaultOpen").click();
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="Versions" class="tabcontent">
|
||||
<h3>Versions</h3>
|
||||
<input type="button" value="New Software Version" onclick="window.location='{% url 'ITAM:_software_version_add' pk=software.id %}';">
|
||||
<table>
|
||||
<thead>
|
||||
<th>Version</th>
|
||||
<th>Installations</th>
|
||||
<th>Vulnerable</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
{% for version in software_versions %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_software_version_view' software_id=software.id pk=version.id %}">{{ version.name }}</a></td>
|
||||
<td>{{ version.installs }}</td>
|
||||
<td>{% include 'icons/issue_link.html.j2' with issue=3 %}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="versions" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.versions %}
|
||||
|
||||
<input type="button" value="New Software Version" onclick="window.location='{% url 'ITAM:_software_version_add' pk=software.id %}';">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Version</th>
|
||||
<th>Installations</th>
|
||||
<th>Vulnerable</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
{% for version in software_versions %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_software_version_view' software_id=software.id pk=version.id %}">{{ version.name }}</a></td>
|
||||
<td>{{ version.installs }}</td>
|
||||
<td>{% include 'icons/issue_link.html.j2' with issue=3 %}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<div id="Licences" class="tabcontent">
|
||||
<h3>Licences</h3>
|
||||
{% include 'icons/issue_link.html.j2' with issue=4 %}
|
||||
<table>
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Available</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>GPL-3</td>
|
||||
<td>Open Source</td>
|
||||
<td>1 / 5</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MIT</td>
|
||||
<td>Open Source</td>
|
||||
<td>Unlimited</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Windows Device</td>
|
||||
<td>CAL</td>
|
||||
<td>11 / 15</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="licences" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.licences %}
|
||||
|
||||
{% include 'icons/issue_link.html.j2' with issue=4 %}
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Available</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>GPL-3</td>
|
||||
<td>Open Source</td>
|
||||
<td>1 / 5</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MIT</td>
|
||||
<td>Open Source</td>
|
||||
<td>Unlimited</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Windows Device</td>
|
||||
<td>CAL</td>
|
||||
<td>11 / 15</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="notes" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.notes %}
|
||||
|
||||
<div id="Notes" class="tabcontent">
|
||||
<h3>
|
||||
Notes
|
||||
</h3>
|
||||
{{ notes_form }}
|
||||
<input type="submit" name="{{notes_form.prefix}}" value="Submit" />
|
||||
<div class="comments">
|
||||
@ -90,61 +128,58 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="installations" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.installations %}
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Device</th>
|
||||
<th>Organization</th>
|
||||
<th title="Not Set/Install/Remove">Action</th>
|
||||
<th>Installed Version</th>
|
||||
<th title="Date Software Installed">Install Date</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
{% if device_software %}
|
||||
{% for device in device_software %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_device_view' pk=device.device.id %}">{{ device.device }}</a></td>
|
||||
<td>{{ device.organization }}</td>
|
||||
<td>
|
||||
{% if device.get_action_display == 'Install' %}
|
||||
{% include 'icons/success_text.html.j2' with icon_text=device.get_action_display %}
|
||||
{% elif device.get_action_display == 'Remove'%}
|
||||
{% include 'icons/cross_text.html.j2' with icon_text=device.get_action_display %}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if device.installedversion %}
|
||||
{{ device.installedversion }}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if device.installed %}
|
||||
{{ device.installed }}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<div id="Installations" class="tabcontent">
|
||||
<h3>Installations</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<th>Device</th>
|
||||
<th>Organization</th>
|
||||
<th title="Not Set/Install/Remove">Action</th>
|
||||
<th>Installed Version</th>
|
||||
<th title="Date Software Installed">Install Date</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
{% if device_software %}
|
||||
{% for device in device_software %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_device_view' pk=device.device.id %}">{{ device.device }}</a></td>
|
||||
<td>{{ device.organization }}</td>
|
||||
<td>
|
||||
{% if device.get_action_display == 'Install' %}
|
||||
{% include 'icons/success_text.html.j2' with icon_text=device.get_action_display %}
|
||||
{% elif device.get_action_display == 'Remove'%}
|
||||
{% include 'icons/cross_text.html.j2' with icon_text=device.get_action_display %}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if device.installedversion %}
|
||||
{{ device.installedversion }}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if device.installed %}
|
||||
{{ device.installed }}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="6">Nothing Found</td>
|
||||
</tr>
|
||||
-
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="6">Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
@ -1,150 +0,0 @@
|
||||
{% extends 'detail.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
|
||||
{% block tabs %}
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<div id="details" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="versions" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.versions %}
|
||||
|
||||
<input type="button" value="New Software Version" onclick="window.location='{% url 'ITAM:_software_version_add' pk=software.id %}';">
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Version</th>
|
||||
<th>Installations</th>
|
||||
<th>Vulnerable</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
{% for version in software_versions %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_software_version_view' software_id=software.id pk=version.id %}">{{ version.name }}</a></td>
|
||||
<td>{{ version.installs }}</td>
|
||||
<td>{% include 'icons/issue_link.html.j2' with issue=3 %}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="licences" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.licences %}
|
||||
|
||||
{% include 'icons/issue_link.html.j2' with issue=4 %}
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Available</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td>GPL-3</td>
|
||||
<td>Open Source</td>
|
||||
<td>1 / 5</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MIT</td>
|
||||
<td>Open Source</td>
|
||||
<td>Unlimited</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Windows Device</td>
|
||||
<td>CAL</td>
|
||||
<td>11 / 15</td>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="notes" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.notes %}
|
||||
|
||||
{{ notes_form }}
|
||||
<input type="submit" name="{{notes_form.prefix}}" value="Submit" />
|
||||
<div class="comments">
|
||||
{% if notes %}
|
||||
{% for note in notes%}
|
||||
{% include 'note.html.j2' %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="installations" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.installations %}
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>Device</th>
|
||||
<th>Organization</th>
|
||||
<th title="Not Set/Install/Remove">Action</th>
|
||||
<th>Installed Version</th>
|
||||
<th title="Date Software Installed">Install Date</th>
|
||||
<th> </th>
|
||||
</thead>
|
||||
{% if device_software %}
|
||||
{% for device in device_software %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_device_view' pk=device.device.id %}">{{ device.device }}</a></td>
|
||||
<td>{{ device.organization }}</td>
|
||||
<td>
|
||||
{% if device.get_action_display == 'Install' %}
|
||||
{% include 'icons/success_text.html.j2' with icon_text=device.get_action_display %}
|
||||
{% elif device.get_action_display == 'Remove'%}
|
||||
{% include 'icons/cross_text.html.j2' with icon_text=device.get_action_display %}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if device.installedversion %}
|
||||
{{ device.installedversion }}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if device.installed %}
|
||||
{{ device.installed }}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="6">Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
@ -30,7 +30,7 @@ class DeviceModelPermissions(TestCase, ModelPermissions):
|
||||
|
||||
url_name_add = '_device_model_add'
|
||||
|
||||
url_name_change = '_device_model_change'
|
||||
url_name_change = '_device_model_view'
|
||||
|
||||
url_name_delete = '_device_model_delete'
|
||||
|
||||
|
@ -26,7 +26,7 @@ class DeviceTypePermissions(TestCase, ModelPermissions):
|
||||
|
||||
url_name_add = '_device_type_add'
|
||||
|
||||
url_name_change = '_device_type_change'
|
||||
url_name_change = '_device_type_view'
|
||||
|
||||
url_name_delete = '_device_type_delete'
|
||||
|
||||
|
@ -27,7 +27,7 @@ class OperatingSystemPermissions(TestCase, ModelPermissions):
|
||||
|
||||
url_name_add = '_operating_system_add'
|
||||
|
||||
url_name_change = '_operating_system_change'
|
||||
url_name_change = '_operating_system_view'
|
||||
|
||||
url_name_delete = '_operating_system_delete'
|
||||
|
||||
|
@ -26,7 +26,7 @@ class SoftwarePermissions(TestCase, ModelPermissions):
|
||||
|
||||
url_name_add = '_software_add'
|
||||
|
||||
url_name_change = '_software_change'
|
||||
url_name_change = '_software_view'
|
||||
|
||||
url_name_delete = '_software_delete'
|
||||
|
||||
|
@ -29,7 +29,7 @@ class SoftwareCategoryPermissions(TestCase, ModelPermissions):
|
||||
|
||||
url_name_add = '_software_category_add'
|
||||
|
||||
url_name_change = '_software_category_change'
|
||||
url_name_change = '_software_category_view'
|
||||
|
||||
url_name_delete = '_software_category_delete'
|
||||
|
||||
|
@ -18,7 +18,6 @@ urlpatterns = [
|
||||
|
||||
path("operating_system", operating_system.IndexView.as_view(), name="Operating Systems"),
|
||||
path("operating_system/<int:pk>", operating_system.View.as_view(), name="_operating_system_view"),
|
||||
path("operating_system/<int:pk>/edit", operating_system.Change.as_view(), name="_operating_system_change"),
|
||||
path("operating_system/add", operating_system.Add.as_view(), name="_operating_system_add"),
|
||||
path("operating_system/delete/<int:pk>", operating_system.Delete.as_view(), name="_operating_system_delete"),
|
||||
|
||||
@ -31,7 +30,6 @@ urlpatterns = [
|
||||
|
||||
path("software/", software.IndexView.as_view(), name="Software"),
|
||||
path("software/<int:pk>/", software.View.as_view(), name="_software_view"),
|
||||
path("software/<int:pk>/change", software.Change.as_view(), name="_software_change"),
|
||||
path("software/<int:pk>/delete", software.Delete.as_view(), name="_software_delete"),
|
||||
path("software/<int:pk>/version/add", software_version.Add.as_view(), name="_software_version_add"),
|
||||
path("software/<int:software_id>/version/<int:pk>", software_version.View.as_view(), name="_software_version_view"),
|
||||
|
@ -21,7 +21,7 @@ from core.views.common import AddView, ChangeView, DeleteView, IndexView
|
||||
|
||||
from itam.forms.device_softwareadd import SoftwareAdd
|
||||
from itam.forms.device_softwareupdate import SoftwareUpdate
|
||||
from itam.forms.device.device import DetailForm, DeviceForm
|
||||
from itam.forms.device.device import DeviceForm
|
||||
from itam.forms.device.operating_system import Update as OperatingSystemForm
|
||||
|
||||
from itim.models.services import Service
|
||||
@ -79,7 +79,7 @@ class View(ChangeView):
|
||||
|
||||
template_name = 'itam/device.html.j2'
|
||||
|
||||
form_class = DetailForm
|
||||
form_class = DeviceForm
|
||||
|
||||
context_object_name = "device"
|
||||
|
||||
|
@ -2,7 +2,7 @@ from django.contrib.auth import decorators as auth_decorator
|
||||
from django.urls import reverse
|
||||
from django.utils.decorators import method_decorator
|
||||
|
||||
from itam.forms.device_model import DetailForm, DeviceModelForm
|
||||
from itam.forms.device_model import DeviceModelForm
|
||||
from itam.models.device_models import DeviceModel
|
||||
|
||||
from core.views.common import AddView, ChangeView, DeleteView
|
||||
@ -11,7 +11,7 @@ from settings.models.user_settings import UserSettings
|
||||
|
||||
|
||||
|
||||
class Change(ChangeView):
|
||||
class View(ChangeView):
|
||||
|
||||
form_class = DeviceModelForm
|
||||
|
||||
@ -20,40 +20,13 @@ class Change(ChangeView):
|
||||
model = DeviceModel
|
||||
|
||||
permission_required = [
|
||||
'itam.view_devicemodel',
|
||||
'itam.change_devicemodel',
|
||||
]
|
||||
|
||||
template_name = 'form.html.j2'
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = self.object.name
|
||||
|
||||
return context
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('Settings:_device_model_view', args=(self.kwargs['pk'],))
|
||||
|
||||
|
||||
|
||||
class View(ChangeView):
|
||||
|
||||
form_class = DetailForm
|
||||
|
||||
context_object_name = "device_model"
|
||||
|
||||
model = DeviceModel
|
||||
|
||||
permission_required = [
|
||||
'itam.view_devicemodel',
|
||||
]
|
||||
|
||||
template_name = 'itam/device_model.html.j2'
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
|
@ -5,11 +5,48 @@ from django.utils.decorators import method_decorator
|
||||
from core.views.common import AddView, ChangeView, DeleteView, IndexView
|
||||
|
||||
from itam.models.device import DeviceType
|
||||
from itam.forms.device_type import DetailForm, DeviceTypeForm
|
||||
from itam.forms.device_type import DeviceTypeForm
|
||||
|
||||
|
||||
|
||||
|
||||
class View(ChangeView):
|
||||
|
||||
form_class = DeviceTypeForm
|
||||
|
||||
model = DeviceType
|
||||
|
||||
permission_required = [
|
||||
'itam.view_devicetype',
|
||||
'itam.change_devicetype'
|
||||
]
|
||||
|
||||
template_name = 'form.html.j2'
|
||||
|
||||
context_object_name = "device_category"
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['model_delete_url'] = reverse('Settings:_device_type_delete', args=(self.kwargs['pk'],))
|
||||
|
||||
context['content_title'] = self.object.name
|
||||
|
||||
return context
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('Settings:_device_type_view', args=(self.kwargs['pk'],))
|
||||
|
||||
|
||||
@method_decorator(auth_decorator.permission_required("itam.change_devicetype", raise_exception=True))
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
|
||||
|
||||
class Add(AddView):
|
||||
|
||||
form_class = DeviceTypeForm
|
||||
@ -36,36 +73,6 @@ class Add(AddView):
|
||||
return context
|
||||
|
||||
|
||||
class Change(ChangeView):
|
||||
|
||||
form_class = DeviceTypeForm
|
||||
|
||||
model = DeviceType
|
||||
|
||||
permission_required = [
|
||||
'itam.change_devicetype'
|
||||
]
|
||||
|
||||
template_name = 'form.html.j2'
|
||||
|
||||
context_object_name = "device_category"
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['model_delete_url'] = reverse('Settings:_device_type_delete', args=(self.kwargs['pk'],))
|
||||
|
||||
context['content_title'] = self.object.name
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('Settings:_device_type_view', args=(self.kwargs['pk'],))
|
||||
|
||||
|
||||
|
||||
class Delete(DeleteView):
|
||||
model = DeviceType
|
||||
@ -91,39 +98,3 @@ class Delete(DeleteView):
|
||||
context['content_title'] = 'Delete ' + self.object.name
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
||||
class View(ChangeView):
|
||||
|
||||
form_class = DetailForm
|
||||
|
||||
model = DeviceType
|
||||
|
||||
permission_required = [
|
||||
'itam.view_devicetype',
|
||||
]
|
||||
|
||||
template_name = 'itam/device_type.html.j2'
|
||||
|
||||
context_object_name = "device_category"
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['model_delete_url'] = reverse('Settings:_device_type_delete', args=(self.kwargs['pk'],))
|
||||
|
||||
context['content_title'] = self.object.name
|
||||
|
||||
return context
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('Settings:_device_type_view', args=(self.kwargs['pk'],))
|
||||
|
||||
|
||||
@method_decorator(auth_decorator.permission_required("itam.change_devicetype", raise_exception=True))
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
@ -9,120 +9,11 @@ from core.views.common import AddView, ChangeView, DeleteView, IndexView
|
||||
|
||||
from itam.models.device import DeviceOperatingSystem
|
||||
from itam.models.operating_system import OperatingSystem, OperatingSystemVersion
|
||||
from itam.forms.operating_system.update import DetailForm, OperatingSystemForm
|
||||
from itam.forms.operating_system.update import OperatingSystemFormCommon, Update
|
||||
|
||||
from settings.models.user_settings import UserSettings
|
||||
|
||||
|
||||
|
||||
class Add(AddView):
|
||||
|
||||
form_class = OperatingSystemForm
|
||||
|
||||
model = OperatingSystem
|
||||
|
||||
permission_required = [
|
||||
'itam.add_operatingsystem',
|
||||
]
|
||||
|
||||
template_name = 'form.html.j2'
|
||||
|
||||
|
||||
def get_initial(self):
|
||||
|
||||
return {
|
||||
'organization': UserSettings.objects.get(user = self.request.user).default_organization
|
||||
}
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('ITAM:Operating Systems')
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = 'Add Operating System'
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
||||
class Change(ChangeView):
|
||||
|
||||
context_object_name = "operating_system"
|
||||
|
||||
form_class = OperatingSystemForm
|
||||
|
||||
model = OperatingSystem
|
||||
|
||||
permission_required = [
|
||||
'itam.change_operatingsystem',
|
||||
]
|
||||
|
||||
template_name = 'form.html.j2'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = self.object.name
|
||||
|
||||
return context
|
||||
|
||||
|
||||
@method_decorator(auth_decorator.permission_required("itam.change_operatingsystem", raise_exception=True))
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
operatingsystem = OperatingSystem.objects.get(pk=self.kwargs['pk'])
|
||||
|
||||
notes = AddNoteForm(request.POST, prefix='note')
|
||||
|
||||
if notes.is_bound and notes.is_valid() and notes.instance.note != '':
|
||||
|
||||
notes.instance.organization = operatingsystem.organization
|
||||
notes.instance.operatingsystem = operatingsystem
|
||||
notes.instance.usercreated = request.user
|
||||
|
||||
notes.save()
|
||||
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('ITAM:_operating_system_view', args=(self.kwargs['pk'],))
|
||||
|
||||
|
||||
|
||||
class Delete(DeleteView):
|
||||
|
||||
model = OperatingSystem
|
||||
|
||||
permission_required = [
|
||||
'itam.delete_operatingsystem',
|
||||
]
|
||||
|
||||
template_name = 'form.html.j2'
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('ITAM:Operating Systems')
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['model_pk'] = self.kwargs['pk']
|
||||
context['model_name'] = self.model._meta.verbose_name.replace(' ', '')
|
||||
|
||||
context['content_title'] = 'Delete ' + self.object.name
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
||||
class IndexView(IndexView):
|
||||
model = OperatingSystem
|
||||
permission_required = [
|
||||
@ -157,12 +48,13 @@ class View(ChangeView):
|
||||
|
||||
context_object_name = "operating_system"
|
||||
|
||||
form_class = DetailForm
|
||||
form_class = Update
|
||||
|
||||
model = OperatingSystem
|
||||
|
||||
permission_required = [
|
||||
'itam.view_operatingsystem',
|
||||
'itam.change_operatingsystem',
|
||||
]
|
||||
|
||||
template_name = 'itam/operating_system.html.j2'
|
||||
@ -204,7 +96,7 @@ class View(ChangeView):
|
||||
return context
|
||||
|
||||
|
||||
# @method_decorator(auth_decorator.permission_required("itam.change_operatingsystem", raise_exception=True))
|
||||
@method_decorator(auth_decorator.permission_required("itam.change_operatingsystem", raise_exception=True))
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
operatingsystem = OperatingSystem.objects.get(pk=self.kwargs['pk'])
|
||||
@ -225,3 +117,65 @@ class View(ChangeView):
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('ITAM:_operating_system_view', args=(self.kwargs['pk'],))
|
||||
|
||||
|
||||
|
||||
class Add(AddView):
|
||||
|
||||
form_class = OperatingSystemFormCommon
|
||||
|
||||
model = OperatingSystem
|
||||
|
||||
permission_required = [
|
||||
'itam.add_operatingsystem',
|
||||
]
|
||||
|
||||
template_name = 'form.html.j2'
|
||||
|
||||
|
||||
def get_initial(self):
|
||||
|
||||
return {
|
||||
'organization': UserSettings.objects.get(user = self.request.user).default_organization
|
||||
}
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('ITAM:Operating Systems')
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = 'Add Operating System'
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
||||
class Delete(DeleteView):
|
||||
|
||||
model = OperatingSystem
|
||||
|
||||
permission_required = [
|
||||
'itam.delete_operatingsystem',
|
||||
]
|
||||
|
||||
template_name = 'form.html.j2'
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('ITAM:Operating Systems')
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['model_pk'] = self.kwargs['pk']
|
||||
context['model_name'] = self.model._meta.verbose_name.replace(' ', '')
|
||||
|
||||
context['content_title'] = 'Delete ' + self.object.name
|
||||
|
||||
return context
|
||||
|
@ -9,7 +9,7 @@ from core.views.common import AddView, ChangeView, DeleteView, IndexView
|
||||
|
||||
from itam.models.device import DeviceSoftware
|
||||
from itam.models.software import Software, SoftwareVersion
|
||||
from itam.forms.software.update import DetailForm, SoftwareForm, SoftwareChange
|
||||
from itam.forms.software.update import SoftwareForm, SoftwareFormUpdate
|
||||
|
||||
from settings.models.user_settings import UserSettings
|
||||
|
||||
@ -51,39 +51,11 @@ class IndexView(IndexView):
|
||||
|
||||
|
||||
|
||||
|
||||
class Change(ChangeView):
|
||||
|
||||
model = Software
|
||||
|
||||
permission_required = [
|
||||
'itam.change_software',
|
||||
]
|
||||
|
||||
template_name = 'form.html.j2'
|
||||
|
||||
form_class = SoftwareChange
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('ITAM:_software_view', args=(self.kwargs['pk'],))
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = 'Edit ' + self.object.name
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
||||
class View(ChangeView):
|
||||
|
||||
context_object_name = "software"
|
||||
|
||||
form_class = DetailForm
|
||||
form_class = SoftwareFormUpdate
|
||||
|
||||
model = Software
|
||||
|
||||
|
@ -4,13 +4,13 @@ from django.utils.decorators import method_decorator
|
||||
|
||||
from core.views.common import AddView, ChangeView, DeleteView
|
||||
|
||||
from itam.forms.software_category import DetailForm, SoftwareCategoryForm
|
||||
from itam.forms.software_category import SoftwareCategoryForm
|
||||
from itam.models.software import Software, SoftwareCategory
|
||||
|
||||
from settings.models.user_settings import UserSettings
|
||||
|
||||
|
||||
class Change(ChangeView):
|
||||
class View(ChangeView):
|
||||
|
||||
context_object_name = "software"
|
||||
|
||||
@ -19,6 +19,7 @@ class Change(ChangeView):
|
||||
model = SoftwareCategory
|
||||
|
||||
permission_required = [
|
||||
'itam.view_softwarecategory',
|
||||
'itam.change_softwarecategory',
|
||||
]
|
||||
|
||||
@ -47,38 +48,6 @@ class Change(ChangeView):
|
||||
|
||||
|
||||
|
||||
class View(ChangeView):
|
||||
|
||||
context_object_name = "software"
|
||||
|
||||
form_class = DetailForm
|
||||
|
||||
model = SoftwareCategory
|
||||
|
||||
permission_required = [
|
||||
'itam.view_softwarecategory',
|
||||
]
|
||||
|
||||
template_name = 'itam/software_categories.html.j2'
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['model_delete_url'] = reverse('Settings:_software_category_delete', args=(self.kwargs['pk'],))
|
||||
|
||||
context['content_title'] = self.object.name
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('Settings:_software_category_view', args=(self.kwargs['pk'],))
|
||||
|
||||
|
||||
|
||||
|
||||
class Add(AddView):
|
||||
|
||||
form_class = SoftwareCategoryForm
|
||||
|
@ -1,94 +0,0 @@
|
||||
from django import forms
|
||||
from django.forms import ValidationError
|
||||
from django.urls import reverse
|
||||
|
||||
from itim.models.clusters import ClusterType
|
||||
|
||||
from app import settings
|
||||
|
||||
from core.forms.common import CommonModelForm
|
||||
|
||||
|
||||
|
||||
class ClusterTypeForm(CommonModelForm):
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
fields = '__all__'
|
||||
|
||||
model = ClusterType
|
||||
|
||||
prefix = 'cluster_type'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
|
||||
class DetailForm(ClusterTypeForm):
|
||||
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'name',
|
||||
'organization',
|
||||
'c_created',
|
||||
'c_modified'
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "single",
|
||||
"name": "Configuration",
|
||||
"fields": [
|
||||
'config'
|
||||
],
|
||||
"json": [
|
||||
'config',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"notes": {
|
||||
"name": "Notes",
|
||||
"slug": "notes",
|
||||
"sections": []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('Settings:_cluster_type_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('Settings:_cluster_types')
|
||||
|
@ -1,152 +0,0 @@
|
||||
from django import forms
|
||||
from django.forms import ValidationError
|
||||
from django.urls import reverse
|
||||
|
||||
from itim.models.clusters import Cluster
|
||||
|
||||
from app import settings
|
||||
|
||||
from core.forms.common import CommonModelForm
|
||||
|
||||
|
||||
|
||||
class ClusterForm(CommonModelForm):
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
fields = '__all__'
|
||||
|
||||
model = Cluster
|
||||
|
||||
prefix = 'cluster'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.fields['parent_cluster'].queryset = self.fields['parent_cluster'].queryset.exclude(
|
||||
id=self.instance.pk
|
||||
)
|
||||
|
||||
self.fields['devices'].queryset = self.fields['devices'].queryset.exclude(
|
||||
is_virtual=False
|
||||
)
|
||||
|
||||
|
||||
def clean(self):
|
||||
|
||||
cleaned_data = super().clean()
|
||||
|
||||
pk = self.instance.id
|
||||
|
||||
parent_cluster = cleaned_data.get("parent_cluster")
|
||||
|
||||
if pk:
|
||||
|
||||
if parent_cluster == pk:
|
||||
|
||||
raise ValidationError("Cluster can't have itself as its parent cluster")
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
|
||||
class DetailForm(ClusterForm):
|
||||
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'parent_cluster',
|
||||
'cluster_type',
|
||||
'name',
|
||||
'organization',
|
||||
'c_created',
|
||||
'c_modified'
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
'resources',
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
"rendered_config": {
|
||||
"name": "Rendered Config",
|
||||
"slug": "rendered_config",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "single",
|
||||
"fields": [
|
||||
'rendered_config',
|
||||
],
|
||||
"json": [
|
||||
'rendered_config'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"notes": {
|
||||
"name": "Notes",
|
||||
"slug": "notes",
|
||||
"sections": []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
# self.fields['config_variables'] = forms.fields.JSONField(
|
||||
# widget = forms.Textarea(
|
||||
# attrs = {
|
||||
# "cols": "80",
|
||||
# "rows": "100"
|
||||
# }
|
||||
# ),
|
||||
# label = 'Rendered Configuration',
|
||||
# initial = self.instance.config_variables,
|
||||
# )
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
self.fields['resources'] = forms.CharField(
|
||||
label = 'Available Resources',
|
||||
disabled = True,
|
||||
initial = 'xx/yy CPU, xx/yy RAM, xx/yy Storage',
|
||||
)
|
||||
|
||||
|
||||
self.fields['rendered_config'] = forms.fields.JSONField(
|
||||
label = 'Available Resources',
|
||||
disabled = True,
|
||||
initial = self.instance.rendered_config,
|
||||
)
|
||||
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('ITIM:_cluster_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('ITIM:Clusters')
|
||||
|
@ -1,8 +1,8 @@
|
||||
|
||||
from django import forms
|
||||
from django.urls import reverse
|
||||
# from django import forms
|
||||
# from django.forms import ValidationError
|
||||
|
||||
from app import settings
|
||||
# from app import settings
|
||||
|
||||
from itim.models.services import Port
|
||||
|
||||
@ -22,67 +22,3 @@ class PortForm(CommonModelForm):
|
||||
model = Port
|
||||
|
||||
prefix = 'port'
|
||||
|
||||
|
||||
|
||||
class DetailForm(PortForm):
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'number',
|
||||
'description',
|
||||
'protocol',
|
||||
'organization',
|
||||
'c_created',
|
||||
'c_modified',
|
||||
'lastinventory',
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"services": {
|
||||
"name": "Services",
|
||||
"slug": "services",
|
||||
"sections": []
|
||||
},
|
||||
"notes": {
|
||||
"name": "Notes",
|
||||
"slug": "notes",
|
||||
"sections": []
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('Settings:_port_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('Settings:_ports')
|
||||
|
@ -44,7 +44,6 @@ class ServiceForm(CommonModelForm):
|
||||
dependent_service = cleaned_data.get("dependent_service")
|
||||
device = cleaned_data.get("device")
|
||||
cluster = cleaned_data.get("cluster")
|
||||
config_key_variable = cleaned_data.get("config_key_variable")
|
||||
is_template = cleaned_data.get("is_template")
|
||||
template = cleaned_data.get("template")
|
||||
port = cleaned_data.get("port")
|
||||
@ -66,10 +65,6 @@ class ServiceForm(CommonModelForm):
|
||||
|
||||
raise ValidationError('Port(s) must be assigned to a service.')
|
||||
|
||||
if not is_template and not config_key_variable:
|
||||
|
||||
raise ValidationError('Configuration Key must be specified')
|
||||
|
||||
if dependent_service:
|
||||
|
||||
for dependency in dependent_service:
|
||||
@ -165,6 +160,3 @@ class DetailForm(ServiceForm):
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('ITIM:_service_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('ITIM:Services')
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.0.7 on 2024-08-17 08:05
|
||||
# Generated by Django 5.0.7 on 2024-07-21 02:35
|
||||
|
||||
import access.fields
|
||||
import access.models
|
||||
@ -14,7 +14,7 @@ class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('access', '0001_initial'),
|
||||
('itam', '0003_alter_device_options_alter_devicemodel_options_and_more'),
|
||||
('itam', '0002_device_config'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
@ -29,8 +29,8 @@ class Migration(migrations.Migration):
|
||||
('organization', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='access.organization', validators=[access.models.TenancyObject.validatate_organization_exists])),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Cluster Type',
|
||||
'verbose_name_plural': 'Cluster Types',
|
||||
'verbose_name': 'ClusterType',
|
||||
'verbose_name_plural': 'ClusterTypes',
|
||||
'ordering': ['name'],
|
||||
},
|
||||
),
|
||||
@ -43,13 +43,11 @@ class Migration(migrations.Migration):
|
||||
('name', models.CharField(help_text='Name of the Cluster', max_length=50, verbose_name='Name')),
|
||||
('slug', access.fields.AutoSlugField()),
|
||||
('config', models.JSONField(blank=True, default=None, help_text='Cluster Configuration', null=True, verbose_name='Configuration')),
|
||||
('created', access.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False)),
|
||||
('modified', access.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False)),
|
||||
('devices', models.ManyToManyField(blank=True, default=None, help_text='Devices that are deployed upon the cluster.', related_name='cluster_device', to='itam.device', verbose_name='Devices')),
|
||||
('nodes', models.ManyToManyField(blank=True, default=None, help_text='Hosts for resource consumption that the cluster is deployed upon', related_name='cluster_node', to='itam.device', verbose_name='Nodes')),
|
||||
('node', models.ManyToManyField(blank=True, default=None, help_text='Hosts for resource consumption that the cluster is deployed upon', related_name='cluster_node', to='itam.device', verbose_name='Nodes')),
|
||||
('organization', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='access.organization', validators=[access.models.TenancyObject.validatate_organization_exists])),
|
||||
('parent_cluster', models.ForeignKey(blank=True, default=None, help_text='Parent Cluster for this cluster', null=True, on_delete=django.db.models.deletion.CASCADE, to='itim.cluster', verbose_name='Parent Cluster')),
|
||||
('cluster_type', models.ForeignKey(blank=True, default=None, help_text='Type of Cluster', null=True, on_delete=django.db.models.deletion.CASCADE, to='itim.clustertype', verbose_name='Cluster Type')),
|
||||
('cluster_type', models.ForeignKey(blank=True, default=None, help_text='Parent Cluster for this cluster', null=True, on_delete=django.db.models.deletion.CASCADE, to='itim.clustertype', verbose_name='Parent Cluster')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Cluster',
|
||||
|
@ -1,25 +0,0 @@
|
||||
# Generated by Django 5.0.7 on 2024-08-18 03:57
|
||||
|
||||
import access.fields
|
||||
import django.utils.timezone
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('itim', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='clustertype',
|
||||
name='created',
|
||||
field=access.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='clustertype',
|
||||
name='modified',
|
||||
field=access.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False),
|
||||
),
|
||||
]
|
@ -1,18 +0,0 @@
|
||||
# Generated by Django 5.0.7 on 2024-08-19 04:57
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('itim', '0002_clustertype_created_clustertype_modified'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='clustertype',
|
||||
name='config',
|
||||
field=models.JSONField(blank=True, default=None, help_text='Cluster Type Configuration that is applied to all clusters of this type', null=True, verbose_name='Configuration'),
|
||||
),
|
||||
]
|
@ -18,9 +18,9 @@ class ClusterType(TenancyObject):
|
||||
'name',
|
||||
]
|
||||
|
||||
verbose_name = "Cluster Type"
|
||||
verbose_name = "ClusterType"
|
||||
|
||||
verbose_name_plural = "Cluster Types"
|
||||
verbose_name_plural = "ClusterTypes"
|
||||
|
||||
|
||||
id = models.AutoField(
|
||||
@ -40,25 +40,6 @@ class ClusterType(TenancyObject):
|
||||
slug = AutoSlugField()
|
||||
|
||||
|
||||
config = models.JSONField(
|
||||
blank = True,
|
||||
default = None,
|
||||
help_text = 'Cluster Type Configuration that is applied to all clusters of this type',
|
||||
null = True,
|
||||
verbose_name = 'Configuration',
|
||||
)
|
||||
|
||||
|
||||
created = AutoCreatedField()
|
||||
|
||||
modified = AutoLastModifiedField()
|
||||
|
||||
|
||||
def __str__(self):
|
||||
|
||||
return self.name
|
||||
|
||||
|
||||
|
||||
class Cluster(TenancyObject):
|
||||
|
||||
@ -94,10 +75,10 @@ class Cluster(TenancyObject):
|
||||
ClusterType,
|
||||
blank = True,
|
||||
default = None,
|
||||
help_text = 'Type of Cluster',
|
||||
help_text = 'Parent Cluster for this cluster',
|
||||
null = True,
|
||||
on_delete = models.CASCADE,
|
||||
verbose_name = 'Cluster Type',
|
||||
verbose_name = 'Parent Cluster',
|
||||
)
|
||||
|
||||
name = models.CharField(
|
||||
@ -118,7 +99,7 @@ class Cluster(TenancyObject):
|
||||
verbose_name = 'Configuration',
|
||||
)
|
||||
|
||||
nodes = models.ManyToManyField(
|
||||
node = models.ManyToManyField(
|
||||
Device,
|
||||
blank = True,
|
||||
default = None,
|
||||
@ -136,44 +117,6 @@ class Cluster(TenancyObject):
|
||||
verbose_name = 'Devices',
|
||||
)
|
||||
|
||||
created = AutoCreatedField()
|
||||
|
||||
modified = AutoLastModifiedField()
|
||||
|
||||
|
||||
@property
|
||||
def rendered_config(self):
|
||||
|
||||
from itim.models.services import Service
|
||||
|
||||
rendered_config: dict = {}
|
||||
|
||||
if self.cluster_type:
|
||||
|
||||
if self.cluster_type.config:
|
||||
|
||||
rendered_config.update(
|
||||
self.cluster_type.config
|
||||
)
|
||||
|
||||
|
||||
for service in Service.objects.filter(cluster = self.pk):
|
||||
|
||||
if service.config_variables:
|
||||
|
||||
rendered_config.update( service.config_variables )
|
||||
|
||||
|
||||
if self.config:
|
||||
|
||||
rendered_config.update(
|
||||
self.config
|
||||
)
|
||||
|
||||
|
||||
|
||||
return rendered_config
|
||||
|
||||
|
||||
def __str__(self):
|
||||
|
||||
|
@ -169,7 +169,7 @@ class Service(TenancyObject):
|
||||
)
|
||||
|
||||
config_key_variable = models.CharField(
|
||||
blank = True,
|
||||
blank = False,
|
||||
help_text = 'Key name to use when merging with cluster/device config.',
|
||||
max_length = 50,
|
||||
null = True,
|
||||
|
@ -1,108 +0,0 @@
|
||||
{% extends 'detail.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
|
||||
{% block tabs %}
|
||||
|
||||
<div id="details" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
|
||||
<hr />
|
||||
|
||||
<div style="display: block; width: 100%;">
|
||||
|
||||
<h3>Nodes</h3>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Organization</th>
|
||||
</tr>
|
||||
{% if cluster.nodes.all %}
|
||||
{% for node in cluster.nodes.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_device_view' node.pk %}">{{ node }}</a></td>
|
||||
<td>{{ node.organization }}</td>
|
||||
</tr>
|
||||
{% endfor%}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="2"> Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="display: block; width: 100%;">
|
||||
|
||||
<h3>Devices</h3>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Organization</th>
|
||||
</tr>
|
||||
{% if cluster.devices.all %}
|
||||
{% for device in cluster.devices.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_device_view' device.pk %}">{{ device }}</a></td>
|
||||
<td>{{ device.organization }}</td>
|
||||
</tr>
|
||||
{% endfor%}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="2"> Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="display: block; width: 100%;">
|
||||
|
||||
<h3>Services</h3>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Ports</th>
|
||||
</tr>
|
||||
{% if services %}
|
||||
{% for service in services.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITIM:_service_view' service.id %}">{{ service.name }}</a></td>
|
||||
<td>
|
||||
{% for port in service.port.all %}
|
||||
{{ port.protocol }}/{{ port.number }} - {{ port.description }},
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor%}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="2"> Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="display: block; width: 100%;">
|
||||
<h3>Config</h3>
|
||||
<pre>{{ cluster.config | json_pretty }}</pre>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="rendered_config" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.rendered_config %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
@ -1,53 +0,0 @@
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<input type="button" value="New Cluster" onclick="window.location='{% url 'ITIM:_cluster_add' %}';">
|
||||
<table class="data">
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Type</th>
|
||||
<th>Organization</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
{% if items %}
|
||||
{% for item in items %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITIM:_cluster_view' pk=item.id %}">{{ item.name }}</a></td>
|
||||
<td>
|
||||
{% if item.cluster_type %}
|
||||
{{ item.cluster_type }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ item.organization }}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4">Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
<br>
|
||||
<div class="pagination">
|
||||
<span class="step-links">
|
||||
{% if page_obj.has_previous %}
|
||||
<a href="?page=1">« first</a>
|
||||
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
|
||||
{% endif %}
|
||||
|
||||
<span class="current">
|
||||
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
|
||||
</span>
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<a href="?page={{ page_obj.next_page_number }}">next</a>
|
||||
<a href="?page={{ page_obj.paginator.num_pages }}">last »</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
@ -1,22 +0,0 @@
|
||||
{% extends 'detail.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
|
||||
{% block tabs %}
|
||||
|
||||
<div id="details" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div id="notes" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.notes %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
@ -1,47 +0,0 @@
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<input type="button" value="New Cluster Type" onclick="window.location='{% url 'Settings:_cluster_type_add' %}';">
|
||||
<table class="data">
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th> </th>
|
||||
<th>Organization</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
{% if items %}
|
||||
{% for item in items %}
|
||||
<tr>
|
||||
<td><a href="{% url 'Settings:_cluster_type_view' pk=item.id %}">{{ item.name }}</a></td>
|
||||
<td> </td>
|
||||
<td>{{ item.organization }}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4">Nothing Found</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
<br>
|
||||
<div class="pagination">
|
||||
<span class="step-links">
|
||||
{% if page_obj.has_previous %}
|
||||
<a href="?page=1">« first</a>
|
||||
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
|
||||
{% endif %}
|
||||
|
||||
<span class="current">
|
||||
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
|
||||
</span>
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<a href="?page={{ page_obj.next_page_number }}">next</a>
|
||||
<a href="?page={{ page_obj.paginator.num_pages }}">last »</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
@ -1,55 +1,196 @@
|
||||
{% extends 'detail.html.j2' %}
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% block tabs %}
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
<div id="details" class="content-tab">
|
||||
<script>
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
function openCity(evt, cityName) {
|
||||
var i, tabcontent, tablinks;
|
||||
|
||||
tabcontent = document.getElementsByClassName("tabcontent");
|
||||
for (i = 0; i < tabcontent.length; i++) {
|
||||
tabcontent[i].style.display = "none";
|
||||
}
|
||||
|
||||
tablinks = document.getElementsByClassName("tablinks");
|
||||
for (i = 0; i < tablinks.length; i++) {
|
||||
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||
}
|
||||
|
||||
document.getElementById(cityName).style.display = "block";
|
||||
evt.currentTarget.className += " active";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.detail-view-field {
|
||||
display: unset;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0px 20px 40px 20px;
|
||||
|
||||
}
|
||||
|
||||
.detail-view-field label {
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
width: 200px;
|
||||
margin: 10px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
}
|
||||
|
||||
.detail-view-field span {
|
||||
display: inline-block;
|
||||
width: 340px;
|
||||
margin: 10px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
}
|
||||
|
||||
pre {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
<div class="tab">
|
||||
<button onclick="window.location='{% url 'Settings:_ports' %}';"
|
||||
style="vertical-align: middle; padding: auto; margin: 0px">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="25px" viewBox="0 -960 960 960" width="25px"
|
||||
style="vertical-align: middle; margin: 0px; padding: 0px border: none; " fill="#6a6e73">
|
||||
<path d="m313-480 155 156q11 11 11.5 27.5T468-268q-11 11-28 11t-28-11L228-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T468-692q11 11 11 28t-11 28L313-480Zm264 0 155 156q11 11 11.5 27.5T732-268q-11 11-28 11t-28-11L492-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T732-692q11 11 11 28t-11 28L577-480Z" />
|
||||
</svg>Back to Ports</button>
|
||||
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Details')">Details</button>
|
||||
<button class="tablinks" onclick="openCity(event, 'Services')">Services</button>
|
||||
{% if perms.assistance.change_service %}
|
||||
<button class="tablinks" onclick="openCity(event, 'Notes')">Notes</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<div id="Details" class="tabcontent">
|
||||
<h3>Details</h3>
|
||||
|
||||
<div id="services" class="content-tab">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.services %}
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Organization</th>
|
||||
</tr>
|
||||
{% for service in services %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITIM:_service_view' service.pk %}">{{ service.name }}</a></td>
|
||||
<td>{{ service.organization }}</td>
|
||||
</tr>
|
||||
{% endfor%}
|
||||
</table>
|
||||
|
||||
</div>
|
||||
{% csrf_token %}
|
||||
|
||||
|
||||
<div style="align-items:flex-start; align-content: center; display: flexbox; width: 100%">
|
||||
|
||||
<div id="notes" class="content-tab">
|
||||
<div style="display: inline; width: 40%; margin: 30px;">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.notes %}
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.number.label }}</label>
|
||||
<span>{{ form.number.value }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.description.label }}</label>
|
||||
<span>
|
||||
{% if form.description.value %}
|
||||
{{ form.description.value }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.protocol.label }}</label>
|
||||
<span>{{ form.protocol.value }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.organization.label }}</label>
|
||||
<span>{{ item.organization }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>Created</label>
|
||||
<span>{{ item.created }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>Modified</label>
|
||||
<span>{{ item.modified }}</span>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div style="display: inline; width: 40%; margin: 30px; text-align: left;">
|
||||
<div>
|
||||
<label
|
||||
style="font-weight: bold; width: 100%; border-bottom: 1px solid #ccc; display: block; text-align: inherit;">{{ form.model_notes.label }}</label>
|
||||
|
||||
<div style="display: inline-block; text-align: left;">
|
||||
{% if form.model_notes.value %}
|
||||
{{ form.model_notes.value | markdown | safe }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<input type="button" value="Edit" onclick="window.location='{% url 'Settings:_port_change' item.pk %}';">
|
||||
|
||||
<br>
|
||||
|
||||
<script>
|
||||
document.getElementById("defaultOpen").click();
|
||||
</script>
|
||||
|
||||
{{ notes_form }}
|
||||
<input type="submit" name="{{notes_form.prefix}}" value="Submit" />
|
||||
<div class="comments">
|
||||
{% if notes %}
|
||||
{% for note in notes%}
|
||||
{% include 'note.html.j2' %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="Services" class="tabcontent">
|
||||
<h3>
|
||||
Services
|
||||
</h3>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Organization</th>
|
||||
</tr>
|
||||
{% for service in services %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITIM:_service_view' service.pk %}">{{ service.name }}</a></td>
|
||||
<td>{{ service.organization }}</td>
|
||||
</tr>
|
||||
{% endfor%}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% if perms.assistance.change_knowledgebase %}
|
||||
<div id="Notes" class="tabcontent">
|
||||
<h3>
|
||||
Notes
|
||||
</h3>
|
||||
{{ notes_form }}
|
||||
<input type="submit" name="{{ notes_form.prefix }}" value="Submit" />
|
||||
<div class="comments">
|
||||
{% if notes %}
|
||||
{% for note in notes %}
|
||||
{% include 'note.html.j2' %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
@ -2,7 +2,7 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
<input type="button" value="New Service" onclick="window.location='{% url 'ITIM:_service_add' %}';">
|
||||
<input type="button" value="New Article" onclick="window.location='{% url 'ITIM:_service_add' %}';">
|
||||
<table class="data">
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
|
@ -1,42 +0,0 @@
|
||||
import pytest
|
||||
import unittest
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from access.models import Organization
|
||||
|
||||
from app.tests.abstract.models import TenancyModel
|
||||
|
||||
from itim.models.clusters import Cluster
|
||||
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class ClusterModel(
|
||||
TestCase,
|
||||
TenancyModel
|
||||
):
|
||||
|
||||
model = Cluster
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. Create an organization for user and item
|
||||
2. Create an item
|
||||
|
||||
"""
|
||||
|
||||
self.organization = Organization.objects.create(name='test_org')
|
||||
|
||||
|
||||
self.item = self.model.objects.create(
|
||||
organization = self.organization,
|
||||
name = 'one',
|
||||
)
|
||||
|
||||
self.second_item = self.model.objects.create(
|
||||
organization = self.organization,
|
||||
name = 'one_two',
|
||||
)
|
@ -1,78 +0,0 @@
|
||||
|
||||
import pytest
|
||||
import unittest
|
||||
import requests
|
||||
|
||||
from django.test import TestCase, Client
|
||||
|
||||
from access.models import Organization
|
||||
|
||||
from core.models.history import History
|
||||
from core.tests.abstract.history_entry import HistoryEntry
|
||||
from core.tests.abstract.history_entry_parent_model import HistoryEntryParentItem
|
||||
|
||||
from itim.models.clusters import Cluster
|
||||
|
||||
|
||||
|
||||
class ClusterHistory(TestCase, HistoryEntry, HistoryEntryParentItem):
|
||||
|
||||
|
||||
model = Cluster
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
""" Setup Test """
|
||||
|
||||
organization = Organization.objects.create(name='test_org')
|
||||
|
||||
self.organization = organization
|
||||
|
||||
self.item_parent = self.model.objects.create(
|
||||
name = 'test_item_parent_' + self.model._meta.model_name,
|
||||
organization = self.organization
|
||||
)
|
||||
|
||||
self.item_create = self.model.objects.create(
|
||||
name = 'test_item_' + self.model._meta.model_name,
|
||||
organization = self.organization,
|
||||
)
|
||||
|
||||
|
||||
self.history_create = History.objects.get(
|
||||
action = History.Actions.ADD[0],
|
||||
item_pk = self.item_create.pk,
|
||||
item_class = self.model._meta.model_name,
|
||||
)
|
||||
|
||||
self.item_change = self.item_create
|
||||
self.item_change.name = 'test_item_' + self.model._meta.model_name + '_changed'
|
||||
self.item_change.save()
|
||||
|
||||
self.field_after_expected_value = '{"name": "' + self.item_change.name + '"}'
|
||||
|
||||
self.history_change = History.objects.get(
|
||||
action = History.Actions.UPDATE[0],
|
||||
item_pk = self.item_change.pk,
|
||||
item_class = self.model._meta.model_name,
|
||||
)
|
||||
|
||||
self.item_delete = self.model.objects.create(
|
||||
name = 'test_item_delete_' + self.model._meta.model_name,
|
||||
organization = self.organization,
|
||||
)
|
||||
|
||||
self.deleted_pk = self.item_delete.pk
|
||||
|
||||
self.item_delete.delete()
|
||||
|
||||
self.history_delete = History.objects.filter(
|
||||
item_pk = self.deleted_pk,
|
||||
item_class = self.model._meta.model_name,
|
||||
)
|
||||
|
||||
self.history_delete_children = History.objects.filter(
|
||||
item_parent_pk = self.deleted_pk,
|
||||
item_parent_class = self.item_parent._meta.model_name,
|
||||
)
|
@ -1,95 +0,0 @@
|
||||
# from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import AnonymousUser, User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.shortcuts import reverse
|
||||
from django.test import TestCase, Client
|
||||
|
||||
import pytest
|
||||
import unittest
|
||||
import requests
|
||||
|
||||
from access.models import Organization, Team, TeamUsers, Permission
|
||||
|
||||
from itim.models.clusters import Cluster
|
||||
|
||||
from core.tests.abstract.history_permissions import HistoryPermissions
|
||||
|
||||
|
||||
|
||||
class ClusterHistoryPermissions(TestCase, HistoryPermissions):
|
||||
|
||||
|
||||
item_model = Cluster
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. Create an organization for user and item
|
||||
2. create an organization that is different to item
|
||||
3. Create a device
|
||||
4. Add history device history entry as item
|
||||
5. create a user
|
||||
6. create user in different organization (with the required permission)
|
||||
"""
|
||||
|
||||
organization = Organization.objects.create(name='test_org')
|
||||
|
||||
self.organization = organization
|
||||
|
||||
different_organization = Organization.objects.create(name='test_different_organization')
|
||||
|
||||
self.item = self.item_model.objects.create(
|
||||
organization=organization,
|
||||
name = 'deviceone'
|
||||
)
|
||||
|
||||
self.history = self.model.objects.get(
|
||||
item_pk = self.item.id,
|
||||
item_class = self.item._meta.model_name,
|
||||
action = self.model.Actions.ADD,
|
||||
)
|
||||
|
||||
view_permissions = Permission.objects.get(
|
||||
codename = 'view_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
view_team = Team.objects.create(
|
||||
team_name = 'view_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
view_team.permissions.set([view_permissions])
|
||||
|
||||
|
||||
self.no_permissions_user = User.objects.create_user(username="test_no_permissions", password="password")
|
||||
|
||||
|
||||
self.view_user = User.objects.create_user(username="test_user_view", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = view_team,
|
||||
user = self.view_user
|
||||
)
|
||||
|
||||
self.different_organization_user = User.objects.create_user(username="test_different_organization_user", password="password")
|
||||
|
||||
|
||||
different_organization_team = Team.objects.create(
|
||||
team_name = 'different_organization_team',
|
||||
organization = different_organization,
|
||||
)
|
||||
|
||||
different_organization_team.permissions.set([
|
||||
view_permissions,
|
||||
])
|
||||
|
||||
TeamUsers.objects.create(
|
||||
team = different_organization_team,
|
||||
user = self.different_organization_user
|
||||
)
|
@ -1,189 +0,0 @@
|
||||
# from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import AnonymousUser, User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.shortcuts import reverse
|
||||
from django.test import TestCase, Client
|
||||
|
||||
import pytest
|
||||
import unittest
|
||||
import requests
|
||||
|
||||
from access.models import Organization, Team, TeamUsers, Permission
|
||||
|
||||
from app.tests.abstract.model_permissions import ModelPermissions
|
||||
|
||||
from itim.models.clusters import Cluster
|
||||
|
||||
|
||||
class ClusterPermissions(TestCase, ModelPermissions):
|
||||
|
||||
|
||||
model = Cluster
|
||||
|
||||
app_namespace = 'ITIM'
|
||||
|
||||
url_name_view = '_cluster_view'
|
||||
|
||||
url_name_add = '_cluster_add'
|
||||
|
||||
url_name_change = '_cluster_change'
|
||||
|
||||
url_name_delete = '_cluster_delete'
|
||||
|
||||
url_delete_response = reverse('ITIM:Clusters')
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. Create an organization for user and item
|
||||
. create an organization that is different to item
|
||||
2. Create a device
|
||||
3. create teams with each permission: view, add, change, delete
|
||||
4. create a user per team
|
||||
"""
|
||||
|
||||
organization = Organization.objects.create(name='test_org')
|
||||
|
||||
self.organization = organization
|
||||
|
||||
different_organization = Organization.objects.create(name='test_different_organization')
|
||||
|
||||
|
||||
self.item = self.model.objects.create(
|
||||
organization=organization,
|
||||
name = 'deviceone'
|
||||
)
|
||||
|
||||
|
||||
self.url_view_kwargs = {'pk': self.item.id}
|
||||
|
||||
# self.url_add_kwargs = {'pk': self.item.id}
|
||||
|
||||
self.add_data = {'device': 'device', 'organization': self.organization.id}
|
||||
|
||||
self.url_change_kwargs = {'pk': self.item.id}
|
||||
|
||||
self.change_data = {'device': 'device', 'organization': self.organization.id}
|
||||
|
||||
self.url_delete_kwargs = {'pk': self.item.id}
|
||||
|
||||
self.delete_data = {'device': 'device', 'organization': self.organization.id}
|
||||
|
||||
|
||||
view_permissions = Permission.objects.get(
|
||||
codename = 'view_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
view_team = Team.objects.create(
|
||||
team_name = 'view_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
view_team.permissions.set([view_permissions])
|
||||
|
||||
|
||||
|
||||
add_permissions = Permission.objects.get(
|
||||
codename = 'add_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
add_team = Team.objects.create(
|
||||
team_name = 'add_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
add_team.permissions.set([add_permissions])
|
||||
|
||||
|
||||
|
||||
change_permissions = Permission.objects.get(
|
||||
codename = 'change_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
change_team = Team.objects.create(
|
||||
team_name = 'change_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
change_team.permissions.set([change_permissions])
|
||||
|
||||
|
||||
|
||||
delete_permissions = Permission.objects.get(
|
||||
codename = 'delete_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
delete_team = Team.objects.create(
|
||||
team_name = 'delete_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
delete_team.permissions.set([delete_permissions])
|
||||
|
||||
|
||||
self.no_permissions_user = User.objects.create_user(username="test_no_permissions", password="password")
|
||||
|
||||
|
||||
self.view_user = User.objects.create_user(username="test_user_view", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = view_team,
|
||||
user = self.view_user
|
||||
)
|
||||
|
||||
self.add_user = User.objects.create_user(username="test_user_add", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = add_team,
|
||||
user = self.add_user
|
||||
)
|
||||
|
||||
self.change_user = User.objects.create_user(username="test_user_change", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = change_team,
|
||||
user = self.change_user
|
||||
)
|
||||
|
||||
self.delete_user = User.objects.create_user(username="test_user_delete", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = delete_team,
|
||||
user = self.delete_user
|
||||
)
|
||||
|
||||
|
||||
self.different_organization_user = User.objects.create_user(username="test_different_organization_user", password="password")
|
||||
|
||||
|
||||
different_organization_team = Team.objects.create(
|
||||
team_name = 'different_organization_team',
|
||||
organization = different_organization,
|
||||
)
|
||||
|
||||
different_organization_team.permissions.set([
|
||||
view_permissions,
|
||||
add_permissions,
|
||||
change_permissions,
|
||||
delete_permissions,
|
||||
])
|
||||
|
||||
TeamUsers.objects.create(
|
||||
team = different_organization_team,
|
||||
user = self.different_organization_user
|
||||
)
|
@ -1,29 +0,0 @@
|
||||
import pytest
|
||||
import unittest
|
||||
import requests
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from app.tests.abstract.models import PrimaryModel
|
||||
|
||||
|
||||
|
||||
class ClusterViews(
|
||||
TestCase,
|
||||
PrimaryModel
|
||||
):
|
||||
|
||||
add_module = 'itim.views.clusters'
|
||||
add_view = 'Add'
|
||||
|
||||
change_module = add_module
|
||||
change_view = 'Change'
|
||||
|
||||
delete_module = add_module
|
||||
delete_view = 'Delete'
|
||||
|
||||
display_module = add_module
|
||||
display_view = 'View'
|
||||
|
||||
index_module = add_module
|
||||
index_view = 'Index'
|
@ -1,42 +0,0 @@
|
||||
import pytest
|
||||
import unittest
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from access.models import Organization
|
||||
|
||||
from app.tests.abstract.models import TenancyModel
|
||||
|
||||
from itim.models.clusters import ClusterType
|
||||
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
class ClusterTypeModel(
|
||||
TestCase,
|
||||
TenancyModel
|
||||
):
|
||||
|
||||
model = ClusterType
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. Create an organization for user and item
|
||||
2. Create an item
|
||||
|
||||
"""
|
||||
|
||||
self.organization = Organization.objects.create(name='test_org')
|
||||
|
||||
|
||||
self.item = self.model.objects.create(
|
||||
organization = self.organization,
|
||||
name = 'one',
|
||||
)
|
||||
|
||||
self.second_item = self.model.objects.create(
|
||||
organization = self.organization,
|
||||
name = 'one_two',
|
||||
)
|
@ -1,78 +0,0 @@
|
||||
|
||||
import pytest
|
||||
import unittest
|
||||
import requests
|
||||
|
||||
from django.test import TestCase, Client
|
||||
|
||||
from access.models import Organization
|
||||
|
||||
from core.models.history import History
|
||||
from core.tests.abstract.history_entry import HistoryEntry
|
||||
from core.tests.abstract.history_entry_parent_model import HistoryEntryParentItem
|
||||
|
||||
from itim.models.clusters import ClusterType
|
||||
|
||||
|
||||
|
||||
class ClusterTypeHistory(TestCase, HistoryEntry, HistoryEntryParentItem):
|
||||
|
||||
|
||||
model = ClusterType
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
""" Setup Test """
|
||||
|
||||
organization = Organization.objects.create(name='test_org')
|
||||
|
||||
self.organization = organization
|
||||
|
||||
self.item_parent = self.model.objects.create(
|
||||
name = 'test_item_parent_' + self.model._meta.model_name,
|
||||
organization = self.organization
|
||||
)
|
||||
|
||||
self.item_create = self.model.objects.create(
|
||||
name = 'test_item_' + self.model._meta.model_name,
|
||||
organization = self.organization,
|
||||
)
|
||||
|
||||
|
||||
self.history_create = History.objects.get(
|
||||
action = History.Actions.ADD[0],
|
||||
item_pk = self.item_create.pk,
|
||||
item_class = self.model._meta.model_name,
|
||||
)
|
||||
|
||||
self.item_change = self.item_create
|
||||
self.item_change.name = 'test_item_' + self.model._meta.model_name + '_changed'
|
||||
self.item_change.save()
|
||||
|
||||
self.field_after_expected_value = '{"name": "' + self.item_change.name + '"}'
|
||||
|
||||
self.history_change = History.objects.get(
|
||||
action = History.Actions.UPDATE[0],
|
||||
item_pk = self.item_change.pk,
|
||||
item_class = self.model._meta.model_name,
|
||||
)
|
||||
|
||||
self.item_delete = self.model.objects.create(
|
||||
name = 'test_item_delete_' + self.model._meta.model_name,
|
||||
organization = self.organization,
|
||||
)
|
||||
|
||||
self.deleted_pk = self.item_delete.pk
|
||||
|
||||
self.item_delete.delete()
|
||||
|
||||
self.history_delete = History.objects.filter(
|
||||
item_pk = self.deleted_pk,
|
||||
item_class = self.model._meta.model_name,
|
||||
)
|
||||
|
||||
self.history_delete_children = History.objects.filter(
|
||||
item_parent_pk = self.deleted_pk,
|
||||
item_parent_class = self.item_parent._meta.model_name,
|
||||
)
|
@ -1,95 +0,0 @@
|
||||
# from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import AnonymousUser, User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.shortcuts import reverse
|
||||
from django.test import TestCase, Client
|
||||
|
||||
import pytest
|
||||
import unittest
|
||||
import requests
|
||||
|
||||
from access.models import Organization, Team, TeamUsers, Permission
|
||||
|
||||
from itim.models.clusters import ClusterType
|
||||
|
||||
from core.tests.abstract.history_permissions import HistoryPermissions
|
||||
|
||||
|
||||
|
||||
class ClusterTypeHistoryPermissions(TestCase, HistoryPermissions):
|
||||
|
||||
|
||||
item_model = ClusterType
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. Create an organization for user and item
|
||||
2. create an organization that is different to item
|
||||
3. Create a device
|
||||
4. Add history device history entry as item
|
||||
5. create a user
|
||||
6. create user in different organization (with the required permission)
|
||||
"""
|
||||
|
||||
organization = Organization.objects.create(name='test_org')
|
||||
|
||||
self.organization = organization
|
||||
|
||||
different_organization = Organization.objects.create(name='test_different_organization')
|
||||
|
||||
self.item = self.item_model.objects.create(
|
||||
organization=organization,
|
||||
name = 'deviceone'
|
||||
)
|
||||
|
||||
self.history = self.model.objects.get(
|
||||
item_pk = self.item.id,
|
||||
item_class = self.item._meta.model_name,
|
||||
action = self.model.Actions.ADD,
|
||||
)
|
||||
|
||||
view_permissions = Permission.objects.get(
|
||||
codename = 'view_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
view_team = Team.objects.create(
|
||||
team_name = 'view_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
view_team.permissions.set([view_permissions])
|
||||
|
||||
|
||||
self.no_permissions_user = User.objects.create_user(username="test_no_permissions", password="password")
|
||||
|
||||
|
||||
self.view_user = User.objects.create_user(username="test_user_view", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = view_team,
|
||||
user = self.view_user
|
||||
)
|
||||
|
||||
self.different_organization_user = User.objects.create_user(username="test_different_organization_user", password="password")
|
||||
|
||||
|
||||
different_organization_team = Team.objects.create(
|
||||
team_name = 'different_organization_team',
|
||||
organization = different_organization,
|
||||
)
|
||||
|
||||
different_organization_team.permissions.set([
|
||||
view_permissions,
|
||||
])
|
||||
|
||||
TeamUsers.objects.create(
|
||||
team = different_organization_team,
|
||||
user = self.different_organization_user
|
||||
)
|
@ -1,189 +0,0 @@
|
||||
# from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import AnonymousUser, User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.shortcuts import reverse
|
||||
from django.test import TestCase, Client
|
||||
|
||||
import pytest
|
||||
import unittest
|
||||
import requests
|
||||
|
||||
from access.models import Organization, Team, TeamUsers, Permission
|
||||
|
||||
from app.tests.abstract.model_permissions import ModelPermissions
|
||||
|
||||
from itim.models.clusters import ClusterType
|
||||
|
||||
|
||||
class ClusterTypePermissions(TestCase, ModelPermissions):
|
||||
|
||||
|
||||
model = ClusterType
|
||||
|
||||
app_namespace = 'Settings'
|
||||
|
||||
url_name_view = '_cluster_type_view'
|
||||
|
||||
url_name_add = '_cluster_type_add'
|
||||
|
||||
url_name_change = '_cluster_type_change'
|
||||
|
||||
url_name_delete = '_cluster_type_delete'
|
||||
|
||||
url_delete_response = reverse('Settings:_cluster_types')
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. Create an organization for user and item
|
||||
. create an organization that is different to item
|
||||
2. Create a device
|
||||
3. create teams with each permission: view, add, change, delete
|
||||
4. create a user per team
|
||||
"""
|
||||
|
||||
organization = Organization.objects.create(name='test_org')
|
||||
|
||||
self.organization = organization
|
||||
|
||||
different_organization = Organization.objects.create(name='test_different_organization')
|
||||
|
||||
|
||||
self.item = self.model.objects.create(
|
||||
organization=organization,
|
||||
name = 'deviceone'
|
||||
)
|
||||
|
||||
|
||||
self.url_view_kwargs = {'pk': self.item.id}
|
||||
|
||||
# self.url_add_kwargs = {'pk': self.item.id}
|
||||
|
||||
self.add_data = {'device': 'device', 'organization': self.organization.id}
|
||||
|
||||
self.url_change_kwargs = {'pk': self.item.id}
|
||||
|
||||
self.change_data = {'device': 'device', 'organization': self.organization.id}
|
||||
|
||||
self.url_delete_kwargs = {'pk': self.item.id}
|
||||
|
||||
self.delete_data = {'device': 'device', 'organization': self.organization.id}
|
||||
|
||||
|
||||
view_permissions = Permission.objects.get(
|
||||
codename = 'view_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
view_team = Team.objects.create(
|
||||
team_name = 'view_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
view_team.permissions.set([view_permissions])
|
||||
|
||||
|
||||
|
||||
add_permissions = Permission.objects.get(
|
||||
codename = 'add_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
add_team = Team.objects.create(
|
||||
team_name = 'add_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
add_team.permissions.set([add_permissions])
|
||||
|
||||
|
||||
|
||||
change_permissions = Permission.objects.get(
|
||||
codename = 'change_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
change_team = Team.objects.create(
|
||||
team_name = 'change_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
change_team.permissions.set([change_permissions])
|
||||
|
||||
|
||||
|
||||
delete_permissions = Permission.objects.get(
|
||||
codename = 'delete_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
delete_team = Team.objects.create(
|
||||
team_name = 'delete_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
delete_team.permissions.set([delete_permissions])
|
||||
|
||||
|
||||
self.no_permissions_user = User.objects.create_user(username="test_no_permissions", password="password")
|
||||
|
||||
|
||||
self.view_user = User.objects.create_user(username="test_user_view", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = view_team,
|
||||
user = self.view_user
|
||||
)
|
||||
|
||||
self.add_user = User.objects.create_user(username="test_user_add", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = add_team,
|
||||
user = self.add_user
|
||||
)
|
||||
|
||||
self.change_user = User.objects.create_user(username="test_user_change", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = change_team,
|
||||
user = self.change_user
|
||||
)
|
||||
|
||||
self.delete_user = User.objects.create_user(username="test_user_delete", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = delete_team,
|
||||
user = self.delete_user
|
||||
)
|
||||
|
||||
|
||||
self.different_organization_user = User.objects.create_user(username="test_different_organization_user", password="password")
|
||||
|
||||
|
||||
different_organization_team = Team.objects.create(
|
||||
team_name = 'different_organization_team',
|
||||
organization = different_organization,
|
||||
)
|
||||
|
||||
different_organization_team.permissions.set([
|
||||
view_permissions,
|
||||
add_permissions,
|
||||
change_permissions,
|
||||
delete_permissions,
|
||||
])
|
||||
|
||||
TeamUsers.objects.create(
|
||||
team = different_organization_team,
|
||||
user = self.different_organization_user
|
||||
)
|
@ -1,29 +0,0 @@
|
||||
import pytest
|
||||
import unittest
|
||||
import requests
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from app.tests.abstract.models import PrimaryModel
|
||||
|
||||
|
||||
|
||||
class ClusterTypeViews(
|
||||
TestCase,
|
||||
PrimaryModel
|
||||
):
|
||||
|
||||
add_module = 'itim.views.cluster_types'
|
||||
add_view = 'Add'
|
||||
|
||||
change_module = add_module
|
||||
change_view = 'Change'
|
||||
|
||||
delete_module = add_module
|
||||
delete_view = 'Delete'
|
||||
|
||||
display_module = add_module
|
||||
display_view = 'View'
|
||||
|
||||
index_module = add_module
|
||||
index_view = 'Index'
|
@ -1,7 +1,7 @@
|
||||
from django.urls import path
|
||||
|
||||
|
||||
from itim.views import clusters, services
|
||||
from itim.views import services
|
||||
|
||||
app_name = "ITIM"
|
||||
urlpatterns = [
|
||||
@ -12,10 +12,4 @@ urlpatterns = [
|
||||
path("service/<int:pk>/delete", services.Delete.as_view(), name="_service_delete"),
|
||||
path("service/<int:pk>", services.View.as_view(), name="_service_view"),
|
||||
|
||||
path("clusters", clusters.Index.as_view(), name="Clusters"),
|
||||
path("clusters/add", clusters.Add.as_view(), name="_cluster_add"),
|
||||
path("clusters/<int:pk>/edit", clusters.Change.as_view(), name="_cluster_change"),
|
||||
path("clusters/<int:pk>/delete", clusters.Delete.as_view(), name="_cluster_delete"),
|
||||
path("clusters/<int:pk>", clusters.View.as_view(), name="_cluster_view"),
|
||||
|
||||
]
|
||||
|
@ -1,185 +0,0 @@
|
||||
from django.contrib.auth import decorators as auth_decorator
|
||||
from django.urls import reverse
|
||||
from django.utils.decorators import method_decorator
|
||||
|
||||
from core.forms.comment import AddNoteForm
|
||||
from core.models.notes import Notes
|
||||
from core.views.common import AddView, ChangeView, DeleteView, IndexView
|
||||
|
||||
from itim.forms.cluster_type import ClusterTypeForm, DetailForm
|
||||
from itim.models.clusters import ClusterType
|
||||
|
||||
from settings.models.user_settings import UserSettings
|
||||
|
||||
|
||||
|
||||
class Add(AddView):
|
||||
|
||||
form_class = ClusterTypeForm
|
||||
|
||||
model = ClusterType
|
||||
|
||||
permission_required = [
|
||||
'itim.add_clustertype',
|
||||
]
|
||||
|
||||
|
||||
def get_initial(self):
|
||||
|
||||
initial: dict = {
|
||||
'organization': UserSettings.objects.get(user = self.request.user).default_organization
|
||||
}
|
||||
|
||||
if 'pk' in self.kwargs:
|
||||
|
||||
if self.kwargs['pk']:
|
||||
|
||||
initial.update({'parent': self.kwargs['pk']})
|
||||
|
||||
self.model.parent.field.hidden = True
|
||||
|
||||
return initial
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('Settings:_cluster_type_types')
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = 'New Cluster Type'
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
||||
class Change(ChangeView):
|
||||
|
||||
form_class = ClusterTypeForm
|
||||
|
||||
model = ClusterType
|
||||
|
||||
permission_required = [
|
||||
'itim.change_clustertype',
|
||||
]
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = str(self.object)
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('Settings:_cluster_type_view', args=(self.kwargs['pk'],))
|
||||
|
||||
|
||||
|
||||
class Delete(DeleteView):
|
||||
|
||||
model = ClusterType
|
||||
|
||||
permission_required = [
|
||||
'itim.delete_clustertype',
|
||||
]
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = 'Delete ' + str(self.object)
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('Settings:_cluster_types')
|
||||
|
||||
|
||||
|
||||
class Index(IndexView):
|
||||
|
||||
context_object_name = "items"
|
||||
|
||||
model = ClusterType
|
||||
|
||||
paginate_by = 10
|
||||
|
||||
permission_required = [
|
||||
'itim.view_clustertype'
|
||||
]
|
||||
|
||||
template_name = 'itim/cluster_type_index.html.j2'
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['model_docs_path'] = self.model._meta.app_label + '/' + self.model._meta.model_name
|
||||
|
||||
context['content_title'] = 'Cluster Types'
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
||||
class View(ChangeView):
|
||||
|
||||
context_object_name = "item"
|
||||
|
||||
form_class = DetailForm
|
||||
|
||||
model = ClusterType
|
||||
|
||||
permission_required = [
|
||||
'itim.view_clustertype',
|
||||
]
|
||||
|
||||
template_name = 'itim/cluster_type.html.j2'
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['notes_form'] = AddNoteForm(prefix='note')
|
||||
context['notes'] = Notes.objects.filter(service=self.kwargs['pk'])
|
||||
|
||||
context['model_pk'] = self.kwargs['pk']
|
||||
context['model_name'] = self.model._meta.model_name
|
||||
|
||||
context['model_delete_url'] = reverse('Settings:_cluster_type_delete', args=(self.kwargs['pk'],))
|
||||
|
||||
|
||||
context['content_title'] = self.object.name
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
item = ClusterType.objects.get(pk=self.kwargs['pk'])
|
||||
|
||||
notes = AddNoteForm(request.POST, prefix='note')
|
||||
|
||||
if notes.is_bound and notes.is_valid() and notes.instance.note != '':
|
||||
|
||||
notes.instance.service = item
|
||||
|
||||
notes.instance.organization = item.organization
|
||||
|
||||
notes.save()
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('Settings:_cluster_type_view', args=(self.kwargs['pk'],))
|
@ -1,190 +0,0 @@
|
||||
from django.contrib.auth import decorators as auth_decorator
|
||||
from django.urls import reverse
|
||||
from django.utils.decorators import method_decorator
|
||||
|
||||
from core.forms.comment import AddNoteForm
|
||||
from core.models.notes import Notes
|
||||
from core.views.common import AddView, ChangeView, DeleteView, IndexView
|
||||
|
||||
from itim.forms.clusters import ClusterForm, DetailForm
|
||||
from itim.models.clusters import Cluster
|
||||
from itim.models.services import Service
|
||||
|
||||
from settings.models.user_settings import UserSettings
|
||||
|
||||
|
||||
|
||||
class Add(AddView):
|
||||
|
||||
form_class = ClusterForm
|
||||
|
||||
model = Cluster
|
||||
|
||||
permission_required = [
|
||||
'itim.add_cluster',
|
||||
]
|
||||
|
||||
|
||||
def get_initial(self):
|
||||
|
||||
initial: dict = {
|
||||
'organization': UserSettings.objects.get(user = self.request.user).default_organization
|
||||
}
|
||||
|
||||
if 'pk' in self.kwargs:
|
||||
|
||||
if self.kwargs['pk']:
|
||||
|
||||
initial.update({'parent': self.kwargs['pk']})
|
||||
|
||||
self.model.parent.field.hidden = True
|
||||
|
||||
return initial
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('ITIM:Clusters')
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = 'New Cluster'
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
||||
class Change(ChangeView):
|
||||
|
||||
form_class = ClusterForm
|
||||
|
||||
model = Cluster
|
||||
|
||||
permission_required = [
|
||||
'itim.change_cluster',
|
||||
]
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = str(self.object)
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('ITIM:_cluster_view', args=(self.kwargs['pk'],))
|
||||
|
||||
|
||||
|
||||
class Delete(DeleteView):
|
||||
|
||||
model = Cluster
|
||||
|
||||
permission_required = [
|
||||
'itim.delete_cluster',
|
||||
]
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = 'Delete ' + str(self.object)
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('ITIM:Clusters')
|
||||
|
||||
|
||||
|
||||
class Index(IndexView):
|
||||
|
||||
context_object_name = "items"
|
||||
|
||||
model = Cluster
|
||||
|
||||
paginate_by = 10
|
||||
|
||||
permission_required = [
|
||||
'itim.view_cluster'
|
||||
]
|
||||
|
||||
template_name = 'itim/cluster_index.html.j2'
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['model_docs_path'] = self.model._meta.app_label + '/' + self.model._meta.model_name
|
||||
|
||||
context['content_title'] = 'Clusters'
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
||||
class View(ChangeView):
|
||||
|
||||
context_object_name = "cluster"
|
||||
|
||||
form_class = DetailForm
|
||||
|
||||
model = Cluster
|
||||
|
||||
permission_required = [
|
||||
'itim.view_cluster',
|
||||
]
|
||||
|
||||
template_name = 'itim/cluster.html.j2'
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['notes_form'] = AddNoteForm(prefix='note')
|
||||
context['notes'] = Notes.objects.filter(service=self.kwargs['pk'])
|
||||
|
||||
context['model_pk'] = self.kwargs['pk']
|
||||
context['model_name'] = self.model._meta.model_name
|
||||
|
||||
context['model_delete_url'] = reverse('ITIM:_cluster_delete', args=(self.kwargs['pk'],))
|
||||
|
||||
context['services'] = Service.objects.filter(
|
||||
cluster = self.kwargs['pk']
|
||||
)
|
||||
|
||||
|
||||
context['content_title'] = self.object.name
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
item = Cluster.objects.get(pk=self.kwargs['pk'])
|
||||
|
||||
notes = AddNoteForm(request.POST, prefix='note')
|
||||
|
||||
if notes.is_bound and notes.is_valid() and notes.instance.note != '':
|
||||
|
||||
notes.instance.service = item
|
||||
|
||||
notes.instance.organization = item.organization
|
||||
|
||||
notes.save()
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('ITIM:_cluster_view', args=(self.kwargs['pk'],))
|
@ -6,7 +6,7 @@ from core.forms.comment import AddNoteForm
|
||||
from core.models.notes import Notes
|
||||
from core.views.common import AddView, ChangeView, DeleteView, IndexView
|
||||
|
||||
from itim.forms.ports import DetailForm, PortForm
|
||||
from itim.forms.ports import PortForm
|
||||
from itim.models.services import Port, Service
|
||||
|
||||
from settings.models.user_settings import UserSettings
|
||||
@ -138,7 +138,7 @@ class View(ChangeView):
|
||||
|
||||
context_object_name = "item"
|
||||
|
||||
form_class = DetailForm
|
||||
form_class = PortForm
|
||||
|
||||
model = Port
|
||||
|
||||
|
@ -1,12 +1,10 @@
|
||||
|
||||
from django import forms
|
||||
# from django.contrib.auth.models import User
|
||||
from django.urls import reverse
|
||||
from django.db.models import Q
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from access.models import Organization, TeamUsers
|
||||
|
||||
from app import settings
|
||||
|
||||
from core.forms.common import CommonModelForm
|
||||
|
||||
from settings.models.external_link import ExternalLink
|
||||
@ -21,64 +19,3 @@ class ExternalLinksForm(CommonModelForm):
|
||||
fields = '__all__'
|
||||
|
||||
model = ExternalLink
|
||||
|
||||
|
||||
|
||||
class DetailForm(ExternalLinksForm):
|
||||
|
||||
tabs: dict = {
|
||||
"details": {
|
||||
"name": "Details",
|
||||
"slug": "details",
|
||||
"sections": [
|
||||
{
|
||||
"layout": "double",
|
||||
"left": [
|
||||
'organization',
|
||||
'name',
|
||||
'template',
|
||||
'colour',
|
||||
'cluster',
|
||||
'devices'
|
||||
'software',
|
||||
'c_created',
|
||||
'c_modified',
|
||||
],
|
||||
"right": [
|
||||
'model_notes',
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"notes": {
|
||||
"name": "Notes",
|
||||
"slug": "notes",
|
||||
"sections": []
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
self.fields['c_created'] = forms.DateTimeField(
|
||||
label = 'Created',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.created,
|
||||
)
|
||||
|
||||
self.fields['c_modified'] = forms.DateTimeField(
|
||||
label = 'Modified',
|
||||
input_formats=settings.DATETIME_FORMAT,
|
||||
disabled = True,
|
||||
initial = self.instance.modified,
|
||||
)
|
||||
|
||||
self.tabs['details'].update({
|
||||
"edit_url": reverse('Settings:_external_link_change', args=(self.instance.pk,))
|
||||
})
|
||||
|
||||
self.url_index_view = reverse('Settings:External Links')
|
||||
|
@ -1,17 +0,0 @@
|
||||
# Generated by Django 5.0.7 on 2024-08-17 08:05
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('settings', '0002_externallink'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='externallink',
|
||||
options={'verbose_name_plural': 'External Links'},
|
||||
),
|
||||
]
|
@ -1,18 +0,0 @@
|
||||
# Generated by Django 5.0.7 on 2024-08-18 05:47
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('settings', '0003_alter_externallink_options'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='externallink',
|
||||
name='cluster',
|
||||
field=models.BooleanField(default=False, help_text='Render link for clusters', verbose_name='Clusters'),
|
||||
),
|
||||
]
|
@ -7,12 +7,6 @@ from access.models import TenancyObject
|
||||
|
||||
class ExternalLink(TenancyObject):
|
||||
|
||||
|
||||
class Meta:
|
||||
|
||||
verbose_name_plural = 'External Links'
|
||||
|
||||
|
||||
id = models.AutoField(
|
||||
primary_key=True,
|
||||
unique=True,
|
||||
@ -47,13 +41,6 @@ class ExternalLink(TenancyObject):
|
||||
verbose_name = 'Button Colour',
|
||||
)
|
||||
|
||||
cluster = models.BooleanField(
|
||||
default = False,
|
||||
blank = False,
|
||||
help_text = 'Render link for clusters',
|
||||
verbose_name = 'Clusters',
|
||||
)
|
||||
|
||||
devices = models.BooleanField(
|
||||
default = False,
|
||||
blank = False,
|
||||
|
@ -1,31 +1,194 @@
|
||||
{% extends 'detail.html.j2' %}
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
{% block title %}{{ externallink.name }}{% endblock %}
|
||||
|
||||
{% block tabs %}
|
||||
{% block content %}
|
||||
|
||||
<div id="details" class="content-tab">
|
||||
<script>
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.details %}
|
||||
function openCity(evt, cityName) {
|
||||
// Declare all variables
|
||||
var i, tabcontent, tablinks;
|
||||
|
||||
// Get all elements with class="tabcontent" and hide them
|
||||
tabcontent = document.getElementsByClassName("tabcontent");
|
||||
for (i = 0; i < tabcontent.length; i++) {
|
||||
tabcontent[i].style.display = "none";
|
||||
}
|
||||
|
||||
// Get all elements with class="tablinks" and remove the class "active"
|
||||
tablinks = document.getElementsByClassName("tablinks");
|
||||
for (i = 0; i < tablinks.length; i++) {
|
||||
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
||||
}
|
||||
|
||||
// Show the current tab, and add an "active" class to the button that opened the tab
|
||||
document.getElementById(cityName).style.display = "block";
|
||||
evt.currentTarget.className += " active";
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<div class="tab">
|
||||
<button onclick="window.location='{% url 'Settings:External Links' %}';"
|
||||
style="vertical-align: middle; padding: auto; margin: 0px">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="25px" viewBox="0 -960 960 960" width="25px"
|
||||
style="vertical-align: middle; margin: 0px; padding: 0px border: none; " fill="#6a6e73">
|
||||
<path d="m313-480 155 156q11 11 11.5 27.5T468-268q-11 11-28 11t-28-11L228-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T468-692q11 11 11 28t-11 28L313-480Zm264 0 155 156q11 11 11.5 27.5T732-268q-11 11-28 11t-28-11L492-452q-6-6-8.5-13t-2.5-15q0-8 2.5-15t8.5-13l184-184q11-11 27.5-11.5T732-692q11 11 11 28t-11 28L577-480Z" />
|
||||
</svg> Back to External Links</button>
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Details')">Details</button>
|
||||
<button id="NotesOpen" class="tablinks" onclick="openCity(event, 'Notes')">Notes</button>
|
||||
</div>
|
||||
<style>
|
||||
|
||||
.detail-view-field {
|
||||
display:unset;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0px 20px 40px 20px;
|
||||
|
||||
}
|
||||
|
||||
.detail-view-field label {
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
width: 200px;
|
||||
margin: 10px;
|
||||
/*padding: 10px;*/
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
}
|
||||
|
||||
.detail-view-field span {
|
||||
display: inline-block;
|
||||
width: 340px;
|
||||
margin: 10px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
|
||||
}
|
||||
</style>
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
|
||||
<div id="notes" class="content-tab">
|
||||
<div id="Details" class="tabcontent">
|
||||
<h3>
|
||||
Details
|
||||
{% for external_link in external_links %}
|
||||
<span style="font-weight: normal; float: right;">{% include 'icons/external_link.html.j2' with external_link=external_link %}</span>
|
||||
{% endfor %}
|
||||
</h3>
|
||||
<div style="align-items:flex-start; align-content: center; display: flexbox; width: 100%">
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.notes %}
|
||||
<div style="display: inline; width: 40%; margin: 30px;">
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.organization.label }}</label>
|
||||
<span>{{ externallink.organization }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.name.label }}</label>
|
||||
<span>{{ form.name.value }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.template.label }}</label>
|
||||
<span>{{ externallink.template }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.colour.label }}</label>
|
||||
<span>
|
||||
{% if form.colour.value %}
|
||||
{{ form.colour.value }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.devices.label }}</label>
|
||||
<span> {{ form.devices.value }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.software.label }}</label>
|
||||
<span>{{ externallink.software }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>Created</label>
|
||||
<span>{{ externallink.created }}</span>
|
||||
</div>
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>Modified</label>
|
||||
<span>{{ externallink.modified }}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style="display: inline; width: 40%; margin: 30px; text-align: left;">
|
||||
<div>
|
||||
<label style="font-weight: bold; width: 100%; border-bottom: 1px solid #ccc; display: block; text-align: inherit;">{{ form.model_notes.label }}</label>
|
||||
|
||||
<div style="display: inline-block; text-align: left;">
|
||||
{% if form.model_notes.value %}
|
||||
{{ form.model_notes.value | markdown | safe }}
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<input type="button" value="Edit" onclick="window.location='{% url 'Settings:_external_link_change' externallink.id %}';">
|
||||
|
||||
|
||||
{% if not tab %}
|
||||
<script>
|
||||
// Get the element with id="defaultOpen" and click on it
|
||||
document.getElementById("defaultOpen").click();
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div id="Notes" class="tabcontent">
|
||||
<h3>
|
||||
Notes
|
||||
</h3>
|
||||
{{ notes_form }}
|
||||
<input type="submit" name="{{notes_form.prefix}}" value="Submit" />
|
||||
<div class="comments">
|
||||
{% if notes %}
|
||||
{% for note in notes%}
|
||||
{% include 'note.html.j2' %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if notes %}
|
||||
{% for note in notes%}
|
||||
{% include 'note.html.j2' %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% if tab == 'notes' %}
|
||||
<script>
|
||||
// Get the element with id="defaultOpen" and click on it
|
||||
document.getElementById("NotesOpen").click();
|
||||
</script>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
@ -62,7 +62,6 @@ div#content article h3 {
|
||||
<article style="">
|
||||
<h3>ITIM</h3>
|
||||
<ul>
|
||||
<li><a href="{% url 'Settings:_cluster_types' %}">Cluster Types</a></li>
|
||||
<li><a href="{% url 'Settings:_ports' %}">Service Ports</a></li>
|
||||
</ul>
|
||||
</article>
|
||||
|
@ -8,49 +8,49 @@ from settings.views import app_settings, home, device_models, device_types, exte
|
||||
|
||||
from itam.views import device_type, device_model, software_category
|
||||
|
||||
from itim.views import cluster_types, ports
|
||||
from itim.views import ports
|
||||
|
||||
app_name = "Settings"
|
||||
urlpatterns = [
|
||||
|
||||
path("", home.View.as_view(), name="Settings"),
|
||||
|
||||
path('application', app_settings.View.as_view(), name="_settings_application"),
|
||||
|
||||
path("cluster_types", cluster_types.Index.as_view(), name="_cluster_types"),
|
||||
path("cluster_types/add", cluster_types.Add.as_view(), name="_cluster_type_add"),
|
||||
path("cluster_types/<int:pk>/edit", cluster_types.Change.as_view(), name="_cluster_type_change"),
|
||||
path("cluster_types/<int:pk>/delete", cluster_types.Delete.as_view(), name="_cluster_type_delete"),
|
||||
path("cluster_types/<int:pk>", cluster_types.View.as_view(), name="_cluster_type_view"),
|
||||
|
||||
path("device_models", device_models.Index.as_view(), name="_device_models"),
|
||||
path("device_model/<int:pk>", device_model.View.as_view(), name="_device_model_view"),
|
||||
path("device_model/<int:pk>/edit", device_model.Change.as_view(), name="_device_model_change"),
|
||||
path("device_model/add/", device_model.Add.as_view(), name="_device_model_add"),
|
||||
path("device_model/<int:pk>/delete", device_model.Delete.as_view(), name="_device_model_delete"),
|
||||
|
||||
path("device_type/", device_types.Index.as_view(), name="_device_types"),
|
||||
path("device_type/<int:pk>", device_type.View.as_view(), name="_device_type_view"),
|
||||
path("device_type/add/", device_type.Add.as_view(), name="_device_type_add"),
|
||||
path("device_type/<int:pk>/delete", device_type.Delete.as_view(), name="_device_type_delete"),
|
||||
path("device_type/<int:pk>/edit", device_type.Change.as_view(), name="_device_type_change"),
|
||||
|
||||
path("external_links", external_link.Index.as_view(), name="External Links"),
|
||||
path("external_links/add", external_link.Add.as_view(), name="_external_link_add"),
|
||||
path("external_links/<int:pk>", external_link.View.as_view(), name="_external_link_view"),
|
||||
path("external_links/<int:pk>/edit", external_link.Change.as_view(), name="_external_link_change"),
|
||||
path("external_links/<int:pk>/delete", external_link.Delete.as_view(), name="_external_link_delete"),
|
||||
|
||||
|
||||
path('application', app_settings.View.as_view(), name="_settings_application"),
|
||||
|
||||
path("task_results", celery_log.Index.as_view(), name="_task_results"),
|
||||
path("task_result/<int:pk>", celery_log.View.as_view(), name="_task_result_view"),
|
||||
|
||||
path("device_models", device_models.Index.as_view(), name="_device_models"),
|
||||
path("device_model/<int:pk>", device_model.View.as_view(), name="_device_model_view"),
|
||||
path("device_model/add/", device_model.Add.as_view(), name="_device_model_add"),
|
||||
path("device_model/<int:pk>/delete", device_model.Delete.as_view(), name="_device_model_delete"),
|
||||
|
||||
path("device_type/", device_types.Index.as_view(), name="_device_types"),
|
||||
path("device_type/<int:pk>", device_type.View.as_view(), name="_device_type_view"),
|
||||
path("device_type/add/", device_type.Add.as_view(), name="_device_type_add"),
|
||||
path("device_type/<int:pk>/delete", device_type.Delete.as_view(), name="_device_type_delete"),
|
||||
|
||||
path("kb/category", knowledge_base_category.Index.as_view(), name="KB Categories"),
|
||||
path("kb/category/add", knowledge_base_category.Add.as_view(), name="_knowledge_base_category_add"),
|
||||
path("kb/category/<int:pk>/edit", knowledge_base_category.Change.as_view(), name="_knowledge_base_category_change"),
|
||||
path("kb/category/<int:pk>/delete", knowledge_base_category.Delete.as_view(), name="_knowledge_base_category_delete"),
|
||||
path("kb/category/<int:pk>", knowledge_base_category.View.as_view(), name="_knowledge_base_category_view"),
|
||||
|
||||
path("software_category", software_categories.Index.as_view(), name="_software_categories"),
|
||||
path("software_category/<int:pk>", software_category.View.as_view(), name="_software_category_view"),
|
||||
path("software_category/add/", software_category.Add.as_view(), name="_software_category_add"),
|
||||
path("software_category/<int:pk>/delete", software_category.Delete.as_view(), name="_software_category_delete"),
|
||||
|
||||
path("manufacturers", manufacturer.Index.as_view(), name="_manufacturers"),
|
||||
path("manufacturer/<int:pk>", manufacturer.View.as_view(), name="_manufacturer_view"),
|
||||
path("manufacturer/add/", manufacturer.Add.as_view(), name="_manufacturer_add"),
|
||||
path("manufacturer/<int:pk>/edit", manufacturer.Change.as_view(), name="_manufacturer_change"),
|
||||
path("manufacturer/<int:pk>/delete", manufacturer.Delete.as_view(), name="_manufacturer_delete"),
|
||||
|
||||
path("ports", ports.Index.as_view(), name="_ports"),
|
||||
@ -59,13 +59,4 @@ urlpatterns = [
|
||||
path("port/<int:pk>/delete", ports.Delete.as_view(), name="_port_delete"),
|
||||
path("port/<int:pk>", ports.View.as_view(), name="_port_view"),
|
||||
|
||||
path("software_category", software_categories.Index.as_view(), name="_software_categories"),
|
||||
path("software_category/<int:pk>", software_category.View.as_view(), name="_software_category_view"),
|
||||
path("software_category/add/", software_category.Add.as_view(), name="_software_category_add"),
|
||||
path("software_category/<int:pk>/edit", software_category.Change.as_view(), name="_software_category_change"),
|
||||
path("software_category/<int:pk>/delete", software_category.Delete.as_view(), name="_software_category_delete"),
|
||||
|
||||
path("task_results", celery_log.Index.as_view(), name="_task_results"),
|
||||
path("task_result/<int:pk>", celery_log.View.as_view(), name="_task_result_view"),
|
||||
|
||||
]
|
||||
|
@ -9,7 +9,7 @@ from access.mixin import OrganizationPermission
|
||||
|
||||
from core.views.common import AddView, ChangeView, DeleteView, DisplayView, IndexView
|
||||
|
||||
from settings.forms.external_links import DetailForm, ExternalLinksForm
|
||||
from settings.forms.external_links import ExternalLinksForm
|
||||
from settings.models.external_link import ExternalLink
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ class View(ChangeView):
|
||||
|
||||
context_object_name = "externallink"
|
||||
|
||||
form_class = DetailForm
|
||||
form_class = ExternalLinksForm
|
||||
|
||||
model = ExternalLink
|
||||
|
||||
|
@ -6,7 +6,7 @@ from django.views import generic
|
||||
|
||||
from access.mixin import OrganizationPermission
|
||||
|
||||
from core.forms.manufacturer import DetailForm, ManufacturerForm
|
||||
from core.forms.manufacturer import ManufacturerForm
|
||||
from core.models.manufacturer import Manufacturer
|
||||
from core.views.common import AddView, ChangeView, DeleteView, IndexView
|
||||
|
||||
@ -37,7 +37,7 @@ class Index(IndexView):
|
||||
|
||||
|
||||
|
||||
class Change(ChangeView):
|
||||
class View(ChangeView):
|
||||
|
||||
context_object_name = "manufacturer"
|
||||
|
||||
@ -46,46 +46,13 @@ class Change(ChangeView):
|
||||
model = Manufacturer
|
||||
|
||||
permission_required = [
|
||||
'core.view_manufacturer',
|
||||
'core.change_manufacturer',
|
||||
]
|
||||
|
||||
template_name = 'form.html.j2'
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = self.object.name
|
||||
|
||||
return context
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return f"/settings/manufacturer/{self.kwargs['pk']}"
|
||||
|
||||
|
||||
@method_decorator(auth_decorator.permission_required("core.change_manufacturer", raise_exception=True))
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
|
||||
|
||||
class View(ChangeView):
|
||||
|
||||
context_object_name = "manufacturer"
|
||||
|
||||
form_class = DetailForm
|
||||
|
||||
model = Manufacturer
|
||||
|
||||
permission_required = [
|
||||
'core.view_manufacturer',
|
||||
]
|
||||
|
||||
template_name = 'core/manufacturer.html.j2'
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
@ -103,6 +70,12 @@ class View(ChangeView):
|
||||
return f"/settings/manufacturer/{self.kwargs['pk']}"
|
||||
|
||||
|
||||
@method_decorator(auth_decorator.permission_required("core.change_manufacturer", raise_exception=True))
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
|
||||
|
||||
class Add(AddView):
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
{% load choice_ids %}
|
||||
|
||||
{% if field.widget_type == 'textarea' or field.label == 'Notes' %}
|
||||
|
||||
@ -30,7 +29,7 @@
|
||||
|
||||
{% if field.value %}
|
||||
|
||||
<div style="display:block; width: 95%; text-align: left;">{{ field.value | markdown | safe }}</div>
|
||||
{{ field.value | markdown | safe }}
|
||||
|
||||
{% else %}
|
||||
|
||||
@ -54,41 +53,18 @@
|
||||
<label>{{ field.label }}</label>
|
||||
<span>
|
||||
{% if field.field.choices %} {# Display the selected choice text value #}
|
||||
{% for id, value in field.field.choices %}
|
||||
|
||||
{% if field.value %}
|
||||
|
||||
{% for field_value in field.value|choice_ids %}
|
||||
{% if field.value == id %}
|
||||
|
||||
{% for id, value in field.field.choices %}
|
||||
{{ value }}
|
||||
|
||||
{% if field_value == id %}
|
||||
{% endif %}
|
||||
|
||||
{{ value }},
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% else %}
|
||||
|
||||
|
||||
|
||||
{% endif %}
|
||||
{%endfor%}
|
||||
|
||||
{% else %}
|
||||
|
||||
{% if field.value is not None %}
|
||||
|
||||
{{ field.value }}
|
||||
|
||||
{% else %}
|
||||
|
||||
|
||||
|
||||
{% endif %}
|
||||
|
||||
{{ field.value }}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user