Commit b0551449 authored by ibuler's avatar ibuler

Merge with audits

parents 7825c107 dd5dd9d7
......@@ -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 %}
\ No newline at end of file
{% 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);
setTimeout( function () {
$data_table.ajax.reload();
}, 3000);
})
.on('click', '#btn_bulk_update', function () {
......
{% extends 'base.html' %}
{% load common_tags %}
{% load static %}
{% load i18n %}
......
{% 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);
setTimeout( function () {
$data_table.ajax.reload();
}, 3000);
})
.on('click', '#btn_bulk_update', function () {
......
{% 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);
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 %}
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
......
{% 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>
......
{% 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 }}
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
......
{% 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);
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
......
{% 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">
......
{% extends 'base.html' %}
{% load common_tags %}
{% load static %}
{% load i18n %}
......
{% 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>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -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 = {
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load static %}
{% load i18n %}
......
{% 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" %}
......
{% 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;
}
{% 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 %}
......
# ~*~ 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()
......
#!/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)
......
#!/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):
......@@ -47,5 +36,9 @@ class IsSuperUserOrAppUser(IsValidUser, permissions.BasePermission):
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
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load bootstrap %}
{% load static %}
{% load i18n %}
......
{% 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.' %}";
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load bootstrap %}
{% load static %}
{% load i18n %}
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load bootstrap %}
{% load static %}
{% load i18n %}
......
{% extends 'base.html' %}
{% load common_tags %}
{% load users_tags %}
{% load bootstrap %}
{% load static %}
{% 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 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(),
......
# ~*~ coding: utf-8 ~*~
from __future__ import unicode_literals
import uuid
import json
import uuid
from django.shortcuts import redirect
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,
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,
])
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'
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