Commit 9306e681 by Bach Dániel

dashboard: add ssh key views

parent 99df6972
...@@ -258,6 +258,7 @@ THIRD_PARTY_APPS = ( ...@@ -258,6 +258,7 @@ THIRD_PARTY_APPS = (
'sizefield', 'sizefield',
'taggit', 'taggit',
'statici18n', 'statici18n',
'django_sshkey',
) )
# Apps specific for this project go here. # Apps specific for this project go here.
......
...@@ -40,6 +40,7 @@ from django.template.loader import render_to_string ...@@ -40,6 +40,7 @@ from django.template.loader import render_to_string
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from sizefield.widgets import FileSizeWidget from sizefield.widgets import FileSizeWidget
from django_sshkey.models import UserKey
from firewall.models import Vlan, Host from firewall.models import Vlan, Host
from storage.models import Disk from storage.models import Disk
from vm.models import ( from vm.models import (
...@@ -1119,3 +1120,30 @@ class UserCreationForm(OrgUserCreationForm): ...@@ -1119,3 +1120,30 @@ class UserCreationForm(OrgUserCreationForm):
if commit: if commit:
user.save() user.save()
return user return user
class UserKeyForm(forms.ModelForm):
name = forms.CharField(required=True, label=_('Name'))
key = forms.CharField(
label=_('Key'), required=True,
help_text=_('For example: ssh-rsa AAAAB3NzaC1yc2ED...'),
widget=forms.Textarea(attrs={'rows': 5}))
class Meta:
fields = ('name', 'key')
model = UserKey
@property
def helper(self):
helper = FormHelper()
helper.add_input(Submit("submit", _("Save")))
return helper
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user", None)
super(UserKeyForm, self).__init__(*args, **kwargs)
def clean(self):
if self.user:
self.instance.user = self.user
return super(UserKeyForm, self).clean()
...@@ -24,6 +24,7 @@ from django_tables2.columns import (TemplateColumn, Column, BooleanColumn, ...@@ -24,6 +24,7 @@ from django_tables2.columns import (TemplateColumn, Column, BooleanColumn,
from vm.models import Instance, Node, InstanceTemplate, Lease from vm.models import Instance, Node, InstanceTemplate, Lease
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_sshkey.models import UserKey
class VmListTable(Table): class VmListTable(Table):
...@@ -291,3 +292,33 @@ class LeaseListTable(Table): ...@@ -291,3 +292,33 @@ class LeaseListTable(Table):
fields = ('name', 'suspend_interval_seconds', fields = ('name', 'suspend_interval_seconds',
'delete_interval_seconds', ) 'delete_interval_seconds', )
prefix = "lease-" prefix = "lease-"
class UserKeyListTable(Table):
name = LinkColumn(
'dashboard.views.userkey-detail',
args=[A('pk')],
verbose_name=_("Name"),
attrs={'th': {'data-sort': "string"}}
)
fingerprint = Column(
verbose_name=_("Fingerprint"),
attrs={'th': {'data-sort': "string"}}
)
created = Column(
verbose_name=_("Created at"),
attrs={'th': {'data-sort': "string"}}
)
actions = TemplateColumn(
verbose_name=_("Actions"),
template_name="dashboard/userkey-list/column-userkey-actions.html",
orderable=False,
)
class Meta:
model = UserKey
attrs = {'class': ('table table-bordered table-striped table-hover')}
fields = ('name', 'fingerprint', 'created', 'actions')
{% extends "dashboard/base.html" %} {% extends "dashboard/base.html" %}
{% load i18n %} {% load i18n %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% load render_table from django_tables2 %}
{% block title-page %}{% trans "Profile" %}{% endblock %} {% block title-page %}{% trans "Profile" %}{% endblock %}
...@@ -49,4 +50,20 @@ ...@@ -49,4 +50,20 @@
</div> </div>
</div> </div>
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<a href="{% url "dashboard.views.userkey-create" %}" class="pull-right btn btn-success btn-xs" style="margin-right: 10px;">
<i class="icon-plus"></i> {% trans "new SSH pubkey" %}
</a>
<h3 class="no-margin"><i class="icon-key"></i> {% trans "SSH public keys" %}</h3>
</div>
<div class="panel-body">
{% render_table userkey_table %}
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}
{% extends "dashboard/base.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block title-page %}{% trans "Create SSH public key" %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<a class="pull-right btn btn-default btn-xs" href="{% url "dashboard.views.profile-preferences" %}">{% trans "Back" %}</a>
<h3 class="no-margin"><i class="icon-key"></i> {% trans "Create SSH public key" %}</h3>
</div>
<div class="panel-body">
{% crispy form %}
</div>
</div>
</div>
</div>
{% endblock %}
{% extends "dashboard/base.html" %}
{% load i18n %}
{% load sizefieldtags %}
{% load crispy_forms_tags %}
{% block title-page %}{% trans "Edit SSH public key" %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<a class="pull-right btn btn-default btn-xs" href="{% url "dashboard.views.profile-preferences" %}">{% trans "Back" %}</a>
<h3 class="no-margin"><i class="icon-key"></i> {% trans "Edit SSH public key" %}</h3>
</div>
<div class="panel-body">
{% crispy form %}
</div>
</div>
</div>
</div>
{% endblock %}
{% load i18n %}
<a href="{% url "dashboard.views.userkey-detail" pk=record.pk%}" id="template-list-edit-button" class="btn btn-default btn-xs" title="{% trans "Edit" %}">
<i class="icon-edit"></i>
</a>
<a data-template-pk="{{ record.pk }}" href="{% url "dashboard.views.userkey-delete" pk=record.pk %}" class="btn btn-danger btn-xs template-delete" title="{% trans "Delete" %}">
<i class="icon-remove"></i>
</a>
...@@ -36,6 +36,7 @@ from .views import ( ...@@ -36,6 +36,7 @@ from .views import (
UserCreationView, UserCreationView,
get_vm_screenshot, get_vm_screenshot,
ProfileView, toggle_use_gravatar, UnsubscribeFormView, ProfileView, toggle_use_gravatar, UnsubscribeFormView,
UserKeyDelete, UserKeyDetail, UserKeyCreate,
) )
urlpatterns = patterns( urlpatterns = patterns(
...@@ -158,4 +159,14 @@ urlpatterns = patterns( ...@@ -158,4 +159,14 @@ urlpatterns = patterns(
url(r'^group/(?P<group_pk>\d+)/create/$', url(r'^group/(?P<group_pk>\d+)/create/$',
UserCreationView.as_view(), UserCreationView.as_view(),
name="dashboard.views.create-user"), name="dashboard.views.create-user"),
url(r'^sshkey/delete/(?P<pk>\d+)/$',
UserKeyDelete.as_view(),
name="dashboard.views.userkey-delete"),
url(r'^sshkey/(?P<pk>\d+)/$',
UserKeyDetail.as_view(),
name="dashboard.views.userkey-detail"),
url(r'^sshkey/create/$',
UserKeyCreate.as_view(),
name="dashboard.views.userkey-create"),
) )
...@@ -53,17 +53,19 @@ from braces.views import (LoginRequiredMixin, SuperuserRequiredMixin, ...@@ -53,17 +53,19 @@ from braces.views import (LoginRequiredMixin, SuperuserRequiredMixin,
PermissionRequiredMixin) PermissionRequiredMixin)
from braces.views._access import AccessMixin from braces.views._access import AccessMixin
from django_sshkey.models import UserKey
from .forms import ( from .forms import (
CircleAuthenticationForm, HostForm, LeaseForm, MyProfileForm, CircleAuthenticationForm, HostForm, LeaseForm, MyProfileForm,
NodeForm, TemplateForm, TraitForm, VmCustomizeForm, GroupCreateForm, NodeForm, TemplateForm, TraitForm, VmCustomizeForm, GroupCreateForm,
UserCreationForm, GroupProfileUpdateForm, UnsubscribeForm, UserCreationForm, GroupProfileUpdateForm, UnsubscribeForm,
VmSaveForm, VmSaveForm, UserKeyForm,
CirclePasswordChangeForm, VmCreateDiskForm, VmDownloadDiskForm, CirclePasswordChangeForm, VmCreateDiskForm, VmDownloadDiskForm,
) )
from .tables import ( from .tables import (
NodeListTable, NodeVmListTable, TemplateListTable, LeaseListTable, NodeListTable, NodeVmListTable, TemplateListTable, LeaseListTable,
GroupListTable, GroupListTable, UserKeyListTable
) )
from vm.models import ( from vm.models import (
Instance, instance_activity, InstanceActivity, InstanceTemplate, Interface, Instance, instance_activity, InstanceActivity, InstanceTemplate, Interface,
...@@ -2538,6 +2540,11 @@ class MyPreferencesView(UpdateView): ...@@ -2538,6 +2540,11 @@ class MyPreferencesView(UpdateView):
user=self.request.user), user=self.request.user),
'change_language': MyProfileForm(instance=self.get_object()), 'change_language': MyProfileForm(instance=self.get_object()),
} }
table = UserKeyListTable(
UserKey.objects.filter(user=self.request.user),
request=self.request)
table.page = None
context['userkey_table'] = table
return context return context
def get_object(self, queryset=None): def get_object(self, queryset=None):
...@@ -2855,3 +2862,72 @@ def toggle_use_gravatar(request, **kwargs): ...@@ -2855,3 +2862,72 @@ def toggle_use_gravatar(request, **kwargs):
json.dumps({'new_avatar_url': new_avatar_url}), json.dumps({'new_avatar_url': new_avatar_url}),
content_type="application/json", content_type="application/json",
) )
class UserKeyDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = UserKey
template_name = "dashboard/userkey-edit.html"
form_class = UserKeyForm
success_message = _("Successfully modified SSH key.")
def get(self, request, *args, **kwargs):
object = self.get_object()
if object.user != request.user:
raise PermissionDenied()
return super(UserKeyDetail, self).get(request, *args, **kwargs)
def get_success_url(self):
return reverse_lazy("dashboard.views.userkey-detail",
kwargs=self.kwargs)
def post(self, request, *args, **kwargs):
object = self.get_object()
if object.user != request.user:
raise PermissionDenied()
return super(UserKeyDetail, self).post(self, request, args, kwargs)
class UserKeyDelete(LoginRequiredMixin, DeleteView):
model = UserKey
def get_success_url(self):
return reverse("dashboard.views.profile-preferences")
def get_template_names(self):
if self.request.is_ajax():
return ['dashboard/confirm/ajax-delete.html']
else:
return ['dashboard/confirm/base-delete.html']
def delete(self, request, *args, **kwargs):
object = self.get_object()
if object.user != request.user:
raise PermissionDenied()
object.delete()
success_url = self.get_success_url()
success_message = _("SSH key successfully deleted.")
if request.is_ajax():
return HttpResponse(
json.dumps({'message': success_message}),
content_type="application/json",
)
else:
messages.success(request, success_message)
return HttpResponseRedirect(success_url)
class UserKeyCreate(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = UserKey
form_class = UserKeyForm
template_name = "dashboard/userkey-create.html"
success_message = _("Successfully created a new SSH key.")
def get_success_url(self):
return reverse_lazy("dashboard.views.profile-preferences")
def get_form_kwargs(self):
kwargs = super(UserKeyCreate, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
...@@ -9,6 +9,7 @@ django-celery==3.1.10 ...@@ -9,6 +9,7 @@ django-celery==3.1.10
django-crispy-forms==1.4.0 django-crispy-forms==1.4.0
django-model-utils==2.0.3 django-model-utils==2.0.3
django-sizefield==0.4 django-sizefield==0.4
django-sshkey==2.2.0
django-statici18n==1.1 django-statici18n==1.1
django-tables2==0.15.0 django-tables2==0.15.0
django-taggit==0.12 django-taggit==0.12
......
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