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
41337d28
Commit
41337d28
authored
Nov 04, 2016
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add proxy log search
parent
1d29c52a
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
167 additions
and
22 deletions
+167
-22
hands.py
apps/audits/hands.py
+2
-0
models.py
apps/audits/models.py
+1
-1
serializers.py
apps/audits/serializers.py
+3
-2
command_log_list.html
apps/audits/templates/audits/command_log_list.html
+39
-2
proxy_log_list.html
apps/audits/templates/audits/proxy_log_list.html
+63
-6
views.py
apps/audits/views.py
+51
-7
asset_permission_create_update.html
...perms/templates/perms/asset_permission_create_update.html
+1
-1
bootstrap-datepicker.js
apps/static/js/plugins/datepicker/bootstrap-datepicker.js
+0
-0
_base_list.html
apps/templates/_base_list.html
+5
-1
terminal_update.html
apps/terminal/templates/terminal/terminal_update.html
+1
-1
_user.html
apps/users/templates/users/_user.html
+1
-1
No files found.
apps/audits/hands.py
View file @
41337d28
# ~*~ coding: utf-8 ~*~
# ~*~ coding: utf-8 ~*~
#
#
from
users.models
import
User
from
assets.models
import
Asset
,
SystemUser
from
users.backends
import
IsSuperUserOrTerminalUser
from
users.backends
import
IsSuperUserOrTerminalUser
from
terminal.models
import
Terminal
from
terminal.models
import
Terminal
apps/audits/models.py
View file @
41337d28
...
@@ -71,7 +71,7 @@ class ProxyLog(models.Model):
...
@@ -71,7 +71,7 @@ class ProxyLog(models.Model):
class
CommandLog
(
models
.
Model
):
class
CommandLog
(
models
.
Model
):
proxy_log
=
models
.
ForeignKey
(
ProxyLog
,
on_delete
=
models
.
CASCADE
,
related_name
=
'command
_log
'
)
proxy_log
=
models
.
ForeignKey
(
ProxyLog
,
on_delete
=
models
.
CASCADE
,
related_name
=
'command
s
'
)
command_no
=
models
.
IntegerField
()
command_no
=
models
.
IntegerField
()
command
=
models
.
CharField
(
max_length
=
1000
,
blank
=
True
)
command
=
models
.
CharField
(
max_length
=
1000
,
blank
=
True
)
output
=
models
.
TextField
(
blank
=
True
)
output
=
models
.
TextField
(
blank
=
True
)
...
...
apps/audits/serializers.py
View file @
41337d28
...
@@ -14,7 +14,8 @@ class ProxyLogSerializer(serializers.ModelSerializer):
...
@@ -14,7 +14,8 @@ class ProxyLogSerializer(serializers.ModelSerializer):
class
Meta
:
class
Meta
:
model
=
models
.
ProxyLog
model
=
models
.
ProxyLog
fields
=
[
'id'
,
'name'
,
'username'
,
'hostname'
,
'ip'
,
'system_user'
,
'login_type'
,
'terminal'
,
fields
=
[
'id'
,
'name'
,
'username'
,
'hostname'
,
'ip'
,
'system_user'
,
'login_type'
,
'terminal'
,
'log_file'
,
'was_failed'
,
'is_finished'
,
'date_start'
,
'time'
,
'command_length'
,
"commands_dict"
]
'log_file'
,
'was_failed'
,
'is_finished'
,
'date_start'
,
'date_finished'
,
'time'
,
'command_length'
,
"commands_dict"
]
@staticmethod
@staticmethod
def
get_time
(
obj
):
def
get_time
(
obj
):
...
@@ -25,7 +26,7 @@ class ProxyLogSerializer(serializers.ModelSerializer):
...
@@ -25,7 +26,7 @@ class ProxyLogSerializer(serializers.ModelSerializer):
@staticmethod
@staticmethod
def
get_command_length
(
obj
):
def
get_command_length
(
obj
):
return
len
(
obj
.
command
_log
.
all
())
return
len
(
obj
.
command
s
.
all
())
class
CommandLogSerializer
(
serializers
.
ModelSerializer
):
class
CommandLogSerializer
(
serializers
.
ModelSerializer
):
...
...
apps/audits/templates/audits/command_log_list.html
View file @
41337d28
...
@@ -3,10 +3,44 @@
...
@@ -3,10 +3,44 @@
{% load static %}
{% load static %}
{% load common_tags %}
{% load common_tags %}
{% block content_left_head %}
{% block content_left_head %}
{#
<a
href=
"{% url 'perms:asset-permission-create' %}"
class=
"btn btn-sm btn-primary "
>
{% trans "Create permission" %}
</a>
#}
<link
href=
"{% static "
css
/
plugins
/
footable
/
footable
.
core
.
css
"
%}"
rel=
"stylesheet"
>
<link
href=
"{% static "
css
/
plugins
/
footable
/
footable
.
core
.
css
"
%}"
rel=
"stylesheet"
>
<style>
#search_btn
{
margin-bottom
:
0
;
}
</style>
{% endblock %}
{% endblock %}
{% block table_search %}
<form
id=
"search_form"
method=
"get"
action=
""
class=
"pull-right form-inline"
>
<div
class=
"input-group"
>
<select
class=
"select2 form-control"
name=
"user"
>
<option>
{% trans 'Select user' %}
</option>
{% for user in user_list %}
<option
value=
"{{ user.username }}"
>
{{ user.username }}
</option>
{% endfor %}
</select>
</div>
<div
class=
"input-group"
>
<select
class=
"select2 form-control"
name=
"asset"
>
<option>
{% trans 'Select asset' %}
</option>
{% for asset in asset_list %}
<option
value=
"{{ asset.ip }}"
>
{{ asset.ip }}
</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_container %}
{% block table_container %}
<table
class=
"footable table table-stripped toggle-arrow-tiny"
data-page=
"false"
>
<table
class=
"footable table table-stripped toggle-arrow-tiny"
data-page=
"false"
>
<thead>
<thead>
...
@@ -16,6 +50,7 @@
...
@@ -16,6 +50,7 @@
<th>
Username
</th>
<th>
Username
</th>
<th>
IP
</th>
<th>
IP
</th>
<th>
System user
</th>
<th>
System user
</th>
<th>
Proxy log
</th>
<th>
Datetime
</th>
<th>
Datetime
</th>
<th
data-hide=
"all"
>
Output
</th>
<th
data-hide=
"all"
>
Output
</th>
</tr>
</tr>
...
@@ -23,11 +58,12 @@
...
@@ -23,11 +58,12 @@
<tbody>
<tbody>
{% for command in command_list %}
{% for command in command_list %}
<tr>
<tr>
<td>
{{ command.
command_no
}}
</td>
<td>
{{ command.
id
}}
</td>
<td>
{{ command.command }}
</td>
<td>
{{ command.command }}
</td>
<td>
{{ command.proxy_log.username }}
</td>
<td>
{{ command.proxy_log.username }}
</td>
<td>
{{ command.proxy_log.ip }}
</td>
<td>
{{ command.proxy_log.ip }}
</td>
<td>
{{ command.proxy_log.system_user }}
</td>
<td>
{{ command.proxy_log.system_user }}
</td>
<td><a
href=
"{% url 'audits:proxy-log-detail' pk=command.proxy_log.id %}"
>
{{ command.proxy_log.id}}
</a></td>
<td>
{{ command.datetime }}
</td>
<td>
{{ command.datetime }}
</td>
<td>
{{ command.output_decode |safe }}
</td>
<td>
{{ command.output_decode |safe }}
</td>
</tr>
</tr>
...
@@ -41,6 +77,7 @@
...
@@ -41,6 +77,7 @@
<script>
<script>
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
$
(
'.footable'
).
footable
();
$
(
'.footable'
).
footable
();
$
(
'.select2'
).
select2
();
});
});
</script>
</script>
{% endblock %}
{% endblock %}
...
...
apps/audits/templates/audits/proxy_log_list.html
View file @
41337d28
{% extends '_base_list.html' %}
{% extends '_base_list.html' %}
{% load i18n %}
{% load i18n %}
{% load static %}
{% load common_tags %}
{% 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 user in user_list %}
<option
value=
"{{ user.username }}"
>
{{ user.username }}
</option>
{% endfor %}
</select>
</div>
<div
class=
"input-group"
>
<select
class=
"select2 form-control"
name=
"ip"
>
<option
value=
""
>
{% trans 'Select asset' %}
</option>
{% for asset in asset_list %}
<option
value=
"{{ asset.ip }}"
>
{{ asset.ip }}
</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 %}
{% block table_head %}
<th
class=
"text-center"
>
{% trans 'ID' %}
</th>
<th
class=
"text-center"
>
{% trans 'ID' %}
</th>
...
@@ -22,8 +71,8 @@
...
@@ -22,8 +71,8 @@
</td>
</td>
<td
class=
"text-center"
>
{{ proxy_log.username }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.username }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.ip }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.ip }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.system_user
.name
}}
</td>
<td
class=
"text-center"
>
{{ proxy_log.system_user }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.command
.count
}}
</td>
<td
class=
"text-center"
>
{{ proxy_log.command
s.all|length
}}
</td>
<td
class=
"text-center"
>
<td
class=
"text-center"
>
{% if proxy_log.was_failed %}
{% if proxy_log.was_failed %}
<i
class=
"fa fa-times text-danger"
></i>
<i
class=
"fa fa-times text-danger"
></i>
...
@@ -33,25 +82,33 @@
...
@@ -33,25 +82,33 @@
</td>
</td>
<td
class=
"text-center"
>
<td
class=
"text-center"
>
{% if proxy_log.is_finished %}
{% if proxy_log.is_finished %}
<i
class=
"fa fa-times text-danger"
></i>
{% else %}
<i
class=
"fa fa-check text-navy"
></i>
<i
class=
"fa fa-check text-navy"
></i>
{% else %}
<i
class=
"fa fa-times text-danger"
></i>
{% endif %}
{% endif %}
</td>
</td>
<td
class=
"text-center"
>
{{ proxy_log.date_start }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.date_start }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.date_finished }}
</td>
<td
class=
"text-center"
>
{{ proxy_log.date_finished
|timeuntil:proxy_log.date_start
}}
</td>
</tr>
</tr>
{% endfor %}
{% endfor %}
{% endblock %}
{% endblock %}
{% block custom_foot_js %}
{% block custom_foot_js %}
<script
src=
"{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"
></script>
<script>
<script>
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
$
(
'table'
).
DataTable
({
$
(
'table'
).
DataTable
({
"searching"
:
false
,
"searching"
:
false
,
"paging"
:
false
,
"paging"
:
false
,
"order"
:
[]
"order"
:
[]
})
});
$
(
'.select2'
).
select2
();
$
(
'#date .input-daterange'
).
datepicker
({
dateFormat
:
'mm/dd/yy'
,
keyboardNavigation
:
false
,
forceParse
:
false
,
autoclose
:
true
});
})
})
</script>
</script>
{% endblock %}
{% endblock %}
...
...
apps/audits/views.py
View file @
41337d28
# ~*~ coding: utf-8 ~*~
# ~*~ coding: utf-8 ~*~
#
#
import
datetime
from
django.views.generic
import
ListView
,
UpdateView
,
DeleteView
,
DetailView
,
TemplateView
from
django.views.generic
import
ListView
,
UpdateView
,
DeleteView
,
DetailView
,
TemplateView
from
django.views.generic.edit
import
SingleObjectMixin
from
django.views.generic.edit
import
SingleObjectMixin
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
django.utils
import
timezone
from
django.urls
import
reverse_lazy
from
django.urls
import
reverse_lazy
from
django.conf
import
settings
from
django.conf
import
settings
from
django.db.models
import
Q
from
.models
import
ProxyLog
,
CommandLog
from
.models
import
ProxyLog
,
CommandLog
from
.utils
import
AdminUserRequiredMixin
from
.utils
import
AdminUserRequiredMixin
from
.hands
import
User
,
Asset
,
SystemUser
class
ProxyLogListView
(
ListView
):
class
ProxyLogListView
(
AdminUserRequiredMixin
,
ListView
):
model
=
ProxyLog
model
=
ProxyLog
template_name
=
'audits/proxy_log_list.html'
template_name
=
'audits/proxy_log_list.html'
context_object_name
=
'proxy_log_list'
context_object_name
=
'proxy_log_list'
def
get_queryset
(
self
):
self
.
queryset
=
super
(
ProxyLogListView
,
self
)
.
get_queryset
()
self
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
username
=
username
=
self
.
request
.
GET
.
get
(
'username'
,
''
)
self
.
ip
=
ip
=
self
.
request
.
GET
.
get
(
'ip'
,
''
)
self
.
date_from_s
=
date_from_s
=
\
self
.
request
.
GET
.
get
(
'date_from'
,
'
%
s'
%
(
datetime
.
datetime
.
now
()
-
datetime
.
timedelta
(
7
))
.
strftime
(
'
%
m/
%
d/
%
Y'
))
self
.
date_to_s
=
date_to_s
=
self
.
request
.
GET
.
get
(
'date_to'
,
'
%
s'
%
datetime
.
datetime
.
now
()
.
strftime
(
'
%
m/
%
d/
%
Y'
))
if
date_from_s
:
date_from
=
timezone
.
datetime
.
strptime
(
date_from_s
,
'
%
m/
%
d/
%
Y'
)
self
.
queryset
=
self
.
queryset
.
filter
(
date_start__gt
=
date_from
)
if
date_to_s
:
date_to
=
timezone
.
datetime
.
strptime
(
date_to_s
+
' 23:59:59'
,
'
%
m/
%
d/
%
Y
%
H:
%
M:
%
S'
)
self
.
queryset
=
self
.
queryset
.
filter
(
date_start__lt
=
date_to
)
if
username
:
self
.
queryset
=
self
.
queryset
.
filter
(
username
=
username
)
if
ip
:
self
.
queryset
=
self
.
queryset
.
filter
(
ip
=
ip
)
if
keyword
:
self
.
queryset
=
self
.
queryset
.
filter
(
Q
(
username__contains
=
keyword
)
|
Q
(
name__icontains
=
keyword
)
|
Q
(
hostname__icontains
=
keyword
)
|
Q
(
ip__icontains
=
keyword
)
|
Q
(
system_user__icontains
=
keyword
))
.
distinct
()
return
self
.
queryset
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
ProxyLogListView
,
self
)
.
get_context_data
(
**
kwargs
)
context
=
{
context
.
update
({
'app'
:
_
(
'Audits'
),
'action'
:
_
(
'Proxy log list'
)})
'app'
:
_
(
'Audits'
),
return
context
'action'
:
_
(
'Proxy log list'
),
'user_list'
:
User
.
objects
.
all
(),
'asset_list'
:
Asset
.
objects
.
all
(),
'system_user_list'
:
SystemUser
.
objects
.
all
(),
'keyword'
:
self
.
keyword
,
'date_from'
:
self
.
date_from_s
,
'date_to'
:
self
.
date_to_s
,
}
kwargs
.
update
(
context
)
return
super
(
ProxyLogListView
,
self
)
.
get_context_data
(
**
kwargs
)
class
ProxyLogDetailView
(
AdminUserRequiredMixin
,
SingleObjectMixin
,
ListView
):
class
ProxyLogDetailView
(
AdminUserRequiredMixin
,
SingleObjectMixin
,
ListView
):
...
@@ -31,7 +72,7 @@ class ProxyLogDetailView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
...
@@ -31,7 +72,7 @@ class ProxyLogDetailView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
return
super
(
ProxyLogDetailView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
return
super
(
ProxyLogDetailView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_queryset
(
self
):
def
get_queryset
(
self
):
return
list
(
self
.
object
.
command
_log
.
all
())
return
list
(
self
.
object
.
command
s
.
all
())
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
context
=
{
...
@@ -74,8 +115,11 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
...
@@ -74,8 +115,11 @@ class CommandLogListView(AdminUserRequiredMixin, ListView):
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
context
=
{
'app'
:
'Audits'
,
'app'
:
_
(
'Audits'
),
'action'
:
'Command log list'
'action'
:
_
(
'Command log list'
),
'user_list'
:
User
.
objects
.
all
(),
'asset_list'
:
Asset
.
objects
.
all
(),
'system_user_list'
:
SystemUser
.
objects
.
all
(),
}
}
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
return
super
(
CommandLogListView
,
self
)
.
get_context_data
(
**
kwargs
)
return
super
(
CommandLogListView
,
self
)
.
get_context_data
(
**
kwargs
)
apps/perms/templates/perms/asset_permission_create_update.html
View file @
41337d28
...
@@ -76,7 +76,7 @@
...
@@ -76,7 +76,7 @@
</div>
</div>
{% endblock %}
{% endblock %}
{% block custom_foot_js %}
{% block custom_foot_js %}
<script
src=
"{% static 'js/plugins/dat
a
picker/bootstrap-datepicker.js' %}"
></script>
<script
src=
"{% static 'js/plugins/dat
e
picker/bootstrap-datepicker.js' %}"
></script>
<script>
<script>
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
$
(
'.select2'
).
select2
();
$
(
'.select2'
).
select2
();
...
...
apps/static/js/plugins/dat
a
picker/bootstrap-datepicker.js
→
apps/static/js/plugins/dat
e
picker/bootstrap-datepicker.js
View file @
41337d28
File moved
apps/templates/_base_list.html
View file @
41337d28
...
@@ -33,15 +33,19 @@
...
@@ -33,15 +33,19 @@
<div
class=
""
id=
"content_start"
>
<div
class=
""
id=
"content_start"
>
{% block content_left_head %} {% endblock %}
{% block content_left_head %} {% endblock %}
{% block table_search %}
{% block table_search %}
<form
id=
"search_form"
method=
"get"
action=
""
class=
"pull-right mail-search"
>
<form
id=
"search_form"
method=
"get"
action=
""
class=
"pull-right mail-search form-inline"
>
{% block search_form %}
<div
class=
"input-group"
>
<div
class=
"input-group"
>
<input
type=
"text"
class=
"form-control input-sm"
name=
"keyword"
placeholder=
"Search"
value=
"{{ keyword }}"
>
<input
type=
"text"
class=
"form-control input-sm"
name=
"keyword"
placeholder=
"Search"
value=
"{{ keyword }}"
>
</div>
<div
class=
"input-group"
>
<div
class=
"input-group-btn"
>
<div
class=
"input-group-btn"
>
<button
id=
'search_btn'
type=
"submit"
class=
"btn btn-sm btn-primary"
>
<button
id=
'search_btn'
type=
"submit"
class=
"btn btn-sm btn-primary"
>
搜索
搜索
</button>
</button>
</div>
</div>
</div>
</div>
{% endblock %}
</form>
</form>
{% endblock %}
{% endblock %}
{% block tags_list %}{% endblock %}
{% block tags_list %}{% endblock %}
...
...
apps/terminal/templates/terminal/terminal_update.html
View file @
41337d28
...
@@ -60,7 +60,7 @@
...
@@ -60,7 +60,7 @@
</div>
</div>
{% endblock %}
{% endblock %}
{% block custom_foot_js %}
{% block custom_foot_js %}
<script
src=
"{% static 'js/plugins/dat
a
picker/bootstrap-datepicker.js' %}"
></script>
<script
src=
"{% static 'js/plugins/dat
e
picker/bootstrap-datepicker.js' %}"
></script>
<script>
<script>
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
$
(
'.select2'
).
select2
();
$
(
'.select2'
).
select2
();
...
...
apps/users/templates/users/_user.html
View file @
41337d28
...
@@ -79,7 +79,7 @@
...
@@ -79,7 +79,7 @@
</div>
</div>
{% endblock %}
{% endblock %}
{% block custom_foot_js %}
{% block custom_foot_js %}
<script
src=
"{% static 'js/plugins/dat
a
picker/bootstrap-datepicker.js' %}"
></script>
<script
src=
"{% static 'js/plugins/dat
e
picker/bootstrap-datepicker.js' %}"
></script>
<script>
<script>
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
$
(
'.select2'
).
select2
();
$
(
'.select2'
).
select2
();
...
...
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