model = UserProfile
fields = ['company', 'ssh_public_key', 'pgp_public_key', 'timezone']
- ssh_public_key = forms.CharField(max_length=2048, widget=forms.Textarea)
- pgp_public_key = forms.CharField(max_length=2048, widget=forms.Textarea)
timezone = forms.ChoiceField(choices=[(x, x) for x in pytz.common_timezones], initial='UTC')
from dashboard.models import Resource
+def upload_to(object, filename):
+ return object.user.username + '/' + filename
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
timezone = models.CharField(max_length=100, blank=False, default='UTC')
- ssh_public_key = models.CharField(max_length=2048, blank=False)
- pgp_public_key = models.CharField(max_length=2048, blank=False)
+ ssh_public_key = models.FileField(upload_to=upload_to, null=True, blank=True)
+ pgp_public_key = models.FileField(upload_to=upload_to, null=True, blank=True)
company = models.CharField(max_length=200, blank=False)
oauth_token = models.CharField(max_length=1024, blank=False)
oauth_secret = models.CharField(max_length=1024, blank=False)
resource = models.ForeignKey(Resource, models.PROTECT)
start = models.DateTimeField()
end = models.DateTimeField()
+ jira_issue_id = models.IntegerField(null=True)
purpose = models.CharField(max_length=300, blank=False)
if user.has_perm('booking.add_booking'):
return True
# Check if User owns this resource
- if user in self.resource.owners.all():
+ if user == self.resource.owner:
return True
return False
-
def save(self, *args, **kwargs):
"""
Save the booking if self.user is authorized and there is no overlapping booking.
from django.test import TestCase
from django.utils import timezone
+from account.models import UserProfile
from booking.models import Booking
from dashboard.models import Resource
from jenkins.models import JenkinsSlave
class BookingModelTestCase(TestCase):
def setUp(self):
self.slave = JenkinsSlave.objects.create(name='test', url='test')
+ self.owner = User.objects.create(username='owner')
- self.res1 = Resource.objects.create(name='res1', slave=self.slave, description='x', url='x')
- self.res2 = Resource.objects.create(name='res2', slave=self.slave, description='x', url='x')
+ self.res1 = Resource.objects.create(name='res1', slave=self.slave, description='x',
+ url='x',owner=self.owner)
+ self.res2 = Resource.objects.create(name='res2', slave=self.slave, description='x',
+ url='x',owner=self.owner)
self.user1 = User.objects.create(username='user1')
def test_authorization(self):
user = User.objects.create(username='user')
+ user.userprofile = UserProfile.objects.create(user=user)
self.assertRaises(PermissionError, Booking.objects.create, start=timezone.now(),
end=timezone.now() + timedelta(days=1), resource=self.res1, user=user)
- self.res1.owners.add(user)
+ self.res1.owner = user
self.assertTrue(
Booking.objects.create(start=timezone.now(), end=timezone.now() + timedelta(days=1),
resource=self.res1, user=user))
+ self.res1.owner = self.owner
user.user_permissions.add(self.add_booking_perm)
user = User.objects.get(pk=user.id)
self.assertTrue(
def setUp(self):
self.client = Client()
self.slave = JenkinsSlave.objects.create(name='test', url='test')
- self.res1 = Resource.objects.create(name='res1', slave=self.slave, description='x', url='x')
+ self.owner = User.objects.create(username='owner')
+ self.res1 = Resource.objects.create(name='res1', slave=self.slave, description='x',
+ url='x',owner=self.owner)
self.user1 = User.objects.create(username='user1')
self.user1.set_password('user1')
self.user1profile = UserProfile.objects.create(user=self.user1)
from django.urls import reverse
from django.views import View
from django.views.generic import FormView
+from django.shortcuts import redirect
+from jira import JIRAError
from account.jira_util import get_jira
from booking.forms import BookingForm
from dashboard.models import Resource
+def create_jira_ticket(user, booking):
+ jira = get_jira(user)
+ issue_dict = {
+ 'project': 'PHAROS',
+ 'summary': str(booking.resource) + ': Access Request',
+ 'description': booking.purpose,
+ 'issuetype': {'name': 'Task'},
+ 'components': [{'name': 'POD Access Request'}],
+ 'assignee': {'name': booking.resource.owner.username}
+ }
+ issue = jira.create_issue(fields=issue_dict)
+ jira.add_attachment(issue, user.userprofile.pgp_public_key)
+ jira.add_attachment(issue, user.userprofile.ssh_public_key)
+ booking.jira_issue_id = issue.id
+
+
class BookingFormView(LoginRequiredMixin, FormView):
template_name = "booking/booking_calendar.html"
form_class = BookingForm
- def open_jira_issue(self,booking):
- jira = get_jira(self.request.user)
- issue_dict = {
- 'project': 'PHAROS',
- 'summary': 'Booking: ' + str(self.resource),
- 'description': str(booking),
- 'issuetype': {'name': 'Task'},
- }
- jira.create_issue(fields=issue_dict)
-
def dispatch(self, request, *args, **kwargs):
self.resource = get_object_or_404(Resource, id=self.kwargs['resource_id'])
return super(BookingFormView, self).dispatch(request, *args, **kwargs)
return reverse('booking:create', kwargs=self.kwargs)
def form_valid(self, form):
+ user = self.request.user
+ if not user.userprofile.ssh_public_key or not user.userprofile.pgp_public_key:
+ messages.add_message(self.request, messages.INFO,
+ 'Please upload your private keys before booking')
+ return redirect('account:settings')
booking = Booking(start=form.cleaned_data['start'], end=form.cleaned_data['end'],
purpose=form.cleaned_data['purpose'], resource=self.resource,
- user=self.request.user)
+ user=user)
try:
booking.save()
except ValueError as err:
except PermissionError as err:
messages.add_message(self.request, messages.ERROR, err)
return super(BookingFormView, self).form_invalid(form)
- self.open_jira_issue(booking)
+ try:
+ create_jira_ticket(user, booking)
+ except JIRAError:
+ messages.add_message(self.request, messages.ERROR, 'Failed to create Jira Ticket. '
+ 'Please check your Jira '
+ 'permissions.')
+ booking.delete()
+ return super(BookingFormView, self).form_invalid(form)
messages.add_message(self.request, messages.SUCCESS, 'Booking saved')
return super(BookingFormView, self).form_valid(form)
"pk": 1,
"fields": {
"name": "Linux Foundation POD 1",
- "slavename": "lf-pod1",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Lf+Lab"
}
"pk": 2,
"fields": {
"name": "Linux Foundation POD 2",
- "slavename": "lf-pod2",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Lf+Lab"
}
"pk": 3,
"fields": {
"name": "Ericsson POD 2",
- "slavename": "ericsson-pod2",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Ericsson+Hosting+and+Request+Process"
}
"pk": 4,
"fields": {
"name": "Intel POD 2",
- "slavename": "intel-pod2",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Intel+Pod2"
}
"pk": 5,
"fields": {
"name": "Intel POD 5",
- "slavename": "intel-pod5",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Intel+Pod5"
}
"pk": 6,
"fields": {
"name": "Intel POD 6",
- "slavename": "intel-pod6",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Intel+Pod6"
}
"pk": 7,
"fields": {
"name": "Intel POD 8",
- "slavename": "intel-pod8",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Intel+Pod8"
}
"pk": 8,
"fields": {
"name": "Huawei POD 1",
- "slavename": "huawei-pod1",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Huawei+Hosting"
}
"pk": 9,
"fields": {
"name": "Intel POD 3",
- "slavename": "intel-pod3",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Intel+Pod3"
}
"pk": 10,
"fields": {
"name": "Dell POD 1",
- "slavename": "dell-pod1",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Dell+Hosting"
}
"pk": 11,
"fields": {
"name": "Dell POD 2",
- "slavename": "dell-pod2",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Dell+Hosting"
}
"pk": 12,
"fields": {
"name": "Orange POD 2",
- "slavename": "orange-pod2",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Opnfv-orange-pod2"
}
"pk": 13,
"fields": {
"name": "Arm POD 1",
- "slavename": "arm-build1",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Enea-pharos-lab"
}
"pk": 14,
"fields": {
"name": "Ericsson POD 1",
- "slavename": "ericsson-pod1",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Ericsson+Hosting+and+Request+Process"
}
"pk": 15,
"fields": {
"name": "Huawei POD 2",
- "slavename": "huawei-pod2",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Huawei+Hosting"
}
"pk": 16,
"fields": {
"name": "Huawei POD 3",
- "slavename": "huawei-pod3",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Huawei+Hosting"
}
"pk": 17,
"fields": {
"name": "Huawei POD 4",
- "slavename": "huawei-pod4",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Huawei+Hosting"
}
"pk": 18,
"fields": {
"name": "Intel POD 9",
- "slavename": "intel-pod9",
"description": "Some description",
"url": "https://wiki.opnfv.org/display/pharos/Intel+Pod9"
}
name = models.CharField(max_length=100, unique=True)
description = models.CharField(max_length=300, blank=True, null=True)
url = models.CharField(max_length=100, blank=True, null=True)
- owners = models.ManyToManyField(User)
- slave = models.ForeignKey(JenkinsSlave, on_delete=models.DO_NOTHING)
+ owner = models.ForeignKey(User)
+ slave = models.ForeignKey(JenkinsSlave, on_delete=models.DO_NOTHING, null=True)
class Meta:
db_table = 'resource'
from datetime import timedelta
+
+from django.contrib.auth.models import User
from django.utils import timezone
from django.views.generic import TemplateView
class Meta:
db_table = 'jenkins_slave'
+ def __str__(self):
+ return self.name
+
class JenkinsStatistic(models.Model):
id = models.AutoField(primary_key=True)
USE_TZ = True
+MEDIA_ROOT = '/home/max/tmp/django_media/'
+
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
</h3>
</div>
<div class="panel-body">
- <form method="post" action="">
+ <form enctype="multipart/form-data" method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn btn-success">
- Submit
+ Save
</button>
{% endbuttons %}
</form>
+++ /dev/null
-{% load bootstrap3 %}
-
-
-{% bootstrap_form_errors form type='non_fields' %}
-<form method="post" action="" class="form" id="bookingform">
- {% csrf_token %}
-
- <div class='input-group' id='starttimepicker'>
- {% bootstrap_field form.start addon_after='<span class="glyphicon glyphicon-calendar"></span>' %}
- </div>
- <div class='input-group' id='endtimepicker'>
- {% bootstrap_field form.end addon_after='<span class="glyphicon glyphicon-calendar"></span>' %}
- </div>
- {% bootstrap_field form.purpose %}
-
- {% buttons %}
- <button type="submit" class="btn btn btn-success">
- Book
- </button>
- {% endbuttons %}
-</form>
\ No newline at end of file
+++ /dev/null
-{% extends "layout.html" %}
-{% load bootstrap3 %}
-
-{% block basecontent %}
- <div class="container">
- <div class="row">
- <div class="col-md-4 col-md-offset-4">
- {% if next %}
- <div class="alert alert-dismissable alert-info">
- <button type="button" class="close" data-dismiss="alert" aria-label="Close">
- <span aria-hidden="true">×</span>
- </button>
- {% if user.is_authenticated %}
- Your account doesn't have access to this page. To proceed,
- please login with an account that has access.
- {% else %}
- Please login to see this page.
- {% endif %}
- </div>
- {% endif %}
- </div>
- </div>
- <div class="row">
- <div class="col-md-4 col-md-offset-4">
- <div class="login-panel panel panel-default">
- <div class="panel-heading">
- <h3 class="panel-title">
- Login
- </h3>
- </div>
- <div class="panel-body">
- <form method="post">
- {% csrf_token %}
- {% bootstrap_form form %}
- {% buttons %}
- <button type="submit" class="btn btn btn-success">
- Login
- </button>
- <a href="{% url 'account:registration' %}" class="btn btn-info"
- role="button">Register</a>
- {% endbuttons %}
- </form>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- {# Assumes you setup the password_reset view in your URLconf #}
- {# <p><a href="{% url 'password_reset' %}">Lost password?</a></p>#}
-{% endblock basecontent %}
+++ /dev/null
-{% extends "layout.html" %}
-{% load bootstrap3 %}
-
-{% block basecontent %}
- <div class="container">
- <div class="row">
- <div class="col-md-4 col-md-offset-4">
- {% bootstrap_messages %}
- <div class="login-panel panel panel-default">
- <div class="panel-heading">
- <h3 class="panel-title">
- {{ title }}
- </h3>
- </div>
- <div class="panel-body">
- <form method="post" action="">
- {% csrf_token %}
- {% bootstrap_form form %}
- {% buttons %}
- <button type="submit" class="btn btn btn-success">
- Submit
- </button>
- {% endbuttons %}
- </form>
- </div>
- </div>
- </div>
- </div>
- </div>
-{% endblock basecontent %}