mirror of https://github.com/jumpserver/jumpserver
temp save for issue 8
parent
62cac20ba7
commit
d8fe59debb
|
@ -1,6 +1,7 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
|
*.swp
|
||||||
env
|
env
|
||||||
env*
|
env*
|
||||||
dist
|
dist
|
||||||
|
|
|
@ -18,6 +18,7 @@ class UserLoginForm(AuthenticationForm):
|
||||||
|
|
||||||
|
|
||||||
class UserCreateForm(forms.ModelForm):
|
class UserCreateForm(forms.ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = [
|
fields = [
|
||||||
|
@ -67,3 +68,14 @@ class UserGroupForm(forms.ModelForm):
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'name': '* required'
|
'name': '* required'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class UserInfoForm(forms.Form):
|
||||||
|
name = forms.CharField(max_length=20)
|
||||||
|
wechat = forms.CharField(max_length=30)
|
||||||
|
phone = forms.CharField(max_length=20)
|
||||||
|
enable_otp = forms.BooleanField()
|
||||||
|
|
||||||
|
|
||||||
|
class UserKeyForm(forms.Form):
|
||||||
|
private_key = forms.CharField(max_length=5000, widget=forms.Textarea)
|
||||||
|
|
|
@ -2,19 +2,17 @@
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.hashers import make_password
|
from django.contrib.auth.hashers import make_password
|
||||||
from django.utils import timezone
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.db import models
|
from django.core import signing
|
||||||
from django.contrib.auth.models import AbstractUser, Permission
|
from django.db import models, IntegrityError
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.db import IntegrityError
|
from django.utils import timezone
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from rest_framework.authtoken.models import Token
|
from rest_framework.authtoken.models import Token
|
||||||
from django.core import signing
|
|
||||||
|
|
||||||
from common.utils import encrypt, decrypt
|
from common.utils import encrypt, decrypt
|
||||||
|
|
||||||
|
@ -44,16 +42,15 @@ class UserGroup(models.Model):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_fake(cls, count=100):
|
def generate_fake(cls, count=100):
|
||||||
from random import seed, randint, choice
|
from random import seed, choice
|
||||||
import forgery_py
|
import forgery_py
|
||||||
from django.db import IntegrityError
|
|
||||||
|
|
||||||
seed()
|
seed()
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
group = cls(name=forgery_py.name.full_name(),
|
group = cls(name=forgery_py.name.full_name(),
|
||||||
comment=forgery_py.lorem_ipsum.sentence(),
|
comment=forgery_py.lorem_ipsum.sentence(),
|
||||||
created_by=choice(User.objects.all()).username
|
created_by=choice(User.objects.all()).username
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
group.save()
|
group.save()
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
|
@ -84,7 +81,7 @@ class User(AbstractUser):
|
||||||
_private_key = models.CharField(max_length=5000, blank=True, verbose_name=_('ssh private key'))
|
_private_key = models.CharField(max_length=5000, blank=True, verbose_name=_('ssh private key'))
|
||||||
_public_key = models.CharField(max_length=1000, blank=True, verbose_name=_('ssh public key'))
|
_public_key = models.CharField(max_length=1000, blank=True, verbose_name=_('ssh public key'))
|
||||||
comment = models.TextField(max_length=200, blank=True, verbose_name=_('Comment'))
|
comment = models.TextField(max_length=200, blank=True, verbose_name=_('Comment'))
|
||||||
is_first_login = models.BooleanField(default=False)
|
is_first_login = models.BooleanField(default=True)
|
||||||
date_expired = models.DateTimeField(default=date_expired_default, blank=True, null=True,
|
date_expired = models.DateTimeField(default=date_expired_default, blank=True, null=True,
|
||||||
verbose_name=_('Date expired'))
|
verbose_name=_('Date expired'))
|
||||||
created_by = models.CharField(max_length=30, default='', verbose_name=_('Created by'))
|
created_by = models.CharField(max_length=30, default='', verbose_name=_('Created by'))
|
||||||
|
@ -235,7 +232,7 @@ class User(AbstractUser):
|
||||||
wechat=forgery_py.internet.user_name(True),
|
wechat=forgery_py.internet.user_name(True),
|
||||||
comment=forgery_py.lorem_ipsum.sentence(),
|
comment=forgery_py.lorem_ipsum.sentence(),
|
||||||
created_by=choice(cls.objects.all()).username,
|
created_by=choice(cls.objects.all()).username,
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
user.save()
|
user.save()
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
|
@ -264,4 +261,3 @@ def create_auth_token(sender, instance=None, created=False, **kwargs):
|
||||||
Token.objects.create(user=instance)
|
Token.objects.create(user=instance)
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load bootstrap %}
|
||||||
|
|
||||||
|
{% block custom_head_css_js %}
|
||||||
|
{{ wizard.form.media }}
|
||||||
|
<link href="{% static 'css/plugins/steps/jquery.steps.css' %}" rel="stylesheet">
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="ibox">
|
||||||
|
<div class="ibox-title">
|
||||||
|
<h5>Basic Wizzard</h5>
|
||||||
|
<div class="ibox-tools">
|
||||||
|
<a class="collapse-link">
|
||||||
|
<i class="fa fa-chevron-up"></i>
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||||
|
<i class="fa fa-wrench"></i>
|
||||||
|
</a>
|
||||||
|
<a class="close-link">
|
||||||
|
<i class="fa fa-times"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ibox-content">
|
||||||
|
<div class="wizard">
|
||||||
|
<div class="steps clearfix">
|
||||||
|
<ul role="tablist">
|
||||||
|
{% for step in wizard.steps.all %}
|
||||||
|
<li role="tab" class="{% ifequal step wizard.steps.first %}first{% endifequal %} {% ifequal step wizard.steps.current %}current{% else %}disabled{% endifequal %} {% ifequal step wizard.steps.last %}last{% endifequal %}"
|
||||||
|
aria-disabled="false" aria-selected="true">
|
||||||
|
<a aria-controls="wizard-p-{{ step }}" href="#wizard-h-{{ step }}" id="wizard-t-{{ step }}"><span class="number">{% trans 'Step' %} {{ step }}</span></a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="content clearfix">
|
||||||
|
<form action="" method="post" class="form col-lg-8 p-m">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ wizard.management_form }}
|
||||||
|
{% if wizard.form.forms %}
|
||||||
|
{{ wizard.form.management_form }}
|
||||||
|
{% for form in wizard.form.forms %}
|
||||||
|
{{ form|bootstrap }}
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
{{ wizard.form|bootstrap }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% if wizard.steps.prev %}
|
||||||
|
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">{% trans "first step" %}</button>
|
||||||
|
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">{% trans "prev step" %}</button>
|
||||||
|
{% endif %}
|
||||||
|
<input type="submit" value="{% trans "submit" %}"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,77 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block custom_head_css_js %}
|
||||||
|
<link href="{% static 'css/plugins/steps/jquery.steps.css' %}" rel="stylesheet">
|
||||||
|
<script src="{% static 'js/plugins/steps/jquery.steps.min.js' %}"></script>
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-12">
|
||||||
|
<div class="ibox float-e-margins">
|
||||||
|
<div class="ibox-title">
|
||||||
|
<h5>Basic Wizzard</h5>
|
||||||
|
<div class="ibox-tools">
|
||||||
|
<a class="collapse-link">
|
||||||
|
<i class="fa fa-chevron-up"></i>
|
||||||
|
</a>
|
||||||
|
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||||
|
<i class="fa fa-wrench"></i>
|
||||||
|
</a>
|
||||||
|
<a class="close-link">
|
||||||
|
<i class="fa fa-times"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ibox-content">
|
||||||
|
<p>
|
||||||
|
This is basic example of Step
|
||||||
|
</p>
|
||||||
|
<div id="wizard">
|
||||||
|
<h1>First Step</h1>
|
||||||
|
<div class="step-content">
|
||||||
|
<div class="text-center m-t-md">
|
||||||
|
<h2>Hello in Step 1</h2>
|
||||||
|
<p>
|
||||||
|
This is the first content.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1>Second Step</h1>
|
||||||
|
<div class="step-content">
|
||||||
|
<div class="text-center m-t-md">
|
||||||
|
<h2>This is step 2</h2>
|
||||||
|
<p>
|
||||||
|
This content is diferent than the first one.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1>Third Step</h1>
|
||||||
|
<div class="step-content">
|
||||||
|
<div class="text-center m-t-md">
|
||||||
|
<h2>This is step 3</h2>
|
||||||
|
<p>
|
||||||
|
This is last content.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block custom_foot_js %}
|
||||||
|
<script>
|
||||||
|
$(document).ready(function(){
|
||||||
|
$("#wizard").steps();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -16,6 +16,7 @@ urlpatterns = [
|
||||||
name='reset-password-success'),
|
name='reset-password-success'),
|
||||||
url(r'^user$', views.UserListView.as_view(), name='user-list'),
|
url(r'^user$', views.UserListView.as_view(), name='user-list'),
|
||||||
url(r'^user/(?P<pk>[0-9]+)$', views.UserDetailView.as_view(), name='user-detail'),
|
url(r'^user/(?P<pk>[0-9]+)$', views.UserDetailView.as_view(), name='user-detail'),
|
||||||
|
url(r'^first-login/$', views.UserFirstLoginView.as_view(), name='user-first-login'),
|
||||||
url(r'^user/(?P<pk>[0-9]+)/assets-perm$', views.UserDetailView.as_view(), name='user-detail'),
|
url(r'^user/(?P<pk>[0-9]+)/assets-perm$', views.UserDetailView.as_view(), name='user-detail'),
|
||||||
url(r'^user/create$', views.UserCreateView.as_view(), name='user-create'),
|
url(r'^user/create$', views.UserCreateView.as_view(), name='user-create'),
|
||||||
url(r'^user/(?P<pk>[0-9]+)/update$', views.UserUpdateView.as_view(), name='user-update'),
|
url(r'^user/(?P<pk>[0-9]+)/update$', views.UserUpdateView.as_view(), name='user-update'),
|
||||||
|
|
|
@ -7,9 +7,10 @@ import logging
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import login as auth_login, logout as auth_logout
|
from django.contrib.auth import login as auth_login, logout as auth_logout
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
from django.core.files.storage import default_storage
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404, reverse, redirect
|
from django.shortcuts import get_object_or_404, reverse, redirect, render
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
|
@ -21,10 +22,12 @@ from django.views.generic.list import ListView
|
||||||
from django.views.generic.edit import CreateView, DeleteView, UpdateView, FormView
|
from django.views.generic.edit import CreateView, DeleteView, UpdateView, FormView
|
||||||
from django.views.generic.detail import DetailView
|
from django.views.generic.detail import DetailView
|
||||||
|
|
||||||
|
from formtools.wizard.views import SessionWizardView
|
||||||
|
|
||||||
from common.utils import get_object_or_none
|
from common.utils import get_object_or_none
|
||||||
|
|
||||||
from .models import User, UserGroup
|
from .models import User, UserGroup
|
||||||
from .forms import UserCreateForm, UserUpdateForm, UserGroupForm, UserLoginForm
|
from .forms import (UserCreateForm, UserUpdateForm, UserGroupForm, UserLoginForm, UserInfoForm, UserKeyForm)
|
||||||
from .utils import AdminUserRequiredMixin, user_add_success_next, send_reset_password_mail
|
from .utils import AdminUserRequiredMixin, user_add_success_next, send_reset_password_mail
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,6 +52,9 @@ class UserLoginView(FormView):
|
||||||
return redirect(self.get_success_url())
|
return redirect(self.get_success_url())
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
|
if self.request.user.is_first_login:
|
||||||
|
return '/firstlogin'
|
||||||
|
|
||||||
return self.request.POST.get(
|
return self.request.POST.get(
|
||||||
self.redirect_field_name,
|
self.redirect_field_name,
|
||||||
self.request.GET.get(self.redirect_field_name, reverse('index')))
|
self.request.GET.get(self.redirect_field_name, reverse('index')))
|
||||||
|
@ -292,3 +298,18 @@ class UserResetPasswordView(TemplateView):
|
||||||
|
|
||||||
user.reset_password(password)
|
user.reset_password(password)
|
||||||
return HttpResponseRedirect(reverse('users:reset-password-success'))
|
return HttpResponseRedirect(reverse('users:reset-password-success'))
|
||||||
|
|
||||||
|
|
||||||
|
class UserFirstLoginView(SessionWizardView):
|
||||||
|
template_name = 'users/first_login.html'
|
||||||
|
form_list = [UserInfoForm, UserKeyForm]
|
||||||
|
file_storage = default_storage
|
||||||
|
|
||||||
|
def done(self, form_list, form_dict, **kwargs):
|
||||||
|
print form_list
|
||||||
|
return redirect(reverse('index'))
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(UserFirstLoginView, self).get_context_data(**kwargs)
|
||||||
|
context.update({'app': _('Users'), 'action': _('First Login')})
|
||||||
|
return context
|
||||||
|
|
|
@ -17,3 +17,4 @@ paramiko==2.0.2
|
||||||
celery==3.1.23
|
celery==3.1.23
|
||||||
ansible==2.1.1.0
|
ansible==2.1.1.0
|
||||||
django-simple-captcha==0.5.2
|
django-simple-captcha==0.5.2
|
||||||
|
django-formtools==1.0
|
||||||
|
|
Loading…
Reference in New Issue