Commit b0551449 authored by ibuler's avatar ibuler

Merge with audits

parents 7825c107 dd5dd9d7
...@@ -19,3 +19,5 @@ config.py ...@@ -19,3 +19,5 @@ config.py
migrations/ migrations/
*.log *.log
host_rsa_key host_rsa_key
*.bat
tags
...@@ -20,13 +20,13 @@ class AssetCreateForm(forms.ModelForm): ...@@ -20,13 +20,13 @@ class AssetCreateForm(forms.ModelForm):
self.instance.tags.clear() self.instance.tags.clear()
self.instance.tags.add(*tuple(tags)) self.instance.tags.add(*tuple(tags))
def clean(self): # def clean(self):
clean_data = super(AssetCreateForm, self).clean() # clean_data = super(AssetCreateForm, self).clean()
ip = clean_data.get('ip') # ip = clean_data.get('ip')
port = clean_data.get('port') # port = clean_data.get('port')
query = Asset.objects.filter(ip=ip, port=port) # query = Asset.objects.filter(ip=ip, port=port)
if query: # if query:
raise forms.ValidationError('this asset has exists.') # raise forms.ValidationError('this asset has exists.')
class Meta: class Meta:
model = Asset model = Asset
......
...@@ -77,10 +77,6 @@ ...@@ -77,10 +77,6 @@
</div> </div>
</form> </form>
{% endblock %} {% endblock %}
{% block modal_confirm_id %}btn_asset_bulk_update{% endblock %} {% block modal_confirm_id %}btn_asset_bulk_update{% endblock %}
\ No newline at end of file
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
...@@ -52,10 +52,11 @@ $(document).ready(function(){ ...@@ -52,10 +52,11 @@ $(document).ready(function(){
$(td).html('<a href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</a>'); $(td).html('<a href="javascript:void(0);" data-toggle="tooltip" title="' + cellData + '">' + innerHtml + '</a>');
}}, }},
{targets: 6, createdCell: function (td, cellData, rowData) { {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 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); 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" %}', ajax_url: '{% url "api-assets:admin-user-list" %}',
columns: [{data: function(){return ""}}, {data: "name" }, {data: "username" }, {data: "assets_amount" }, {data: function () {return 'lost'} }, columns: [{data: function(){return ""}}, {data: "name" }, {data: "username" }, {data: "assets_amount" }, {data: function () {return 'lost'} },
...@@ -72,7 +73,9 @@ $(document).ready(function(){ ...@@ -72,7 +73,9 @@ $(document).ready(function(){
var uid = $this.data('uid'); var uid = $this.data('uid');
var the_url = '{% url "api-assets:admin-user-detail" pk=99991937 %}'.replace('99991937', uid); var the_url = '{% url "api-assets:admin-user-detail" pk=99991937 %}'.replace('99991937', uid);
objectDelete($this, name, the_url); objectDelete($this, name, the_url);
setTimeout( function () {
$data_table.ajax.reload(); $data_table.ajax.reload();
}, 3000);
}) })
.on('click', '#btn_bulk_update', function () { .on('click', '#btn_bulk_update', function () {
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
...@@ -70,7 +70,9 @@ $(document).ready(function(){ ...@@ -70,7 +70,9 @@ $(document).ready(function(){
var uid = $this.data('uid'); var uid = $this.data('uid');
var the_url = '{% url "api-assets:asset-group-detail" pk=99991937 %}'.replace('99991937', uid); var the_url = '{% url "api-assets:asset-group-detail" pk=99991937 %}'.replace('99991937', uid);
objectDelete($this, name, the_url); objectDelete($this, name, the_url);
setTimeout( function () {
$data_table.ajax.reload(); $data_table.ajax.reload();
}, 3000);
}) })
.on('click', '#btn_bulk_update', function () { .on('click', '#btn_bulk_update', function () {
......
{% extends '_base_list.html' %} {% extends '_base_list.html' %}
{% load i18n %} {% load i18n %}
{% load static %} {% load static %}
{% load common_tags %}
{% block custom_head_css_js %} {% block custom_head_css_js %}
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet"> <link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script> <script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
...@@ -33,7 +32,7 @@ ...@@ -33,7 +32,7 @@
<div class="tagBtnList"> <div class="tagBtnList">
{% for tag in tag_list %} {% for tag in tag_list %}
<a href="{% url 'assets:asset-tags' tag_id=tag.0 %}" <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"> class="tagBtn2 label label-warning" name="tag_on">
{% else %} {% else %}
class="tagBtn2 label label-default"> class="tagBtn2 label label-default">
...@@ -105,6 +104,38 @@ function tagShow() { ...@@ -105,6 +104,38 @@ function tagShow() {
} }
} //onload; } //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(){ $(document).ready(function(){
var options = { var options = {
ele: $('#asset_list_table'), ele: $('#asset_list_table'),
...@@ -187,8 +218,11 @@ $(document).ready(function(){ ...@@ -187,8 +218,11 @@ $(document).ready(function(){
var name = $(this).closest("tr").find(":nth-child(2)").children('a').html(); var name = $(this).closest("tr").find(":nth-child(2)").children('a').html();
var uid = $this.data('uid'); var uid = $this.data('uid');
var the_url = '{% url "api-assets:asset-detail" pk=99991937 %}'.replace('99991937', uid); var the_url = '{% url "api-assets:asset-detail" pk=99991937 %}'.replace('99991937', uid);
objectDelete($this, name, the_url); console.log(the_url);
objDelete($this, name, the_url);
setTimeout( function () {
$data_table.ajax.reload(); $data_table.ajax.reload();
}, 3000);
}) })
.on('click', '#btn_bulk_update', function () { .on('click', '#btn_bulk_update', function () {
...@@ -324,5 +358,6 @@ $(document).ready(function(){ ...@@ -324,5 +358,6 @@ $(document).ready(function(){
{# APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(post_list), success: success});#} {# APIUpdateAttr({url: the_url, method: 'PATCH', body: JSON.stringify(post_list), success: success});#}
$('#asset_bulk_update_modal').modal('hide'); $('#asset_bulk_update_modal').modal('hide');
}); });
</script> </script>
{% endblock %} {% endblock %}
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends '_base_list.html' %} {% extends '_base_list.html' %}
{% load i18n static %} {% load i18n static %}
{#{% load common_tags %}#}
{% block custom_head_css_js %} {% block custom_head_css_js %}
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet"> <link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script> <script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3 class="widget-head-color-box">IP段</h3> <h3 class="widget-head-color-box">IP段</h3>
{{ form.operator|bootstrap_horizontal }}
{{ form.intranet|bootstrap_horizontal }} {{ form.intranet|bootstrap_horizontal }}
{{ form.extranet|bootstrap_horizontal }} {{ form.extranet|bootstrap_horizontal }}
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends '_base_list.html' %} {% extends '_base_list.html' %}
{% load i18n %} {% load i18n %}
{% load common_tags %}
{% block table_search %} {% block table_search %}
{% endblock %} {% endblock %}
...@@ -75,7 +74,9 @@ $(document).ready(function(){ ...@@ -75,7 +74,9 @@ $(document).ready(function(){
var uid = $this.data('uid'); var uid = $this.data('uid');
var the_url = '{% url "api-assets:system-user-detail" pk=99991937 %}'.replace('99991937', uid); var the_url = '{% url "api-assets:system-user-detail" pk=99991937 %}'.replace('99991937', uid);
objectDelete($this, name, the_url); objectDelete($this, name, the_url);
setTimeout( function () {
$data_table.ajax.reload(); $data_table.ajax.reload();
}, 3000);
}) })
.on('click', '#btn_bulk_update', function () { .on('click', '#btn_bulk_update', function () {
......
...@@ -139,15 +139,15 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateAssetTagsMiXin, UpdateView): ...@@ -139,15 +139,15 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateAssetTagsMiXin, UpdateView):
print(form.errors) print(form.errors)
return super(AssetUpdateView, self).form_invalid(form) return super(AssetUpdateView, self).form_invalid(form)
def form_valid(self, form): # def form_valid(self, form):
asset = form.save(commit=False) # asset = form.save(commit=False)
#
def prn_obj_key(obj_form): # def prn_obj_key(obj_form):
return obj_form.clean().keys() # return obj_form.clean().keys()
#
for i in prn_obj_key(form): # for i in prn_obj_key(form):
if i not in self.new_form.keys(): # if i not in self.new_form.keys():
print i # print i
#delattr(asset, '"%s" % i') #delattr(asset, '"%s" % i')
#del asset.i #del asset.i
......
{% extends '_base_list.html' %} {% extends '_base_list.html' %}
{% load i18n %} {% load i18n %}
{% load static %} {% load static %}
{% load common_tags %}
{% block content_left_head %} {% block content_left_head %}
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet"> <link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet"> <link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends '_base_list.html' %} {% extends '_base_list.html' %}
{% load i18n %} {% load i18n %}
{% load static %} {% load static %}
{% load common_tags %}
{% block content_left_head %} {% block content_left_head %}
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet"> <link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
<style> <style>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -14,7 +14,6 @@ import os ...@@ -14,7 +14,6 @@ import os
import sys import sys
from django.urls import reverse_lazy from django.urls import reverse_lazy
from datetime import timedelta
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
...@@ -300,11 +299,11 @@ CELERY_RESULT_BACKEND = BROKER_URL ...@@ -300,11 +299,11 @@ CELERY_RESULT_BACKEND = BROKER_URL
# crontab job # crontab job
# CELERYBEAT_SCHEDULE = { # CELERYBEAT_SCHEDULE = {
# Check applications is alive every 10m # Check applications is alive every 10m
# 'check_terminal_alive': { # 'check_terminal_alive': {
# 'task': 'applications.tasks.check_terminal_alive', # 'task': 'applications.tasks.check_terminal_alive',
# 'schedule': timedelta(seconds=TERMINAL_HEATBEAT_INTERVAL), # 'schedule': timedelta(seconds=TERMINAL_HEATBEAT_INTERVAL),
# 'args': (), # 'args': (),
# }, # },
# } # }
...@@ -326,3 +325,4 @@ CAPTCHA_FOREGROUND_COLOR = '#001100' ...@@ -326,3 +325,4 @@ CAPTCHA_FOREGROUND_COLOR = '#001100'
COMMAND_STORE_BACKEND = 'audits.backends.command.db' COMMAND_STORE_BACKEND = 'audits.backends.command.db'
RECORD_STORE_BACKEND = 'audits.backends.record.db' RECORD_STORE_BACKEND = 'audits.backends.record.db'
CAPTCHA_TEST_MODE = CONFIG.CAPTCHA_TEST_MODE
...@@ -6,7 +6,6 @@ import logging ...@@ -6,7 +6,6 @@ import logging
from uuid import uuid4 from uuid import uuid4
from assets.models import Asset from assets.models import Asset
from ops.models import TaskRecord from ops.models import TaskRecord
from ops.utils.ansible_api import ADHocRunner, Config
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
...@@ -20,7 +19,7 @@ logger = logging.getLogger(__name__) ...@@ -20,7 +19,7 @@ logger = logging.getLogger(__name__)
class Task(models.Model): class Task(models.Model):
record = models.OneToOneField(TaskRecord) record = models.OneToOneField(TaskRecord)
name = models.CharField(max_length=128, blank=True, verbose_name=_('Name')) 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') assets = models.ManyToManyField(Asset, related_name='tasks')
def __unicode__(self): def __unicode__(self):
...@@ -31,6 +30,7 @@ class Task(models.Model): ...@@ -31,6 +30,7 @@ class Task(models.Model):
return [] return []
def run(self): def run(self):
from ops.utils.ansible_api import ADHocRunner, Config
conf = Config() conf = Config()
gather_facts = "yes" if self.is_gather_facts else "no" gather_facts = "yes" if self.is_gather_facts else "no"
play_source = { play_source = {
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends '_base_list.html' %} {% extends '_base_list.html' %}
{% load i18n %} {% load i18n %}
{% load common_tags %}
{% block content_left_head %} {% block content_left_head %}
<a href="{% url 'perms:asset-permission-create' %}" class="btn btn-sm btn-primary"> <a href="{% url 'perms:asset-permission-create' %}" class="btn btn-sm btn-primary">
{% trans "Create permission" %} {% trans "Create permission" %}
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
...@@ -225,6 +225,7 @@ table.dataTable tbody td.selected td i.text-navy ...@@ -225,6 +225,7 @@ table.dataTable tbody td.selected td i.text-navy
background: #f1f1f1; background: #f1f1f1;
margin-right: 2px; margin-right: 2px;
} }
.form-asset-on{ .form-asset-on{
border: 1px solid #e5e6e7; border: 1px solid #e5e6e7;
padding-top:5px; padding-top:5px;
...@@ -264,3 +265,15 @@ div.dataTables_wrapper div.dataTables_filter, ...@@ -264,3 +265,15 @@ div.dataTables_wrapper div.dataTables_filter,
div.dataTables_wrapper div.dataTables_filter { div.dataTables_wrapper div.dataTables_filter {
margin-left: 15px; 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;
}
{% extends 'base.html' %} {% extends 'base.html' %}
{% load static %} {% load static %}
{% load common_tags %}
{% block custom_head_css_js %} {% block custom_head_css_js %}
<link href="{% static "css/plugins/dataTables/dataTables.min.css" %}" rel="stylesheet"> <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"> <link href="{% static "css/plugins/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css" %}" rel="stylesheet">
......
...@@ -24,9 +24,9 @@ ...@@ -24,9 +24,9 @@
{% block first_login_message %} {% block first_login_message %}
{% if user.is_authenticated and user.is_first_login %} {% if user.is_authenticated and user.is_first_login %}
<div class="alert alert-danger" style="margin: 20px auto 0px"> <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 %} {% 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 %} {% endblocktrans %}
</div> </div>
{% endif %} {% endif %}
...@@ -34,8 +34,9 @@ ...@@ -34,8 +34,9 @@
{% block update_public_key_message %} {% block update_public_key_message %}
{% if user.is_authenticated and not user.is_public_key_valid %} {% if user.is_authenticated and not user.is_public_key_valid %}
<div class="alert alert-danger" style="margin: 20px auto 0px"> <div class="alert alert-danger" style="margin: 20px auto 0px">
{% url 'users:user-profile' as profile_url %}
{% blocktrans %} {% 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 %} {% endblocktrans %}
</div> </div>
{% endif %} {% endif %}
......
# ~*~ coding: utf-8 ~*~ # ~*~ 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.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from rest_framework.permissions import AllowAny
from rest_framework_bulk import BulkModelViewSet 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.mixins import IDInFilterMixin
from common.utils import get_logger 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__) logger = get_logger(__name__)
...@@ -41,7 +38,7 @@ class UserResetPasswordApi(generics.UpdateAPIView): ...@@ -41,7 +38,7 @@ class UserResetPasswordApi(generics.UpdateAPIView):
def perform_update(self, serializer): def perform_update(self, serializer):
# Note: we are not updating the user object here. # 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 import uuid
from .utils import send_reset_password_mail from .utils import send_reset_password_mail
user = self.get_object() user = self.get_object()
...@@ -65,6 +62,7 @@ class UserResetPKApi(generics.UpdateAPIView): ...@@ -65,6 +62,7 @@ class UserResetPKApi(generics.UpdateAPIView):
class UserUpdatePKApi(generics.UpdateAPIView): class UserUpdatePKApi(generics.UpdateAPIView):
queryset = User.objects.all() queryset = User.objects.all()
serializer_class = serializers.UserPKUpdateSerializer serializer_class = serializers.UserPKUpdateSerializer
permission_classes = (IsCurrentUserOrReadOnly,)
def perform_update(self, serializer): def perform_update(self, serializer):
user = self.get_object() user = self.get_object()
......
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import os
from collections import OrderedDict from collections import OrderedDict
from django.conf import settings
from django.contrib.auth.hashers import make_password from django.contrib.auth.hashers import make_password
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.core import signing from django.core import signing
from django.conf import settings from django.db import models
from django.db import models, IntegrityError
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone from django.utils import timezone
from django.shortcuts import reverse from django.shortcuts import reverse
from common.utils import signer, date_expired_default
from . import UserGroup from . import UserGroup
from common.utils import signer, date_expired_default
__all__ = ['User'] __all__ = ['User']
...@@ -61,6 +62,15 @@ class User(AbstractUser): ...@@ -61,6 +62,15 @@ class User(AbstractUser):
def get_absolute_url(self): def get_absolute_url(self):
return reverse('users:user-detail', args=(self.id,)) 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 @property
def is_expired(self): def is_expired(self):
if self.date_expired < timezone.now(): if self.date_expired < timezone.now():
...@@ -156,6 +166,17 @@ class User(AbstractUser): ...@@ -156,6 +166,17 @@ class User(AbstractUser):
return True return True
return False 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): def generate_reset_token(self):
return signer.sign_t({'reset': self.id, 'email': self.email}, expires_in=3600) return signer.sign_t({'reset': self.id, 'email': self.email}, expires_in=3600)
......
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
#
import base64 from rest_framework import permissions
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
class IsValidUser(permissions.IsAuthenticated, permissions.BasePermission): class IsValidUser(permissions.IsAuthenticated, permissions.BasePermission):
...@@ -47,5 +36,9 @@ class IsSuperUserOrAppUser(IsValidUser, permissions.BasePermission): ...@@ -47,5 +36,9 @@ class IsSuperUserOrAppUser(IsValidUser, permissions.BasePermission):
and (request.user.is_superuser or request.user.is_app) and (request.user.is_superuser or request.user.is_app)
if __name__ == '__main__': class IsCurrentUserOrReadOnly(permissions.BasePermission):
pass
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj == request.user
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load bootstrap %} {% load bootstrap %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
...@@ -18,16 +16,16 @@ ...@@ -18,16 +16,16 @@
<div class="panel-options"> <div class="panel-options">
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"> <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>
<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>
<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>
<li class="pull-right"> <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>
<li class="pull-right"> <li class="pull-right">
<a class="btn btn-outline btn-danger btn-delete-user"> <a class="btn btn-outline btn-danger btn-delete-user">
...@@ -40,7 +38,7 @@ ...@@ -40,7 +38,7 @@
<div class="col-sm-7" style="padding-left: 0"> <div class="col-sm-7" style="padding-left: 0">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <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"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>
...@@ -60,56 +58,56 @@ ...@@ -60,56 +58,56 @@
<tbody> <tbody>
<tr class="no-borders-tr"> <tr class="no-borders-tr">
<td colspan="2"> <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> </td>
</tr> </tr>
<tr> <tr>
<td width="20%">{% trans 'Name' %}:</td> <td width="20%">{% trans 'Name' %}:</td>
<td><b>{{ user.name }}</b></td> <td><b>{{ user_object.name }}</b></td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Username' %}:</td> <td>{% trans 'Username' %}:</td>
<td><b>{{ user.username }}</b></td> <td><b>{{ user_object.username }}</b></td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Email' %}:</td> <td>{% trans 'Email' %}:</td>
<td><b>{{ user.email }}</b></td> <td><b>{{ user_object.email }}</b></td>
</tr> </tr>
{% if user.phone %} {% if user.phone %}
<tr> <tr>
<td>{% trans 'Phone' %}:</td> <td>{% trans 'Phone' %}:</td>
<td><b>{{ user.phone }}</b></td> <td><b>{{ user_object.phone }}</b></td>
</tr> </tr>
{% endif %} {% endif %}
{% if user.wechat %} {% if user_object.wechat %}
<tr> <tr>
<td>{% trans 'Wechat' %}:</td> <td>{% trans 'Wechat' %}:</td>
<td><b>{{ user.wechat }}</b></td> <td><b>{{ user_object.wechat }}</b></td>
</tr> </tr>
{% endif %} {% endif %}
<tr> <tr>
<td>{% trans 'Role' %}:</td> <td>{% trans 'Role' %}:</td>
<td><b>{{ user.get_role_display }}</b></td> <td><b>{{ user_object.get_role_display }}</b></td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Date expired' %}:</td> <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>
<tr> <tr>
<td>{% trans 'Created by' %}:</td> <td>{% trans 'Created by' %}:</td>
<td><b>{{ user.created_by }}</b></td> <td><b>{{ user_object.created_by }}</b></td>
</tr> </tr>
<tr> <tr>
<td>{% trans 'Date joined' %}:</td> <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>
<tr> <tr>
<td>{% trans 'Last login' %}:</td> <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>
<tr> <tr>
<td>{% trans 'Comment' %}:</td> <td>{% trans 'Comment' %}:</td>
<td><b>{{ user.comment }}</b></td> <td><b>{{ user_object.comment }}</b></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
...@@ -129,7 +127,7 @@ ...@@ -129,7 +127,7 @@
<td><span class="pull-right"> <td><span class="pull-right">
<div class="switch"> <div class="switch">
<div class="onoffswitch"> <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"> <label class="onoffswitch-label" for="is_active">
<span class="onoffswitch-inner"></span> <span class="onoffswitch-inner"></span>
<span class="onoffswitch-switch"></span> <span class="onoffswitch-switch"></span>
...@@ -143,7 +141,7 @@ ...@@ -143,7 +141,7 @@
<td><span class="pull-right"> <td><span class="pull-right">
<div class="switch"> <div class="switch">
<div class="onoffswitch"> <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"> id="enable_otp">
<label class="onoffswitch-label" for="enable_otp"> <label class="onoffswitch-label" for="enable_otp">
<span class="onoffswitch-inner"></span> <span class="onoffswitch-inner"></span>
...@@ -169,14 +167,6 @@ ...@@ -169,14 +167,6 @@
</span> </span>
</td> </td>
</tr> </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> </tbody>
</table> </table>
</div> </div>
...@@ -206,7 +196,7 @@ ...@@ -206,7 +196,7 @@
</tr> </tr>
</form> </form>
{% for group in user.groups.all %} {% for group in user_object.groups.all %}
<tr> <tr>
<td > <td >
<b class="bdg_group" data-gid={{ group.id }}>{{ group.name }}</b> <b class="bdg_group" data-gid={{ group.id }}>{{ group.name }}</b>
...@@ -233,7 +223,7 @@ ...@@ -233,7 +223,7 @@
jumpserver.groups_selected = {}; jumpserver.groups_selected = {};
function updateUserGroups(groups) { 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 = { var body = {
groups: Object.assign([], groups) groups: Object.assign([], groups)
}; };
...@@ -273,7 +263,7 @@ $(document).ready(function() { ...@@ -273,7 +263,7 @@ $(document).ready(function() {
}) })
}) })
.on('click', '#is_active', 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 checked = $(this).prop('checked');
var body = { var body = {
'is_active': checked 'is_active': checked
...@@ -286,7 +276,7 @@ $(document).ready(function() { ...@@ -286,7 +276,7 @@ $(document).ready(function() {
}); });
}) })
.on('click', '#enable_otp', 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 checked = $(this).prop('checked');
var body = { var body = {
'enable_otp': checked 'enable_otp': checked
...@@ -326,7 +316,7 @@ $(document).ready(function() { ...@@ -326,7 +316,7 @@ $(document).ready(function() {
updateUserGroups(groups) updateUserGroups(groups)
}).on('click', '#btn_reset_password', function() { }).on('click', '#btn_reset_password', function() {
function doReset() { 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 body = {};
var success = function() { var success = function() {
var msg = "{% trans "An e-mail has been sent to the user\'s mailbox." %}"; var msg = "{% trans "An e-mail has been sent to the user\'s mailbox." %}";
...@@ -340,7 +330,7 @@ $(document).ready(function() { ...@@ -340,7 +330,7 @@ $(document).ready(function() {
} }
swal({ swal({
title: "{% trans 'Are you sure?' %}", 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", type: "warning",
showCancelButton: true, showCancelButton: true,
confirmButtonColor: "#DD6B55", confirmButtonColor: "#DD6B55",
...@@ -351,7 +341,7 @@ $(document).ready(function() { ...@@ -351,7 +341,7 @@ $(document).ready(function() {
}); });
}).on('click', '#btn_reset_pk', function() { }).on('click', '#btn_reset_pk', function() {
function doReset() { 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 body = {};
var success = function() { 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.' %}"; 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.' %}";
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load bootstrap %} {% load bootstrap %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load bootstrap %} {% load bootstrap %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% extends 'base.html' %} {% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load bootstrap %} {% load bootstrap %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
......
{% 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 %}
# ~*~ 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'
from __future__ import absolute_import from __future__ import absolute_import
from django.conf.urls import url from django.conf.urls import url
from .. import views from .. import views
app_name = 'users' app_name = 'users'
...@@ -20,6 +21,11 @@ urlpatterns = [ ...@@ -20,6 +21,11 @@ urlpatterns = [
views.UserResetPasswordSuccessView.as_view(), views.UserResetPasswordSuccessView.as_view(),
name='reset-password-success'), name='reset-password-success'),
# Profile
url(r'^profile/$',
views.UserProfileView.as_view(),
name='user-profile'),
# User view # User view
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(), url(r'^user/(?P<pk>[0-9]+)$', views.UserDetailView.as_view(),
......
# ~*~ coding: utf-8 ~*~ # ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals from __future__ import unicode_literals
import uuid
import json import json
import uuid
from django.shortcuts import redirect from openpyxl import load_workbook
from openpyxl import Workbook from openpyxl import Workbook
from openpyxl.writer.excel import save_virtual_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.core.cache import cache
from django.http import HttpResponse, JsonResponse 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.urls import reverse_lazy, reverse
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
...@@ -19,22 +21,23 @@ from django.utils.decorators import method_decorator ...@@ -19,22 +21,23 @@ from django.utils.decorators import method_decorator
from django.views import View from django.views import View
from django.views.generic import ListView from django.views.generic import ListView
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.views.generic.edit import CreateView, UpdateView, FormMixin, \ from django.views.generic.edit import (CreateView, UpdateView, FormMixin,
FormView FormView)
from django.views.generic.detail import DetailView, SingleObjectMixin from django.views.generic.detail import DetailView, SingleObjectMixin
from django.views.decorators.csrf import csrf_exempt 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.mixins import JSONResponseMixin
from common.utils import get_logger from common.utils import get_logger
from perms.models import AssetPermission 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', __all__ = ['UserListView', 'UserCreateView', 'UserDetailView',
'UserUpdateView', 'UserAssetPermissionCreateView', 'UserUpdateView', 'UserAssetPermissionCreateView',
'UserAssetPermissionView', 'UserGrantedAssetView', 'UserAssetPermissionView', 'UserGrantedAssetView',
'UserExportView', 'UserBulkImportView'] 'UserExportView', 'UserBulkImportView', 'UserProfileView']
logger = get_logger(__name__) logger = get_logger(__name__)
...@@ -103,7 +106,7 @@ class UserUpdateView(AdminUserRequiredMixin, UpdateView): ...@@ -103,7 +106,7 @@ class UserUpdateView(AdminUserRequiredMixin, UpdateView):
class UserDetailView(AdminUserRequiredMixin, DetailView): class UserDetailView(AdminUserRequiredMixin, DetailView):
model = User model = User
template_name = 'users/user_detail.html' template_name = 'users/user_detail.html'
context_object_name = "user" context_object_name = "user_object"
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
groups = UserGroup.objects.exclude(id__in=self.object.groups.all()) groups = UserGroup.objects.exclude(id__in=self.object.groups.all())
...@@ -134,18 +137,16 @@ class UserExportView(View): ...@@ -134,18 +137,16 @@ class UserExportView(View):
ws.append(header) ws.append(header)
for user in users: for user in users:
print(user.name) ws.append([user.name, user.username, user.email,
ws.append([
user.name, user.username, user.email,
','.join([group.name for group in user.groups.all()]), ','.join([group.name for group in user.groups.all()]),
user.role, user.phone, user.wechat, user.comment, user.role, user.phone, user.wechat, user.comment])
])
filename = 'users-{}.xlsx'.format( filename = 'users-{}.xlsx'.format(
timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S')) timezone.localtime(timezone.now()).strftime('%Y-%m-%d_%H-%M-%S'))
response = HttpResponse(save_virtual_workbook(wb), response = HttpResponse(save_virtual_workbook(wb),
content_type='applications/vnd.ms-excel') content_type='applications/vnd.ms-excel')
response['Content-Disposition'] = 'attachment; filename="%s"' % filename response[
'Content-Disposition'] = 'attachment; filename="%s"' % filename
return response return response
def post(self, request): def post(self, request):
...@@ -304,3 +305,24 @@ class UserGrantedAssetView(AdminUserRequiredMixin, DetailView): ...@@ -304,3 +305,24 @@ class UserGrantedAssetView(AdminUserRequiredMixin, DetailView):
} }
kwargs.update(context) kwargs.update(context)
return super(UserGrantedAssetView, self).get_context_data(**kwargs) 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: ...@@ -81,6 +81,8 @@ class Config:
# EMAIL_USE_TLS = False # If port is 587, set True # EMAIL_USE_TLS = False # If port is 587, set True
# EMAIL_SUBJECT_PREFIX = '[Jumpserver] ' # EMAIL_SUBJECT_PREFIX = '[Jumpserver] '
CAPTCHA_TEST_MODE = False
def __init__(self): def __init__(self):
pass pass
...@@ -121,4 +123,3 @@ config = { ...@@ -121,4 +123,3 @@ config = {
} }
env = 'development' env = 'development'
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 to comment