From 7022542bc70c448f71fa56c06d90595e276d7dcc Mon Sep 17 00:00:00 2001 From: maxbr Date: Wed, 5 Oct 2016 14:24:11 +0200 Subject: Sync dashboard user data with jira JIRA: PHAROS-264 Change-Id: Ic4533af04946ee0493c762ca79aaf46ee0f80e00 Signed-off-by: maxbr --- tools/pharos-dashboard/docker-compose.yml | 2 +- .../account/migrations/0002_auto_20161005_1201.py | 25 ++++++++++++++++ tools/pharos-dashboard/src/account/models.py | 8 +++++ tools/pharos-dashboard/src/account/tasks.py | 34 ++++++++++++++++++++++ tools/pharos-dashboard/src/account/views.py | 21 ++++++++----- tools/pharos-dashboard/src/api/urls.py | 1 + tools/pharos-dashboard/src/api/views.py | 18 +++++++++++- .../migrations/0002_auto_20161005_1202.py | 21 +++++++++++++ tools/pharos-dashboard/src/dashboard/models.py | 2 +- .../src/templates/account/user_list.html | 20 +++++++++---- .../templates/account/userprofile_update_form.html | 10 ++++++- .../src/templates/dashboard/resource_detail.html | 1 + 12 files changed, 146 insertions(+), 17 deletions(-) create mode 100644 tools/pharos-dashboard/src/account/migrations/0002_auto_20161005_1201.py create mode 100644 tools/pharos-dashboard/src/account/tasks.py create mode 100644 tools/pharos-dashboard/src/dashboard/migrations/0002_auto_20161005_1202.py diff --git a/tools/pharos-dashboard/docker-compose.yml b/tools/pharos-dashboard/docker-compose.yml index 00a8d151..b487620b 100644 --- a/tools/pharos-dashboard/docker-compose.yml +++ b/tools/pharos-dashboard/docker-compose.yml @@ -59,7 +59,7 @@ services: worker: restart: always build: ./worker/ - command: bash -c "celery -A pharos_dashboard worker -l info -B" + command: bash -c "celery -A pharos_dashboard worker -l info -B --schedule=~/celerybeat-schedule"" env_file: config.env links: - postgres diff --git a/tools/pharos-dashboard/src/account/migrations/0002_auto_20161005_1201.py b/tools/pharos-dashboard/src/account/migrations/0002_auto_20161005_1201.py new file mode 100644 index 00000000..33d2cc54 --- /dev/null +++ b/tools/pharos-dashboard/src/account/migrations/0002_auto_20161005_1201.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10 on 2016-10-05 12:01 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='userprofile', + name='full_name', + field=models.CharField(default='', max_length=100), + ), + migrations.AddField( + model_name='userprofile', + name='jira_url', + field=models.CharField(default='', max_length=100), + ), + ] diff --git a/tools/pharos-dashboard/src/account/models.py b/tools/pharos-dashboard/src/account/models.py index 621f6697..d87ee183 100644 --- a/tools/pharos-dashboard/src/account/models.py +++ b/tools/pharos-dashboard/src/account/models.py @@ -11,6 +11,7 @@ from django.db import models from django.contrib.auth.models import User +from rest_framework.authtoken.models import Token from dashboard.models import Resource @@ -23,8 +24,15 @@ class UserProfile(models.Model): 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) + jira_url = models.CharField(max_length=100, default='') + full_name = models.CharField(max_length=100, default='') + class Meta: db_table = 'user_profile' + + def __str__(self): + return self.user.username diff --git a/tools/pharos-dashboard/src/account/tasks.py b/tools/pharos-dashboard/src/account/tasks.py new file mode 100644 index 00000000..bfb865dd --- /dev/null +++ b/tools/pharos-dashboard/src/account/tasks.py @@ -0,0 +1,34 @@ +############################################################################## +# Copyright (c) 2016 Max Breitenfeldt and others. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## + + +from celery import shared_task +from django.contrib.auth.models import User +from jira import JIRAError + +from account.jira_util import get_jira + + +@shared_task +def sync_jira_accounts(): + users = User.objects.all() + for user in users: + jira = get_jira(user) + try: + user_dict = jira.myself() + except JIRAError: + # User can be anonymous (local django admin account) + continue + user.email = user_dict['emailAddress'] + user.userprofile.url = user_dict['self'] + user.userprofile.full_name = user_dict['displayName'] + print(user_dict) + + user.userprofile.save() + user.save() \ No newline at end of file diff --git a/tools/pharos-dashboard/src/account/views.py b/tools/pharos-dashboard/src/account/views.py index 3b4269de..ac973f53 100644 --- a/tools/pharos-dashboard/src/account/views.py +++ b/tools/pharos-dashboard/src/account/views.py @@ -12,6 +12,7 @@ import os import urllib import oauth2 as oauth +from django.conf import settings from django.contrib import messages from django.contrib.auth import logout, authenticate, login from django.contrib.auth.decorators import login_required @@ -19,17 +20,14 @@ from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import User from django.urls import reverse from django.utils.decorators import method_decorator -from django.views.generic import RedirectView -from django.views.generic import TemplateView -from django.views.generic import UpdateView +from django.views.generic import RedirectView, TemplateView, UpdateView + from jira import JIRA +from rest_framework.authtoken.models import Token from account.forms import AccountSettingsForm from account.jira_util import SignatureMethod_RSA_SHA1 from account.models import UserProfile -from django.conf import settings - -consumer = oauth.Consumer(settings.OAUTH_CONSUMER_KEY, settings.OAUTH_CONSUMER_SECRET) @method_decorator(login_required, name='dispatch') @@ -46,9 +44,16 @@ class AccountSettingsView(UpdateView): def get_object(self, queryset=None): return self.request.user.userprofile + def get_context_data(self, **kwargs): + token, created = Token.objects.get_or_create(user=self.request.user) + context = super(AccountSettingsView, self).get_context_data(**kwargs) + context.update({'title': "Settings", 'token': token}) + return context + class JiraLoginView(RedirectView): def get_redirect_url(self, *args, **kwargs): + consumer = oauth.Consumer(settings.OAUTH_CONSUMER_KEY, settings.OAUTH_CONSUMER_SECRET) client = oauth.Client(consumer) client.set_signature_method(SignatureMethod_RSA_SHA1()) @@ -61,7 +66,7 @@ class JiraLoginView(RedirectView): self.request.session['request_token'] = dict(urllib.parse.parse_qsl(content.decode())) # Step 3. Redirect the user to the authentication URL. url = settings.OAUTH_AUTHORIZE_URL + '?oauth_token=' + \ - self.request.session['request_token']['oauth_token'] + \ + self.request.session['request_token']['oauth_token'] + \ '&oauth_callback=' + settings.OAUTH_CALLBACK_URL return url @@ -75,6 +80,7 @@ class JiraLogoutView(LoginRequiredMixin, RedirectView): class JiraAuthenticatedView(RedirectView): def get_redirect_url(self, *args, **kwargs): # Step 1. Use the request token in the session to build a new client. + consumer = oauth.Consumer(settings.OAUTH_CONSUMER_KEY, settings.OAUTH_CONSUMER_SECRET) token = oauth.Token(self.request.session['request_token']['oauth_token'], self.request.session['request_token']['oauth_token_secret']) client = oauth.Client(consumer, token) @@ -122,6 +128,7 @@ class JiraAuthenticatedView(RedirectView): # redirect user to settings page to complete profile return url +@method_decorator(login_required, name='dispatch') class UserListView(TemplateView): template_name = "account/user_list.html" diff --git a/tools/pharos-dashboard/src/api/urls.py b/tools/pharos-dashboard/src/api/urls.py index 5206ac7f..dfbe1ac9 100644 --- a/tools/pharos-dashboard/src/api/urls.py +++ b/tools/pharos-dashboard/src/api/urls.py @@ -35,4 +35,5 @@ router.register(r'bookings', BookingViewSet) urlpatterns = [ url(r'^', include(router.urls)), + url(r'^token$', GenerateTokenView.as_view(), name='generate_token'), ] \ No newline at end of file diff --git a/tools/pharos-dashboard/src/api/views.py b/tools/pharos-dashboard/src/api/views.py index 761ce6e7..55de5c6a 100644 --- a/tools/pharos-dashboard/src/api/views.py +++ b/tools/pharos-dashboard/src/api/views.py @@ -10,9 +10,14 @@ from rest_framework import viewsets +from django.contrib.auth.decorators import login_required +from django.utils.decorators import method_decorator from api.serializers import ResourceSerializer, ServerSerializer, BookingSerializer from booking.models import Booking from dashboard.models import Resource, Server +from django.views import View +from rest_framework.authtoken.models import Token +from django.shortcuts import redirect class BookingViewSet(viewsets.ModelViewSet): @@ -30,4 +35,15 @@ class ServerViewSet(viewsets.ModelViewSet): class ResourceViewSet(viewsets.ModelViewSet): queryset = Resource.objects.all() serializer_class = ResourceSerializer - filter_fields = ('name',) \ No newline at end of file + filter_fields = ('name',) + + +@method_decorator(login_required, name='dispatch') +class GenerateTokenView(View): + def get(self, request, *args, **kwargs): + user = self.request.user + token, created = Token.objects.get_or_create(user=user) + if not created: + token.delete() + Token.objects.create(user=user) + return redirect('account:settings') diff --git a/tools/pharos-dashboard/src/dashboard/migrations/0002_auto_20161005_1202.py b/tools/pharos-dashboard/src/dashboard/migrations/0002_auto_20161005_1202.py new file mode 100644 index 00000000..e47c3b13 --- /dev/null +++ b/tools/pharos-dashboard/src/dashboard/migrations/0002_auto_20161005_1202.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10 on 2016-10-05 12:02 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dashboard', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='resource', + name='vpn_users', + field=models.ManyToManyField(blank=True, related_name='user_vpn_users', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/tools/pharos-dashboard/src/dashboard/models.py b/tools/pharos-dashboard/src/dashboard/models.py index 050834ea..e3f22e69 100644 --- a/tools/pharos-dashboard/src/dashboard/models.py +++ b/tools/pharos-dashboard/src/dashboard/models.py @@ -23,7 +23,7 @@ class Resource(models.Model): description = models.CharField(max_length=300, blank=True, null=True) url = models.CharField(max_length=100, blank=True, null=True) owner = models.ForeignKey(User, related_name='user_lab_owner', null=True) - vpn_users = models.ManyToManyField(User, related_name='user_vpn_users') + vpn_users = models.ManyToManyField(User, related_name='user_vpn_users', blank=True) slave = models.ForeignKey(JenkinsSlave, on_delete=models.DO_NOTHING, null=True) def get_booking_utilization(self, weeks): diff --git a/tools/pharos-dashboard/src/templates/account/user_list.html b/tools/pharos-dashboard/src/templates/account/user_list.html index c2b81938..f18e1618 100644 --- a/tools/pharos-dashboard/src/templates/account/user_list.html +++ b/tools/pharos-dashboard/src/templates/account/user_list.html @@ -5,6 +5,8 @@ Username + Full Name + Email Company SSH Key GPG Key @@ -16,18 +18,24 @@ {{ user.username }} + + {{ user.userprofile.full_name }} + + + {{ user.email }} + {{ user.userprofile.company }} - {% if user.userprofile.ssh_public_key %} - SSH - {% endif %} + {% if user.userprofile.ssh_public_key %} + SSH + {% endif %} - {% if user.userprofile.pgp_public_key %} - GPG - {% endif %} + {% if user.userprofile.pgp_public_key %} + GPG + {% endif %} {% endfor %} diff --git a/tools/pharos-dashboard/src/templates/account/userprofile_update_form.html b/tools/pharos-dashboard/src/templates/account/userprofile_update_form.html index 542ea81e..f4bb7b55 100644 --- a/tools/pharos-dashboard/src/templates/account/userprofile_update_form.html +++ b/tools/pharos-dashboard/src/templates/account/userprofile_update_form.html @@ -16,9 +16,17 @@
{% csrf_token %} {% bootstrap_form form %} +

API Token + + Generate + +

+

{{ token.key }}

+ +

{% buttons %} {% endbuttons %}
diff --git a/tools/pharos-dashboard/src/templates/dashboard/resource_detail.html b/tools/pharos-dashboard/src/templates/dashboard/resource_detail.html index 657d5656..e0b29bd9 100644 --- a/tools/pharos-dashboard/src/templates/dashboard/resource_detail.html +++ b/tools/pharos-dashboard/src/templates/dashboard/resource_detail.html @@ -106,6 +106,7 @@

Email: + {{ resource.owner.email }}