Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revamp of Allocation Notes #582

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ <h3 class="d-inline"><i class="fas fa-users" aria-hidden="true"></i> Users in Al
</div>

<!-- Start Admin Messages -->

<div class="card mb-3">
<div class="card-header">
<h3 class="d-inline"><i class="fas fa-users" aria-hidden="true"></i> Notifications</h3>
Expand All @@ -346,16 +347,28 @@ <h3 class="d-inline"><i class="fas fa-users" aria-hidden="true"></i> Notificatio
<a class="btn btn-success" href="{% url 'allocation-note-add' allocation.pk %}" role="button">
<i class="fas fa-plus" aria-hidden="true"></i> Add Notification
</a>
<a class="btn btn-info" href="{% url 'notes-download' project.id %}" role="button"><i class="fas fa-plus" aria-hidden="true"></i> Export to CSV</a>
{% endif %}
</div>
</div>
<div class="card-body">
{% if notes %}
<br>
<div class="bd-example">
<nav>
<div class="nav nav-tabs mb-3" id="nav-tab" role="tablist">
<button class="nav-link active" id="nav-home-tab" data-bs-toggle="tab" data-bs-target="#nav-home" type="button" role="tab" aria-controls="nav-home" aria-selected="false" fdprocessedid="d6nz6" tabindex="-1">All</button>
{% for note_tag in note_tags %}
<button class="nav-link" id="{{ note_tag }}" data-bs-toggle="tab" data-bs-target="#{{ note_tag }}" type="button" role="tab" aria-controls="{{ note_tag }}" aria-selected="false" tabindex="-1">{{ note_tag }}</button>
{% endfor %}
</div>
</nav>
<div class="tab-content" id="nav-tabContent">
<div class="tab-pane fade active show" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab" tabindex="0">
<div class="table-responsive">
<table class="table table-hover">
<table class="table table-hover" table id="notes_table">
<thead>
<tr>
<th scope="col">Note</th>
<th scope="col">Tag</th>
<th scope="col">Administrator</th>
<th scope="col">Last Modified</th>
</tr>
Expand All @@ -364,22 +377,51 @@ <h3 class="d-inline"><i class="fas fa-users" aria-hidden="true"></i> Notificatio
{% for note in notes %}
{% if not note.is_private or request.user.is_superuser %}
<tr>
<td>{{ note.note }}</td>
<td>{{ note.message }}</td>
<td>{{ note.tags }}</td>
<td>{{ note.author.first_name }} {{ note.author.last_name }}</td>
<td>{{ note.modified }}</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="alert alert-info" role="alert">
<i class="fa fa-info-circle" aria-hidden="true"></i> There are no notes from system administrators.
</div>
{% endif %}
</div> </div>
{% for note_tag in note_tags %}
<div class="tab-pane fade" id="a" role="tabpanel" aria-labelledby="a" tabindex="0">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Note</th>
<th scope="col">Tag</th>
<th scope="col">Administrator</th>
<th scope="col">Last Modified</th>
</tr>
</thead>
<tbody>
{% for note in notes %}
{% if not note.is_private or request.user.is_superuser %}
<tr>
<td>{{ note.message }}</td>
<td>{{ note.tags }}</td>
<td>{{ note.author.first_name }} {{ note.author.last_name }}</td>
<td>{{ note.modified }}</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div> </div>
{% endfor %}

</div>
</div>
</div>





<script>
$(document).ready(function () {
Expand All @@ -401,6 +443,13 @@ <h3 class="d-inline"><i class="fas fa-users" aria-hidden="true"></i> Notificatio
'aTargets': ['nosort']
}]
});

$('#notes_table').DataTable({
'aoColumnDefs': [{
'bSortable': false,
'aTargets': ['nosort']
}]
});
});

