提交 ec8106e4 编写于 作者: baltery's avatar baltery

[Feature] 完成登陆日志

上级 a5f97359
...@@ -94,7 +94,6 @@ class IndexView(LoginRequiredMixin, TemplateView): ...@@ -94,7 +94,6 @@ class IndexView(LoginRequiredMixin, TemplateView):
for asset in assets: for asset in assets:
last_login = self.session_week.filter(asset=asset["asset"]).order_by('date_start').last() last_login = self.session_week.filter(asset=asset["asset"]).order_by('date_start').last()
asset['last'] = last_login asset['last'] = last_login
print(asset)
return assets return assets
def get_week_top10_user(self): def get_week_top10_user(self):
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<ul class="nav nav-second-level active"> <ul class="nav nav-second-level active">
<li id="user"><a href="{% url 'users:user-list' %}">{% trans 'User' %}</a></li> <li id="user"><a href="{% url 'users:user-list' %}">{% trans 'User' %}</a></li>
<li id="user-group"><a href="{% url 'users:user-group-list' %}">{% trans 'User group' %}</a></li> <li id="user-group"><a href="{% url 'users:user-group-list' %}">{% trans 'User group' %}</a></li>
<li id="user-group"><a href="{% url 'users:user-group-list' %}">{% trans 'Login logs' %}</a></li> <li id="login-log"><a href="{% url 'users:login-log-list' %}">{% trans 'Login logs' %}</a></li>
</ul> </ul>
</li> </li>
<li id="assets"> <li id="assets">
......
...@@ -164,9 +164,8 @@ class UserAuthApi(APIView): ...@@ -164,9 +164,8 @@ class UserAuthApi(APIView):
if user: if user:
token = generate_token(request, user) token = generate_token(request, user)
write_login_log_async.delay( write_login_log_async.delay(
user.username, name=user.name, user.username, ip=login_ip,
user_agent=user_agent, login_ip=login_ip, type=login_type, user_agent=user_agent,
login_type=login_type
) )
return Response({'token': token, 'user': user.to_json()}) return Response({'token': token, 'user': user.to_json()})
else: else:
......
...@@ -16,8 +16,7 @@ class AccessKey(models.Model): ...@@ -16,8 +16,7 @@ class AccessKey(models.Model):
default=uuid.uuid4, editable=False) default=uuid.uuid4, editable=False)
secret = models.UUIDField(verbose_name='AccessKeySecret', secret = models.UUIDField(verbose_name='AccessKeySecret',
default=uuid.uuid4, editable=False) default=uuid.uuid4, editable=False)
user = models.ForeignKey(User, verbose_name='User', user = models.ForeignKey(User, verbose_name='User', on_delete=models.CASCADE, related_name='access_key')
related_name='access_key')
def get_id(self): def get_id(self):
return str(self.id) return str(self.id)
...@@ -39,8 +38,7 @@ class PrivateToken(Token): ...@@ -39,8 +38,7 @@ class PrivateToken(Token):
class LoginLog(models.Model): class LoginLog(models.Model):
LOGIN_TYPE_CHOICE = ( LOGIN_TYPE_CHOICE = (
('W', 'Web'), ('W', 'Web'),
('ST', 'SSH Terminal'), ('T', 'Terminal'),
('WT', 'Web Terminal')
) )
id = models.UUIDField(default=uuid.uuid4, primary_key=True) id = models.UUIDField(default=uuid.uuid4, primary_key=True)
username = models.CharField(max_length=20, verbose_name=_('Username')) username = models.CharField(max_length=20, verbose_name=_('Username'))
......
{% 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>
#search_btn {
margin-bottom: 0;
}
</style>
{% endblock %}
{% block table_search %}
<form id="search_form" method="get" action="" class="pull-right form-inline">
<div class="form-group" id="date">
<div class="input-daterange input-group" id="datepicker">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_from" value="{{ date_from }}">
<span class="input-group-addon">to</span>
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_to" value="{{ date_to }}">
</div>
</div>
<div class="input-group">
<select class="select2 form-control" name="username">
<option value="">{% trans 'Select user' %}</option>
{% for u in user_list %}
<option value="{{ u }}" {% if u == username %} selected {% endif %}>{{ u }}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<input type="text" class="form-control input-sm" name="keyword" placeholder="Search" value="{{ keyword }}">
</div>
<div class="input-group">
<div class="input-group-btn">
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
搜索
</button>
</div>
</div>
</form>
{% endblock %}
{% block table_head %}
<th class="text-center">{% trans 'ID' %}</th>
<th class="text-center">{% trans 'Username' %}</th>
<th class="text-center">{% trans 'Type' %}</th>
<th class="text-center">{% trans 'UA' %}</th>
<th class="text-center">{% trans 'IP' %}</th>
<th class="text-center">{% trans 'City' %}</th>
<th class="text-center">{% trans 'Date' %}</th>
{% endblock %}
{% block table_body %}
{% for login_log in object_list %}
<tr class="gradeX">
<td class="text-center">{{ forloop.counter }}</td>
<td class="text-center">{{ login_log.username }}</td>
<td class="text-center">{{ login_log.get_type_display }}</td>
<td class="text-center">
<span href="javascript:void(0);" data-toggle="tooltips" title="{{ login_log.user_agent }}">{{ login_log.user_agent | truncatechars:20 }}</span>
</td>
<td class="text-center">{{ login_log.ip }}</td>
<td class="text-center">{{ login_log.city }}</td>
<td class="text-center">{{ login_log.datetime }}</td>
</tr>
{% endfor %}
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<script>
$(document).ready(function() {
$('table').DataTable({
"searching": false,
"bInfo" : false,
"paging": false,
"order": []
});
$('#date .input-daterange').datepicker({
dateFormat: 'mm/dd/yy',
keyboardNavigation: false,
forceParse: false,
autoclose: true
});
$('.select2').select2();
})
</script>
{% endblock %}
...@@ -43,4 +43,7 @@ urlpatterns = [ ...@@ -43,4 +43,7 @@ urlpatterns = [
url(r'^user-group/(?P<pk>[0-9a-zA-Z\-]+)/asset-permission$', views.UserGroupAssetPermissionView.as_view(), name='user-group-asset-permission'), url(r'^user-group/(?P<pk>[0-9a-zA-Z\-]+)/asset-permission$', views.UserGroupAssetPermissionView.as_view(), name='user-group-asset-permission'),
url(r'^user-group/(?P<pk>[0-9a-zA-Z\-]+)/asset-permission/create$', views.UserGroupAssetPermissionCreateView.as_view(), name='user-group-asset-permission-create'), url(r'^user-group/(?P<pk>[0-9a-zA-Z\-]+)/asset-permission/create$', views.UserGroupAssetPermissionCreateView.as_view(), name='user-group-asset-permission-create'),
url(r'^user-group/(?P<pk>[0-9a-zA-Z\-]+)/assets', views.UserGroupGrantedAssetView.as_view(), name='user-group-granted-asset'), url(r'^user-group/(?P<pk>[0-9a-zA-Z\-]+)/assets', views.UserGroupGrantedAssetView.as_view(), name='user-group-granted-asset'),
# Login log
url(r'^login-log/$', views.LoginLogListView.as_view(), name='login-log-list'),
] ]
...@@ -9,7 +9,7 @@ import requests ...@@ -9,7 +9,7 @@ import requests
import ipaddress import ipaddress
from django.conf import settings from django.conf import settings
from django.contrib.auth.mixins import UserPassesTestMixin from django.contrib.auth.mixins import UserPassesTestMixin
from django.contrib.auth import authenticate from django.contrib.auth import authenticate, login as auth_login
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.core.cache import cache from django.core.cache import cache
......
...@@ -5,7 +5,9 @@ from django import forms ...@@ -5,7 +5,9 @@ from django import forms
from django.shortcuts import render from django.shortcuts import render
from django.contrib.auth import login as auth_login, logout as auth_logout from django.contrib.auth import login as auth_login, logout as auth_logout
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView
from django.core.files.storage import default_storage from django.core.files.storage import default_storage
from django.db.models import Q
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.shortcuts import reverse, redirect from django.shortcuts import reverse, redirect
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
...@@ -17,9 +19,10 @@ from django.views.generic.base import TemplateView ...@@ -17,9 +19,10 @@ from django.views.generic.base import TemplateView
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from formtools.wizard.views import SessionWizardView from formtools.wizard.views import SessionWizardView
from django.conf import settings from django.conf import settings
from django.utils import timezone
from common.utils import get_object_or_none from common.utils import get_object_or_none
from ..models import User from ..models import User, LoginLog
from ..utils import send_reset_password_mail from ..utils import send_reset_password_mail
from ..tasks import write_login_log_async from ..tasks import write_login_log_async
from .. import forms from .. import forms
...@@ -28,7 +31,7 @@ from .. import forms ...@@ -28,7 +31,7 @@ from .. import forms
__all__ = ['UserLoginView', 'UserLogoutView', __all__ = ['UserLoginView', 'UserLogoutView',
'UserForgotPasswordView', 'UserForgotPasswordSendmailSuccessView', 'UserForgotPasswordView', 'UserForgotPasswordSendmailSuccessView',
'UserResetPasswordView', 'UserResetPasswordSuccessView', 'UserResetPasswordView', 'UserResetPasswordSuccessView',
'UserFirstLoginView'] 'UserFirstLoginView', 'LoginLogListView']
@method_decorator(sensitive_post_parameters(), name='dispatch') @method_decorator(sensitive_post_parameters(), name='dispatch')
...@@ -48,10 +51,10 @@ class UserLoginView(FormView): ...@@ -48,10 +51,10 @@ class UserLoginView(FormView):
auth_login(self.request, form.get_user()) auth_login(self.request, form.get_user())
login_ip = self.request.META.get('REMOTE_ADDR', '') login_ip = self.request.META.get('REMOTE_ADDR', '')
user_agent = self.request.META.get('HTTP_USER_AGENT', '') user_agent = self.request.META.get('HTTP_USER_AGENT', '')
write_login_log_async.delay(self.request.user.username, write_login_log_async.delay(
self.request.user.name, self.request.user.username, type='W',
login_type='W', login_ip=login_ip, ip=login_ip, user_agent=user_agent
user_agent=user_agent) )
return redirect(self.get_success_url()) return redirect(self.get_success_url())
def get_success_url(self): def get_success_url(self):
...@@ -202,3 +205,60 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView): ...@@ -202,3 +205,60 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
form.instance = self.request.user form.instance = self.request.user
return form return form
class LoginLogListView(ListView):
template_name = 'users/login_log_list.html'
model = LoginLog
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
username = keyword = date_from_s = date_to_s = ""
date_format = '%m/%d/%Y'
def get_queryset(self):
date_to_default = timezone.now()
date_from_default = timezone.now() - timezone.timedelta(7)
date_to_default_s = date_to_default.strftime(self.date_format)
date_from_default_s = date_from_default.strftime(self.date_format)
self.username = self.request.GET.get('username', '')
self.keyword = self.request.GET.get("keyword", '')
self.date_from_s = self.request.GET.get('date_from', date_from_default_s)
self.date_to_s = self.request.GET.get('date_to', date_to_default_s)
self.queryset = super().get_queryset()
if self.username:
self.queryset = self.queryset.filter(username=self.username)
if self.date_from_s:
date_from = timezone.datetime.strptime(self.date_from_s, '%m/%d/%Y')
date_from = date_from.replace(
tzinfo=timezone.get_current_timezone()
)
self.queryset = self.queryset.filter(datetime__gt=date_from)
if self.date_to_s:
date_to = timezone.datetime.strptime(
self.date_to_s + ' 23:59:59', '%m/%d/%Y %H:%M:%S'
)
date_to = date_to.replace(
tzinfo=timezone.get_current_timezone()
)
self.queryset = self.queryset.filter(datetime__lt=date_to)
if self.keyword:
self.queryset = self.queryset.filter(
Q(ip__contains=self.keyword) |
Q(city__contains=self.keyword) |
Q(username__contains=self.keyword)
)
return self.queryset
def get_context_data(self, **kwargs):
context = {
'app': _('Users'),
'action': _('Login log list'),
'date_from': self.date_from_s,
'date_to': self.date_to_s,
'username': self.username,
'keyword': self.keyword,
'user_list': set(LoginLog.objects.all().values_list('username', flat=True))
}
kwargs.update(context)
return super().get_context_data(**kwargs)
\ No newline at end of file
Django>=1.11 Django==1.11
django-bootstrap3>=8.2.2 django-bootstrap3>=8.2.2
Pillow>=4.1.0 Pillow>=4.1.0
djangorestframework>=3.6.2 djangorestframework>=3.6.2
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册