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
e89d3b38
Commit
e89d3b38
authored
Nov 17, 2016
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update asset
parent
6e69c018
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
85 additions
and
130 deletions
+85
-130
api.py
apps/assets/api.py
+8
-3
serializers.py
apps/assets/serializers.py
+15
-2
asset_detail.html
apps/assets/templates/assets/asset_detail.html
+1
-4
asset_group_detail.html
apps/assets/templates/assets/asset_group_detail.html
+0
-0
asset_group_list.html
apps/assets/templates/assets/asset_group_list.html
+47
-52
asset_list.html
apps/assets/templates/assets/asset_list.html
+0
-0
idc_assets.html
apps/assets/templates/assets/idc_assets.html
+1
-1
views.py
apps/assets/views.py
+11
-67
user_list.html
apps/users/templates/users/user_list.html
+2
-1
No files found.
apps/assets/api.py
View file @
e89d3b38
...
@@ -20,9 +20,14 @@ class AssetViewSet(viewsets.ModelViewSet):
...
@@ -20,9 +20,14 @@ class AssetViewSet(viewsets.ModelViewSet):
def
get_queryset
(
self
):
def
get_queryset
(
self
):
queryset
=
super
(
AssetViewSet
,
self
)
.
get_queryset
()
queryset
=
super
(
AssetViewSet
,
self
)
.
get_queryset
()
idc
=
self
.
request
.
query_params
.
get
(
'idc'
,
''
)
idc_id
=
self
.
request
.
query_params
.
get
(
'idc_id'
,
''
)
if
idc
:
asset_group_id
=
self
.
request
.
query_params
.
get
(
'asset_group_id'
,
''
)
queryset
=
queryset
.
filter
(
idc__id
=
idc
)
if
idc_id
:
queryset
=
queryset
.
filter
(
idc__id
=
idc_id
)
if
asset_group_id
:
queryset
=
queryset
.
filter
(
groups__id
=
asset_group_id
)
return
queryset
return
queryset
...
...
apps/assets/serializers.py
View file @
e89d3b38
...
@@ -40,13 +40,26 @@ class SystemUserSerializer(serializers.ModelSerializer):
...
@@ -40,13 +40,26 @@ class SystemUserSerializer(serializers.ModelSerializer):
class
AssetSerializer
(
BulkSerializerMixin
,
serializers
.
ModelSerializer
):
class
AssetSerializer
(
BulkSerializerMixin
,
serializers
.
ModelSerializer
):
system_users
=
SystemUserSerializer
(
many
=
True
,
read_only
=
True
)
# system_users = SystemUserSerializer(many=True, read_only=True)
admin_user
=
AdminUserSerializer
(
many
=
False
,
read_only
=
True
)
# admin_user = AdminUserSerializer(many=False, read_only=True)
hardware
=
serializers
.
SerializerMethodField
()
type_display
=
serializers
.
SerializerMethodField
()
class
Meta
(
object
):
class
Meta
(
object
):
model
=
Asset
model
=
Asset
list_serializer_class
=
BulkListSerializer
list_serializer_class
=
BulkListSerializer
@staticmethod
def
get_hardware
(
obj
):
return
'
%
s
%
s
%
s'
%
(
obj
.
cpu
,
obj
.
memory
,
obj
.
disk
)
@staticmethod
def
get_type_display
(
obj
):
if
obj
.
type
:
return
obj
.
type
.
value
else
:
return
''
class
AssetGrantedSerializer
(
serializers
.
ModelSerializer
):
class
AssetGrantedSerializer
(
serializers
.
ModelSerializer
):
system_users
=
SystemUserSerializer
(
many
=
True
,
read_only
=
True
)
system_users
=
SystemUserSerializer
(
many
=
True
,
read_only
=
True
)
...
...
apps/assets/templates/assets/asset_detail.html
View file @
e89d3b38
...
@@ -19,9 +19,6 @@
...
@@ -19,9 +19,6 @@
<li
class=
"active"
>
<li
class=
"active"
>
<a
href=
""
class=
"text-center"
><i
class=
"fa fa-laptop"
></i>
{% trans 'Asset detail' %}
</a>
<a
href=
""
class=
"text-center"
><i
class=
"fa fa-laptop"
></i>
{% trans 'Asset detail' %}
</a>
</li>
</li>
<li>
<a
href=
""
class=
"text-center"
><i
class=
"fa fa-bar-chart-o"
></i>
{% trans 'Asset login log' %}
</a>
</li>
<li
class=
"pull-right"
>
<li
class=
"pull-right"
>
<a
class=
"btn btn-outline btn-default"
href=
"{% url 'assets:asset-update' pk=asset.id %}"
><i
class=
"fa fa-edit"
></i>
Update
</a>
<a
class=
"btn btn-outline btn-default"
href=
"{% url 'assets:asset-update' pk=asset.id %}"
><i
class=
"fa fa-edit"
></i>
Update
</a>
</li>
</li>
...
@@ -236,7 +233,7 @@
...
@@ -236,7 +233,7 @@
</div>
</div>
<div
class=
"panel panel-warning"
>
<div
class=
"panel panel-warning"
>
<div
class=
"panel-heading"
>
<div
class=
"panel-heading"
>
<i
class=
"fa fa-info-circle"
></i>
{% trans '
Asset group
s' %}
<i
class=
"fa fa-info-circle"
></i>
{% trans '
System user
s' %}
</div>
</div>
<div
class=
"panel-body"
>
<div
class=
"panel-body"
>
<table
class=
"table group_edit"
>
<table
class=
"table group_edit"
>
...
...
apps/assets/templates/assets/asset_group_detail.html
View file @
e89d3b38
This diff is collapsed.
Click to expand it.
apps/assets/templates/assets/asset_group_list.html
View file @
e89d3b38
{% extends '_base_list.html' %}
{% extends '_base_list.html' %}
{% load i18n %}
{% load i18n static %}
{% load common_tags %}
{% block table_search %}
{% block content_left_head %}
<a
href=
"{% url 'assets:asset-group-create' %}"
class=
"btn btn-sm btn-primary "
>
{% trans "Create asset group" %}
</a>
{% endblock %}
{% endblock %}
{% block table_container %}
{% block table_head %}
<div
class=
"uc pull-left m-l-5 m-r-5"
>
<th
class=
"text-center"
>
<a
href=
"{% url "
assets:asset-group-create
"
%}"
class=
"btn btn-sm btn-primary"
>
{% trans "Create asset group" %}
</a>
<input
type=
"checkbox"
id=
"check_all"
onclick=
"checkAll('check_all', 'checked')"
>
</div>
</th>
<table
class=
"table table-striped table-bordered table-hover "
id=
"admin_user_list_table"
>
<th
class=
"text-center"
><a
href=
"{% url 'assets:asset-group-list' %}?sort=name"
>
{% trans 'Name' %}
</a></th>
<thead>
<th
class=
"text-center"
>
{% trans 'Asset num' %}
</th>
<tr>
<th
class=
"text-center"
><a
href=
"{% url 'assets:asset-group-list' %}?sort=date_expired"
>
{% trans 'Comment' %}
</a></th>
<th
class=
"text-center"
>
<th
class=
"text-center"
></th>
<input
type=
"checkbox"
id=
"check_all"
class=
"ipt_check_all"
>
</th>
<th
class=
"text-center"
>
{% trans 'Name' %}
</th>
<th
class=
"text-center"
>
{% trans 'Asset' %}
</th>
<th
class=
"text-center"
>
{% trans 'Comment' %}
</th>
<th
class=
"text-center"
>
{% trans 'Action' %}
</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
{% endblock %}
{% endblock %}
{% block content_bottom_left %}{% endblock %}
{% block table_body %}
{% block custom_foot_js %}
{% for asset_group in asset_group_list %}
<script>
<tr
class=
"gradeX"
>
$
(
document
).
ready
(
function
(){
<td
class=
"text-center"
>
var
options
=
{
<input
type=
"checkbox"
name=
"checked"
value=
"{{ asset_group.id }}"
>
ele
:
$
(
'#admin_user_list_table'
),
</td>
columnDefs
:
[
<td
class=
"text-center"
>
{
targets
:
1
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
<a
href=
"{% url 'assets:asset-group-detail' pk=asset_group.id %}"
>
var
detail_btn
=
'<a href="{% url "assets:asset-group-detail" pk=99991937 %}">'
+
cellData
+
'</a>'
;
{{ asset_group.name }}
$
(
td
).
html
(
detail_btn
.
replace
(
'99991937'
,
rowData
.
id
));
</a>
}},
</td>
{
targets
:
3
,
createdCell
:
function
(
td
,
cellData
)
{
<td
class=
"text-center"
>
{{ asset_group.assets.count }}
</td>
var
innerHtml
=
cellData
.
length
>
30
?
cellData
.
substring
(
0
,
30
)
+
'...'
:
cellData
;
<td
class=
"text-center"
>
{{ asset_group.comment|truncatewords:8 }}
</td>
$
(
td
).
html
(
'<a href="javascript:void(0);" data-toggle="tooltip" title="'
+
cellData
+
'">'
+
innerHtml
+
'</a>'
);
<td
class=
"text-center"
>
}},
<a
href=
"{% url 'assets:asset-group-update' pk=asset_group.id %}"
class=
"btn btn-xs btn-info"
>
{% trans 'Update' %}
</a>
{
targets
:
4
,
createdCell
:
function
(
td
,
cellData
,
rowData
)
{
<a
onclick=
"objectDelete(this,'{{ asset_group.name }}','{% url 'assets:asset-group-delete' asset_group.id %}')"
class=
"btn btn-xs btn-danger del"
>
{% trans 'Delete' %}
</a>
var
update_btn
=
'<a href="{% url "assets:asset-group-update" pk=99991937 %}" class="btn btn-xs m-l-xs btn-info">{% trans "Update" %}</a>'
.
replace
(
'99991937'
,
cellData
);
</td>
var
del_btn
=
'<a class="btn btn-xs btn-danger m-l-xs btn_asset_group_delete" data-uid="99991937">{% trans "Delete" %}</a>'
.
replace
(
'99991937'
,
cellData
);
</tr>
$
(
td
).
html
(
update_btn
+
del_btn
)
{% endfor %}
}}],
ajax_url
:
'{% url "api-assets:asset-group-list" %}'
,
columns
:
[{
data
:
"id"
},
{
data
:
"name"
},
{
data
:
"assets_amount"
},
{
data
:
"comment"
},
{
data
:
"id"
}]
};
jumpserver
.
initDataTable
(
options
);
});
</script>
{% endblock %}
{% endblock %}
{% block content_bottom_left %}
<form
id=
""
method=
"get"
action=
""
class=
" mail-search"
>
<div
class=
"input-group"
>
<select
class=
"form-control m-b"
style=
"width: auto"
>
<option>
{% trans 'Delete selected' %}
</option>
<option>
{% trans 'Update selected' %}
</option>
<option>
{% trans 'Deactive selected' %}
</option>
<option>
{% trans 'Export selected' %}
</option>
</select>
<div
class=
"input-group-btn pull-left"
style=
"padding-left: 5px;"
>
<button
id=
'search_btn'
type=
"submit"
style=
"height: 32px;"
class=
"btn btn-sm btn-primary"
>
{% trans 'Submit' %}
</button>
</div>
</div>
</form>
{% endblock %}
apps/assets/templates/assets/asset_list.html
View file @
e89d3b38
This diff is collapsed.
Click to expand it.
apps/assets/templates/assets/idc_assets.html
View file @
e89d3b38
...
@@ -118,7 +118,7 @@
...
@@ -118,7 +118,7 @@
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
$
(
td
).
html
(
'<i class="fa fa-check text-navy"></i>'
)
}
}
}}],
}}],
ajax_url
:
'{% url "api-assets:asset-list" %}?idc={{ idc.id }}'
,
ajax_url
:
'{% url "api-assets:asset-list" %}?idc
_id
={{ idc.id }}'
,
columns
:
[{
data
:
function
(){
return
""
}},
{
data
:
"hostname"
},
{
data
:
"ip"
},
{
data
:
"port"
},
columns
:
[{
data
:
function
(){
return
""
}},
{
data
:
"hostname"
},
{
data
:
"ip"
},
{
data
:
"port"
},
{
data
:
"type"
},
{
data
:
"is_active"
}]
{
data
:
"type"
},
{
data
:
"is_active"
}]
};
};
...
...
apps/assets/views.py
View file @
e89d3b38
...
@@ -16,23 +16,9 @@ from .forms import *
...
@@ -16,23 +16,9 @@ from .forms import *
from
.hands
import
AdminUserRequiredMixin
from
.hands
import
AdminUserRequiredMixin
class
AssetListView
(
AdminUserRequiredMixin
,
ListView
):
class
AssetListView
(
AdminUserRequiredMixin
,
TemplateView
):
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
model
=
Asset
context_object_name
=
'asset_list'
template_name
=
'assets/asset_list.html'
template_name
=
'assets/asset_list.html'
def
get_queryset
(
self
):
queryset
=
super
(
AssetListView
,
self
)
.
get_queryset
()
queryset
=
sorted
(
queryset
,
key
=
self
.
sorted_by_valid_and_ip
)
return
queryset
@staticmethod
def
sorted_by_valid_and_ip
(
asset
):
ip_list
=
int_seq
(
asset
.
ip
.
split
(
'.'
))
ip_list
.
insert
(
0
,
asset
.
is_valid
[
0
])
return
ip_list
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
context
=
{
'app'
:
'Assets'
,
'app'
:
'Assets'
,
...
@@ -73,7 +59,6 @@ class AssetCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, CreateView):
...
@@ -73,7 +59,6 @@ class AssetCreateView(AdminUserRequiredMixin, CreateAssetTagsMiXin, CreateView):
class
AssetModalCreateView
(
AdminUserRequiredMixin
,
CreateAssetTagsMiXin
,
ListView
):
class
AssetModalCreateView
(
AdminUserRequiredMixin
,
CreateAssetTagsMiXin
,
ListView
):
model
=
Asset
model
=
Asset
# tag_type = 'asset'
form_class
=
AssetCreateForm
form_class
=
AssetCreateForm
template_name
=
'assets/asset_modal_update.html'
template_name
=
'assets/asset_modal_update.html'
success_url
=
reverse_lazy
(
'assets:asset-list'
)
success_url
=
reverse_lazy
(
'assets:asset-list'
)
...
@@ -119,16 +104,10 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateAssetTagsMiXin, UpdateView):
...
@@ -119,16 +104,10 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateAssetTagsMiXin, UpdateView):
'admin_user'
,
'admin_user'
,
]
]
self
.
assets_ids
=
self
.
request
.
POST
.
getlist
(
'assets_ids'
)
self
.
assets_ids
=
self
.
request
.
POST
.
getlist
(
'assets_ids'
)
print
self
.
assets_ids
self
.
new_form
=
self
.
request
.
POST
.
copy
()
self
.
new_form
=
self
.
request
.
POST
.
copy
()
print
len
(
self
.
new_form
)
print
type
(
self
.
new_form
)
for
i
in
default_keys
:
for
i
in
default_keys
:
if
self
.
new_form
.
has_key
(
i
):
if
self
.
new_form
.
has_key
(
i
):
self
.
new_form
.
pop
(
i
)
self
.
new_form
.
pop
(
i
)
print
self
.
new_form
.
items
()
for
i
in
self
.
new_form
:
print
i
return
super
(
AssetUpdateView
,
self
)
.
post
(
request
,
*
args
,
**
kwargs
)
return
super
(
AssetUpdateView
,
self
)
.
post
(
request
,
*
args
,
**
kwargs
)
...
@@ -145,10 +124,7 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateAssetTagsMiXin, UpdateView):
...
@@ -145,10 +124,7 @@ class AssetUpdateView(AdminUserRequiredMixin, UpdateAssetTagsMiXin, UpdateView):
return
super
(
AssetUpdateView
,
self
)
.
form_invalid
(
form
)
return
super
(
AssetUpdateView
,
self
)
.
form_invalid
(
form
)
def
form_valid
(
self
,
form
):
def
form_valid
(
self
,
form
):
print
self
.
new_form
.
keys
()
print
form
.
clean
()
.
keys
()
asset
=
form
.
save
(
commit
=
False
)
asset
=
form
.
save
(
commit
=
False
)
print
"1111"
def
prn_obj_key
(
obj_form
):
def
prn_obj_key
(
obj_form
):
return
obj_form
.
clean
()
.
keys
()
return
obj_form
.
clean
()
.
keys
()
...
@@ -264,12 +240,8 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
...
@@ -264,12 +240,8 @@ class AssetGroupCreateView(AdminUserRequiredMixin, CreateView):
return
super
(
AssetGroupCreateView
,
self
)
.
form_valid
(
form
)
return
super
(
AssetGroupCreateView
,
self
)
.
form_valid
(
form
)
class
AssetGroupListView
(
AdminUserRequiredMixin
,
ListView
):
class
AssetGroupListView
(
AdminUserRequiredMixin
,
TemplateView
):
model
=
AssetGroup
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
context_object_name
=
'asset_group_list'
template_name
=
'assets/asset_group_list.html'
template_name
=
'assets/asset_group_list.html'
ordering
=
'-id'
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
{
context
=
{
...
@@ -280,34 +252,22 @@ class AssetGroupListView(AdminUserRequiredMixin, ListView):
...
@@ -280,34 +252,22 @@ class AssetGroupListView(AdminUserRequiredMixin, ListView):
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
return
super
(
AssetGroupListView
,
self
)
.
get_context_data
(
**
kwargs
)
return
super
(
AssetGroupListView
,
self
)
.
get_context_data
(
**
kwargs
)
def
get_queryset
(
self
):
self
.
queryset
=
super
(
AssetGroupListView
,
self
)
.
get_queryset
()
self
.
keyword
=
keyword
=
self
.
request
.
GET
.
get
(
'keyword'
,
''
)
self
.
sort
=
sort
=
self
.
request
.
GET
.
get
(
'sort'
,
'-date_created'
)
if
keyword
:
self
.
queryset
=
self
.
queryset
.
filter
(
Q
(
name__icontains
=
keyword
)
|
Q
(
comment__icontains
=
keyword
))
if
sort
:
self
.
queryset
=
self
.
queryset
.
order_by
(
sort
)
return
self
.
queryset
class
AssetGroupDetailView
(
SingleObjectMixin
,
AdminUserRequiredMixin
,
ListView
):
class
AssetGroupDetailView
(
AdminUserRequiredMixin
,
DetailView
):
model
=
AssetGroup
template_name
=
'assets/asset_group_detail.html'
template_name
=
'assets/asset_group_detail.html'
paginate_by
=
settings
.
CONFIG
.
DISPLAY_PER_PAGE
context_object_name
=
'asset_group'
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
(
queryset
=
AssetGroup
.
objects
.
all
())
return
super
(
AssetGroupDetailView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_queryset
(
self
):
return
self
.
object
.
assets
.
all
()
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
assets_remain
=
Asset
.
objects
.
exclude
(
id__in
=
self
.
object
.
assets
.
all
())
system_users
=
self
.
object
.
system_users
.
all
()
system_users_remain
=
SystemUser
.
objects
.
exclude
(
id__in
=
system_users
)
context
=
{
context
=
{
'app'
:
_
(
'Assets'
),
'app'
:
_
(
'Assets'
),
'action'
:
_
(
'Asset group detail'
),
'action'
:
_
(
'Asset group detail'
),
'asset_group'
:
self
.
object
,
'assets_remain'
:
assets_remain
,
'system_users'
:
system_users
,
'system_users_remain'
:
system_users_remain
,
}
}
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
return
super
(
AssetGroupDetailView
,
self
)
.
get_context_data
(
**
kwargs
)
return
super
(
AssetGroupDetailView
,
self
)
.
get_context_data
(
**
kwargs
)
...
@@ -343,9 +303,6 @@ class AssetGroupDeleteView(AdminUserRequiredMixin, DeleteView):
...
@@ -343,9 +303,6 @@ class AssetGroupDeleteView(AdminUserRequiredMixin, DeleteView):
class
IDCListView
(
AdminUserRequiredMixin
,
TemplateView
):
class
IDCListView
(
AdminUserRequiredMixin
,
TemplateView
):
# model = IDC
# paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
# context_object_name = 'idc_list'
template_name
=
'assets/idc_list.html'
template_name
=
'assets/idc_list.html'
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
...
@@ -357,19 +314,6 @@ class IDCListView(AdminUserRequiredMixin, TemplateView):
...
@@ -357,19 +314,6 @@ class IDCListView(AdminUserRequiredMixin, TemplateView):
kwargs
.
update
(
context
)
kwargs
.
update
(
context
)
return
super
(
IDCListView
,
self
)
.
get_context_data
(
**
kwargs
)
return
super
(
IDCListView
,
self
)
.
get_context_data
(
**
kwargs
)
# def get_queryset(self):
# self.queryset = super(IDCListView, self).get_queryset()
# self.keyword = keyword = self.request.GET.get('keyword', '')
# self.sort = sort = self.request.GET.get('sort', '-date_created')
#
# if keyword:
# self.queryset = self.queryset.filter(Q(name__icontains=keyword) |
# Q(comment__icontains=keyword))
#
# if sort:
# self.queryset = self.queryset.order_by(sort)
# return self.queryset
class
IDCCreateView
(
AdminUserRequiredMixin
,
CreateView
):
class
IDCCreateView
(
AdminUserRequiredMixin
,
CreateView
):
model
=
IDC
model
=
IDC
...
...
apps/users/templates/users/user_list.html
View file @
e89d3b38
...
@@ -83,7 +83,8 @@ $(document).ready(function(){
...
@@ -83,7 +83,8 @@ $(document).ready(function(){
}}],
}}],
ajax_url
:
'{% url "api-users:user-list" %}'
,
ajax_url
:
'{% url "api-users:user-list" %}'
,
columns
:
[{
data
:
"id"
},
{
data
:
"username"
},
{
data
:
"name"
},
{
data
:
"get_role_display"
},
columns
:
[{
data
:
"id"
},
{
data
:
"username"
},
{
data
:
"name"
},
{
data
:
"get_role_display"
},
{
data
:
"groups_display"
},
{
data
:
"is_valid"
},
{
data
:
"id"
}]
{
data
:
"groups_display"
},
{
data
:
"is_valid"
},
{
data
:
"id"
}],
op_html
:
$
(
'#actions'
).
html
()
};
};
var
table
=
jumpserver
.
initDataTable
(
options
);
var
table
=
jumpserver
.
initDataTable
(
options
);
...
...
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