Skip to content

Commit

Permalink
Add Jamf Overview page
Browse files Browse the repository at this point in the history
  • Loading branch information
mazzi authored Oct 23, 2023
1 parent 29c9ea0 commit cfc5d10
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 2 deletions.
26 changes: 26 additions & 0 deletions tests/jamf/test_jamf_setup_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,32 @@ def _force_tag_config(self):
regex=r"^YOLOFOMO: (.*)$",
replacement=r"\1")

# jamf index

def test_jamf_index_redirect(self):
self._login_redirect(reverse("jamf:index"))

def test_jamf_index_permission_denied(self):
self._login()
response = self.client.get(reverse("jamf:index"))
self.assertEqual(response.status_code, 403)

def test_jamf_index(self):
self._login("jamf.view_jamfinstance")
jamf_instance = self._force_jamf_instance()
response = self.client.get(reverse("jamf:index"))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "jamf/index.html")
self.assertContains(response, jamf_instance.host)

def test_jamf_index_no_list(self):
self._login("jamf.view_tagconfig")
jamf_instance = self._force_jamf_instance()
response = self.client.get(reverse("jamf:index"))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "jamf/index.html")
self.assertNotContains(response, jamf_instance.host)

# jamf instances

def test_jamf_instances_redirect(self):
Expand Down
121 changes: 121 additions & 0 deletions zentral/contrib/jamf/templates/jamf/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
{% extends 'base.html' %}
{% load ui_extras %}

{% block content %}
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item active">Jamf</li>
</ol>

<div class="row">
<div class="col-md-12">
<h2>Jamf</h2>
</div>
<div class="col-sm-6">
<canvas class="chart"
data-app="jamf"
data-dataset="event_count"
width="200"
height="120"></canvas>
</div>
<div class="col-sm-6">
<canvas class="chart"
data-app="jamf"
data-dataset="unique_msn"
width="200"
height="120"></canvas>
</div>
<div class="col-md-12">
{% if perms.jamf.view_jamfinstance %}
<h3>Instance{{ instances_count|pluralize }} ({{ instances_count }})</h3>
{% if instances %}
<table class="table table-light table-striped align-middle table-hover">
<thead>
<tr>
<th>Host</th>
<th>API User</th>
<th>Business unit</th>
{% if perms.jamf.change_jamfinstance %}
<th></th>
{% endif %}
</tr>
</thead>
<tbody>
{% for jamf_instance in instances %}
<tr class="data-row">
<td><a href="{{ jamf_instance.get_absolute_url }}">{{ jamf_instance.host }}</a></td>
<td>{{ jamf_instance.user }}</td>
<td>
{% if jamf_instance.business_unit %}
{{ jamf_instance.business_unit }}
{% else %}
-
{% endif %}
</td>
{% if perms.jamf.change_jamfinstance %}
<td class="text-end py-0">
{% url 'jamf:update_jamf_instance' jamf_instance.pk as url %}
{% button 'UPDATE' url "Edit Instance" %}
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
{% if perms.jamf.add_jamfinstance %}
{% url 'jamf:create_jamf_instance' as link %}
{% no_entities 'Instances' link %}
{% else %}
{% no_entities 'Instances' %}
{% endif %}
{% endif %}
{% endif %}
</div>
</div>
{% endblock %}

{% block extrajs %}
<script nonce="{{ request.csp_nonce }}">
function get_data_and_make_chart(url, charts) {
$.getJSON(url, function(data) {
for (var dataset in data.datasets) {
if (data.datasets.hasOwnProperty(dataset)) {
var canvas = charts[data.app][dataset];
var chart = new Chart(canvas, {
type: 'bar',
data: {labels: data.labels,
datasets: [data.datasets[dataset]]},
options: {
scales: {
xAxes: [{gridLines: { color: "darkgray", zeroLineColor: "darkgray" }}],
yAxes: [{gridLines: { color: "darkgray", zeroLineColor: "darkgray" }}]
}
}
});
}
}
});
}

$(document).ready(function(){
var charts = {};
var urls = Array();
$(".chart").each(function(index, canvas) {
canvas = $(canvas);
var app = canvas.data('app');
var dataset = canvas.data('dataset');
if(! charts.hasOwnProperty(app)) {
charts[app] = {};
urls.push('/app/' + app + '/hist_data/day/14/');
}
charts[app][dataset] = canvas;
});
for (var idx in urls) {
if (urls.hasOwnProperty(idx)) {
get_data_and_make_chart(urls[idx], charts);
}
}
});
</script>
{% endblock %}
5 changes: 5 additions & 0 deletions zentral/contrib/jamf/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

app_name = "jamf"
urlpatterns = [

# index
path('', views.IndexView.as_view(), name="index"),

# setup > jamf instances
path('instances/', views.JamfInstancesView.as_view(), name="jamf_instances"),
path('instances/create/', views.CreateJamfInstanceView.as_view(), name="create_jamf_instance"),
Expand All @@ -27,6 +31,7 @@

modules_menu_cfg = {
'items': (
('index', 'Overview', False, ('jamf',)),
('jamf_instances', 'jamf instances', False, ('jamf.view_jamfinstance',)),
),
'weight': 60,
Expand Down
17 changes: 15 additions & 2 deletions zentral/contrib/jamf/views.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import logging
from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import PermissionDenied
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse_lazy
from django.views.generic import DetailView, View, ListView
from django.views.generic import DetailView, TemplateView, ListView, View
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from zentral.utils.api_views import APIAuthError, JSONPostAPIView
from .api_client import APIClient, APIClientError
Expand All @@ -17,6 +18,18 @@

# setup > jamf instances

class IndexView(LoginRequiredMixin, TemplateView):
template_name = "jamf/index.html"

def get_context_data(self, **kwargs):
if not self.request.user.has_module_perms("jamf"):
raise PermissionDenied("Not allowed")
ctx = super().get_context_data(**kwargs)
jamf_instances = JamfInstance.objects.all()
ctx["instances"] = jamf_instances
ctx["instances_count"] = jamf_instances.count()
return ctx


class JamfInstancesView(PermissionRequiredMixin, ListView):
permission_required = "jamf.view_jamfinstance"
Expand Down

0 comments on commit cfc5d10

Please sign in to comment.