function drawGauges(guage_data) {
Expand Down
107 changes: 82 additions & 25 deletions coldfront/core/allocation/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import csv
import datetime
import logging
from datetime import date
Expand All @@ -13,7 +14,7 @@
from django.db.models import Q
from django.db.models.query import QuerySet
from django.forms import formset_factory
from django.http import HttpResponseRedirect, JsonResponse, HttpResponseBadRequest
from django.http import HttpResponseRedirect, JsonResponse, HttpResponseBadRequest, HttpResponse, StreamingHttpResponse
from django.shortcuts import get_object_or_404, render
from django.urls import reverse, reverse_lazy
from django.utils.html import format_html, mark_safe
Expand All @@ -31,7 +32,7 @@
AllocationAttributeUpdateForm,
AllocationForm,
AllocationInvoiceNoteDeleteForm,
AllocationInvoiceUpdateForm,
AllocationInvoiceUpdateForm, AllocationNoteCreateForm,
AllocationRemoveUserForm,
AllocationReviewUserForm,
AllocationSearchForm,
Expand Down Expand Up @@ -59,7 +60,7 @@
from coldfront.core.project.models import (Project, ProjectUser, ProjectPermission,
ProjectUserStatusChoice)
from coldfront.core.resource.models import Resource
from coldfront.core.utils.common import get_domain_url, import_from_settings
from coldfront.core.utils.common import Echo, get_domain_url, import_from_settings
from coldfront.core.utils.mail import send_allocation_admin_email, send_allocation_customer_email

ALLOCATION_ENABLE_ALLOCATION_RENEWAL = import_from_settings(
Expand Down Expand Up @@ -885,47 +886,103 @@ def post(self, request, *args, **kwargs):
return HttpResponseRedirect(reverse('allocation-detail', kwargs={'pk': pk}))


class AllocationNoteCreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
model = AllocationUserNote
fields = '__all__'
class AllocationNoteCreateView(LoginRequiredMixin, UserPassesTestMixin, FormView):
form_class = AllocationNoteCreateForm
# fields = '__all__'
template_name = 'allocation/allocation_note_create.html'

def test_func(self):
""" UserPassesTestMixin Tests"""

allocation_obj = get_object_or_404(Allocation, pk=self.kwargs.get('pk'))
if self.request.user.is_superuser:
return True
messages.error( self.request, 'You do not have permission to add allocation notes.')
return False

else:
messages.error(
self.request, 'You do not have permission to add allocation notes.')

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
pk = self.kwargs.get('pk')
allocation_obj = get_object_or_404(Allocation, pk=pk)
context['allocation'] = allocation_obj
project_obj = get_object_or_404(Allocation, pk=pk)
context['allocation'] = project_obj
return context

def get_initial(self):
initial = super().get_initial()
pk = self.kwargs.get('pk')
allocation_obj = get_object_or_404(Allocation, pk=pk)
author = self.request.user
initial['allocation'] = allocation_obj
initial['author'] = author
return initial


def get_form(self, form_class=None):
def get_form(self, form_class=form_class):
"""Return an instance of the form to be used in this view."""
form = super().get_form(form_class)
form.fields['allocation'].widget = forms.HiddenInput()
form.fields['author'].widget = forms.HiddenInput()
form.order_fields([ 'allocation', 'author', 'note', 'is_private' ])
return form
pk = self.kwargs.get('pk')
return form_class(self.kwargs.get('pk'), **self.get_form_kwargs())

def form_valid(self, form) -> HttpResponse:
obj = form
allocation_obj = get_object_or_404(Allocation, pk=self.kwargs.get('pk'))
form_complete = AllocationNoteCreateForm(allocation_obj.pk,self.request.POST,initial = {"author":self.request.user,"message":obj.data['message']})
if form_complete.is_valid():
form_data = form_complete.cleaned_data
new_note_obj = AllocationUserNote.objects.create(
allocation = allocation_obj,
message = form_data["message"],
tags = form_data["tags"],
author = self.request.user,
)

# obj.project = allocation_obj

self.object = obj

return super().form_valid(form)


def get_success_url(self):
return reverse('allocation-detail', kwargs={'pk': self.kwargs.get('pk')})



class AllocationNoteDownloadView(LoginRequiredMixin, UserPassesTestMixin, ListView):
def test_func(self):
""" UserPassesTestMixin Tests"""
if self.request.user.is_superuser:
return True

allocation_obj = get_object_or_404(Allocation, pk=self.kwargs.get('pk'))

if allocation_obj.project.pi == self.request.user:
return True

if allocation_obj.projectuser_set.filter(user=self.request.user, role__name='Manager', status__name='Active').exists():
return True

messages.error(self.request, 'You do not have permission to download all notes.')

def get(self, request, pk):
header = [
"Comment",
"Administrator",
"Created By",
"Last Modified"
]
rows = []
allocation_obj = get_object_or_404(Allocation, pk=self.kwargs.get('pk'))

notes = allocation_obj.allocationusernote_set.all()

for note in notes:
row = [
note.message,
note.author,
note.tags,
note.modified
]
rows.append(row)
rows.insert(0, header)
pseudo_buffer = Echo()
writer = csv.writer(pseudo_buffer)
response = StreamingHttpResponse((writer.writerow(row) for row in rows),
content_type="text/csv")
response['Content-Disposition'] = 'attachment; filename="notes.csv"'
return response
class AllocationRequestListView(LoginRequiredMixin, UserPassesTestMixin, TemplateView):
template_name = 'allocation/allocation_request_list.html'
login_url = '/'
Expand Down