mirror of https://github.com/jumpserver/jumpserver
Merge with audits
commit
b055144908
|
@ -19,3 +19,5 @@ config.py
|
|||
migrations/
|
||||
*.log
|
||||
host_rsa_key
|
||||
*.bat
|
||||
tags
|
||||
|
|
|
@ -20,13 +20,13 @@ class AssetCreateForm(forms.ModelForm):
|
|||
self.instance.tags.clear()
|
||||
self.instance.tags.add(*tuple(tags))
|
||||
|
||||
def clean(self):
|
||||
clean_data = super(AssetCreateForm, self).clean()
|
||||
ip = clean_data.get('ip')
|
||||
port = clean_data.get('port')
|
||||
query = Asset.objects.filter(ip=ip, port=port)
|
||||
if query:
|
||||
raise forms.ValidationError('this asset has exists.')
|
||||
# def clean(self):
|
||||
# clean_data = super(AssetCreateForm, self).clean()
|
||||
# ip = clean_data.get('ip')
|
||||
# port = clean_data.get('port')
|
||||
# query = Asset.objects.filter(ip=ip, port=port)
|
||||
# if query:
|
||||
# raise forms.ValidationError('this asset has exists.')
|
||||
|
||||
class Meta:
|
||||
model = Asset
|
||||
|
|
|
@ -77,10 +77,6 @@
|
|||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% block modal_confirm_id %}btn_asset_bulk_update{% endblock %}
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -52,10 +52,11 @@ $(document).ready(function(){
|
|||
$(td).html('<a href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</a>');
|
||||
}},
|
||||
{targets: 6, createdCell: function (td, cellData, rowData) {
|
||||
var script_btn = '<a href="{% url "assets:admin-user-update" pk=99991937 %}" class="btn btn-xs btn-primary">{% trans "Script" %}</a>'.replace('99991937', cellData);
|
||||
{# var script_btn = '<a href="{% url "assets:admin-user-update" pk=99991937 %}" class="btn btn-xs btn-primary">{% trans "Script" %}</a>'.replace('99991937', cellData);#}
|
||||
var update_btn = '<a href="{% url "assets:admin-user-update" pk=99991937 %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'.replace('99991937', cellData);
|
||||
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn_admin_user_delete" data-uid="99991937">{% trans "Delete" %}</a>'.replace('99991937', cellData);
|
||||
$(td).html(script_btn + update_btn + del_btn)
|
||||
{# $(td).html(script_btn + update_btn + del_btn)#}
|
||||
$(td).html(update_btn + del_btn)
|
||||
}}],
|
||||
ajax_url: '{% url "api-assets:admin-user-list" %}',
|
||||
columns: [{data: function(){return ""}}, {data: "name" }, {data: "username" }, {data: "assets_amount" }, {data: function () {return 'lost'} },
|
||||
|
@ -72,7 +73,9 @@ $(document).ready(function(){
|
|||
var uid = $this.data('uid');
|
||||
var the_url = '{% url "api-assets:admin-user-detail" pk=99991937 %}'.replace('99991937', uid);
|
||||
objectDelete($this, name, the_url);
|
||||
$data_table.ajax.reload();
|
||||
setTimeout( function () {
|
||||
$data_table.ajax.reload();
|
||||
}, 3000);
|
||||
})
|
||||
|
||||
.on('click', '#btn_bulk_update', function () {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -70,7 +70,9 @@ $(document).ready(function(){
|
|||
var uid = $this.data('uid');
|
||||
var the_url = '{% url "api-assets:asset-group-detail" pk=99991937 %}'.replace('99991937', uid);
|
||||
objectDelete($this, name, the_url);
|
||||
$data_table.ajax.reload();
|
||||
setTimeout( function () {
|
||||
$data_table.ajax.reload();
|
||||
}, 3000);
|
||||
})
|
||||
|
||||
.on('click', '#btn_bulk_update', function () {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load common_tags %}
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||
|
@ -33,7 +32,7 @@
|
|||
<div class="tagBtnList">
|
||||
{% for tag in tag_list %}
|
||||
<a href="{% url 'assets:asset-tags' tag_id=tag.0 %}"
|
||||
{% if tag.0|int_to_str == tag_id %}
|
||||
{% if tag.0 == tag_id %}
|
||||
class="tagBtn2 label label-warning" name="tag_on">
|
||||
{% else %}
|
||||
class="tagBtn2 label label-default">
|
||||
|
@ -105,6 +104,38 @@ function tagShow() {
|
|||
}
|
||||
} //onload;
|
||||
|
||||
function objDelete(obj, name, url) {
|
||||
function doDelete() {
|
||||
var body = {};
|
||||
var success = function() {
|
||||
swal('Deleted!', "[ "+name+"]"+" has been deleted ", "success");
|
||||
$(obj).parent().parent().remove();
|
||||
};
|
||||
var fail = function() {
|
||||
swal("Failed", "Delete"+"[ "+name+" ]"+"failed", "error");
|
||||
};
|
||||
APIUpdateAttr({
|
||||
url: url,
|
||||
body: JSON.stringify(body),
|
||||
method: 'DELETE',
|
||||
success: success,
|
||||
error: fail
|
||||
});
|
||||
}
|
||||
swal({
|
||||
title: 'Are you sure delete ?',
|
||||
text: " [" + name + "] ",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
cancelButtonText: 'Cancel',
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: 'Confirm',
|
||||
closeOnConfirm: false
|
||||
}, function () {
|
||||
doDelete()
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
var options = {
|
||||
ele: $('#asset_list_table'),
|
||||
|
@ -187,8 +218,11 @@ $(document).ready(function(){
|
|||
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
|
||||
var uid = $this.data('uid');
|
||||
var the_url = '{% url "api-assets:asset-detail" pk=99991937 %}'.replace('99991937', uid);
|
||||
objectDelete($this, name, the_url);
|
||||
$data_table.ajax.reload();
|
||||
console.log(the_url);
|
||||
objDelete($this, name, the_url);
|
||||
setTimeout( function () {
|
||||
$data_table.ajax.reload();
|
||||
}, 3000);
|
||||
})
|
||||
|
||||
.on('click', '#btn_bulk_update', function () {
|
||||
|
@ -324,5 +358,6 @@ $(document).ready(function(){
|
|||
{# APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(post_list), success: success});#}
|
||||
$('#asset_bulk_update_modal').modal('hide');
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n static %}
|
||||
{#{% load common_tags %}#}
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
||||
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
<div class="hr-line-dashed"></div>
|
||||
<h3 class="widget-head-color-box">IP段</h3>
|
||||
{{ form.operator|bootstrap_horizontal }}
|
||||
{{ form.intranet|bootstrap_horizontal }}
|
||||
{{ form.extranet|bootstrap_horizontal }}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load common_tags %}
|
||||
|
||||
{% block table_search %}
|
||||
{% endblock %}
|
||||
|
@ -75,7 +74,9 @@ $(document).ready(function(){
|
|||
var uid = $this.data('uid');
|
||||
var the_url = '{% url "api-assets:system-user-detail" pk=99991937 %}'.replace('99991937', uid);
|
||||
objectDelete($this, name, the_url);
|
||||
$data_table.ajax.reload();
|
||||
setTimeout( function () {
|
||||
$data_table.ajax.reload();
|
||||
}, 3000);
|
||||
})
|
||||
|
||||
.on('click', '#btn_bulk_update', function () {
|
||||
|
|
|
@ -139,15 +139,15 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateAssetTagsMiXin, UpdateView):
|
|||
print(form.errors)
|
||||
return super(AssetUpdateView, self).form_invalid(form)
|
||||
|
||||
def form_valid(self, form):
|
||||
asset = form.save(commit=False)
|
||||
|
||||
def prn_obj_key(obj_form):
|
||||
return obj_form.clean().keys()
|
||||
|
||||
for i in prn_obj_key(form):
|
||||
if i not in self.new_form.keys():
|
||||
print i
|
||||
# def form_valid(self, form):
|
||||
# asset = form.save(commit=False)
|
||||
#
|
||||
# def prn_obj_key(obj_form):
|
||||
# return obj_form.clean().keys()
|
||||
#
|
||||
# for i in prn_obj_key(form):
|
||||
# if i not in self.new_form.keys():
|
||||
# print i
|
||||
|
||||
#delattr(asset, '"%s" % i')
|
||||
#del asset.i
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load common_tags %}
|
||||
{% block content_left_head %}
|
||||
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
|
||||
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load common_tags %}
|
||||
{% block content_left_head %}
|
||||
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
|
||||
<style>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -14,7 +14,6 @@ import os
|
|||
import sys
|
||||
|
||||
from django.urls import reverse_lazy
|
||||
from datetime import timedelta
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
@ -300,11 +299,11 @@ CELERY_RESULT_BACKEND = BROKER_URL
|
|||
# crontab job
|
||||
# CELERYBEAT_SCHEDULE = {
|
||||
# Check applications is alive every 10m
|
||||
# 'check_terminal_alive': {
|
||||
# 'task': 'applications.tasks.check_terminal_alive',
|
||||
# 'schedule': timedelta(seconds=TERMINAL_HEATBEAT_INTERVAL),
|
||||
# 'args': (),
|
||||
# },
|
||||
# 'check_terminal_alive': {
|
||||
# 'task': 'applications.tasks.check_terminal_alive',
|
||||
# 'schedule': timedelta(seconds=TERMINAL_HEATBEAT_INTERVAL),
|
||||
# 'args': (),
|
||||
# },
|
||||
# }
|
||||
|
||||
|
||||
|
@ -326,3 +325,4 @@ CAPTCHA_FOREGROUND_COLOR = '#001100'
|
|||
|
||||
COMMAND_STORE_BACKEND = 'audits.backends.command.db'
|
||||
RECORD_STORE_BACKEND = 'audits.backends.record.db'
|
||||
CAPTCHA_TEST_MODE = CONFIG.CAPTCHA_TEST_MODE
|
||||
|
|
|
@ -6,7 +6,6 @@ import logging
|
|||
from uuid import uuid4
|
||||
from assets.models import Asset
|
||||
from ops.models import TaskRecord
|
||||
from ops.utils.ansible_api import ADHocRunner, Config
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
@ -20,7 +19,7 @@ logger = logging.getLogger(__name__)
|
|||
class Task(models.Model):
|
||||
record = models.OneToOneField(TaskRecord)
|
||||
name = models.CharField(max_length=128, blank=True, verbose_name=_('Name'))
|
||||
is_gather_facts = models.BooleanField(default=False,verbose_name=_('Is Gather Ansible Facts'))
|
||||
is_gather_facts = models.BooleanField(default=False, verbose_name=_('Is Gather Ansible Facts'))
|
||||
assets = models.ManyToManyField(Asset, related_name='tasks')
|
||||
|
||||
def __unicode__(self):
|
||||
|
@ -31,6 +30,7 @@ class Task(models.Model):
|
|||
return []
|
||||
|
||||
def run(self):
|
||||
from ops.utils.ansible_api import ADHocRunner, Config
|
||||
conf = Config()
|
||||
gather_facts = "yes" if self.is_gather_facts else "no"
|
||||
play_source = {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{% extends '_base_list.html' %}
|
||||
{% load i18n %}
|
||||
{% load common_tags %}
|
||||
{% block content_left_head %}
|
||||
<a href="{% url 'perms:asset-permission-create' %}" class="btn btn-sm btn-primary">
|
||||
{% trans "Create permission" %}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
|
|
@ -225,6 +225,7 @@ table.dataTable tbody td.selected td i.text-navy
|
|||
background: #f1f1f1;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.form-asset-on{
|
||||
border: 1px solid #e5e6e7;
|
||||
padding-top:5px;
|
||||
|
@ -264,3 +265,15 @@ div.dataTables_wrapper div.dataTables_filter,
|
|||
div.dataTables_wrapper div.dataTables_filter {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.simple-tag {
|
||||
background-color: #f3f3f4;
|
||||
border: 1px solid #e7eaec;
|
||||
border-radius: 2px;
|
||||
color: inherit;
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
margin-right: 5px;
|
||||
margin-top: 5px;
|
||||
padding: 5px 12px;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load common_tags %}
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/dataTables/dataTables.min.css" %}" rel="stylesheet">
|
||||
<link href="{% static "css/plugins/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css" %}" rel="stylesheet">
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
{% block first_login_message %}
|
||||
{% if user.is_authenticated and user.is_first_login %}
|
||||
<div class="alert alert-danger" style="margin: 20px auto 0px">
|
||||
{% url 'users:user-first-login' as the_url %}
|
||||
{% url 'users:user-first-login' as first_login_url %}
|
||||
{% blocktrans %}
|
||||
Your information was incomplete. Please click <a href="{{ the_url }}"> this link </a>to complete your information.
|
||||
Your information was incomplete. Please click <a href="{{ first_login_url }}"> this link </a>to complete your information.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -34,8 +34,9 @@
|
|||
{% block update_public_key_message %}
|
||||
{% if user.is_authenticated and not user.is_public_key_valid %}
|
||||
<div class="alert alert-danger" style="margin: 20px auto 0px">
|
||||
{% url 'users:user-profile' as profile_url %}
|
||||
{% blocktrans %}
|
||||
Your ssh-public-key has been expired. Please click <a href="#"> this link </a>to update your ssh-public-key.
|
||||
Your ssh-public-key has been expired. Please click <a href="{{ profile_url }}"> this link </a>to update your ssh-public-key.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
#
|
||||
|
||||
from rest_framework import generics, viewsets
|
||||
from rest_framework import generics
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework_bulk import BulkModelViewSet
|
||||
# from django_filters.rest_framework import DjangoFilterBackend
|
||||
|
||||
from . import serializers
|
||||
from .hands import write_login_log_async
|
||||
from .models import User, UserGroup
|
||||
from .permissions import IsSuperUser, IsValidUser, IsCurrentUserOrReadOnly
|
||||
from .utils import check_user_valid, generate_token
|
||||
from common.mixins import IDInFilterMixin
|
||||
from common.utils import get_logger
|
||||
from .utils import check_user_valid, generate_token
|
||||
from .models import User, UserGroup
|
||||
from .hands import write_login_log_async
|
||||
from .permissions import (
|
||||
IsSuperUser, IsAppUser, IsValidUser)
|
||||
from . import serializers
|
||||
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
@ -41,7 +38,7 @@ class UserResetPasswordApi(generics.UpdateAPIView):
|
|||
|
||||
def perform_update(self, serializer):
|
||||
# Note: we are not updating the user object here.
|
||||
# We just do the reset-password staff.
|
||||
# We just do the reset-password stuff.
|
||||
import uuid
|
||||
from .utils import send_reset_password_mail
|
||||
user = self.get_object()
|
||||
|
@ -65,6 +62,7 @@ class UserResetPKApi(generics.UpdateAPIView):
|
|||
class UserUpdatePKApi(generics.UpdateAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = serializers.UserPKUpdateSerializer
|
||||
permission_classes = (IsCurrentUserOrReadOnly,)
|
||||
|
||||
def perform_update(self, serializer):
|
||||
user = self.get_object()
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
import os
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.core import signing
|
||||
from django.conf import settings
|
||||
from django.db import models, IntegrityError
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
from django.shortcuts import reverse
|
||||
|
||||
from common.utils import signer, date_expired_default
|
||||
from . import UserGroup
|
||||
from common.utils import signer, date_expired_default
|
||||
|
||||
|
||||
__all__ = ['User']
|
||||
|
@ -61,6 +62,15 @@ class User(AbstractUser):
|
|||
def get_absolute_url(self):
|
||||
return reverse('users:user-detail', args=(self.id,))
|
||||
|
||||
def is_public_key_valid(self):
|
||||
"""
|
||||
Check if the user's ssh public key is valid.
|
||||
This function is used in base.html.
|
||||
"""
|
||||
if self._public_key:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_expired(self):
|
||||
if self.date_expired < timezone.now():
|
||||
|
@ -156,6 +166,17 @@ class User(AbstractUser):
|
|||
return True
|
||||
return False
|
||||
|
||||
def avatar_url(self):
|
||||
if self.avatar:
|
||||
return self.avatar.url
|
||||
else:
|
||||
default_dir = os.path.join(settings.MEDIA_ROOT, 'avatar', 'default')
|
||||
if os.path.isdir(default_dir):
|
||||
default_avatar_list = os.listdir(default_dir)
|
||||
default_avatar = default_avatar_list[len(self.username) % len(default_avatar_list)]
|
||||
return os.path.join(settings.MEDIA_URL, 'avatar', 'default', default_avatar)
|
||||
return 'https://www.gravatar.com/avatar/c6812ab450230979465d7bf288eadce2a?s=120&d=identicon'
|
||||
|
||||
def generate_reset_token(self):
|
||||
return signer.sign_t({'reset': self.id, 'email': self.email}, expires_in=3600)
|
||||
|
||||
|
|
|
@ -1,18 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
|
||||
import base64
|
||||
|
||||
from django.core.cache import cache
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from rest_framework import authentication, exceptions, permissions
|
||||
from rest_framework.compat import is_authenticated
|
||||
|
||||
from common.utils import signer, get_object_or_none
|
||||
from .hands import Terminal
|
||||
from .models import User
|
||||
from rest_framework import permissions
|
||||
|
||||
|
||||
class IsValidUser(permissions.IsAuthenticated, permissions.BasePermission):
|
||||
|
@ -20,7 +9,7 @@ class IsValidUser(permissions.IsAuthenticated, permissions.BasePermission):
|
|||
|
||||
def has_permission(self, request, view):
|
||||
return super(IsValidUser, self).has_permission(request, view) \
|
||||
and request.user.is_valid
|
||||
and request.user.is_valid
|
||||
|
||||
|
||||
class IsAppUser(IsValidUser, permissions.BasePermission):
|
||||
|
@ -28,7 +17,7 @@ class IsAppUser(IsValidUser, permissions.BasePermission):
|
|||
|
||||
def has_permission(self, request, view):
|
||||
return super(IsAppUser, self).has_permission(request, view) \
|
||||
and request.user.is_app
|
||||
and request.user.is_app
|
||||
|
||||
|
||||
class IsSuperUser(IsValidUser, permissions.BasePermission):
|
||||
|
@ -36,7 +25,7 @@ class IsSuperUser(IsValidUser, permissions.BasePermission):
|
|||
|
||||
def has_permission(self, request, view):
|
||||
return super(IsSuperUser, self).has_permission(request, view) \
|
||||
and request.user.is_superuser
|
||||
and request.user.is_superuser
|
||||
|
||||
|
||||
class IsSuperUserOrAppUser(IsValidUser, permissions.BasePermission):
|
||||
|
@ -44,8 +33,12 @@ class IsSuperUserOrAppUser(IsValidUser, permissions.BasePermission):
|
|||
|
||||
def has_permission(self, request, view):
|
||||
return super(IsSuperUserOrAppUser, self).has_permission(request, view) \
|
||||
and (request.user.is_superuser or request.user.is_app)
|
||||
and (request.user.is_superuser or request.user.is_app)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pass
|
||||
class IsCurrentUserOrReadOnly(permissions.BasePermission):
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
if request.method in permissions.SAFE_METHODS:
|
||||
return True
|
||||
return obj == request.user
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load bootstrap %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
|
@ -18,16 +16,16 @@
|
|||
<div class="panel-options">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active">
|
||||
<a href="{% url 'users:user-detail' pk=user.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'User detail' %} </a>
|
||||
<a href="{% url 'users:user-detail' pk=user_object.id %}" class="text-center"><i class="fa fa-laptop"></i> {% trans 'User detail' %} </a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'users:user-asset-permission' pk=user.id %}" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset permission' %}</a>
|
||||
<a href="{% url 'users:user-asset-permission' pk=user_object.id %}" class="text-center"><i class="fa fa-bar-chart-o"></i> {% trans 'Asset permission' %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'users:user-granted-asset' pk=user.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a>
|
||||
<a href="{% url 'users:user-granted-asset' pk=user_object.id %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Asset granted' %}</a>
|
||||
</li>
|
||||
<li class="pull-right">
|
||||
<a class="btn btn-outline btn-default" href="{% url 'users:user-update' pk=user.id %}"><i class="fa fa-edit"></i>Update</a>
|
||||
<a class="btn btn-outline btn-default" href="{% url 'users:user-update' pk=user_object.id %}"><i class="fa fa-edit"></i>Update</a>
|
||||
</li>
|
||||
<li class="pull-right">
|
||||
<a class="btn btn-outline btn-danger btn-delete-user">
|
||||
|
@ -40,7 +38,7 @@
|
|||
<div class="col-sm-7" style="padding-left: 0">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label"><b>{{ user.name }}</b></span>
|
||||
<span class="label"><b>{{ user_object.name }}</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
|
@ -60,56 +58,56 @@
|
|||
<tbody>
|
||||
<tr class="no-borders-tr">
|
||||
<td colspan="2">
|
||||
<img src="{{ user|user_avatar_url }}" class="img-circle" width="64" height="64">
|
||||
<img src="{{ user_object.avatar_url }}" class="img-circle" width="64" height="64">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%">{% trans 'Name' %}:</td>
|
||||
<td><b>{{ user.name }}</b></td>
|
||||
<td><b>{{ user_object.name }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Username' %}:</td>
|
||||
<td><b>{{ user.username }}</b></td>
|
||||
<td><b>{{ user_object.username }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Email' %}:</td>
|
||||
<td><b>{{ user.email }}</b></td>
|
||||
<td><b>{{ user_object.email }}</b></td>
|
||||
</tr>
|
||||
{% if user.phone %}
|
||||
<tr>
|
||||
<td>{% trans 'Phone' %}:</td>
|
||||
<td><b>{{ user.phone }}</b></td>
|
||||
<td><b>{{ user_object.phone }}</b></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if user.wechat %}
|
||||
{% if user_object.wechat %}
|
||||
<tr>
|
||||
<td>{% trans 'Wechat' %}:</td>
|
||||
<td><b>{{ user.wechat }}</b></td>
|
||||
<td><b>{{ user_object.wechat }}</b></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>{% trans 'Role' %}:</td>
|
||||
<td><b>{{ user.get_role_display }}</b></td>
|
||||
<td><b>{{ user_object.get_role_display }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date expired' %}:</td>
|
||||
<td><b>{{ user.date_expired|date:"Y-m-j H:i:s" }}</b></td>
|
||||
<td><b>{{ user_object.date_expired|date:"Y-m-j H:i:s" }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Created by' %}:</td>
|
||||
<td><b>{{ user.created_by }}</b></td>
|
||||
<td><b>{{ user_object.created_by }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Date joined' %}:</td>
|
||||
<td><b>{{ user.date_joined|date:"Y-m-j H:i:s" }}</b></td>
|
||||
<td><b>{{ user_object.date_joined|date:"Y-m-j H:i:s" }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Last login' %}:</td>
|
||||
<td><b>{{ user.last_login|date:"Y-m-j H:i:s" }}</b></td>
|
||||
<td><b>{{ user_object.last_login|date:"Y-m-j H:i:s" }}</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Comment' %}:</td>
|
||||
<td><b>{{ user.comment }}</b></td>
|
||||
<td><b>{{ user_object.comment }}</b></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -129,7 +127,7 @@
|
|||
<td><span class="pull-right">
|
||||
<div class="switch">
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" {% if user.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active">
|
||||
<input type="checkbox" {% if user_object.is_active %} checked {% endif %} class="onoffswitch-checkbox" id="is_active">
|
||||
<label class="onoffswitch-label" for="is_active">
|
||||
<span class="onoffswitch-inner"></span>
|
||||
<span class="onoffswitch-switch"></span>
|
||||
|
@ -143,7 +141,7 @@
|
|||
<td><span class="pull-right">
|
||||
<div class="switch">
|
||||
<div class="onoffswitch">
|
||||
<input type="checkbox" class="onoffswitch-checkbox" {% if user.enable_otp %} checked {% endif %}
|
||||
<input type="checkbox" class="onoffswitch-checkbox" {% if user_object.enable_otp %} checked {% endif %}
|
||||
id="enable_otp">
|
||||
<label class="onoffswitch-label" for="enable_otp">
|
||||
<span class="onoffswitch-inner"></span>
|
||||
|
@ -169,14 +167,6 @@
|
|||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{% trans 'Update ssh key' %}:</td>
|
||||
<td>
|
||||
<span class="pull-right">
|
||||
<button type="button" class="btn btn-primary btn-xs" id="btn_update_pk" style="width: 54px;" data-toggle="modal" data-target="#user_update_pk_modal">{% trans 'Update' %}</button>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -206,7 +196,7 @@
|
|||
</tr>
|
||||
</form>
|
||||
|
||||
{% for group in user.groups.all %}
|
||||
{% for group in user_object.groups.all %}
|
||||
<tr>
|
||||
<td >
|
||||
<b class="bdg_group" data-gid={{ group.id }}>{{ group.name }}</b>
|
||||
|
@ -233,7 +223,7 @@
|
|||
jumpserver.groups_selected = {};
|
||||
|
||||
function updateUserGroups(groups) {
|
||||
var the_url = "{% url 'api-users:user-update-group' pk=user.id %}";
|
||||
var the_url = "{% url 'api-users:user-update-group' pk=user_object.id %}";
|
||||
var body = {
|
||||
groups: Object.assign([], groups)
|
||||
};
|
||||
|
@ -273,7 +263,7 @@ $(document).ready(function() {
|
|||
})
|
||||
})
|
||||
.on('click', '#is_active', function() {
|
||||
var the_url = "{% url 'api-users:user-detail' pk=user.id %}";
|
||||
var the_url = "{% url 'api-users:user-detail' pk=user_object.id %}";
|
||||
var checked = $(this).prop('checked');
|
||||
var body = {
|
||||
'is_active': checked
|
||||
|
@ -286,7 +276,7 @@ $(document).ready(function() {
|
|||
});
|
||||
})
|
||||
.on('click', '#enable_otp', function() {
|
||||
var the_url = "{% url 'api-users:user-detail' pk=user.id %}";
|
||||
var the_url = "{% url 'api-users:user-detail' pk=user_object.id %}";
|
||||
var checked = $(this).prop('checked');
|
||||
var body = {
|
||||
'enable_otp': checked
|
||||
|
@ -326,7 +316,7 @@ $(document).ready(function() {
|
|||
updateUserGroups(groups)
|
||||
}).on('click', '#btn_reset_password', function() {
|
||||
function doReset() {
|
||||
var the_url = '{% url "api-users:user-reset-password" pk=user.id %}';
|
||||
var the_url = '{% url "api-users:user-reset-password" pk=user_object.id %}';
|
||||
var body = {};
|
||||
var success = function() {
|
||||
var msg = "{% trans "An e-mail has been sent to the user\'s mailbox." %}";
|
||||
|
@ -340,7 +330,7 @@ $(document).ready(function() {
|
|||
}
|
||||
swal({
|
||||
title: "{% trans 'Are you sure?' %}",
|
||||
text: "{% trans 'This will reset the user\'s password.' %}",
|
||||
text: "{% trans 'This will reset the user\'s password. A password-reset email will be sent to the user\'s mailbox.' %}",
|
||||
type: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#DD6B55",
|
||||
|
@ -351,7 +341,7 @@ $(document).ready(function() {
|
|||
});
|
||||
}).on('click', '#btn_reset_pk', function() {
|
||||
function doReset() {
|
||||
var the_url = '{% url "api-users:user-public-key-reset" pk=user.id %}';
|
||||
var the_url = '{% url "api-users:user-public-key-reset" pk=user_object.id %}';
|
||||
var body = {};
|
||||
var success = function() {
|
||||
var msg = "{% trans 'The reset-ssh-public-key E-mail has been sent successfully. Please inform the user to update his new ssh public key.' %}";
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load bootstrap %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load bootstrap %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load common_tags %}
|
||||
{% load users_tags %}
|
||||
{% load bootstrap %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block custom_head_css_js %}
|
||||
<link href="{% static "css/plugins/sweetalert/sweetalert.css" %}" rel="stylesheet">
|
||||
<script src="{% static "js/plugins/sweetalert/sweetalert.min.js" %}"></script>
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="wrapper wrapper-content animated fadeInRight">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary"><b>{{ user.name }}</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<div class="text-left">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td class="text-navy">用户名</td>
|
||||
<td>{{ user.username }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">姓名</td>
|
||||
<td>{{ user.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">权限</td>
|
||||
<td>{{ user.get_role_display }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">Email</td>
|
||||
<td>{{ user.email }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">激活</td>
|
||||
<td>{{ user.is_active }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">添加日期</td>
|
||||
<td>{{ user.date_joined|date:"Y-m-d H:i:s" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">最后登录</td>
|
||||
<td>{{ user.last_login|date:"Y-m-d H:i:s" }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">所在用户组</td>
|
||||
<td>
|
||||
{% for group in user.groups.all %}
|
||||
<span class="simple-tag with-link">
|
||||
<a href="{% url 'users:user-group-detail' group.id %}">{{ group.name }}</a>
|
||||
</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">授权主机数量</td>
|
||||
<td>{{ assets | length }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">授权主机组</td>
|
||||
<td>
|
||||
{% for group in asset_groups %}
|
||||
<span class="simple-tag with-link">
|
||||
<a href="{% url 'assets:asset-group-detail' group.id %}">{{ group.name }}</a>
|
||||
</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-navy">授权规则</td>
|
||||
<td>
|
||||
{% for perm in permissions %}
|
||||
<span class="simple-tag with-link">
|
||||
<a href="{% url 'perms:asset-permission-detail' perm.id %}">{{ perm.name }}</a>
|
||||
</span>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<span class="label label-primary"><b>{% trans "Update Public Key" %}</b></span>
|
||||
<div class="ibox-tools">
|
||||
<a class="collapse-link">
|
||||
<i class="fa fa-chevron-up"></i>
|
||||
</a>
|
||||
<a class="close-link">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ibox-content">
|
||||
<p>{% trans "Paste your SSH Public Key here" %}</p>
|
||||
<textarea id="txt_pk" class="form-control" cols="30" rows="10" placeholder="ssh-rsa AAAAB3NzaC1yc2EAA....."></textarea>
|
||||
<button id="btn_update_pk" class="btn btn-primary m-t-15">{% trans 'Update' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block custom_foot_js %}
|
||||
<script>
|
||||
$(document).on('click', '#btn_update_pk', function() {
|
||||
var $this = $(this);
|
||||
var pk = $('#txt_pk').val();
|
||||
var the_url = '{% url "api-users:user-public-key-update" pk=user.id %}';
|
||||
var body = {'_public_key': pk};
|
||||
var success = function() {
|
||||
$('#txt_pk').val('');
|
||||
var msg = "{% trans 'Successfully updated the SSH public key.' %}";
|
||||
swal("{% trans 'User SSH Public Key Update' %}", msg, "success");
|
||||
};
|
||||
var fail = function() {
|
||||
var msg = "{% trans 'Failed to update SSH public key.' %}";
|
||||
swal({
|
||||
title: "{% trans 'User SSH Public Key Update' %}",
|
||||
text: msg,
|
||||
type: "error",
|
||||
showCancelButton: false,
|
||||
confirmButtonColor: "#DD6B55",
|
||||
confirmButtonText: "{% trans 'Confirm' %}",
|
||||
closeOnConfirm: true
|
||||
}, function () {
|
||||
$('#txt_pk').focus();
|
||||
}
|
||||
);
|
||||
}
|
||||
APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,38 +0,0 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
import os
|
||||
import urllib
|
||||
import hashlib
|
||||
|
||||
from django import template
|
||||
from django.utils import timezone
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter
|
||||
def join_queryset_attr(queryset, attr, delimiter=', '):
|
||||
return delimiter.join([getattr(obj, attr, '') for obj in queryset])
|
||||
|
||||
|
||||
@register.filter
|
||||
def is_expired(datetime):
|
||||
if datetime > timezone.now():
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
@register.filter
|
||||
def user_avatar_url(user):
|
||||
if user.avatar:
|
||||
return user.avatar.url
|
||||
else:
|
||||
default_dir = os.path.join(settings.MEDIA_ROOT, 'avatar', 'default')
|
||||
if os.path.isdir(default_dir):
|
||||
default_avatar_list = os.listdir(default_dir)
|
||||
default_avatar = default_avatar_list[len(user.username) % len(default_avatar_list)]
|
||||
return os.path.join(settings.MEDIA_URL, 'avatar', 'default', default_avatar)
|
||||
return 'https://www.gravatar.com/avatar/c6812ab450230979465d7bf288eadce2a?s=120&d=identicon'
|
|
@ -1,6 +1,7 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from .. import views
|
||||
|
||||
app_name = 'users'
|
||||
|
@ -20,6 +21,11 @@ urlpatterns = [
|
|||
views.UserResetPasswordSuccessView.as_view(),
|
||||
name='reset-password-success'),
|
||||
|
||||
# Profile
|
||||
url(r'^profile/$',
|
||||
views.UserProfileView.as_view(),
|
||||
name='user-profile'),
|
||||
|
||||
# User view
|
||||
url(r'^user$', views.UserListView.as_view(), name='user-list'),
|
||||
url(r'^user/(?P<pk>[0-9]+)$', views.UserDetailView.as_view(),
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
# ~*~ coding: utf-8 ~*~
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import uuid
|
||||
import json
|
||||
|
||||
from django.shortcuts import redirect
|
||||
import json
|
||||
import uuid
|
||||
|
||||
from openpyxl import load_workbook
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.writer.excel import save_virtual_workbook
|
||||
from openpyxl import load_workbook
|
||||
from django import forms
|
||||
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.core.cache import cache
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse_lazy, reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext as _
|
||||
|
@ -19,22 +21,23 @@ from django.utils.decorators import method_decorator
|
|||
from django.views import View
|
||||
from django.views.generic import ListView
|
||||
from django.views.generic.base import TemplateView
|
||||
from django.views.generic.edit import CreateView, UpdateView, FormMixin, \
|
||||
FormView
|
||||
from django.views.generic.edit import (CreateView, UpdateView, FormMixin,
|
||||
FormView)
|
||||
from django.views.generic.detail import DetailView, SingleObjectMixin
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from .. import forms
|
||||
from ..models import User, UserGroup
|
||||
from ..utils import AdminUserRequiredMixin, user_add_success_next
|
||||
from common.mixins import JSONResponseMixin
|
||||
from common.utils import get_logger
|
||||
from perms.models import AssetPermission
|
||||
from ..models import User, UserGroup
|
||||
from ..utils import AdminUserRequiredMixin, user_add_success_next
|
||||
from .. import forms
|
||||
|
||||
__all__ = ['UserListView', 'UserCreateView', 'UserDetailView',
|
||||
'UserUpdateView', 'UserAssetPermissionCreateView',
|
||||
'UserAssetPermissionView', 'UserGrantedAssetView',
|
||||
'UserExportView', 'UserBulkImportView']
|
||||
'UserExportView', 'UserBulkImportView', 'UserProfileView']
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
|
@ -103,7 +106,7 @@ class UserUpdateView(AdminUserRequiredMixin, UpdateView):
|
|||
class UserDetailView(AdminUserRequiredMixin, DetailView):
|
||||
model = User
|
||||
template_name = 'users/user_detail.html'
|
||||
context_object_name = "user"
|
||||
context_object_name = "user_object"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
groups = UserGroup.objects.exclude(id__in=self.object.groups.all())
|
||||
|
@ -134,18 +137,16 @@ class UserExportView(View):
|
|||
ws.append(header)
|
||||
|
||||
for user in users:
|
||||
print(user.name)
|
||||
ws.append([
|
||||
user.name, user.username, user.email,
|
||||
','.join([group.name for group in user.groups.all()]),
|
||||
user.role, user.phone, user.wechat, user.comment,
|
||||
])
|
||||
ws.append([user.name, user.username, user.email,
|
||||
','.join([group.name for group in user.groups.all()]),
|
||||
user.role, user.phone, user.wechat, user.comment])
|
||||
|
||||
filename = 'users-{}.xlsx'.format(
|
||||
timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S'))
|
||||
response = HttpResponse(save_virtual_workbook(wb),
|
||||
content_type='applications/vnd.ms-excel')
|
||||
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
|
||||
response[
|
||||
'Content-Disposition'] = 'attachment; filename="%s"' % filename
|
||||
return response
|
||||
|
||||
def post(self, request):
|
||||
|
@ -304,3 +305,24 @@ class UserGrantedAssetView(AdminUserRequiredMixin, DetailView):
|
|||
}
|
||||
kwargs.update(context)
|
||||
return super(UserGrantedAssetView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class UserProfileView(LoginRequiredMixin, TemplateView):
|
||||
template_name = 'users/user_profile.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
from perms.utils import (get_user_granted_assets,
|
||||
get_user_granted_asset_groups,
|
||||
get_user_asset_permissions)
|
||||
assets = get_user_granted_assets(self.request.user)
|
||||
asset_groups = get_user_granted_asset_groups(self.request.user)
|
||||
permissions = get_user_asset_permissions(self.request.user)
|
||||
context = {
|
||||
'app': 'User',
|
||||
'action': 'User Profile',
|
||||
'assets': assets,
|
||||
'asset_groups': asset_groups,
|
||||
'permissions': permissions
|
||||
}
|
||||
kwargs.update(context)
|
||||
return super(UserProfileView, self).get_context_data(**kwargs)
|
||||
|
|
|
@ -81,6 +81,8 @@ class Config:
|
|||
# EMAIL_USE_TLS = False # If port is 587, set True
|
||||
# EMAIL_SUBJECT_PREFIX = '[Jumpserver] '
|
||||
|
||||
CAPTCHA_TEST_MODE = False
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
@ -121,4 +123,3 @@ config = {
|
|||
}
|
||||
|
||||
env = 'development'
|
||||
|
||||
|
|
Loading…
Reference in New Issue