Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
J
jumpserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
jumpserver
Commits
9aae1069
Commit
9aae1069
authored
6 years ago
by
ibuler
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev' of github.com:jumpserver/jumpserver into dev
parents
c82044f6
e4e6f595
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
167 additions
and
32 deletions
+167
-32
models.py
apps/audits/models.py
+18
-0
login_log_list.html
apps/audits/templates/audits/login_log_list.html
+74
-32
view_urls.py
apps/audits/urls/view_urls.py
+1
-0
utils.py
apps/audits/utils.py
+23
-0
views.py
apps/audits/views.py
+51
-0
django.mo
apps/locale/zh/LC_MESSAGES/django.mo
+0
-0
django.po
apps/locale/zh/LC_MESSAGES/django.po
+0
-0
No files found.
apps/audits/models.py
View file @
9aae1069
import
uuid
from
django.db
import
models
from
django.db.models
import
Q
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils
import
timezone
...
...
@@ -100,5 +101,22 @@ class UserLoginLog(models.Model):
status
=
models
.
BooleanField
(
max_length
=
2
,
default
=
True
,
choices
=
STATUS_CHOICE
,
verbose_name
=
_
(
'Status'
))
datetime
=
models
.
DateTimeField
(
default
=
timezone
.
now
,
verbose_name
=
_
(
'Date login'
))
@classmethod
def
get_login_logs
(
cls
,
date_form
=
None
,
date_to
=
None
,
user
=
None
,
keyword
=
None
):
login_logs
=
cls
.
objects
.
all
()
if
date_form
and
date_to
:
login_logs
=
login_logs
.
filter
(
datetime__gt
=
date_form
,
datetime__lt
=
date_to
)
if
user
:
login_logs
=
login_logs
.
filter
(
username
=
user
)
if
keyword
:
login_logs
=
login_logs
.
filter
(
Q
(
ip__contains
=
keyword
)
|
Q
(
city__contains
=
keyword
)
|
Q
(
username__contains
=
keyword
)
)
return
login_logs
class
Meta
:
ordering
=
[
'-datetime'
,
'username'
]
This diff is collapsed.
Click to expand it.
apps/audits/templates/audits/login_log_list.html
View file @
9aae1069
...
...
@@ -17,10 +17,10 @@
<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|date:'Y-m-d'}}"
>
<input
type=
"text"
id=
"id_date_from"
class=
"input-sm form-control"
style=
"width: 100px;"
name=
"date_from"
value=
"{{ date_from|date:'Y-m-d'}}"
>
{#
<input
type=
"text"
class=
"input-sm form-control"
style=
"width: 100px;"
name=
"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|date:'Y-m-d'}}"
>
<input
type=
"text"
id=
"id_date_to"
class=
"input-sm form-control"
style=
"width: 100px;"
name=
"date_to"
value=
"{{ date_to|date:'Y-m-d'}}"
>
</div>
</div>
<div
class=
"input-group"
>
...
...
@@ -32,7 +32,7 @@
</select>
</div>
<div
class=
"input-group"
>
<input
type=
"text"
class=
"form-control input-sm"
name=
"keyword"
placeholder=
"{% trans 'Search' %}"
value=
"{{ keyword }}"
>
<input
type=
"text"
id=
"search"
class=
"form-control input-sm"
name=
"keyword"
placeholder=
"{% trans 'Search' %}"
value=
"{{ keyword }}"
>
</div>
<div
class=
"input-group"
>
<div
class=
"input-group-btn"
>
...
...
@@ -43,39 +43,58 @@
</div>
</form>
{% endblock %}
{% block table_container %}
<table
class=
"table table-striped table-bordered table-hover "
id=
"login_log_table"
>
<thead>
<tr>
<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 'MFA' %}
</th>
<th
class=
"text-center"
>
{% trans 'Reason' %}
</th>
<th
class=
"text-center"
>
{% trans 'Status' %}
</th>
<th
class=
"text-center"
>
{% trans 'Date' %}
</th>
</tr>
<thead>
{% 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 'MFA' %}
</th>
<th
class=
"text-center"
>
{% trans 'Reason' %}
</th>
<th
class=
"text-center"
>
{% trans 'Status' %}
</th>
<th
class=
"text-center"
>
{% trans 'Date' %}
</th>
{% endblock %}
<tbody>
{% 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.get_mfa_display }}
</td>
<td
class=
"text-center"
>
{{ login_log.get_reason_display }}
</td>
<td
class=
"text-center"
>
{{ login_log.get_status_display }}
</td>
<td
class=
"text-center"
>
{{ login_log.datetime }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div
id=
"actions"
class=
""
style=
"margin-top: -20px"
>
<div
class=
"input-group"
>
<select
class=
"form-control m-b"
style=
"width: auto"
id=
"slct_bulk_update"
>
<option
value=
"export"
>
{% trans 'Export login log' %}
</option>
</select>
<div
class=
"input-group-btn pull-left"
style=
"padding-left: 5px;"
>
<button
id=
'btn_bulk_update'
style=
"height: 32px;"
class=
"btn btn-sm btn-primary btn_export"
>
{% trans 'Submit' %}
</button>
</div>
</div>
</div>
{% 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.get_mfa_display }}
</td>
<td
class=
"text-center"
>
{{ login_log.get_reason_display }}
</td>
<td
class=
"text-center"
>
{{ login_log.get_status_display }}
</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>
...
...
@@ -95,6 +114,29 @@
width
:
'auto'
});
})
.
on
(
'click'
,
'.btn_export'
,
function
()
{
var
date_form
=
$
(
'#id_date_from'
).
val
();
var
date_to
=
$
(
'#id_date_to'
).
val
();
var
user
=
$
(
'.select2 option:selected'
).
val
();
var
keyword
=
$
(
'#search'
).
val
();
$
.
ajax
({
url
:
"{% url "
audits
:
login
-
log
-
export
" %}"
,
method
:
'POST'
,
data
:
JSON
.
stringify
({
'date_form'
:
date_form
,
'date_to'
:
date_to
,
'user'
:
user
,
'keyword'
:
keyword
}),
dataType
:
"json"
,
success
:
function
(
data
,
textStatus
)
{
window
.
open
(
data
.
redirect
)
},
error
:
function
()
{
toastr
.
error
(
'Export failed'
);
}
})
})
</script>
{% endblock %}
This diff is collapsed.
Click to expand it.
apps/audits/urls/view_urls.py
View file @
9aae1069
...
...
@@ -14,4 +14,5 @@ urlpatterns = [
path
(
'operate-log/'
,
views
.
OperateLogListView
.
as_view
(),
name
=
'operate-log-list'
),
path
(
'password-change-log/'
,
views
.
PasswordChangeLogList
.
as_view
(),
name
=
'password-change-log-list'
),
path
(
'command-execution-log/'
,
views
.
CommandExecutionListView
.
as_view
(),
name
=
'command-execution-log-list'
),
path
(
'login-log/export/'
,
views
.
LoginLogExportView
.
as_view
(),
name
=
'login-log-export'
),
]
This diff is collapsed.
Click to expand it.
apps/audits/utils.py
0 → 100644
View file @
9aae1069
import
csv
import
codecs
from
django.http
import
HttpResponse
def
get_excel_response
(
filename
):
excel_response
=
HttpResponse
(
content_type
=
'text/csv'
)
excel_response
[
'Content-Disposition'
]
=
'attachment; filename="
%
s"'
%
filename
excel_response
.
write
(
codecs
.
BOM_UTF8
)
return
excel_response
def
write_content_to_excel
(
response
,
header
=
None
,
login_logs
=
None
,
fields
=
None
):
writer
=
csv
.
writer
(
response
,
dialect
=
'excel'
,
quoting
=
csv
.
QUOTE_MINIMAL
)
if
header
:
writer
.
writerow
(
header
)
if
login_logs
:
for
log
in
login_logs
:
data
=
[
getattr
(
log
,
field
.
name
)
for
field
in
fields
]
writer
.
writerow
(
data
)
return
response
\ No newline at end of file
This diff is collapsed.
Click to expand it.
apps/audits/views.py
View file @
9aae1069
import
csv
import
json
import
uuid
import
codecs
from
django.conf
import
settings
from
django.urls
import
reverse
from
django.utils
import
timezone
from
django.core.cache
import
cache
from
django.http
import
HttpResponse
,
JsonResponse
from
django.utils.decorators
import
method_decorator
from
django.views
import
View
from
django.views.decorators.csrf
import
csrf_exempt
from
django.views.generic
import
ListView
from
django.utils.translation
import
ugettext
as
_
from
django.contrib.auth.mixins
import
LoginRequiredMixin
from
django.db.models
import
Q
from
audits.utils
import
get_excel_response
,
write_content_to_excel
from
common.mixins
import
DatetimeSearchMixin
from
common.permissions
import
AdminUserRequiredMixin
...
...
@@ -232,3 +247,38 @@ class CommandExecutionListView(UserCommandExecutionListView):
}
kwargs
.
update
(
context
)
return
super
()
.
get_context_data
(
**
kwargs
)
@method_decorator
(
csrf_exempt
,
name
=
'dispatch'
)
class
LoginLogExportView
(
LoginRequiredMixin
,
View
):
def
get
(
self
,
request
):
fields
=
[
field
for
field
in
UserLoginLog
.
_meta
.
fields
]
filename
=
'login-logs-{}.csv'
.
format
(
timezone
.
localtime
(
timezone
.
now
())
.
strftime
(
'
%
Y-
%
m-
%
d_
%
H-
%
M-
%
S'
)
)
excel_response
=
get_excel_response
(
filename
)
header
=
[
field
.
verbose_name
for
field
in
fields
]
login_logs
=
cache
.
get
(
request
.
GET
.
get
(
'spm'
,
''
),
[])
response
=
write_content_to_excel
(
excel_response
,
login_logs
=
login_logs
,
header
=
header
,
fields
=
fields
)
return
response
def
post
(
self
,
request
):
try
:
date_form
=
json
.
loads
(
request
.
body
)
.
get
(
'date_form'
,
[])
date_to
=
json
.
loads
(
request
.
body
)
.
get
(
'date_to'
,
[])
user
=
json
.
loads
(
request
.
body
)
.
get
(
'user'
,
[])
keyword
=
json
.
loads
(
request
.
body
)
.
get
(
'keyword'
,
[])
login_logs
=
UserLoginLog
.
get_login_logs
(
date_form
=
date_form
,
date_to
=
date_to
,
user
=
user
,
keyword
=
keyword
)
except
ValueError
:
return
HttpResponse
(
'Json object not valid'
,
status
=
400
)
spm
=
uuid
.
uuid4
()
.
hex
cache
.
set
(
spm
,
login_logs
,
300
)
url
=
reverse
(
'audits:login-log-export'
)
+
'?spm=
%
s'
%
spm
return
JsonResponse
({
'redirect'
:
url
})
\ No newline at end of file
This diff is collapsed.
Click to expand it.
apps/locale/zh/LC_MESSAGES/django.mo
View file @
9aae1069
No preview for this file type
This diff is collapsed.
Click to expand it.
apps/locale/zh/LC_MESSAGES/django.po
View file @
9aae1069
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment