Commit 9cf54290 by Kálmán Viktor

request: add reason for decline

parent 9915ef55
......@@ -1296,3 +1296,14 @@ textarea[name="new_members"] {
text-align: center;
}
}
#request-buttons {
form {
display: inline;
}
textarea {
resize: none;
min-height: 80px;
}
}
......@@ -26,8 +26,8 @@
{% trans "Changing resources is only possible on virtual machines with STOPPED state. We suggest to turn off the VM after submitting the request otherwise it will be automatically stopped in the future when the request is accepted." %}
</div>
<div class="form-group">
<label>{% trans "Reason" %}*</label>
<textarea class="form-control" name="reason">{% include "request/initials/resources.html" %}</textarea>
<label>{% trans "Message" %}*</label>
<textarea class="form-control" name="message">{% include "request/initials/resources.html" %}</textarea>
</div>
<input type="submit" class="btn btn-success btn-sm"/>
</div>
......
......@@ -63,7 +63,7 @@ class InitialFromFileMixin(object):
request = kwargs.pop("request", None)
super(InitialFromFileMixin, self).__init__(*args, **kwargs)
self.initial['reason'] = render_to_string(
self.initial['message'] = render_to_string(
self.initial_template,
RequestContext(request, {}),
)
......@@ -74,17 +74,17 @@ class TemplateRequestForm(InitialFromFileMixin, Form):
label=_("Template share"))
level = ChoiceField(TemplateAccessAction.LEVELS, widget=RadioSelect,
initial=TemplateAccessAction.LEVELS.user)
reason = CharField(widget=forms.Textarea, label=_("Reason"))
message = CharField(widget=forms.Textarea, label=_("Message"))
initial_template = "request/initials/template.html"
class LeaseRequestForm(InitialFromFileMixin, Form):
lease = ModelChoiceField(LeaseType.objects.all(), label=_("Lease"))
reason = CharField(widget=forms.Textarea)
message = CharField(widget=forms.Textarea)
initial_template = "request/initials/lease.html"
class ResourceRequestForm(VmResourcesForm):
reason = CharField(widget=forms.Textarea)
message = CharField(widget=forms.Textarea)
......@@ -46,12 +46,14 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, verbose_name='created', editable=False)),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, verbose_name='modified', editable=False)),
('status', models.CharField(default=b'UNSEEN', max_length=10, choices=[(b'UNSEEN', 'unseen'), (b'PENDING', 'pending'), (b'ACCEPTED', 'accepted'), (b'DECLINED', 'declined')])),
('status', models.CharField(default=b'PENDING', max_length=10, choices=[(b'PENDING', 'pending'), (b'ACCEPTED', 'accepted'), (b'DECLINED', 'declined')])),
('type', models.CharField(max_length=10, choices=[(b'resource', 'resource request'), (b'lease', 'lease request'), (b'template', 'template access')])),
('reason', models.TextField(help_text=b'szia')),
('message', models.TextField(verbose_name='Message')),
('reason', models.TextField(verbose_name='Reason')),
('object_id', models.IntegerField()),
('closed_by', models.ForeignKey(related_name='closed_by', to=settings.AUTH_USER_MODEL, null=True)),
('content_type', models.ForeignKey(to='contenttypes.ContentType')),
('user', models.ForeignKey(verbose_name='user', to=settings.AUTH_USER_MODEL)),
('user', models.ForeignKey(related_name='user', to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('request', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='request',
name='closed_by',
field=models.ForeignKey(related_name='closed_by', to=settings.AUTH_USER_MODEL, null=True),
preserve_default=True,
),
migrations.AlterField(
model_name='request',
name='user',
field=models.ForeignKey(related_name='user', to=settings.AUTH_USER_MODEL),
preserve_default=True,
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('request', '0002_auto_20150317_1211'),
]
operations = [
migrations.AlterField(
model_name='request',
name='reason',
field=models.TextField(verbose_name='Reason'),
preserve_default=True,
),
]
......@@ -52,12 +52,11 @@ class RequestType(Model):
class Request(TimeStampedModel):
STATUSES = Choices(
('UNSEEN', _("unseen")),
('PENDING', _('pending')),
('ACCEPTED', _('accepted')),
('DECLINED', _('declined')),
)
status = CharField(choices=STATUSES, default=STATUSES.UNSEEN,
status = CharField(choices=STATUSES, default=STATUSES.PENDING,
max_length=10)
user = ForeignKey(User, related_name="user")
closed_by = ForeignKey(User, related_name="closed_by", null=True)
......@@ -67,6 +66,7 @@ class Request(TimeStampedModel):
('template', _("template access")),
)
type = CharField(choices=TYPES, max_length=10)
message = TextField(verbose_name=_("Message"))
reason = TextField(verbose_name=_("Reason"))
content_type = ForeignKey(ContentType)
......@@ -91,7 +91,6 @@ class Request(TimeStampedModel):
def get_effect(self):
return {
"UNSEEN": "primary",
"PENDING": "warning",
"ACCEPTED": "success",
"DECLINED": "danger",
......@@ -99,7 +98,6 @@ class Request(TimeStampedModel):
def get_status_icon(self):
return {
"UNSEEN": "eye-slash",
"PENDING": "exclamation-triangle",
"ACCEPTED": "check",
"DECLINED": "times",
......@@ -111,9 +109,10 @@ class Request(TimeStampedModel):
self.closed_by = user
self.save()
def decline(self, user):
def decline(self, user, reason):
self.status = "DECLINED"
self.closed_by = user
self.reason = reason
self.save()
......@@ -202,5 +201,10 @@ def send_notification_to_superusers(sender, instance, created, **kwargs):
ugettext_noop("New %(request_type)s"), notification_msg, context
)
instance.user.profile.notify(
ugettext_noop("Request submitted"),
ugettext_noop('You can view the request\'s status at this '
'<a href="%(request_url)s">link</a>.'), context
)
post_save.connect(send_notification_to_superusers, sender=Request)
......@@ -5,6 +5,6 @@
{% include "display-form-errors.html" %}
{% csrf_token %}
{{ form.lease|as_crispy_field }}
{{ form.reason|as_crispy_field }}
{{ form.message|as_crispy_field }}
<input type="submit" class="btn btn-primary"/>
</form>
......@@ -21,6 +21,6 @@
</label>
</div>
{% endfor %}
{{ form.reason|as_crispy_field }}
{{ form.message|as_crispy_field }}
<input type="submit" class="btn btn-primary"/>
</form>
......@@ -12,9 +12,11 @@
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<a href="{% url "request.views.request-list" %}" class="btn btn-default btn-xs pull-right">
{% trans "Back" %}
</a>
{% if request.user.is_superuser %}
<a href="{% url "request.views.request-list" %}" class="btn btn-default btn-xs pull-right">
{% trans "Back" %}
</a>
{% endif %}
<h3 class="no-margin">
<i class="fa fa-{{ object.get_request_icon }}"></i>
{{ object.get_readable_type|capfirst }}
......@@ -32,7 +34,7 @@
</a>
</p>
<p>
<pre>{{ object.reason }}</pre>
<pre>{{ object.message }}</pre>
</p>
<hr />
{% if object.type == "lease" %}
......@@ -87,36 +89,44 @@
hacks!!!
{% endif %}
{% if object.status == "PENDING" %}
{% if object.status == "PENDING" and request.user.is_superuser %}
<hr />
<div class="pull-right">
<form method="POST" style="display: inline;">
<div class="pull-right" id="request-buttons">
<form method="POST">
{% csrf_token %}
<p>
<textarea class="form-control" placeholder="{% trans "Reason (sent to the user if the request is declined)" %}" name="reason"></textarea>
</p>
<button class="btn btn-danger" type="submit">
<i class="fa fa-thumbs-down"></i>
{% trans "Decline" %}
</button>
</form>
{{ acceptable_statuses }}
{% if object.type == "resource" and action.instance.status not in accept_states %}
{% trans "You can't accept this request because of the VM's state." %}
{% else %}
<form method="POST" style="display: inline;">
{% csrf_token %}
<input type="hidden" name="accept" value="1"/>
<button class="btn btn-success">
<i class="fa fa-thumbs-up"></i>
{% trans "Accept" %}
</button>
</form>
<form method="POST">
{% csrf_token %}
<input type="hidden" name="accept" value="1"/>
<button class="btn btn-success">
<i class="fa fa-thumbs-up"></i>
{% trans "Accept" %}
</button>
</form>
{% endif %}
</div>
{% else %}
{% endif %}
{% if object.status != "PENDING" %}
<div class="text-right">
{% blocktrans with closed=object.modified|arrowfilter:LANGUAGE_CODE user=object.closed_by.profile.get_display_name %}
Closed {{ closed }} by <a href="{{ user.profile.get_absolute_url }}">{{ user }}</a>
{% endblocktrans %}
{% if object.status == "DECLINED" %}
<p>
<strong>{% trans "Reason" %}:</strong> {{ object.reason }}
</p>
{% endif %}
</div>
{% endif %}
</div><!-- .panel-body -->
......
......@@ -24,7 +24,7 @@
</div>
{% include "display-form-errors.html" %}
{% include "dashboard/_resources-sliders.html" with field_priority=form.priority field_num_cores=form.num_cores field_ram_size=form.ram_size %}
{{ form.reason|as_crispy_field }}
{{ form.message|as_crispy_field }}
<button type="submit" class="btn btn-success">
{% trans "Request new resources" %}
</button>
......
......@@ -20,7 +20,7 @@ from django.views.generic import (
UpdateView, TemplateView, DetailView, CreateView, FormView,
)
from django.shortcuts import redirect, get_object_or_404
from django.core.exceptions import PermissionDenied
from django.core.exceptions import PermissionDenied, SuspiciousOperation
from braces.views import SuperuserRequiredMixin, LoginRequiredMixin
from django_tables2 import SingleTableView
......@@ -59,32 +59,39 @@ class RequestList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView):
return data
class RequestDetail(LoginRequiredMixin, SuperuserRequiredMixin, DetailView):
class RequestDetail(LoginRequiredMixin, DetailView):
model = Request
template_name = "request/detail.html"
def post(self, *args, **kwargs):
if self.get_object().status in ["PENDING", "UNSEEN"]:
user = self.request.user
user = self.request.user
request = self.get_object() # not self.request!
if not user.is_superuser:
raise SuspiciousOperation
if self.get_object().status == "PENDING":
accept = self.request.POST.get("accept")
request = self.get_object() # not self.request!
reason = self.request.POST.get("reason")
if accept:
request.accept(user)
else:
request.decline(user)
request.decline(user, reason)
return redirect(request.get_absolute_url())
def get_context_data(self, **kwargs):
request = self.object
user = self.request.user
if not user.is_superuser and request.user != user:
raise SuspiciousOperation
context = super(RequestDetail, self).get_context_data(**kwargs)
context['action'] = request.action
context['accept_states'] = ResourcesRequestOperation.accept_states
if request.status == Request.STATUSES.UNSEEN:
request.status = Request.STATUSES.PENDING
request.save()
return context
......@@ -151,7 +158,7 @@ class TemplateRequestView(FormView):
req = Request(
user=user,
reason=data['reason'],
message=data['message'],
type=Request.TYPES.template,
action=ta
)
......@@ -203,7 +210,7 @@ class LeaseRequestView(VmRequestMixin, FormView):
req = Request(
user=user,
reason=data['reason'],
message=data['message'],
type=Request.TYPES.lease,
action=el
)
......@@ -245,7 +252,7 @@ class ResourceRequestView(VmRequestMixin, FormView):
req = Request(
user=user,
reason=data['reason'],
message=data['message'],
type=Request.TYPES.resource,
action=rc
)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment