Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Gelencsér Szabolcs
/
cloud
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
A prog2-höz tartozó friss repo anyagok itt elérhetőek:
https://git.iit.bme.hu/
Commit
7fed7d2c
authored
Jan 01, 2015
by
Bach Dániel
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature-remove-garbage'
parents
32e83265
f876f926
Hide whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
477 additions
and
1369 deletions
+477
-1369
circle/circle/settings/base.py
+1
-0
circle/common/operations.py
+2
-0
circle/dashboard/forms.py
+31
-1
circle/dashboard/static/dashboard/activity.js
+116
-4
circle/dashboard/static/dashboard/dashboard.js
+27
-171
circle/dashboard/static/dashboard/group-details.js
+0
-36
circle/dashboard/static/dashboard/group-list.js
+3
-3
circle/dashboard/static/dashboard/node-create.js
+0
-10
circle/dashboard/static/dashboard/node-details.js
+0
-33
circle/dashboard/static/dashboard/node-list.js
+0
-45
circle/dashboard/static/dashboard/template-list.js
+0
-86
circle/dashboard/static/dashboard/vm-create.js
+16
-18
circle/dashboard/static/dashboard/vm-details.js
+1
-219
circle/dashboard/templates/dashboard/confirm/ajax-delete.html
+14
-8
circle/dashboard/templates/dashboard/confirm/ajax-node-status.html
+0
-27
circle/dashboard/templates/dashboard/confirm/ajax-remove.html
+0
-22
circle/dashboard/templates/dashboard/confirm/base-delete.html
+10
-4
circle/dashboard/templates/dashboard/confirm/base-remove.html
+0
-14
circle/dashboard/templates/dashboard/confirm/base-renew.html
+0
-32
circle/dashboard/templates/dashboard/confirm/mass-delete.html
+0
-18
circle/dashboard/templates/dashboard/confirm/node-flush.html
+0
-33
circle/dashboard/templates/dashboard/confirm/node-status.html
+0
-35
circle/dashboard/templates/dashboard/group-list/column-name.html
+1
-1
circle/dashboard/templates/dashboard/index-templates.html
+1
-1
circle/dashboard/templates/dashboard/modal-wrapper.html
+0
-19
circle/dashboard/templates/dashboard/node-detail.html
+2
-1
circle/dashboard/templates/dashboard/node-detail/_activity-timeline.html
+30
-29
circle/dashboard/templates/dashboard/node-detail/activity.html
+1
-1
circle/dashboard/templates/dashboard/vm-detail.html
+2
-1
circle/dashboard/templates/dashboard/vm-detail/network.html
+14
-7
circle/dashboard/tests/test_views.py
+22
-96
circle/dashboard/urls.py
+7
-8
circle/dashboard/views/group.py
+20
-78
circle/dashboard/views/node.py
+28
-87
circle/dashboard/views/template.py
+19
-95
circle/dashboard/views/user.py
+10
-48
circle/dashboard/views/util.py
+43
-1
circle/dashboard/views/vm.py
+50
-73
circle/vm/models/instance.py
+6
-4
No files found.
circle/circle/settings/base.py
View file @
7fed7d2c
...
@@ -198,6 +198,7 @@ PIPELINE_JS = {
...
@@ -198,6 +198,7 @@ PIPELINE_JS = {
"jquery-knob/dist/jquery.knob.min.js"
,
"jquery-knob/dist/jquery.knob.min.js"
,
"jquery-simple-slider/js/simple-slider.js"
,
"jquery-simple-slider/js/simple-slider.js"
,
"dashboard/dashboard.js"
,
"dashboard/dashboard.js"
,
"dashboard/activity.js"
,
"dashboard/group-details.js"
,
"dashboard/group-details.js"
,
"dashboard/group-list.js"
,
"dashboard/group-list.js"
,
"dashboard/js/stupidtable.min.js"
,
# no bower file
"dashboard/js/stupidtable.min.js"
,
# no bower file
...
...
circle/common/operations.py
View file @
7fed7d2c
...
@@ -282,6 +282,8 @@ def register_operation(op_cls, op_id=None, target_cls=None):
...
@@ -282,6 +282,8 @@ def register_operation(op_cls, op_id=None, target_cls=None):
"in the 'target_cls' parameter to this "
"in the 'target_cls' parameter to this "
"call."
)
"call."
)
assert
not
hasattr
(
target_cls
,
op_id
),
(
"target class already has an attribute with this id"
)
if
not
issubclass
(
target_cls
,
OperatedMixin
):
if
not
issubclass
(
target_cls
,
OperatedMixin
):
raise
TypeError
(
"
%
r is not a subclass of
%
r"
%
raise
TypeError
(
"
%
r is not a subclass of
%
r"
%
(
target_cls
.
__name__
,
OperatedMixin
.
__name__
))
(
target_cls
.
__name__
,
OperatedMixin
.
__name__
))
...
...
circle/dashboard/forms.py
View file @
7fed7d2c
...
@@ -898,7 +898,7 @@ class VmDownloadDiskForm(OperationForm):
...
@@ -898,7 +898,7 @@ class VmDownloadDiskForm(OperationForm):
def
clean
(
self
):
def
clean
(
self
):
cleaned_data
=
super
(
VmDownloadDiskForm
,
self
)
.
clean
()
cleaned_data
=
super
(
VmDownloadDiskForm
,
self
)
.
clean
()
if
not
cleaned_data
[
'name'
]:
if
not
cleaned_data
[
'name'
]:
if
cleaned_data
[
'url'
]
:
if
cleaned_data
.
get
(
'url'
)
:
cleaned_data
[
'name'
]
=
urlparse
(
cleaned_data
[
'name'
]
=
urlparse
(
cleaned_data
[
'url'
])
.
path
.
split
(
'/'
)[
-
1
]
cleaned_data
[
'url'
])
.
path
.
split
(
'/'
)[
-
1
]
if
not
cleaned_data
[
'name'
]:
if
not
cleaned_data
[
'name'
]:
...
@@ -908,6 +908,36 @@ class VmDownloadDiskForm(OperationForm):
...
@@ -908,6 +908,36 @@ class VmDownloadDiskForm(OperationForm):
return
cleaned_data
return
cleaned_data
class
VmRemoveInterfaceForm
(
OperationForm
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
choices
=
kwargs
.
pop
(
'choices'
)
self
.
interface
=
kwargs
.
pop
(
'default'
)
super
(
VmRemoveInterfaceForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
self
.
fields
.
insert
(
0
,
'interface'
,
forms
.
ModelChoiceField
(
queryset
=
choices
,
initial
=
self
.
interface
,
required
=
True
,
empty_label
=
None
,
label
=
_
(
'Interface'
)))
if
self
.
interface
:
self
.
fields
[
'interface'
]
.
widget
=
HiddenInput
()
@property
def
helper
(
self
):
helper
=
super
(
VmRemoveInterfaceForm
,
self
)
.
helper
if
self
.
interface
:
helper
.
layout
=
Layout
(
AnyTag
(
"div"
,
HTML
(
format_html
(
_
(
"<label>Vlan:</label> {0}"
),
self
.
interface
.
vlan
)),
css_class
=
"form-group"
,
),
Field
(
"interface"
),
)
return
helper
class
VmAddInterfaceForm
(
OperationForm
):
class
VmAddInterfaceForm
(
OperationForm
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
choices
=
kwargs
.
pop
(
'choices'
)
choices
=
kwargs
.
pop
(
'choices'
)
...
...
circle/dashboard/static/dashboard/
vm-common
.js
→
circle/dashboard/static/dashboard/
activity
.js
View file @
7fed7d2c
/* for functions in both vm list and vm detail */
$
(
function
()
{
$
(
function
()
{
var
in_progress
=
false
;
var
activity_hash
=
5
;
var
show_all
=
false
;
var
reload_vm_detail
=
false
;
/* do we need to check for new activities */
if
(
decideActivityRefresh
())
{
if
(
!
in_progress
)
{
checkNewActivity
(
1
);
in_progress
=
true
;
}
}
/* vm operations */
$
(
'a[href="#activity"]'
).
click
(
function
(){
$
(
'a[href="#activity"] i'
).
addClass
(
'fa-spin'
);
if
(
!
in_progress
)
{
checkNewActivity
(
1
);
in_progress
=
true
;
}
});
$
(
"#activity-refresh"
).
on
(
"click"
,
"#show-all-activities"
,
function
()
{
$
(
this
).
find
(
"i"
).
addClass
(
"fa-spinner fa-spin"
);
show_all
=
!
show_all
;
$
(
'a[href="#activity"]'
).
trigger
(
"click"
);
return
false
;
});
/* operations */
$
(
'#ops, #vm-details-resources-disk, #vm-details-renew-op, #vm-details-pw-reset, #vm-details-add-interface, .operation-wrapper'
).
on
(
'click'
,
'.operation'
,
function
(
e
)
{
$
(
'#ops, #vm-details-resources-disk, #vm-details-renew-op, #vm-details-pw-reset, #vm-details-add-interface, .operation-wrapper'
).
on
(
'click'
,
'.operation'
,
function
(
e
)
{
var
icon
=
$
(
this
).
children
(
"i"
).
addClass
(
'fa-spinner fa-spin'
);
var
icon
=
$
(
this
).
children
(
"i"
).
addClass
(
'fa-spinner fa-spin'
);
...
@@ -23,7 +48,7 @@ $(function() {
...
@@ -23,7 +48,7 @@ $(function() {
});
});
/* if the operation fails show the modal again */
/* if the operation fails show the modal again */
$
(
"body"
).
on
(
"click"
,
"#op-form-send"
,
function
()
{
$
(
"body"
).
on
(
"click"
,
"#
confirmation-modal #
op-form-send"
,
function
()
{
var
url
=
$
(
this
).
closest
(
"form"
).
prop
(
"action"
);
var
url
=
$
(
this
).
closest
(
"form"
).
prop
(
"action"
);
$
.
ajax
({
$
.
ajax
({
...
@@ -77,4 +102,91 @@ $(function() {
...
@@ -77,4 +102,91 @@ $(function() {
return
false
;
return
false
;
});
});
function
decideActivityRefresh
()
{
var
check
=
false
;
/* if something is still spinning */
if
(
$
(
'.timeline .activity i'
).
hasClass
(
'fa-spin'
))
check
=
true
;
return
check
;
}
function
checkNewActivity
(
runs
)
{
$
.
ajax
({
type
:
'GET'
,
url
:
$
(
'a[href="#activity"]'
).
attr
(
'data-activity-url'
),
data
:
{
'show_all'
:
show_all
},
success
:
function
(
data
)
{
var
new_activity_hash
=
(
data
.
activities
+
""
).
hashCode
();
if
(
new_activity_hash
!=
activity_hash
)
{
$
(
"#activity-refresh"
).
html
(
data
.
activities
);
}
activity_hash
=
new_activity_hash
;
$
(
"#ops"
).
html
(
data
.
ops
);
$
(
"#disk-ops"
).
html
(
data
.
disk_ops
);
$
(
"[title]"
).
tooltip
();
/* changing the status text */
var
icon
=
$
(
"#vm-details-state i"
);
if
(
data
.
is_new_state
)
{
if
(
!
icon
.
hasClass
(
"fa-spin"
))
icon
.
prop
(
"class"
,
"fa fa-spinner fa-spin"
);
}
else
{
icon
.
prop
(
"class"
,
"fa "
+
data
.
icon
);
}
var
vm_state
=
$
(
"#vm-details-state"
);
if
(
vm_state
.
length
)
{
vm_state
.
data
(
"status"
,
data
[
'status'
]);
$
(
"#vm-details-state span"
).
html
(
data
[
'human_readable_status'
].
toUpperCase
());
}
if
(
data
[
'status'
]
==
"RUNNING"
)
{
if
(
data
[
'connect_uri'
])
{
$
(
"#dashboard-vm-details-connect-button"
).
removeClass
(
'disabled'
);
}
$
(
"[data-target=#_console]"
).
attr
(
"data-toggle"
,
"pill"
).
attr
(
"href"
,
"#console"
).
parent
(
"li"
).
removeClass
(
"disabled"
);
}
else
{
if
(
data
[
'connect_uri'
])
{
$
(
"#dashboard-vm-details-connect-button"
).
addClass
(
'disabled'
);
}
$
(
"[data-target=#_console]"
).
attr
(
"data-toggle"
,
"_pill"
).
attr
(
"href"
,
"#"
).
parent
(
"li"
).
addClass
(
"disabled"
);
}
if
(
data
.
status
==
"STOPPED"
||
data
.
status
==
"PENDING"
)
{
$
(
".change-resources-button"
).
prop
(
"disabled"
,
false
);
$
(
".change-resources-help"
).
hide
();
}
else
{
$
(
".change-resources-button"
).
prop
(
"disabled"
,
true
);
$
(
".change-resources-help"
).
show
();
}
if
(
runs
>
0
&&
decideActivityRefresh
())
{
setTimeout
(
function
()
{
checkNewActivity
(
runs
+
1
);},
1000
+
Math
.
exp
(
runs
*
0.05
)
);
}
else
{
in_progress
=
false
;
if
(
reload_vm_detail
)
location
.
reload
();
}
$
(
'a[href="#activity"] i'
).
removeClass
(
'fa-spin'
);
},
error
:
function
()
{
in_progress
=
false
;
}
});
}
});
});
String
.
prototype
.
hashCode
=
function
()
{
var
hash
=
0
,
i
,
chr
,
len
;
if
(
this
.
length
==
0
)
return
hash
;
for
(
i
=
0
,
len
=
this
.
length
;
i
<
len
;
i
++
)
{
chr
=
this
.
charCodeAt
(
i
);
hash
=
((
hash
<<
5
)
-
hash
)
+
chr
;
hash
|=
0
;
// Convert to 32bit integer
}
return
hash
;
};
circle/dashboard/static/dashboard/dashboard.js
View file @
7fed7d2c
...
@@ -5,63 +5,39 @@ $(function () {
...
@@ -5,63 +5,39 @@ $(function () {
var
template
=
$
(
this
).
data
(
"template"
);
var
template
=
$
(
this
).
data
(
"template"
);
$
.
ajax
({
$
.
ajax
({
type
:
'GET'
,
type
:
'GET'
,
url
:
'/dashboard/vm/create/'
+
(
typeof
template
===
"undefined"
?
''
:
'?template='
+
template
),
url
:
$
(
this
).
attr
(
'href'
),
success
:
function
(
data
)
{
success
:
function
(
data
)
{
$
(
'body'
).
append
(
data
);
$
(
'body'
).
append
(
data
);
vmCreateLoaded
();
vmCreateLoaded
();
addSliderMiscs
();
addSliderMiscs
();
$
(
'#create-modal'
).
modal
(
'show'
);
var
modal
=
$
(
'#confirmation-modal'
);
$
(
'#create-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
modal
.
modal
(
'show'
);
$
(
'#create-modal'
).
remove
();
modal
.
on
(
'hidden.bs.modal'
,
function
()
{
modal
.
remove
();
});
});
}
}
});
});
return
false
;
return
false
;
});
});
$
(
'.
node-create
'
).
click
(
function
(
e
)
{
$
(
'.
group-create, .node-create, .tx-tpl-ownership, .group-delete, .node-delete, .disk-remove, .template-delete, .delete-from-group
'
).
click
(
function
(
e
)
{
$
.
ajax
({
$
.
ajax
({
type
:
'GET'
,
type
:
'GET'
,
url
:
'/dashboard/node/create/'
,
url
:
$
(
this
).
prop
(
'href'
)
,
success
:
function
(
data
)
{
success
:
function
(
data
)
{
$
(
'body'
).
append
(
data
);
$
(
'body'
).
append
(
data
);
nodeCreateLoaded
();
var
modal
=
$
(
'#confirmation-modal'
);
addSliderMiscs
();
modal
.
modal
(
'show'
);
$
(
'#create-modal'
).
modal
(
'show'
);
modal
.
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#create-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
modal
.
remove
();
$
(
'#create-modal'
).
remove
();
});
}
});
return
false
;
});
$
(
'.group-create'
).
click
(
function
(
e
)
{
$
.
ajax
({
type
:
'GET'
,
url
:
'/dashboard/group/create/'
,
success
:
function
(
data
)
{
$
(
'body'
).
append
(
data
);
addSliderMiscs
();
$
(
'#create-modal'
).
modal
(
'show'
);
$
(
'#create-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#create-modal'
).
remove
();
});
}
});
return
false
;
});
$
(
'.tx-tpl-ownership'
).
click
(
function
(
e
)
{
$
.
ajax
({
type
:
'GET'
,
url
:
$
(
'.tx-tpl-ownership'
).
attr
(
'href'
),
success
:
function
(
data
)
{
$
(
'body'
).
append
(
data
);
$
(
'#confirmation-modal'
).
modal
(
'show'
);
$
(
'#confirmation-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#confirmation-modal'
).
remove
();
});
});
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
if
(
xhr
.
status
===
403
)
{
addMessage
(
gettext
(
"Only the owners can delete the selected object."
),
"warning"
);
}
else
{
addMessage
(
gettext
(
"An error occurred. ("
)
+
xhr
.
status
+
")"
,
'danger'
)
}
}
}
});
});
return
false
;
return
false
;
...
@@ -70,12 +46,13 @@ $(function () {
...
@@ -70,12 +46,13 @@ $(function () {
$
(
'.template-choose'
).
click
(
function
(
e
)
{
$
(
'.template-choose'
).
click
(
function
(
e
)
{
$
.
ajax
({
$
.
ajax
({
type
:
'GET'
,
type
:
'GET'
,
url
:
'/dashboard/template/choose/'
,
url
:
$
(
this
).
prop
(
'href'
)
,
success
:
function
(
data
)
{
success
:
function
(
data
)
{
$
(
'body'
).
append
(
data
);
$
(
'body'
).
append
(
data
);
$
(
'#create-modal'
).
modal
(
'show'
);
var
modal
=
$
(
'#confirmation-modal'
);
$
(
'#create-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
modal
.
modal
(
'show'
);
$
(
'#create-modal'
).
remove
();
modal
.
on
(
'hidden.bs.modal'
,
function
()
{
modal
.
remove
();
});
});
// check if user selected anything
// check if user selected anything
$
(
"#template-choose-next-button"
).
click
(
function
()
{
$
(
"#template-choose-next-button"
).
click
(
function
()
{
...
@@ -101,6 +78,7 @@ $(function () {
...
@@ -101,6 +78,7 @@ $(function () {
e
.
stopImmediatePropagation
();
e
.
stopImmediatePropagation
();
return
false
;
return
false
;
});
});
$
(
'[href=#index-list-view]'
).
click
(
function
(
e
)
{
$
(
'[href=#index-list-view]'
).
click
(
function
(
e
)
{
var
box
=
$
(
this
).
data
(
'index-box'
);
var
box
=
$
(
this
).
data
(
'index-box'
);
$
(
'#'
+
box
+
'-graph-view'
).
hide
();
$
(
'#'
+
box
+
'-graph-view'
).
hide
();
...
@@ -110,9 +88,10 @@ $(function () {
...
@@ -110,9 +88,10 @@ $(function () {
e
.
stopImmediatePropagation
();
e
.
stopImmediatePropagation
();
return
false
;
return
false
;
});
});
$
(
'body [title]:not(.title-favourite)'
).
tooltip
();
$
(
'body .title-favourite'
).
tooltip
({
'placement'
:
'right'
});
$
(
'body .title-favourite'
).
tooltip
({
'placement'
:
'right'
});
$
(
'body :input[title]'
).
tooltip
({
trigger
:
'focus'
,
placement
:
'auto right'
});
$
(
'body :input[title]'
).
tooltip
({
trigger
:
'focus'
,
placement
:
'auto right'
});
$
(
'body [title]'
).
tooltip
();
$
(
".knob"
).
knob
();
$
(
".knob"
).
knob
();
$
(
'[data-toggle="pill"]'
).
click
(
function
()
{
$
(
'[data-toggle="pill"]'
).
click
(
function
()
{
...
@@ -167,74 +146,6 @@ $(function () {
...
@@ -167,74 +146,6 @@ $(function () {
addSliderMiscs
();
addSliderMiscs
();
/* for VM removes buttons */
$
(
'.vm-delete'
).
click
(
function
()
{
var
vm_pk
=
$
(
this
).
data
(
'vm-pk'
);
var
dir
=
window
.
location
.
pathname
.
indexOf
(
'list'
)
==
-
1
;
addModalConfirmation
(
deleteObject
,
{
'url'
:
'/dashboard/vm/delete/'
+
vm_pk
+
'/'
,
'data'
:
[],
'pk'
:
vm_pk
,
'type'
:
"vm"
,
'redirect'
:
dir
});
return
false
;
});
/* for disk remove buttons */
$
(
'.disk-remove'
).
click
(
function
()
{
var
disk_pk
=
$
(
this
).
data
(
'disk-pk'
);
addModalConfirmation
(
deleteObject
,
{
'url'
:
'/dashboard/disk/'
+
disk_pk
+
'/remove/'
,
'data'
:
[],
'pk'
:
disk_pk
,
'type'
:
"disk"
,
});
return
false
;
});
/* for Node removes buttons */
$
(
'.node-delete'
).
click
(
function
()
{
var
node_pk
=
$
(
this
).
data
(
'node-pk'
);
var
dir
=
window
.
location
.
pathname
.
indexOf
(
'list'
)
==
-
1
;
addModalConfirmation
(
deleteObject
,
{
'url'
:
'/dashboard/node/delete/'
+
node_pk
+
'/'
,
'data'
:
[],
'pk'
:
node_pk
,
'type'
:
"node"
,
'redirect'
:
dir
});
return
false
;
});
/* for Node flush buttons */
$
(
'.node-flush'
).
click
(
function
()
{
var
node_pk
=
$
(
this
).
data
(
'node-pk'
);
var
postto
=
$
(
this
).
attr
(
'href'
);
var
dir
=
window
.
location
.
pathname
.
indexOf
(
'list'
)
==
-
1
;
addModalConfirmation
(
function
(){},
{
'url'
:
postto
,
'data'
:
[],
'pk'
:
node_pk
,
'type'
:
"node"
,
'redirect'
:
dir
});
return
false
;
});
/* for Group removes buttons */
$
(
'.group-delete'
).
click
(
function
()
{
var
group_pk
=
$
(
this
).
data
(
'group-pk'
);
var
dir
=
window
.
location
.
pathname
.
indexOf
(
'list'
)
==
-
1
;
addModalConfirmation
(
deleteObject
,
{
'url'
:
'/dashboard/group/delete/'
+
group_pk
+
'/'
,
'data'
:
[],
'type'
:
"group"
,
'pk'
:
group_pk
,
'redirect'
:
dir
});
return
false
;
});
/* search for vms */
/* search for vms */
var
my_vms
=
[];
var
my_vms
=
[];
$
(
"#dashboard-vm-search-input"
).
keyup
(
function
(
e
)
{
$
(
"#dashboard-vm-search-input"
).
keyup
(
function
(
e
)
{
...
@@ -558,62 +469,6 @@ function setDefaultSliderValues() {
...
@@ -558,62 +469,6 @@ function setDefaultSliderValues() {
}
}
/* deletes the VM with the pk
* if dir is true, then redirect to the dashboard landing page
* else it adds a success message */
function
deleteObject
(
data
)
{
$
.
ajax
({
type
:
'POST'
,
data
:
{
'redirect'
:
data
.
redirect
},
url
:
data
.
url
,
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
success
:
function
(
re
,
textStatus
,
xhr
)
{
if
(
!
data
.
redirect
)
{
selected
=
[];
addMessage
(
re
.
message
,
'success'
);
if
(
data
.
type
===
"disk"
)
{
// no need to remove them from DOM
$
(
'a[data-disk-pk="'
+
data
.
pk
+
'"]'
).
parent
(
"li"
).
fadeOut
();
$
(
'a[data-disk-pk="'
+
data
.
pk
+
'"]'
).
parent
(
"h4"
).
fadeOut
();
}
else
{
$
(
'a[data-'
+
data
.
type
+
'-pk="'
+
data
.
pk
+
'"]'
).
closest
(
'tr'
).
fadeOut
(
function
()
{
$
(
this
).
remove
();
});
}
}
else
{
window
.
location
.
replace
(
'/dashboard'
);
}
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
addMessage
(
'Uh oh :('
,
'danger'
);
}
});
}
function
massDeleteVm
(
data
)
{
f
=
function
()
{
selected
=
[];
// reset group buttons
$
(
'.vm-list-group-control a'
).
attr
(
'disabled'
,
true
);
$
(
this
).
remove
();
};
$
.
ajax
({
traditional
:
true
,
url
:
data
.
url
,
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
type
:
'POST'
,
data
:
{
'vms'
:
data
.
data
.
v
},
success
:
function
(
re
,
textStatus
,
xhr
)
{
for
(
var
i
=
0
;
i
<
data
.
data
.
v
.
length
;
i
++
)
$
(
'.vm-list-table tbody tr[data-vm-pk="'
+
data
.
data
.
v
[
i
]
+
'"]'
).
fadeOut
(
500
,
f
);
addMessage
(
re
.
message
,
'success'
);
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
// TODO this
}
});
}
function
addMessage
(
text
,
type
)
{
function
addMessage
(
text
,
type
)
{
...
@@ -701,6 +556,7 @@ function csrfSafeMethod(method) {
...
@@ -701,6 +556,7 @@ function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
// these HTTP methods do not require CSRF protection
return
(
/^
(
GET|HEAD|OPTIONS|TRACE
)
$/
.
test
(
method
));
return
(
/^
(
GET|HEAD|OPTIONS|TRACE
)
$/
.
test
(
method
));
}
}
$
.
ajaxSetup
({
$
.
ajaxSetup
({
beforeSend
:
function
(
xhr
,
settings
)
{
beforeSend
:
function
(
xhr
,
settings
)
{
if
(
!
csrfSafeMethod
(
settings
.
type
)
&&
!
this
.
crossDomain
)
{
if
(
!
csrfSafeMethod
(
settings
.
type
)
&&
!
this
.
crossDomain
)
{
...
...
circle/dashboard/static/dashboard/group-details.js
View file @
7fed7d2c
...
@@ -28,39 +28,3 @@
...
@@ -28,39 +28,3 @@
$
(
".group-details-help-button"
).
click
(
function
()
{
$
(
".group-details-help-button"
).
click
(
function
()
{
$
(
".group-details-help"
).
stop
().
slideToggle
();
$
(
".group-details-help"
).
stop
().
slideToggle
();
});
});
/* for Node removes buttons */
$
(
'.delete-from-group'
).
click
(
function
()
{
var
href
=
$
(
this
).
attr
(
'href'
);
var
tr
=
$
(
this
).
closest
(
'tr'
);
var
group
=
$
(
this
).
data
(
'group_pk'
);
var
member
=
$
(
this
).
data
(
'member_pk'
);
var
dir
=
window
.
location
.
pathname
.
indexOf
(
'list'
)
==
-
1
;
addModalConfirmation
(
removeMember
,
{
'url'
:
href
,
'data'
:
[],
'tr'
:
tr
,
'group_pk'
:
group
,
'member_pk'
:
member
,
'type'
:
"user"
,
'redirect'
:
dir
});
return
false
;
});
function
removeMember
(
data
)
{
$
.
ajax
({
type
:
'POST'
,
url
:
data
.
url
,
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
success
:
function
(
re
,
textStatus
,
xhr
)
{
data
.
tr
.
fadeOut
(
function
()
{
$
(
this
).
remove
();});
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
addMessage
(
'Uh oh :('
,
'danger'
);
}
});
}
circle/dashboard/static/dashboard/group-list.js
View file @
7fed7d2c
$
(
function
()
{
$
(
function
()
{
/* rename */
/* rename */
$
(
"#group-list-rename-button, .group-details-rename-button"
).
click
(
function
()
{
$
(
"#group-list-rename-button, .group-details-rename-button"
).
click
(
function
()
{
$
(
"
#
group-list-column-name"
,
$
(
this
).
closest
(
"tr"
)).
hide
();
$
(
"
.
group-list-column-name"
,
$
(
this
).
closest
(
"tr"
)).
hide
();
$
(
"#group-list-rename"
,
$
(
this
).
closest
(
"tr"
)).
css
(
'display'
,
'inline'
);
$
(
"#group-list-rename"
,
$
(
this
).
closest
(
"tr"
)).
css
(
'display'
,
'inline'
);
$
(
"#group-list-rename"
).
find
(
"input"
).
select
();
$
(
"#group-list-rename"
).
find
(
"input"
).
select
();
});
});
...
@@ -10,7 +10,7 @@ $(function() {
...
@@ -10,7 +10,7 @@ $(function() {
$
(
'.group-list-rename-submit'
).
click
(
function
()
{
$
(
'.group-list-rename-submit'
).
click
(
function
()
{
var
row
=
$
(
this
).
closest
(
"tr"
);
var
row
=
$
(
this
).
closest
(
"tr"
);
var
name
=
$
(
'#group-list-rename-name'
,
row
).
val
();
var
name
=
$
(
'#group-list-rename-name'
,
row
).
val
();
var
url
=
'/dashboard/group/'
+
row
.
children
(
"td:first-child"
).
text
().
replace
(
" "
,
""
)
+
'/'
;
var
url
=
row
.
find
(
".group-list-column-name a"
).
prop
(
"href"
)
;
$
.
ajax
({
$
.
ajax
({
method
:
'POST'
,
method
:
'POST'
,
url
:
url
,
url
:
url
,
...
@@ -18,7 +18,7 @@ $(function() {
...
@@ -18,7 +18,7 @@ $(function() {
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
success
:
function
(
data
,
textStatus
,
xhr
)
{
success
:
function
(
data
,
textStatus
,
xhr
)
{
$
(
"
#
group-list-column-name"
,
row
).
html
(
$
(
"
.
group-list-column-name"
,
row
).
html
(
$
(
"<a/>"
,
{
$
(
"<a/>"
,
{
'class'
:
"real-link"
,
'class'
:
"real-link"
,
href
:
"/dashboard/group/"
+
data
.
group_pk
+
"/"
,
href
:
"/dashboard/group/"
+
data
.
group_pk
+
"/"
,
...
...
circle/dashboard/static/dashboard/node-create.js
deleted
100644 → 0
View file @
32e83265
$
(
function
()
{
nodeCreateLoaded
();
});
function
nodeCreateLoaded
()
{
/* no js compatibility */
$
(
'.no-js-hidden'
).
show
();
$
(
'.js-hidden'
).
hide
();
}
circle/dashboard/static/dashboard/node-details.js
View file @
7fed7d2c
...
@@ -30,20 +30,6 @@ $(function() {
...
@@ -30,20 +30,6 @@ $(function() {
$
(
".node-details-help"
).
stop
().
slideToggle
();
$
(
".node-details-help"
).
stop
().
slideToggle
();
});
});
/* for Node removes buttons */
$
(
'.node-enable'
).
click
(
function
()
{
var
node_pk
=
$
(
this
).
data
(
'node-pk'
);
var
dir
=
window
.
location
.
pathname
.
indexOf
(
'list'
)
==
-
1
;
addModalConfirmation
(
changeNodeStatus
,
{
'url'
:
'/dashboard/node/status/'
+
node_pk
+
'/'
,
'data'
:
[],
'pk'
:
node_pk
,
'type'
:
"node"
,
'redirect'
:
dir
});
return
false
;
});
// remove trait
// remove trait
$
(
'.node-details-remove-trait'
).
click
(
function
()
{
$
(
'.node-details-remove-trait'
).
click
(
function
()
{
var
to_remove
=
$
(
this
).
data
(
"trait-pk"
);
var
to_remove
=
$
(
this
).
data
(
"trait-pk"
);
...
@@ -69,22 +55,3 @@ $(function() {
...
@@ -69,22 +55,3 @@ $(function() {
});
});
});
});
function
changeNodeStatus
(
data
)
{
$
.
ajax
({
type
:
'POST'
,
url
:
data
.
url
,
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
success
:
function
(
re
,
textStatus
,
xhr
)
{
if
(
!
data
.
redirect
)
{
selected
=
[];
addMessage
(
re
.
message
,
'success'
);
}
else
{
window
.
location
.
replace
(
'/dashboard'
);
}
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
addMessage
(
'Uh oh :('
,
'danger'
);
}
});
}
circle/dashboard/static/dashboard/node-list.js
View file @
7fed7d2c
...
@@ -9,49 +9,4 @@ $(function() {
...
@@ -9,49 +9,4 @@ $(function() {
$
(
'.false'
).
closest
(
"tr"
).
addClass
(
'danger'
);
$
(
'.false'
).
closest
(
"tr"
).
addClass
(
'danger'
);
$
(
'.true'
).
closest
(
"tr"
).
removeClass
(
'danger'
);
$
(
'.true'
).
closest
(
"tr"
).
removeClass
(
'danger'
);
}
}
function
statuschangeSuccess
(
tr
){
var
tspan
=
tr
.
children
(
'.enabled'
).
children
();
var
buttons
=
tr
.
children
(
'.actions'
).
children
(
'.btn-group'
).
children
(
'.dropdown-menu'
).
children
(
'li'
).
children
(
'.node-enable'
);
buttons
.
each
(
function
(
index
){
if
(
$
(
this
).
css
(
"display"
)
==
"block"
){
$
(
this
).
css
(
"display"
,
"none"
);
}
else
{
$
(
this
).
css
(
"display"
,
"block"
);
}
});
if
(
tspan
.
hasClass
(
"false"
)){
tspan
.
removeClass
(
"false"
);
tspan
.
addClass
(
"true"
);
tspan
.
text
(
"✔"
);
}
else
{
tspan
.
removeClass
(
"true"
);
tspan
.
addClass
(
"false"
);
tspan
.
text
(
"✘"
);
}
colortable
();
}
$
(
'#table_container'
).
on
(
'click'
,
'.node-enable'
,
function
()
{
var
tr
=
$
(
this
).
closest
(
"tr"
);
var
pk
=
$
(
this
).
attr
(
'data-node-pk'
);
var
url
=
$
(
this
).
attr
(
'href'
);
$
.
ajax
({
method
:
'POST'
,
url
:
url
,
data
:
{
'change_status'
:
''
},
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
success
:
function
(
data
,
textStatus
,
xhr
)
{
statuschangeSuccess
(
tr
);
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
addMessage
(
"Error!"
,
"danger"
);
}
});
return
false
;
});
});
});
circle/dashboard/static/dashboard/template-list.js
View file @
7fed7d2c
$
(
function
()
{
$
(
function
()
{
/* for template removes buttons */
$
(
'.template-delete'
).
click
(
function
()
{
var
template_pk
=
$
(
this
).
data
(
'template-pk'
);
addModalConfirmationOrDisplayMessage
(
deleteTemplate
,
{
'url'
:
'/dashboard/template/delete/'
+
template_pk
+
'/'
,
'data'
:
[],
'template_pk'
:
template_pk
,
});
return
false
;
});
/* for lease removes buttons */
$
(
'.lease-delete'
).
click
(
function
()
{
var
lease_pk
=
$
(
this
).
data
(
'lease-pk'
);
addModalConfirmationOrDisplayMessage
(
deleteLease
,
{
'url'
:
'/dashboard/lease/delete/'
+
lease_pk
+
'/'
,
'data'
:
[],
'lease_pk'
:
lease_pk
,
});
return
false
;
});
/* template table sort */
/* template table sort */
var
ttable
=
$
(
".template-list-table"
).
stupidtable
();
var
ttable
=
$
(
".template-list-table"
).
stupidtable
();
...
@@ -43,67 +21,3 @@ $(function() {
...
@@ -43,67 +21,3 @@ $(function() {
event
.
preventDefault
();
event
.
preventDefault
();
});
});
});
});
// send POST request then delete the row in table
function
deleteTemplate
(
data
)
{
$
.
ajax
({
type
:
'POST'
,
url
:
data
.
url
,
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
success
:
function
(
re
,
textStatus
,
xhr
)
{
addMessage
(
re
.
message
,
'success'
);
$
(
'a[data-template-pk="'
+
data
.
template_pk
+
'"]'
).
closest
(
'tr'
).
fadeOut
(
function
()
{
$
(
this
).
remove
();
});
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
addMessage
(
'Uh oh :('
,
'danger'
);
}
});
}
// send POST request then delete the row in table
function
deleteLease
(
data
)
{
$
.
ajax
({
type
:
'POST'
,
url
:
data
.
url
,
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
success
:
function
(
re
,
textStatus
,
xhr
)
{
addMessage
(
re
.
message
,
'success'
);
$
(
'a[data-lease-pk="'
+
data
.
lease_pk
+
'"]'
).
closest
(
'tr'
).
fadeOut
(
function
()
{
$
(
this
).
remove
();
});
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
addMessage
(
'Uh oh :('
,
'danger'
);
}
});
}
function
addModalConfirmationOrDisplayMessage
(
func
,
data
)
{
$
.
ajax
({
type
:
'GET'
,
url
:
data
[
'url'
],
data
:
jQuery
.
param
(
data
[
'data'
]),
success
:
function
(
result
)
{
$
(
'body'
).
append
(
result
);
$
(
'#confirmation-modal'
).
modal
(
'show'
);
$
(
'#confirmation-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#confirmation-modal'
).
remove
();
});
$
(
'#confirmation-modal-button'
).
click
(
function
()
{
func
(
data
);
$
(
'#confirmation-modal'
).
modal
(
'hide'
);
});
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
if
(
xhr
.
status
===
403
)
{
addMessage
(
gettext
(
"Only the owners can delete the selected object."
),
"warning"
);
}
else
{
addMessage
(
gettext
(
"An error occurred. ("
)
+
xhr
.
status
+
")"
,
'danger'
)
}
}
});
}
circle/dashboard/static/dashboard/vm-create.js
View file @
7fed7d2c
...
@@ -20,15 +20,15 @@ function vmCreateLoaded() {
...
@@ -20,15 +20,15 @@ function vmCreateLoaded() {
var
template
=
$
(
this
).
data
(
"template-pk"
);
var
template
=
$
(
this
).
data
(
"template-pk"
);
$
.
get
(
"/dashboard/vm/create/?template="
+
template
,
function
(
data
)
{
$
.
get
(
"/dashboard/vm/create/?template="
+
template
,
function
(
data
)
{
var
r
=
$
(
'#c
reate
-modal'
);
r
.
next
(
'div'
).
remove
();
r
.
remove
();
var
r
=
$
(
'#c
onfirmation
-modal'
);
r
.
next
(
'div'
).
remove
();
r
.
remove
();
$
(
'body'
).
append
(
data
);
$
(
'body'
).
append
(
data
);
vmCreateLoaded
();
vmCreateLoaded
();
addSliderMiscs
();
addSliderMiscs
();
$
(
'#c
reate
-modal'
).
modal
(
'show'
);
$
(
'#c
onfirmation
-modal'
).
modal
(
'show'
);
$
(
'#c
reate
-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#c
onfirmation
-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#c
reate
-modal'
).
remove
();
$
(
'#c
onfirmation
-modal'
).
remove
();
});
});
$
(
"#c
reate
-modal"
).
on
(
"shown.bs.modal"
,
function
()
{
$
(
"#c
onfirmation
-modal"
).
on
(
"shown.bs.modal"
,
function
()
{
setDefaultSliderValues
();
setDefaultSliderValues
();
});
});
});
});
...
@@ -48,18 +48,18 @@ function vmCreateLoaded() {
...
@@ -48,18 +48,18 @@ function vmCreateLoaded() {
window
.
location
.
replace
(
data
.
redirect
+
'#activity'
);
window
.
location
.
replace
(
data
.
redirect
+
'#activity'
);
}
}
else
{
else
{
var
r
=
$
(
'#c
reate
-modal'
);
r
.
next
(
'div'
).
remove
();
r
.
remove
();
var
r
=
$
(
'#c
onfirmation
-modal'
);
r
.
next
(
'div'
).
remove
();
r
.
remove
();
$
(
'body'
).
append
(
data
);
$
(
'body'
).
append
(
data
);
vmCreateLoaded
();
vmCreateLoaded
();
addSliderMiscs
();
addSliderMiscs
();
$
(
'#c
reate
-modal'
).
modal
(
'show'
);
$
(
'#c
onfirmation
-modal'
).
modal
(
'show'
);
$
(
'#c
reate
-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#c
onfirmation
-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#c
reate
-modal'
).
remove
();
$
(
'#c
onfirmation
-modal'
).
remove
();
});
});
}
}
},
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
error
:
function
(
xhr
,
textStatus
,
error
)
{
var
r
=
$
(
'#c
reate
-modal'
);
r
.
next
(
'div'
).
remove
();
r
.
remove
();
var
r
=
$
(
'#c
onfirmation
-modal'
);
r
.
next
(
'div'
).
remove
();
r
.
remove
();
if
(
xhr
.
status
==
500
)
{
if
(
xhr
.
status
==
500
)
{
addMessage
(
"500 Internal Server Error"
,
"danger"
);
addMessage
(
"500 Internal Server Error"
,
"danger"
);
...
@@ -211,7 +211,7 @@ function vmCustomizeLoaded() {
...
@@ -211,7 +211,7 @@ function vmCustomizeLoaded() {
});
});
/* start vm button clicks */
/* start vm button clicks */
$
(
'#vm-create-customized-start'
).
click
(
function
()
{
$
(
'#
confirmation-modal #
vm-create-customized-start'
).
click
(
function
()
{
var
error
=
false
;
var
error
=
false
;
$
(
".cpu-count-input, .ram-input, #id_name, #id_amount "
).
each
(
function
()
{
$
(
".cpu-count-input, .ram-input, #id_name, #id_amount "
).
each
(
function
()
{
if
(
!
$
(
this
)[
0
].
checkValidity
())
{
if
(
!
$
(
this
)[
0
].
checkValidity
())
{
...
@@ -222,8 +222,6 @@ function vmCustomizeLoaded() {
...
@@ -222,8 +222,6 @@ function vmCustomizeLoaded() {
$
(
this
).
find
(
"i"
).
prop
(
"class"
,
"fa fa-spinner fa-spin"
);
$
(
this
).
find
(
"i"
).
prop
(
"class"
,
"fa fa-spinner fa-spin"
);
if
(
$
(
"#create-modal"
))
return
true
;
$
.
ajax
({
$
.
ajax
({
url
:
'/dashboard/vm/create/'
,
url
:
'/dashboard/vm/create/'
,
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
...
@@ -238,18 +236,18 @@ function vmCustomizeLoaded() {
...
@@ -238,18 +236,18 @@ function vmCustomizeLoaded() {
window
.
location
.
href
=
data
.
redirect
+
'#activity'
;
window
.
location
.
href
=
data
.
redirect
+
'#activity'
;
}
}
else
{
else
{
var
r
=
$
(
'#c
reate
-modal'
);
r
.
next
(
'div'
).
remove
();
r
.
remove
();
var
r
=
$
(
'#c
onfirmation
-modal'
);
r
.
next
(
'div'
).
remove
();
r
.
remove
();
$
(
'body'
).
append
(
data
);
$
(
'body'
).
append
(
data
);
vmCreateLoaded
();
vmCreateLoaded
();
addSliderMiscs
();
addSliderMiscs
();
$
(
'#c
reate
-modal'
).
modal
(
'show'
);
$
(
'#c
onfirmation
-modal'
).
modal
(
'show'
);
$
(
'#c
reate
-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#c
onfirmation
-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#c
reate
-modal'
).
remove
();
$
(
'#c
onfirmation
-modal'
).
remove
();
});
});
}
}
},
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
error
:
function
(
xhr
,
textStatus
,
error
)
{
var
r
=
$
(
'#c
reate
-modal'
);
r
.
next
(
'div'
).
remove
();
r
.
remove
();
var
r
=
$
(
'#c
onfirmation
-modal'
);
r
.
next
(
'div'
).
remove
();
r
.
remove
();
if
(
xhr
.
status
==
500
)
{
if
(
xhr
.
status
==
500
)
{
addMessage
(
"500 Internal Server Error"
,
"danger"
);
addMessage
(
"500 Internal Server Error"
,
"danger"
);
...
...
circle/dashboard/static/dashboard/vm-details.js
View file @
7fed7d2c
var
show_all
=
false
;
var
in_progress
=
false
;
var
activity_hash
=
5
;
var
Websock_native
;
// not sure
var
Websock_native
;
// not sure
var
reload_vm_detail
=
false
;
$
(
function
()
{
$
(
function
()
{
/* do we need to check for new activities */
if
(
decideActivityRefresh
())
{
if
(
!
in_progress
)
{
checkNewActivity
(
1
);
in_progress
=
true
;
}
}
$
(
'a[href="#activity"]'
).
click
(
function
(){
$
(
'a[href="#activity"] i'
).
addClass
(
'fa-spin'
);
if
(
!
in_progress
)
{
checkNewActivity
(
1
);
in_progress
=
true
;
}
});
$
(
"#activity-refresh"
).
on
(
"click"
,
"#show-all-activities"
,
function
()
{
$
(
this
).
find
(
"i"
).
addClass
(
"fa-spinner fa-spin"
);
show_all
=
!
show_all
;
$
(
'a[href="#activity"]'
).
trigger
(
"click"
);
return
false
;
});
/* save resources */
/* save resources */
$
(
'#vm-details-resources-save'
).
click
(
function
(
e
)
{
$
(
'#vm-details-resources-save'
).
click
(
function
(
e
)
{
var
error
=
false
;
var
error
=
false
;
...
@@ -43,7 +16,7 @@ $(function() {
...
@@ -43,7 +16,7 @@ $(function() {
var
vm
=
$
(
this
).
data
(
"vm"
);
var
vm
=
$
(
this
).
data
(
"vm"
);
$
.
ajax
({
$
.
ajax
({
type
:
'POST'
,
type
:
'POST'
,
url
:
"/dashboard/vm/"
+
vm
+
"/op/resources_change/"
,
url
:
$
(
this
).
parent
(
"form"
).
prop
(
'action'
)
,
data
:
$
(
'#vm-details-resources-form'
).
serialize
(),
data
:
$
(
'#vm-details-resources-form'
).
serialize
(),
success
:
function
(
data
,
textStatus
,
xhr
)
{
success
:
function
(
data
,
textStatus
,
xhr
)
{
if
(
data
.
success
)
{
if
(
data
.
success
)
{
...
@@ -89,17 +62,6 @@ $(function() {
...
@@ -89,17 +62,6 @@ $(function() {
return
false
;
return
false
;
});
});
/* remove port */
$
(
'.vm-details-remove-port'
).
click
(
function
()
{
addModalConfirmation
(
removePort
,
{
'url'
:
$
(
this
).
prop
(
"href"
),
'data'
:
[],
'rule'
:
$
(
this
).
data
(
"rule"
)
});
return
false
;
});
/* for js fallback */
/* for js fallback */
$
(
"#vm-details-pw-show"
).
parent
(
"div"
).
children
(
"input"
).
prop
(
"type"
,
"password"
);
$
(
"#vm-details-pw-show"
).
parent
(
"div"
).
children
(
"input"
).
prop
(
"type"
,
"password"
);
...
@@ -123,80 +85,6 @@ $(function() {
...
@@ -123,80 +85,6 @@ $(function() {
span
.
tooltip
();
span
.
tooltip
();
});
});
/* change password confirmation */
$
(
"#vm-details-pw-change"
).
click
(
function
()
{
$
(
"#vm-details-pw-confirm"
).
fadeIn
();
return
false
;
});
/* change password */
$
(
".vm-details-pw-confirm-choice"
).
click
(
function
()
{
choice
=
$
(
this
).
data
(
"choice"
);
if
(
choice
)
{
pk
=
$
(
this
).
data
(
"vm"
);
$
.
ajax
({
type
:
'POST'
,
url
:
"/dashboard/vm/"
+
pk
+
"/"
,
data
:
{
'change_password'
:
'true'
},
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
success
:
function
(
re
,
textStatus
,
xhr
)
{
location
.
reload
();
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
if
(
xhr
.
status
==
500
)
{
addMessage
(
"Internal Server Error"
,
"danger"
);
}
else
{
addMessage
(
xhr
.
status
+
" Unknown Error"
,
"danger"
);
}
}
});
}
else
{
$
(
"#vm-details-pw-confirm"
).
fadeOut
();
}
return
false
;
});
/* add network button */
$
(
"#vm-details-network-add"
).
click
(
function
()
{
$
(
"#vm-details-network-add-form"
).
toggle
();
return
false
;
});
/* add disk button */
$
(
"#vm-details-disk-add"
).
click
(
function
()
{
$
(
"#vm-details-disk-add-for-form"
).
html
(
$
(
"#vm-details-disk-add-form"
).
html
());
return
false
;
});
/* for interface remove buttons */
$
(
'.interface-remove'
).
click
(
function
()
{
var
interface_pk
=
$
(
this
).
data
(
'interface-pk'
);
addModalConfirmation
(
removeInterface
,
{
'url'
:
'/dashboard/interface/'
+
interface_pk
+
'/delete/'
,
'data'
:
[],
'pk'
:
interface_pk
,
'type'
:
"interface"
,
});
return
false
;
});
/* removing interface post */
function
removeInterface
(
data
)
{
$
.
ajax
({
type
:
'POST'
,
url
:
data
.
url
,
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
success
:
function
(
re
,
textStatus
,
xhr
)
{
/* remove the html element */
$
(
'a[data-interface-pk="'
+
data
.
pk
+
'"]'
).
closest
(
"div"
).
fadeOut
();
location
.
reload
();
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
addMessage
(
'Uh oh :('
,
'danger'
);
}
});
}
/* rename */
/* rename */
$
(
"#vm-details-h1-name, .vm-details-rename-button"
).
click
(
function
()
{
$
(
"#vm-details-h1-name, .vm-details-rename-button"
).
click
(
function
()
{
$
(
"#vm-details-h1-name"
).
hide
();
$
(
"#vm-details-h1-name"
).
hide
();
...
@@ -336,109 +224,3 @@ $(function() {
...
@@ -336,109 +224,3 @@ $(function() {
});
});
});
});
function
removePort
(
data
)
{
$
.
ajax
({
type
:
'POST'
,
url
:
data
.
url
,
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
success
:
function
(
re
,
textStatus
,
xhr
)
{
$
(
"a[data-rule="
+
data
.
rule
+
"]"
).
each
(
function
()
{
$
(
this
).
closest
(
"tr"
).
fadeOut
(
500
,
function
()
{
$
(
this
).
remove
();
});
});
addMessage
(
re
.
message
,
"success"
);
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
}
});
}
function
decideActivityRefresh
()
{
var
check
=
false
;
/* if something is still spinning */
if
(
$
(
'.timeline .activity i'
).
hasClass
(
'fa-spin'
))
check
=
true
;
return
check
;
}
function
checkNewActivity
(
runs
)
{
var
instance
=
location
.
href
.
split
(
'/'
);
instance
=
instance
[
instance
.
length
-
2
];
$
.
ajax
({
type
:
'GET'
,
url
:
'/dashboard/vm/'
+
instance
+
'/activity/'
,
data
:
{
'show_all'
:
show_all
},
success
:
function
(
data
)
{
var
new_activity_hash
=
(
data
.
activities
+
""
).
hashCode
();
if
(
new_activity_hash
!=
activity_hash
)
{
$
(
"#activity-refresh"
).
html
(
data
.
activities
);
}
activity_hash
=
new_activity_hash
;
$
(
"#ops"
).
html
(
data
.
ops
);
$
(
"#disk-ops"
).
html
(
data
.
disk_ops
);
$
(
"[title]"
).
tooltip
();
/* changing the status text */
var
icon
=
$
(
"#vm-details-state i"
);
if
(
data
.
is_new_state
)
{
if
(
!
icon
.
hasClass
(
"fa-spin"
))
icon
.
prop
(
"class"
,
"fa fa-spinner fa-spin"
);
}
else
{
icon
.
prop
(
"class"
,
"fa "
+
data
.
icon
);
}
$
(
"#vm-details-state"
).
data
(
"status"
,
data
[
'status'
]);
$
(
"#vm-details-state span"
).
html
(
data
[
'human_readable_status'
].
toUpperCase
());
if
(
data
[
'status'
]
==
"RUNNING"
)
{
if
(
data
[
'connect_uri'
])
{
$
(
"#dashboard-vm-details-connect-button"
).
removeClass
(
'disabled'
);
}
$
(
"[data-target=#_console]"
).
attr
(
"data-toggle"
,
"pill"
).
attr
(
"href"
,
"#console"
).
parent
(
"li"
).
removeClass
(
"disabled"
);
}
else
{
if
(
data
[
'connect_uri'
])
{
$
(
"#dashboard-vm-details-connect-button"
).
addClass
(
'disabled'
);
}
$
(
"[data-target=#_console]"
).
attr
(
"data-toggle"
,
"_pill"
).
attr
(
"href"
,
"#"
).
parent
(
"li"
).
addClass
(
"disabled"
);
}
if
(
data
.
status
==
"STOPPED"
||
data
.
status
==
"PENDING"
)
{
$
(
".change-resources-button"
).
prop
(
"disabled"
,
false
);
$
(
".change-resources-help"
).
hide
();
}
else
{
$
(
".change-resources-button"
).
prop
(
"disabled"
,
true
);
$
(
".change-resources-help"
).
show
();
}
if
(
runs
>
0
&&
decideActivityRefresh
())
{
setTimeout
(
function
()
{
checkNewActivity
(
runs
+
1
);},
1000
+
Math
.
exp
(
runs
*
0.05
)
);
}
else
{
in_progress
=
false
;
if
(
reload_vm_detail
)
location
.
reload
();
}
$
(
'a[href="#activity"] i'
).
removeClass
(
'fa-spin'
);
},
error
:
function
()
{
in_progress
=
false
;
}
});
}
String
.
prototype
.
hashCode
=
function
()
{
var
hash
=
0
,
i
,
chr
,
len
;
if
(
this
.
length
===
0
)
return
hash
;
for
(
i
=
0
,
len
=
this
.
length
;
i
<
len
;
i
++
)
{
chr
=
this
.
charCodeAt
(
i
);
hash
=
((
hash
<<
5
)
-
hash
)
+
chr
;
hash
|=
0
;
// Convert to 32bit integer
}
return
hash
;
};
circle/dashboard/templates/dashboard/confirm/ajax-delete.html
View file @
7fed7d2c
...
@@ -3,19 +3,25 @@
...
@@ -3,19 +3,25 @@
<div
class=
"modal-dialog"
>
<div
class=
"modal-dialog"
>
<div
class=
"modal-content"
>
<div
class=
"modal-content"
>
<div
class=
"modal-body"
>
<div
class=
"modal-body"
>
{% if text %}
{% if member %}
{{ text|safe }}
{% blocktrans with group=object member=member %}
Do you really want to remove
<strong>
{{ member }}
</strong>
from {{ group }}?
{% endblocktrans %}
{% else %}
{% else %}
{%
blocktrans with object=object
%}
{%
blocktrans with object=object
%}
Are you sure you want to delete
<strong>
{{ object }}
</strong>
?
Are you sure you want to delete
<strong>
{{ object }}
</strong>
?
{%
endblocktrans
%}
{%
endblocktrans
%}
{% endif %}
{% endif %}
<br
/>
<br
/>
<div
class=
"pull-right"
style=
"margin-top: 15px;"
>
<div
class=
"pull-right"
style=
"margin-top: 15px;"
>
<button
type=
"button"
class=
"btn btn-default"
data-dismiss=
"modal"
>
{% trans "Cancel" %}
</button>
<form
action=
"{{ request.path }}"
method=
"POST"
>
<button
id=
"confirmation-modal-button"
type=
"button"
class=
"btn btn-danger"
{% csrf_token %}
{%
if
disable_submit
%}
disabled
{%
endif
%}
<button
type=
"button"
class=
"btn btn-default"
data-dismiss=
"modal"
>
{% trans "Cancel" %}
</button>
>
{% trans "Delete" %}
</button>
<input
type=
"hidden"
name=
"next"
value=
"{{ request.GET.next }}"
/>
<button
class=
"btn btn-danger"
{%
if
disable_submit
%}
disabled
{%
endif
%}
>
{% trans "Delete" %}
</button>
</form>
</div>
</div>
<div
class=
"clearfix"
></div>
<div
class=
"clearfix"
></div>
</div>
</div>
...
...
circle/dashboard/templates/dashboard/confirm/ajax-node-status.html
deleted
100644 → 0
View file @
32e83265
{% load i18n %}
<div
class=
"modal fade"
id=
"confirmation-modal"
tabindex=
"-1"
role=
"dialog"
>
<div
class=
"modal-dialog"
>
<div
class=
"modal-content"
>
<div
class=
"modal-body"
>
{% if text %}
{{ text }}
{% else %}
{%blocktrans with object=object%}
Are you sure you want to change
<strong>
{{ object }}
</strong>
status?
{%endblocktrans%}
{% endif %}
<div
class=
"pull-right"
>
<form
action=
"{% url "
dashboard
.
views
.
status-node
"
pk=
object.pk
%}"
method=
"POST"
>
{% csrf_token %}
<button
type=
"button"
class=
"btn btn-default"
data-dismiss=
"modal"
>
{% trans "Cancel" %}
</button>
<input
type=
"hidden"
name=
"change_status"
value=
""
/>
<button
class=
"btn btn-warning"
>
{% blocktrans with status=status %}Yes, {{status}}{% endblocktrans %}
</button>
</form>
</div>
<div
class=
"clearfix"
></div>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
circle/dashboard/templates/dashboard/confirm/ajax-remove.html
deleted
100644 → 0
View file @
32e83265
{% load i18n %}
<div
class=
"modal fade"
id=
"confirmation-modal"
tabindex=
"-1"
role=
"dialog"
>
<div
class=
"modal-dialog"
>
<div
class=
"modal-content"
>
<div
class=
"modal-body"
>
{% if text %}
{{ text }}
{% else %}
{%blocktrans with object=object%}
Are you sure you want to remove
<strong>
{{ member }}
</strong>
from
<strong>
{{ object }}
</strong>
?
{%endblocktrans%}
{% endif %}
<br
/>
<div
class=
"pull-right"
style=
"margin-top: 15px;"
>
<button
type=
"button"
class=
"btn btn-default"
data-dismiss=
"modal"
>
Cancel
</button>
<button
id=
"confirmation-modal-button"
type=
"button"
class=
"btn btn-warning"
>
Remove
</button>
</div>
<div
class=
"clearfix"
></div>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
circle/dashboard/templates/dashboard/confirm/base-delete.html
View file @
7fed7d2c
...
@@ -17,12 +17,18 @@
...
@@ -17,12 +17,18 @@
{% if text %}
{% if text %}
{{ text|safe }}
{{ text|safe }}
{% else %}
{% else %}
{%blocktrans with object=object%}
{% if member %}
Are you sure you want to delete
<strong>
{{ object }}
</strong>
?
{% blocktrans with group=object member=member %}
{%endblocktrans%}
Do you really want to remove
<strong>
{{ member }}
</strong>
from {{ group }}?
{% endblocktrans %}
{% else %}
{% blocktrans with object=object %}
Are you sure you want to delete
<strong>
{{ object }}
</strong>
?
{% endblocktrans %}
{% endif %}
{% endif %}
{% endif %}
<div
class=
"pull-right"
>
<div
class=
"pull-right"
>
<form
action=
""
method=
"POST"
>
<form
action=
"
{{ request.path }}
"
method=
"POST"
>
{% csrf_token %}
{% csrf_token %}
<a
class=
"btn btn-default"
>
{% trans "Cancel" %}
</a>
<a
class=
"btn btn-default"
>
{% trans "Cancel" %}
</a>
<input
type=
"hidden"
name=
"next"
value=
"{{ request.GET.next }}"
/>
<input
type=
"hidden"
name=
"next"
value=
"{{ request.GET.next }}"
/>
...
...
circle/dashboard/templates/dashboard/confirm/base-remove.html
deleted
100644 → 0
View file @
32e83265
{% extends "base.html" %}
{% load i18n %}
{% block title-site %}Dashboard | CIRCLE{% endblock %}
{% block content %}
{% blocktrans with group=object member=member %}
Do you really want to remove {{member}} from {{group}}?
{% endblocktrans %}
<form
action=
""
method=
"POST"
>
{% csrf_token %}
<input
type=
"submit"
value=
"{% trans "
Remove
"
%}"
/>
</form>
{% endblock %}
circle/dashboard/templates/dashboard/confirm/base-renew.html
deleted
100644 → 0
View file @
32e83265
{% extends "dashboard/base.html" %}
{% load i18n %}
{% block content %}
<div
class=
"body-content"
>
<div
class=
"panel panel-default"
>
<div
class=
"panel-heading"
>
<h3
class=
"no-margin"
>
{%blocktrans with instance=instance.name%}
Renewing
<em>
{{instance}}
</em>
{%endblocktrans%}
</h3>
</div>
<div
class=
"panel-body"
>
{%blocktrans with object=instance.name%}
Do you want to renew
<strong>
{{ object }}
</strong>
?
{%endblocktrans%}
{%blocktrans with suspend=time_of_suspend delete=time_of_delete|default:"n/a" %}
The instance will be suspended at
<em>
{{suspend}}
</em>
and removed at
<em>
{{delete}}
</em>
if you renew it now.
{%endblocktrans%}
<div
class=
"pull-right"
>
<form
action=
""
method=
"POST"
>
{% csrf_token %}
<a
class=
"btn btn-default"
href=
"{{instance.get_absolute_path}}"
>
{% trans "Back" %}
</a>
<button
class=
"btn btn-danger"
>
{% trans "Renew" %}
</button>
</form>
</div>
</div>
</div>
{% endblock %}
circle/dashboard/templates/dashboard/confirm/mass-delete.html
deleted
100644 → 0
View file @
32e83265
{% load i18n %}
<div
class=
"modal fade"
id=
"confirmation-modal"
tabindex=
"-1"
role=
"dialog"
>
<div
class=
"modal-dialog"
>
<div
class=
"modal-content"
>
<div
class=
"modal-body"
>
{% trans "Are you sure you want to delete the following objects?" %}
<br
/>
{% for o in objects %}
<strong>
{{ o }}
</strong>
{% if not forloop.last %},{% endif %}
{% endfor %}
<div
class=
"pull-right"
style=
"margin-top: 40px;"
>
<button
type=
"button"
class=
"btn btn-default"
data-dismiss=
"modal"
>
{% trans "Cancel" %}
</button>
<button
id=
"confirmation-modal-button"
type=
"button"
class=
"btn btn-danger"
>
{% trans "Delete" %}
</button>
</div>
<div
class=
"clearfix"
></div>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
circle/dashboard/templates/dashboard/confirm/node-flush.html
deleted
100644 → 0
View file @
32e83265
{% extends "dashboard/base.html" %}
{% load i18n %}
{% block content %}
<div
class=
"body-content"
>
<div
class=
"panel panel-default"
>
<div
class=
"panel-heading"
>
<h3
class=
"no-margin"
>
{% if title %}
{{ title }}
{% else %}
Flush confirmation
{% endif %}
</h3>
</div>
<div
class=
"panel-body"
>
{% if text %}
{{ text }}
{% else %}
{%blocktrans with object=object%}
Are you sure you want to flush
<strong>
{{ object }}
</strong>
?
{%endblocktrans%}
{% endif %}
<div
class=
"pull-right"
>
<form
action=
""
method=
"POST"
>
{% csrf_token %}
<a
class=
"btn btn-default"
>
{% trans "Back" %}
</a>
<input
type=
"hidden"
name=
"flush"
value=
""
/>
<button
class=
"btn btn-warning"
>
{% trans "Yes" %}
</button>
</form>
</div>
</div>
</div>
{% endblock %}
circle/dashboard/templates/dashboard/confirm/node-status.html
deleted
100644 → 0
View file @
32e83265
{% extends "dashboard/base.html" %}
{% load i18n %}
{% block content %}
<div
class=
"body-content"
>
<div
class=
"panel panel-default"
>
<div
class=
"panel-heading"
>
<h3
class=
"no-margin"
>
{% if title %}
{{ title }}
{% else %}
{% trans "Status changing confirmation" %}
{% endif %}
</h3>
</div>
<div
class=
"panel-body"
>
{% if text %}
{{ text }}
{% else %}
{%blocktrans with object=object%}
Are you sure you want to change
<strong>
{{ object }}
</strong>
status?
{%endblocktrans%}
{% endif %}
<div
class=
"pull-right"
>
<form
action=
""
method=
"POST"
>
{% csrf_token %}
<a
class=
"btn btn-default"
>
{% trans "Cancel" %}
</a>
<button
type=
"button"
class=
"btn btn-default"
data-dismiss=
"modal"
></button>
<input
type=
"hidden"
name=
"change_status"
value=
""
/>
<button
class=
"btn btn-warning"
>
{% blocktrans with status=status %}Yes, {{status}}{% endblocktrans %}
</button>
</form>
</div>
</div>
</div>
{% endblock %}
circle/dashboard/templates/dashboard/group-list/column-name.html
View file @
7fed7d2c
...
@@ -7,6 +7,6 @@
...
@@ -7,6 +7,6 @@
<button
type=
"submit"
class=
"group-list-rename-submit btn btn-sm"
>
{% trans "Rename" %}
</button>
<button
type=
"submit"
class=
"group-list-rename-submit btn btn-sm"
>
{% trans "Rename" %}
</button>
</form>
</form>
</div>
</div>
<div
id
=
"group-list-column-name"
>
<div
class
=
"group-list-column-name"
>
<a
class=
"real-link"
href=
"{% url "
dashboard
.
views
.
group-detail
"
pk=
record.pk
%}"
>
{{ record.name }}
</a>
<a
class=
"real-link"
href=
"{% url "
dashboard
.
views
.
group-detail
"
pk=
record.pk
%}"
>
{{ record.name }}
</a>
</div>
</div>
circle/dashboard/templates/dashboard/index-templates.html
View file @
7fed7d2c
...
@@ -16,7 +16,7 @@
...
@@ -16,7 +16,7 @@
<i
class=
"fa fa-{{ t.os_type }}"
></i>
{{ t.name }}
<i
class=
"fa fa-{{ t.os_type }}"
></i>
{{ t.name }}
</span>
</span>
<small
class=
"text-muted index-template-list-system"
>
{{ t.system }}
</small>
<small
class=
"text-muted index-template-list-system"
>
{{ t.system }}
</small>
<div
class=
"pull-right vm-create"
data-template=
"{{ t.pk }}
"
>
<div
href=
"{% url "
dashboard
.
views
.
vm-create
"
%}?
template=
{{
t
.
pk
}}"
class=
"pull-right vm-create
"
>
<i
data-container=
"body"
title=
"{% trans "
Start
VM
instance
"
%}"
<i
data-container=
"body"
title=
"{% trans "
Start
VM
instance
"
%}"
class=
"fa fa-play"
></i>
class=
"fa fa-play"
></i>
</div>
</div>
...
...
circle/dashboard/templates/dashboard/modal-wrapper.html
deleted
100644 → 0
View file @
32e83265
<div
class=
"modal fade"
id=
"create-modal"
tabindex=
"-1"
role=
"dialog"
>
<div
class=
"modal-dialog"
>
<div
class=
"modal-content"
>
{% if box_title and ajax_title %}
<div
class=
"modal-header"
>
<button
type=
"button"
class=
"close"
data-dismiss=
"modal"
aria-hidden=
"true"
>
×
</button>
<h4
class=
"modal-title"
>
{{ box_title }}
</h4>
</div>
{% endif %}
<div
class=
"modal-body"
>
{% include template %}
</div>
<!--<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>-->
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
circle/dashboard/templates/dashboard/node-detail.html
View file @
7fed7d2c
...
@@ -80,7 +80,8 @@
...
@@ -80,7 +80,8 @@
</a>
</a>
</li>
</li>
<li>
<li>
<a
href=
"#activity"
data-toggle=
"pill"
class=
"text-center"
>
<a
href=
"#activity"
data-toggle=
"pill"
class=
"text-center"
data-activity-url=
"{% url "
dashboard
.
views
.
node-activity-list
"
node
.
pk
%}"
>
<i
class=
"fa fa-clock-o fa-2x"
></i><br>
<i
class=
"fa fa-clock-o fa-2x"
></i><br>
{% trans "Activity" %}
{% trans "Activity" %}
</a>
</a>
...
...
circle/dashboard/templates/dashboard/node-detail/_activity-timeline.html
View file @
7fed7d2c
{% load i18n %}
{% load i18n %}
{% load hro %}
{% load hro %}
<div
id=
"activity-timeline"
class=
"timeline"
>
<div
id=
"activity-timeline"
class=
"timeline"
>
{% for a in activities %}
{% for a in activities %}
<div
class=
"activity"
data-activity-id=
"{{ a.pk }}"
>
<div
class=
"activity"
data-activity-id=
"{{ a.pk }}"
>
<span
class=
"timeline-icon{% if a.has_failed %} timeline-icon-failed{% endif %}"
>
<span
class=
"timeline-icon{% if a.has_failed %} timeline-icon-failed{% endif %}"
>
<i
class=
"fa {% if not a.finished %}fa-refresh fa-spin {% else %}fa-plus{% endif %}"
></i>
<i
class=
"fa {% if not a.finished %}fa-refresh fa-spin {% else %}fa-plus{% endif %}"
></i>
</span>
</span>
<strong
title=
"{{ a.result.get_admin_text }}"
>
<strong
title=
"{{ a.result.get_admin_text }}"
>
{{ a.readable_name.get_admin_text|capfirst }}
{{ a.readable_name.get_admin_text|capfirst }}
</strong>
</strong>
{{ a.started|date:"Y-m-d H:i" }}, {{ a.user }}
{{ a.started|date:"Y-m-d H:i" }}{% if a.user %}, {{ a.user }}{% endif %}
{% if a.children.count > 0 %}
{% if a.children.count > 0 %}
<div
class=
"sub-timeline"
>
<div
class=
"sub-timeline"
>
{% for s in a.children.all %}
{% for s in a.children.all %}
<div
data-activity-id=
"{{ s.pk }}"
<div
data-activity-id=
"{{ s.pk }}"
class=
"sub-activity{% if s.has_failed %} sub-activity-failed{% endif %}"
class=
"sub-activity{% if s.has_failed %} sub-activity-failed{% endif %}"
>
>
<span
title=
"{{ s.result.get_admin_text }}"
>
{{ s.readable_name|get_text:user }}
{{ s.readable_name|get_text:user }}
–
</span>
{% if s.finished %}
–
{{ s.finished|time:"H:i:s" }}
{% if s.finished %}
{% else %}
{{ s.finished|time:"H:i:s" }}
<i
class=
"fa fa-refresh fa-spin"
class=
"sub-activity-loading-icon"
></i>
{% else %}
{% endif %}
<i
class=
"fa fa-refresh fa-spin"
class=
"sub-activity-loading-icon"
></i>
{% if s.has_failed %}
{% endif %}
<div
title=
"{{ s.result.get_admin_text }}"
class=
"label label-danger"
>
{% trans "failed" %}
</div>
{% if s.has_failed %}
{% endif %}
<div
class=
"label label-danger"
>
{% trans "failed" %}
</div>
</div>
{% endif %}
{% endfor %}
</div>
</div>
{% endfor %}
{% endif %}
</div>
{% endif %}
</div>
</div>
{% endfor %}
{% endfor %}
</div>
</div>
circle/dashboard/templates/dashboard/node-detail/activity.html
View file @
7fed7d2c
...
@@ -2,6 +2,6 @@
...
@@ -2,6 +2,6 @@
<h3>
{% trans "Activity" %}
</h3>
<h3>
{% trans "Activity" %}
</h3>
<div
id=
"activity-
timeline-wrapper
"
>
<div
id=
"activity-
refresh
"
>
{% include "dashboard/node-detail/_activity-timeline.html" %}
{% include "dashboard/node-detail/_activity-timeline.html" %}
</div>
</div>
circle/dashboard/templates/dashboard/vm-detail.html
View file @
7fed7d2c
...
@@ -207,7 +207,8 @@
...
@@ -207,7 +207,8 @@
{% trans "Network" %}
</a>
{% trans "Network" %}
</a>
</li>
</li>
<li>
<li>
<a
href=
"#activity"
data-toggle=
"pill"
data-target=
"#_activity"
class=
"text-center"
>
<a
href=
"#activity"
data-toggle=
"pill"
data-target=
"#_activity"
class=
"text-center"
data-activity-url=
"{% url "
dashboard
.
views
.
vm-activity-list
"
instance
.
pk
%}"
>
<i
class=
"fa fa-clock-o fa-2x"
></i><br>
<i
class=
"fa fa-clock-o fa-2x"
></i><br>
{% trans "Activity" %}
</a>
{% trans "Activity" %}
</a>
</li>
</li>
...
...
circle/dashboard/templates/dashboard/vm-detail/network.html
View file @
7fed7d2c
...
@@ -21,13 +21,14 @@
...
@@ -21,13 +21,14 @@
<a
href=
"{{ i.host.get_absolute_url }}"
<a
href=
"{{ i.host.get_absolute_url }}"
class=
"btn btn-default btn-xs"
>
{% trans "edit" %}
</a>
class=
"btn btn-default btn-xs"
>
{% trans "edit" %}
</a>
{% endif %}
{% endif %}
{%
if is_owner
%}
{%
with op=op.remove_interface %}{% if op
%}
<a
href=
"{% url "
dashboard
.
views
.
interface-delete
"
pk=
i.pk
%}?
next=
{{
request
.
path
}}"
<span
class=
"operation-wrapper"
>
class=
"btn btn-danger btn-xs interface-remove
"
<a
href=
"{{op.get_url}}?interface={{ i.pk }}
"
data-interface-pk=
"{{ i.pk }}"
>
class=
"btn btn-{{op.effect}} btn-xs operation interface-remove"
{% trans "remove" %}
{%
if
op
.
disabled
%}
disabled
{%
endif
%}
>
{% trans "remove" %}
</a>
</a>
{% endif %}
</span>
{% endif %}{% endwith %}
</h3>
</h3>
{% if i.host %}
{% if i.host %}
<div
class=
"row"
>
<div
class=
"row"
>
...
@@ -78,7 +79,13 @@
...
@@ -78,7 +79,13 @@
{{ l.private }}/{{ l.proto }}
{{ l.private }}/{{ l.proto }}
</td>
</td>
<td>
<td>
<a
href=
"{{ op.remove_port.get_url }}?rule={{ l.ipv4.pk }}"
class=
"btn btn-link btn-xs vm-details-remove-port"
data-rule=
"{{ l.ipv4.pk }}"
title=
"{% trans "
Remove
"
%}"
><i
class=
"fa fa-times"
><span
class=
"sr-only"
>
{% trans "Remove" %}
</span></i></a>
<span
class=
"operation-wrapper"
>
<a
href=
"{{ op.remove_port.get_url }}?rule={{ l.ipv4.pk }}"
class=
"btn btn-link btn-xs operation"
title=
"{% trans "
Remove
"
%}"
>
<i
class=
"fa fa-times"
><span
class=
"sr-only"
>
{% trans "Remove" %}
</span></i>
</a>
</span>
</td>
</td>
</tr>
</tr>
{% endif %}
{% endif %}
...
...
circle/dashboard/tests/test_views.py
View file @
7fed7d2c
...
@@ -27,7 +27,7 @@ from django.contrib.auth import authenticate
...
@@ -27,7 +27,7 @@ from django.contrib.auth import authenticate
from
dashboard.views
import
VmAddInterfaceView
from
dashboard.views
import
VmAddInterfaceView
from
vm.models
import
Instance
,
InstanceTemplate
,
Lease
,
Node
,
Trait
from
vm.models
import
Instance
,
InstanceTemplate
,
Lease
,
Node
,
Trait
from
vm.operations
import
(
WakeUpOperation
,
AddInterfaceOperation
,
from
vm.operations
import
(
WakeUpOperation
,
AddInterfaceOperation
,
AddPortOperation
)
AddPortOperation
,
RemoveInterfaceOperation
)
from
..models
import
Profile
from
..models
import
Profile
from
firewall.models
import
Vlan
,
Host
,
VlanGroup
from
firewall.models
import
Vlan
,
Host
,
VlanGroup
from
mock
import
Mock
,
patch
from
mock
import
Mock
,
patch
...
@@ -169,26 +169,12 @@ class VmDetailTest(LoginMixin, TestCase):
...
@@ -169,26 +169,12 @@ class VmDetailTest(LoginMixin, TestCase):
inst
.
save
()
inst
.
save
()
iface_count
=
inst
.
interface_set
.
count
()
iface_count
=
inst
.
interface_set
.
count
()
c
.
post
(
"/dashboard/interface/1/delete/"
)
with
patch
.
object
(
RemoveInterfaceOperation
,
'async'
)
as
mock_method
:
self
.
assertEqual
(
inst
.
interface_set
.
count
(),
iface_count
-
1
)
mock_method
.
side_effect
=
inst
.
remove_interface
response
=
c
.
post
(
"/dashboard/vm/1/op/remove_interface/"
,
def
test_permitted_network_delete_w_ajax
(
self
):
{
'interface'
:
1
})
c
=
Client
()
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
login
(
c
,
"user1"
)
assert
mock_method
.
called
inst
=
Instance
.
objects
.
get
(
pk
=
1
)
inst
.
set_level
(
self
.
u1
,
'owner'
)
vlan
=
Vlan
.
objects
.
get
(
pk
=
1
)
inst
.
add_interface
(
vlan
=
vlan
,
user
=
self
.
us
)
inst
.
status
=
'RUNNING'
inst
.
save
()
iface_count
=
inst
.
interface_set
.
count
()
response
=
c
.
post
(
"/dashboard/interface/1/delete/"
,
HTTP_X_REQUESTED_WITH
=
'XMLHttpRequest'
)
removed_network
=
json
.
loads
(
response
.
content
)[
'removed_network'
]
self
.
assertEqual
(
removed_network
[
'vlan'
],
vlan
.
name
)
self
.
assertEqual
(
removed_network
[
'vlan_pk'
],
vlan
.
pk
)
self
.
assertEqual
(
removed_network
[
'managed'
],
vlan
.
managed
)
self
.
assertEqual
(
inst
.
interface_set
.
count
(),
iface_count
-
1
)
self
.
assertEqual
(
inst
.
interface_set
.
count
(),
iface_count
-
1
)
def
test_unpermitted_network_delete
(
self
):
def
test_unpermitted_network_delete
(
self
):
...
@@ -199,7 +185,10 @@ class VmDetailTest(LoginMixin, TestCase):
...
@@ -199,7 +185,10 @@ class VmDetailTest(LoginMixin, TestCase):
inst
.
add_interface
(
vlan
=
Vlan
.
objects
.
get
(
pk
=
1
),
user
=
self
.
us
)
inst
.
add_interface
(
vlan
=
Vlan
.
objects
.
get
(
pk
=
1
),
user
=
self
.
us
)
iface_count
=
inst
.
interface_set
.
count
()
iface_count
=
inst
.
interface_set
.
count
()
response
=
c
.
post
(
"/dashboard/interface/1/delete/"
)
with
patch
.
object
(
RemoveInterfaceOperation
,
'async'
)
as
mock_method
:
mock_method
.
side_effect
=
inst
.
remove_interface
response
=
c
.
post
(
"/dashboard/vm/1/op/remove_interface/"
,
{
'interface'
:
1
})
self
.
assertEqual
(
iface_count
,
inst
.
interface_set
.
count
())
self
.
assertEqual
(
iface_count
,
inst
.
interface_set
.
count
())
self
.
assertEqual
(
response
.
status_code
,
403
)
self
.
assertEqual
(
response
.
status_code
,
403
)
...
@@ -766,42 +755,6 @@ class NodeDetailTest(LoginMixin, TestCase):
...
@@ -766,42 +755,6 @@ class NodeDetailTest(LoginMixin, TestCase):
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
assertEqual
(
len
(
Node
.
objects
.
get
(
pk
=
1
)
.
traits
.
all
()),
trait_count
)
self
.
assertEqual
(
len
(
Node
.
objects
.
get
(
pk
=
1
)
.
traits
.
all
()),
trait_count
)
def
test_anon_change_node_status
(
self
):
c
=
Client
()
node
=
Node
.
objects
.
get
(
pk
=
1
)
node_enabled
=
node
.
enabled
response
=
c
.
post
(
"/dashboard/node/1/"
,
{
'change_status'
:
''
})
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
assertEqual
(
node_enabled
,
Node
.
objects
.
get
(
pk
=
1
)
.
enabled
)
def
test_unpermitted_change_node_status
(
self
):
c
=
Client
()
self
.
login
(
c
,
"user2"
)
node
=
Node
.
objects
.
get
(
pk
=
1
)
node_enabled
=
node
.
enabled
response
=
c
.
post
(
"/dashboard/node/status/1/"
,
{
'change_status'
:
''
})
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
assertEqual
(
node_enabled
,
Node
.
objects
.
get
(
pk
=
1
)
.
enabled
)
def
test_permitted_change_node_status
(
self
):
c
=
Client
()
self
.
login
(
c
,
"superuser"
)
node
=
Node
.
objects
.
get
(
pk
=
1
)
node_enabled
=
node
.
enabled
response
=
c
.
post
(
"/dashboard/node/status/1/"
,
{
'change_status'
:
''
})
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
assertEqual
(
node_enabled
,
not
Node
.
objects
.
get
(
pk
=
1
)
.
enabled
)
def
test_permitted_change_node_status_w_ajax
(
self
):
c
=
Client
()
self
.
login
(
c
,
"superuser"
)
node
=
Node
.
objects
.
get
(
pk
=
1
)
node_enabled
=
node
.
enabled
response
=
c
.
post
(
"/dashboard/node/status/1/"
,
{
'change_status'
:
''
},
HTTP_X_REQUESTED_WITH
=
'XMLHttpRequest'
)
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
node_enabled
,
not
Node
.
objects
.
get
(
pk
=
1
)
.
enabled
)
class
GroupCreateTest
(
LoginMixin
,
TestCase
):
class
GroupCreateTest
(
LoginMixin
,
TestCase
):
fixtures
=
[
'test-vm-fixture.json'
,
'node.json'
]
fixtures
=
[
'test-vm-fixture.json'
,
'node.json'
]
...
@@ -949,21 +902,26 @@ class GroupDeleteTest(LoginMixin, TestCase):
...
@@ -949,21 +902,26 @@ class GroupDeleteTest(LoginMixin, TestCase):
def
test_permitted_group_page
(
self
):
def
test_permitted_group_page
(
self
):
c
=
Client
()
c
=
Client
()
self
.
login
(
c
,
'user0'
)
self
.
login
(
c
,
'user0'
)
response
=
c
.
get
(
'/dashboard/group/delete/'
+
str
(
self
.
g1
.
pk
)
+
'/'
)
with
patch
(
'dashboard.views.util.messages'
)
as
msg
:
response
=
c
.
get
(
'/dashboard/group/delete/
%
d/'
%
self
.
g1
.
pk
)
assert
not
msg
.
error
.
called
and
not
msg
.
warning
.
called
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertEqual
(
response
.
status_code
,
200
)
def
test_unpermitted_group_page
(
self
):
def
test_unpermitted_group_page
(
self
):
c
=
Client
()
c
=
Client
()
self
.
login
(
c
,
'user1'
)
self
.
login
(
c
,
'user1'
)
response
=
c
.
get
(
'/dashboard/group/delete/'
+
str
(
self
.
g1
.
pk
)
+
'/'
)
with
patch
(
'dashboard.views.util.messages'
)
as
msg
:
self
.
assertEqual
(
response
.
status_code
,
403
)
response
=
c
.
get
(
'/dashboard/group/delete/
%
d/'
%
self
.
g1
.
pk
)
assert
msg
.
error
.
called
or
msg
.
warning
.
called
self
.
assertEqual
(
response
.
status_code
,
302
)
def
test_anon_group_delete
(
self
):
def
test_anon_group_delete
(
self
):
c
=
Client
()
c
=
Client
()
groupnum
=
Group
.
objects
.
count
()
response
=
c
.
get
(
'/dashboard/group/delete/
%
d/'
%
self
.
g1
.
pk
)
response
=
c
.
post
(
'/dashboard/group/delete/'
+
str
(
self
.
g1
.
pk
)
+
'/'
)
self
.
assertRedirects
(
response
,
'/accounts/login/?next=/dashboard/group/delete/5/'
,
status_code
=
302
)
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
assertEqual
(
Group
.
objects
.
count
(),
groupnum
)
def
test_unpermitted_group_delete
(
self
):
def
test_unpermitted_group_delete
(
self
):
c
=
Client
()
c
=
Client
()
...
@@ -1484,38 +1442,6 @@ class TransferOwnershipViewTest(LoginMixin, TestCase):
...
@@ -1484,38 +1442,6 @@ class TransferOwnershipViewTest(LoginMixin, TestCase):
response
=
c
.
post
(
'/dashboard/vm/1/tx/'
,
{
'name'
:
'user2'
})
response
=
c
.
post
(
'/dashboard/vm/1/tx/'
,
{
'name'
:
'user2'
})
self
.
assertEqual
(
self
.
u2
.
notification_set
.
count
(),
c2
+
1
)
self
.
assertEqual
(
self
.
u2
.
notification_set
.
count
(),
c2
+
1
)
def
test_transfer
(
self
):
self
.
skipTest
(
"How did this ever pass?"
)
c
=
Client
()
self
.
login
(
c
,
'user1'
)
response
=
c
.
post
(
'/dashboard/vm/1/tx/'
,
{
'name'
:
'user2'
})
url
=
response
.
context
[
'token'
]
c
=
Client
()
self
.
login
(
c
,
'user2'
)
response
=
c
.
post
(
url
)
self
.
assertEquals
(
Instance
.
objects
.
get
(
pk
=
1
)
.
owner
.
pk
,
self
.
u2
.
pk
)
def
test_transfer_token_used_by_others
(
self
):
self
.
skipTest
(
"How did this ever pass?"
)
c
=
Client
()
self
.
login
(
c
,
'user1'
)
response
=
c
.
post
(
'/dashboard/vm/1/tx/'
,
{
'name'
:
'user2'
})
url
=
response
.
context
[
'token'
]
response
=
c
.
post
(
url
)
# token is for user2
assert
response
.
status_code
==
403
self
.
assertEquals
(
Instance
.
objects
.
get
(
pk
=
1
)
.
owner
.
pk
,
self
.
u1
.
pk
)
def
test_transfer_by_superuser
(
self
):
self
.
skipTest
(
"How did this ever pass?"
)
c
=
Client
()
self
.
login
(
c
,
'superuser'
)
response
=
c
.
post
(
'/dashboard/vm/1/tx/'
,
{
'name'
:
'user2'
})
url
=
response
.
context
[
'token'
]
c
=
Client
()
self
.
login
(
c
,
'user2'
)
response
=
c
.
post
(
url
)
self
.
assertEquals
(
Instance
.
objects
.
get
(
pk
=
1
)
.
owner
.
pk
,
self
.
u2
.
pk
)
class
IndexViewTest
(
LoginMixin
,
TestCase
):
class
IndexViewTest
(
LoginMixin
,
TestCase
):
fixtures
=
[
'test-vm-fixture.json'
,
'node.json'
]
fixtures
=
[
'test-vm-fixture.json'
,
'node.json'
]
...
...
circle/dashboard/urls.py
View file @
7fed7d2c
...
@@ -25,12 +25,12 @@ from .views import (
...
@@ -25,12 +25,12 @@ from .views import (
GroupDetailView
,
GroupList
,
IndexView
,
GroupDetailView
,
GroupList
,
IndexView
,
InstanceActivityDetail
,
LeaseCreate
,
LeaseDelete
,
LeaseDetail
,
InstanceActivityDetail
,
LeaseCreate
,
LeaseDelete
,
LeaseDetail
,
MyPreferencesView
,
NodeAddTraitView
,
NodeCreate
,
NodeDelete
,
MyPreferencesView
,
NodeAddTraitView
,
NodeCreate
,
NodeDelete
,
NodeDetailView
,
NodeList
,
NodeStatus
,
NodeDetailView
,
NodeList
,
NotificationView
,
TemplateAclUpdateView
,
TemplateCreate
,
NotificationView
,
TemplateAclUpdateView
,
TemplateCreate
,
TemplateDelete
,
TemplateDetail
,
TemplateList
,
TemplateDelete
,
TemplateDetail
,
TemplateList
,
vm_activity
,
VmCreate
,
VmDetailView
,
vm_activity
,
VmCreate
,
VmDetailView
,
VmDetailVncTokenView
,
VmList
,
VmDetailVncTokenView
,
VmList
,
DiskRemoveView
,
get_disk_download_status
,
InterfaceDeleteView
,
DiskRemoveView
,
get_disk_download_status
,
GroupRemoveUserView
,
GroupRemoveUserView
,
GroupRemoveFutureUserView
,
GroupRemoveFutureUserView
,
GroupCreate
,
GroupProfileUpdate
,
GroupCreate
,
GroupProfileUpdate
,
...
@@ -51,6 +51,7 @@ from .views import (
...
@@ -51,6 +51,7 @@ from .views import (
TransferInstanceOwnershipView
,
TransferInstanceOwnershipConfirmView
,
TransferInstanceOwnershipView
,
TransferInstanceOwnershipConfirmView
,
TransferTemplateOwnershipView
,
TransferTemplateOwnershipConfirmView
,
TransferTemplateOwnershipView
,
TransferTemplateOwnershipConfirmView
,
OpenSearchDescriptionView
,
OpenSearchDescriptionView
,
NodeActivityView
,
)
)
from
.views.vm
import
vm_ops
,
vm_mass_ops
from
.views.vm
import
vm_ops
,
vm_mass_ops
from
.views.node
import
node_ops
from
.views.node
import
node_ops
...
@@ -94,7 +95,8 @@ urlpatterns = patterns(
...
@@ -94,7 +95,8 @@ urlpatterns = patterns(
url
(
r'^vm/list/$'
,
VmList
.
as_view
(),
name
=
'dashboard.views.vm-list'
),
url
(
r'^vm/list/$'
,
VmList
.
as_view
(),
name
=
'dashboard.views.vm-list'
),
url
(
r'^vm/create/$'
,
VmCreate
.
as_view
(),
url
(
r'^vm/create/$'
,
VmCreate
.
as_view
(),
name
=
'dashboard.views.vm-create'
),
name
=
'dashboard.views.vm-create'
),
url
(
r'^vm/(?P<pk>\d+)/activity/$'
,
vm_activity
),
url
(
r'^vm/(?P<pk>\d+)/activity/$'
,
vm_activity
,
name
=
'dashboard.views.vm-activity-list'
),
url
(
r'^vm/activity/(?P<pk>\d+)/$'
,
InstanceActivityDetail
.
as_view
(),
url
(
r'^vm/activity/(?P<pk>\d+)/$'
,
InstanceActivityDetail
.
as_view
(),
name
=
'dashboard.views.vm-activity'
),
name
=
'dashboard.views.vm-activity'
),
url
(
r'^vm/(?P<pk>\d+)/screenshot/$'
,
get_vm_screenshot
,
url
(
r'^vm/(?P<pk>\d+)/screenshot/$'
,
get_vm_screenshot
,
...
@@ -119,8 +121,8 @@ urlpatterns = patterns(
...
@@ -119,8 +121,8 @@ urlpatterns = patterns(
name
=
'dashboard.views.template-transfer-ownership-confirm'
),
name
=
'dashboard.views.template-transfer-ownership-confirm'
),
url
(
r'^node/delete/(?P<pk>\d+)/$'
,
NodeDelete
.
as_view
(),
url
(
r'^node/delete/(?P<pk>\d+)/$'
,
NodeDelete
.
as_view
(),
name
=
"dashboard.views.delete-node"
),
name
=
"dashboard.views.delete-node"
),
url
(
r'^node/
status/(?P<pk>\d+)/$'
,
NodeStatus
.
as_view
(),
url
(
r'^node/
(?P<pk>\d+)/activity/$'
,
NodeActivityView
.
as_view
(),
name
=
"dashboard.views.status-node"
),
name
=
'dashboard.views.node-activity-list'
),
url
(
r'^node/create/$'
,
NodeCreate
.
as_view
(),
url
(
r'^node/create/$'
,
NodeCreate
.
as_view
(),
name
=
'dashboard.views.node-create'
),
name
=
'dashboard.views.node-create'
),
...
@@ -156,9 +158,6 @@ urlpatterns = patterns(
...
@@ -156,9 +158,6 @@ urlpatterns = patterns(
url
(
r'^disk/(?P<pk>\d+)/status/$'
,
get_disk_download_status
,
url
(
r'^disk/(?P<pk>\d+)/status/$'
,
get_disk_download_status
,
name
=
"dashboard.views.disk-status"
),
name
=
"dashboard.views.disk-status"
),
url
(
r'^interface/(?P<pk>\d+)/delete/$'
,
InterfaceDeleteView
.
as_view
(),
name
=
"dashboard.views.interface-delete"
),
url
(
r'^profile/$'
,
MyPreferencesView
.
as_view
(),
url
(
r'^profile/$'
,
MyPreferencesView
.
as_view
(),
name
=
"dashboard.views.profile-preferences"
),
name
=
"dashboard.views.profile-preferences"
),
url
(
r'^subscribe/(?P<token>.*)/$'
,
UnsubscribeFormView
.
as_view
(),
url
(
r'^subscribe/(?P<token>.*)/$'
,
UnsubscribeFormView
.
as_view
(),
...
...
circle/dashboard/views/group.py
View file @
7fed7d2c
...
@@ -29,7 +29,7 @@ from django.core.urlresolvers import reverse, reverse_lazy
...
@@ -29,7 +29,7 @@ from django.core.urlresolvers import reverse, reverse_lazy
from
django.http
import
HttpResponse
,
Http404
from
django.http
import
HttpResponse
,
Http404
from
django.shortcuts
import
redirect
from
django.shortcuts
import
redirect
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
django.views.generic
import
UpdateView
,
DeleteView
,
TemplateView
from
django.views.generic
import
UpdateView
,
TemplateView
from
braces.views
import
SuperuserRequiredMixin
,
LoginRequiredMixin
from
braces.views
import
SuperuserRequiredMixin
,
LoginRequiredMixin
from
django_tables2
import
SingleTableView
from
django_tables2
import
SingleTableView
...
@@ -41,7 +41,8 @@ from ..forms import (
...
@@ -41,7 +41,8 @@ from ..forms import (
from
..models
import
FutureMember
,
GroupProfile
from
..models
import
FutureMember
,
GroupProfile
from
vm.models
import
Instance
,
InstanceTemplate
from
vm.models
import
Instance
,
InstanceTemplate
from
..tables
import
GroupListTable
from
..tables
import
GroupListTable
from
.util
import
CheckedDetailView
,
AclUpdateView
,
search_user
,
saml_available
from
.util
import
(
CheckedDetailView
,
AclUpdateView
,
search_user
,
saml_available
,
DeleteViewBase
)
logger
=
logging
.
getLogger
(
__name__
)
logger
=
logging
.
getLogger
(
__name__
)
...
@@ -224,15 +225,18 @@ class GroupList(LoginRequiredMixin, SingleTableView):
...
@@ -224,15 +225,18 @@ class GroupList(LoginRequiredMixin, SingleTableView):
return
groups
return
groups
class
GroupRemoveUserView
(
CheckedDetailView
,
DeleteView
):
class
GroupRemoveUserView
(
DeleteViewBase
):
model
=
Group
model
=
Group
slug_field
=
'pk'
slug_field
=
'pk'
slug_url_kwarg
=
'group_pk'
slug_url_kwarg
=
'group_pk'
read_
level
=
'operator'
level
=
'operator'
member_key
=
'member_pk'
member_key
=
'member_pk'
success_message
=
_
(
"Member successfully removed from group."
)
def
get_has_level
(
self
):
def
check_auth
(
self
):
return
self
.
object
.
profile
.
has_level
if
not
self
.
get_object
()
.
profile
.
has_level
(
self
.
request
.
user
,
self
.
level
):
raise
PermissionDenied
()
def
get_context_data
(
self
,
**
kwargs
):
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
GroupRemoveUserView
,
self
)
.
get_context_data
(
**
kwargs
)
context
=
super
(
GroupRemoveUserView
,
self
)
.
get_context_data
(
**
kwargs
)
...
@@ -243,50 +247,24 @@ class GroupRemoveUserView(CheckedDetailView, DeleteView):
...
@@ -243,50 +247,24 @@ class GroupRemoveUserView(CheckedDetailView, DeleteView):
return
context
return
context
def
get_success_url
(
self
):
def
get_success_url
(
self
):
next
=
self
.
request
.
POST
.
get
(
'next'
)
return
reverse_lazy
(
"dashboard.views.group-detail"
,
if
next
:
kwargs
=
{
'pk'
:
self
.
get_object
()
.
pk
})
return
next
else
:
return
reverse_lazy
(
"dashboard.views.group-detail"
,
kwargs
=
{
'pk'
:
self
.
get_object
()
.
pk
})
def
get
(
self
,
request
,
member_pk
,
*
args
,
**
kwargs
):
def
get
(
self
,
request
,
member_pk
,
*
args
,
**
kwargs
):
self
.
member_pk
=
member_pk
self
.
member_pk
=
member_pk
return
super
(
GroupRemoveUserView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
return
super
(
GroupRemoveUserView
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
return
[
'dashboard/confirm/ajax-remove.html'
]
else
:
return
[
'dashboard/confirm/base-remove.html'
]
def
remove_member
(
self
,
pk
):
def
remove_member
(
self
,
pk
):
container
=
self
.
get_object
()
container
=
self
.
get_object
()
container
.
user_set
.
remove
(
User
.
objects
.
get
(
pk
=
pk
))
container
.
user_set
.
remove
(
User
.
objects
.
get
(
pk
=
pk
))
def
get_success_message
(
self
):
def
delete_obj
(
self
,
request
,
*
args
,
**
kwargs
):
return
_
(
"Member successfully removed from group."
)
def
delete
(
self
,
request
,
*
args
,
**
kwargs
):
object
=
self
.
get_object
()
if
not
object
.
profile
.
has_level
(
request
.
user
,
'operator'
):
raise
PermissionDenied
()
self
.
remove_member
(
kwargs
[
self
.
member_key
])
self
.
remove_member
(
kwargs
[
self
.
member_key
])
success_url
=
self
.
get_success_url
()
success_message
=
self
.
get_success_message
()
if
request
.
is_ajax
():
return
HttpResponse
(
json
.
dumps
({
'message'
:
success_message
}),
content_type
=
"application/json"
,
)
else
:
messages
.
success
(
request
,
success_message
)
return
redirect
(
success_url
)
class
GroupRemoveFutureUserView
(
GroupRemoveUserView
):
class
GroupRemoveFutureUserView
(
GroupRemoveUserView
):
member_key
=
'member_org_id'
member_key
=
'member_org_id'
success_message
=
_
(
"Future user successfully removed from group."
)
def
get
(
self
,
request
,
member_org_id
,
*
args
,
**
kwargs
):
def
get
(
self
,
request
,
member_org_id
,
*
args
,
**
kwargs
):
self
.
member_org_id
=
member_org_id
self
.
member_org_id
=
member_org_id
...
@@ -305,53 +283,17 @@ class GroupRemoveFutureUserView(GroupRemoveUserView):
...
@@ -305,53 +283,17 @@ class GroupRemoveFutureUserView(GroupRemoveUserView):
FutureMember
.
objects
.
filter
(
org_id
=
org_id
,
FutureMember
.
objects
.
filter
(
org_id
=
org_id
,
group
=
self
.
get_object
())
.
delete
()
group
=
self
.
get_object
())
.
delete
()
def
get_success_message
(
self
):
return
_
(
"Future user successfully removed from group."
)
class
GroupDelete
(
DeleteViewBase
):
class
GroupDelete
(
CheckedDetailView
,
DeleteView
):
"""This stuff deletes the group.
"""
model
=
Group
model
=
Group
template_name
=
"dashboard/confirm/base-delete.html"
success_message
=
_
(
"Group successfully deleted."
)
read_level
=
'operator'
def
get_has_level
(
self
):
return
self
.
object
.
profile
.
has_level
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
return
[
'dashboard/confirm/ajax-delete.html'
]
else
:
return
[
'dashboard/confirm/base-delete.html'
]
# github.com/django/django/blob/master/django/views/generic/edit.py#L245
def
check_auth
(
self
):
def
delete
(
self
,
request
,
*
args
,
**
kwargs
):
if
not
self
.
get_object
()
.
profile
.
has_level
(
self
.
request
.
user
,
'owner'
):
object
=
self
.
get_object
()
if
not
object
.
profile
.
has_level
(
request
.
user
,
'owner'
):
raise
PermissionDenied
()
raise
PermissionDenied
()
object
.
delete
()
success_url
=
self
.
get_success_url
()
success_message
=
_
(
"Group successfully deleted."
)
if
request
.
is_ajax
():
if
request
.
POST
.
get
(
'redirect'
)
.
lower
()
==
"true"
:
messages
.
success
(
request
,
success_message
)
return
HttpResponse
(
json
.
dumps
({
'message'
:
success_message
}),
content_type
=
"application/json"
,
)
else
:
messages
.
success
(
request
,
success_message
)
return
redirect
(
success_url
)
def
get_success_url
(
self
):
def
get_success_url
(
self
):
next
=
self
.
request
.
POST
.
get
(
'next'
)
return
reverse_lazy
(
'dashboard.views.group-list'
)
if
next
:
return
next
else
:
return
reverse_lazy
(
'dashboard.index'
)
class
GroupCreate
(
GroupCodeMixin
,
LoginRequiredMixin
,
TemplateView
):
class
GroupCreate
(
GroupCodeMixin
,
LoginRequiredMixin
,
TemplateView
):
...
@@ -360,7 +302,7 @@ class GroupCreate(GroupCodeMixin, LoginRequiredMixin, TemplateView):
...
@@ -360,7 +302,7 @@ class GroupCreate(GroupCodeMixin, LoginRequiredMixin, TemplateView):
def
get_template_names
(
self
):
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
if
self
.
request
.
is_ajax
():
return
[
'dashboard/
modal-wrapper
.html'
]
return
[
'dashboard/
_modal
.html'
]
else
:
else
:
return
[
'dashboard/nojs-wrapper.html'
]
return
[
'dashboard/nojs-wrapper.html'
]
...
...
circle/dashboard/views/node.py
View file @
7fed7d2c
...
@@ -27,8 +27,10 @@ from django.db.models import Count
...
@@ -27,8 +27,10 @@ from django.db.models import Count
from
django.forms.models
import
inlineformset_factory
from
django.forms.models
import
inlineformset_factory
from
django.http
import
HttpResponse
from
django.http
import
HttpResponse
from
django.shortcuts
import
redirect
from
django.shortcuts
import
redirect
from
django.template
import
RequestContext
from
django.template.loader
import
render_to_string
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
django.views.generic
import
DetailView
,
TemplateView
,
Delete
View
from
django.views.generic
import
DetailView
,
TemplateView
,
View
from
braces.views
import
LoginRequiredMixin
,
SuperuserRequiredMixin
from
braces.views
import
LoginRequiredMixin
,
SuperuserRequiredMixin
from
django_tables2
import
SingleTableView
from
django_tables2
import
SingleTableView
...
@@ -38,7 +40,7 @@ from vm.models import Node, NodeActivity, Trait
...
@@ -38,7 +40,7 @@ from vm.models import Node, NodeActivity, Trait
from
..forms
import
TraitForm
,
HostForm
,
NodeForm
from
..forms
import
TraitForm
,
HostForm
,
NodeForm
from
..tables
import
NodeListTable
from
..tables
import
NodeListTable
from
.util
import
AjaxOperationMixin
,
OperationView
,
GraphMixin
from
.util
import
AjaxOperationMixin
,
OperationView
,
GraphMixin
,
DeleteViewBase
def
get_operations
(
instance
,
user
):
def
get_operations
(
instance
,
user
):
...
@@ -59,6 +61,8 @@ class NodeOperationView(AjaxOperationMixin, OperationView):
...
@@ -59,6 +61,8 @@ class NodeOperationView(AjaxOperationMixin, OperationView):
model
=
Node
model
=
Node
context_object_name
=
'node'
# much simpler to mock object
context_object_name
=
'node'
# much simpler to mock object
with_reload
=
True
wait_for_result
=
1
node_ops
=
OrderedDict
([
node_ops
=
OrderedDict
([
...
@@ -193,7 +197,7 @@ class NodeCreate(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
...
@@ -193,7 +197,7 @@ class NodeCreate(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
def
get_template_names
(
self
):
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
if
self
.
request
.
is_ajax
():
return
[
'dashboard/
modal-wrapper
.html'
]
return
[
'dashboard/
_modal
.html'
]
else
:
else
:
return
[
'dashboard/nojs-wrapper.html'
]
return
[
'dashboard/nojs-wrapper.html'
]
...
@@ -205,7 +209,7 @@ class NodeCreate(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
...
@@ -205,7 +209,7 @@ class NodeCreate(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
context
=
self
.
get_context_data
(
**
kwargs
)
context
=
self
.
get_context_data
(
**
kwargs
)
context
.
update
({
context
.
update
({
'template'
:
'dashboard/node-create.html'
,
'template'
:
'dashboard/node-create.html'
,
'box_title'
:
'Create a Node'
,
'box_title'
:
_
(
'Create a node'
)
,
'hostform'
:
hostform
,
'hostform'
:
hostform
,
'formset'
:
formset
,
'formset'
:
formset
,
...
@@ -238,44 +242,16 @@ class NodeCreate(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
...
@@ -238,44 +242,16 @@ class NodeCreate(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
return
redirect
(
path
)
return
redirect
(
path
)
class
NodeDelete
(
LoginRequiredMixin
,
SuperuserRequiredMixin
,
DeleteView
):
class
NodeDelete
(
SuperuserRequiredMixin
,
DeleteViewBase
):
"""This stuff deletes the node.
"""
model
=
Node
model
=
Node
template_name
=
"dashboard/confirm/base-delete.html"
success_message
=
_
(
"Node successfully deleted."
)
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
return
[
'dashboard/confirm/ajax-delete.html'
]
else
:
return
[
'dashboard/confirm/base-delete.html'
]
# github.com/django/django/blob/master/django/views/generic/edit.py#L245
def
delete
(
self
,
request
,
*
args
,
**
kwargs
):
object
=
self
.
get_object
()
object
.
delete
()
def
check_auth
(
self
):
success_url
=
self
.
get_success_url
()
# SuperuserRequiredMixin
success_message
=
_
(
"Node successfully deleted."
)
pass
if
request
.
is_ajax
():
if
request
.
POST
.
get
(
'redirect'
)
.
lower
()
==
"true"
:
messages
.
success
(
request
,
success_message
)
return
HttpResponse
(
json
.
dumps
({
'message'
:
success_message
}),
content_type
=
"application/json"
,
)
else
:
messages
.
success
(
request
,
success_message
)
return
redirect
(
success_url
)
def
get_success_url
(
self
):
def
get_success_url
(
self
):
next
=
self
.
request
.
POST
.
get
(
'next'
)
return
reverse_lazy
(
'dashboard.views.node-list'
)
if
next
:
return
next
else
:
return
reverse_lazy
(
'dashboard.index'
)
class
NodeAddTraitView
(
SuperuserRequiredMixin
,
DetailView
):
class
NodeAddTraitView
(
SuperuserRequiredMixin
,
DetailView
):
...
@@ -311,55 +287,20 @@ class NodeAddTraitView(SuperuserRequiredMixin, DetailView):
...
@@ -311,55 +287,20 @@ class NodeAddTraitView(SuperuserRequiredMixin, DetailView):
return
self
.
get
(
self
,
request
,
pk
,
*
args
,
**
kwargs
)
return
self
.
get
(
self
,
request
,
pk
,
*
args
,
**
kwargs
)
class
NodeStatus
(
LoginRequiredMixin
,
SuperuserRequiredMixin
,
DetailView
):
class
NodeActivityView
(
LoginRequiredMixin
,
SuperuserRequiredMixin
,
View
):
template_name
=
"dashboard/confirm/node-status.html"
def
get
(
self
,
request
,
pk
):
model
=
Node
node
=
Node
.
objects
.
get
(
pk
=
pk
)
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
return
[
'dashboard/confirm/ajax-node-status.html'
]
else
:
return
[
'dashboard/confirm/node-status.html'
]
def
get_success_url
(
self
):
next
=
self
.
request
.
GET
.
get
(
'next'
)
if
next
:
return
next
else
:
return
reverse_lazy
(
"dashboard.views.node-detail"
,
kwargs
=
{
'pk'
:
self
.
object
.
pk
})
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
NodeStatus
,
self
)
.
get_context_data
(
**
kwargs
)
if
self
.
object
.
enabled
:
context
[
'status'
]
=
"disable"
else
:
context
[
'status'
]
=
"enable"
return
context
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
activities
=
NodeActivity
.
objects
.
filter
(
if
request
.
POST
.
get
(
'change_status'
)
is
not
None
:
node
=
node
,
parent
=
None
)
.
order_by
(
'-started'
)
.
select_related
()
return
self
.
__set_status
(
request
)
return
redirect
(
reverse_lazy
(
"dashboard.views.node-detail"
,
kwargs
=
{
'pk'
:
self
.
get_object
()
.
pk
}))
def
__set_status
(
self
,
request
):
response
=
{
self
.
object
=
self
.
get_object
()
'activities'
:
render_to_string
(
if
not
self
.
object
.
enabled
:
"dashboard/node-detail/_activity-timeline.html"
,
self
.
object
.
enable
(
user
=
request
.
user
)
RequestContext
(
request
,
{
'activities'
:
activities
}))
else
:
}
self
.
object
.
disable
(
user
=
request
.
user
)
success_message
=
_
(
"Node successfully changed status."
)
if
request
.
is_ajax
():
return
HttpResponse
(
response
=
{
json
.
dumps
(
response
),
'message'
:
success_message
,
content_type
=
"application/json"
'node_pk'
:
self
.
object
.
pk
)
}
return
HttpResponse
(
json
.
dumps
(
response
),
content_type
=
"application/json"
)
else
:
messages
.
success
(
request
,
success_message
)
return
redirect
(
self
.
get_success_url
())
circle/dashboard/views/template.py
View file @
7fed7d2c
...
@@ -28,7 +28,7 @@ from django.http import HttpResponse, HttpResponseRedirect
...
@@ -28,7 +28,7 @@ from django.http import HttpResponse, HttpResponseRedirect
from
django.shortcuts
import
redirect
,
get_object_or_404
from
django.shortcuts
import
redirect
,
get_object_or_404
from
django.utils.translation
import
ugettext
as
_
,
ugettext_noop
from
django.utils.translation
import
ugettext
as
_
,
ugettext_noop
from
django.views.generic
import
(
from
django.views.generic
import
(
TemplateView
,
CreateView
,
DeleteView
,
UpdateView
,
TemplateView
,
CreateView
,
UpdateView
,
)
)
from
braces.views
import
(
from
braces.views
import
(
...
@@ -47,6 +47,7 @@ from ..tables import TemplateListTable, LeaseListTable
...
@@ -47,6 +47,7 @@ from ..tables import TemplateListTable, LeaseListTable
from
.util
import
(
from
.util
import
(
AclUpdateView
,
FilterMixin
,
AclUpdateView
,
FilterMixin
,
TransferOwnershipConfirmView
,
TransferOwnershipView
,
TransferOwnershipConfirmView
,
TransferOwnershipView
,
DeleteViewBase
)
)
logger
=
logging
.
getLogger
(
__name__
)
logger
=
logging
.
getLogger
(
__name__
)
...
@@ -56,7 +57,7 @@ class TemplateChoose(LoginRequiredMixin, TemplateView):
...
@@ -56,7 +57,7 @@ class TemplateChoose(LoginRequiredMixin, TemplateView):
def
get_template_names
(
self
):
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
if
self
.
request
.
is_ajax
():
return
[
'dashboard/
modal-wrapper
.html'
]
return
[
'dashboard/
_modal
.html'
]
else
:
else
:
return
[
'dashboard/nojs-wrapper.html'
]
return
[
'dashboard/nojs-wrapper.html'
]
...
@@ -231,46 +232,17 @@ class TemplateList(LoginRequiredMixin, FilterMixin, SingleTableView):
...
@@ -231,46 +232,17 @@ class TemplateList(LoginRequiredMixin, FilterMixin, SingleTableView):
return
qs
.
select_related
(
"lease"
,
"owner"
,
"owner__profile"
)
return
qs
.
select_related
(
"lease"
,
"owner"
,
"owner__profile"
)
class
TemplateDelete
(
LoginRequiredMixin
,
DeleteView
):
class
TemplateDelete
(
DeleteViewBase
):
model
=
InstanceTemplate
model
=
InstanceTemplate
success_message
=
_
(
"Template successfully deleted."
)
def
get_success_url
(
self
):
def
get_success_url
(
self
):
return
reverse
(
"dashboard.views.template-list"
)
return
reverse
(
"dashboard.views.template-list"
)
def
get_template_names
(
self
):
def
delete_obj
(
self
,
request
,
*
args
,
**
kwargs
):
if
self
.
request
.
is_ajax
():
return
[
'dashboard/confirm/ajax-delete.html'
]
else
:
return
[
'dashboard/confirm/base-delete.html'
]
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
if
not
self
.
get_object
()
.
has_level
(
request
.
user
,
"owner"
):
message
=
_
(
"Only the owners can delete the selected template."
)
if
request
.
is_ajax
():
raise
PermissionDenied
()
else
:
messages
.
warning
(
request
,
message
)
return
redirect
(
self
.
get_success_url
())
return
super
(
TemplateDelete
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
delete
(
self
,
request
,
*
args
,
**
kwargs
):
object
=
self
.
get_object
()
object
=
self
.
get_object
()
if
not
object
.
has_level
(
request
.
user
,
'owner'
):
raise
PermissionDenied
()
object
.
destroy_disks
()
object
.
destroy_disks
()
object
.
delete
()
object
.
delete
()
success_url
=
self
.
get_success_url
()
success_message
=
_
(
"Template successfully deleted."
)
if
request
.
is_ajax
():
return
HttpResponse
(
json
.
dumps
({
'message'
:
success_message
}),
content_type
=
"application/json"
,
)
else
:
messages
.
success
(
request
,
success_message
)
return
HttpResponseRedirect
(
success_url
)
class
TemplateDetail
(
LoginRequiredMixin
,
SuccessMessageMixin
,
UpdateView
):
class
TemplateDetail
(
LoginRequiredMixin
,
SuccessMessageMixin
,
UpdateView
):
...
@@ -333,25 +305,24 @@ class TemplateDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
...
@@ -333,25 +305,24 @@ class TemplateDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
return
kwargs
return
kwargs
class
DiskRemoveView
(
DeleteView
):
class
DiskRemoveView
(
DeleteView
Base
):
model
=
Disk
model
=
Disk
success_message
=
_
(
"Disk successfully removed."
)
def
get_queryset
(
self
):
def
get_queryset
(
self
):
qs
=
super
(
DiskRemoveView
,
self
)
.
get_queryset
()
qs
=
super
(
DiskRemoveView
,
self
)
.
get_queryset
()
return
qs
.
exclude
(
template_set
=
None
)
return
qs
.
exclude
(
template_set
=
None
)
def
get_template_names
(
self
):
def
check_auth
(
self
):
if
self
.
request
.
is_ajax
():
return
[
'dashboard/confirm/ajax-delete.html'
]
else
:
return
[
'dashboard/confirm/base-delete.html'
]
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
DiskRemoveView
,
self
)
.
get_context_data
(
**
kwargs
)
disk
=
self
.
get_object
()
disk
=
self
.
get_object
()
template
=
disk
.
template_set
.
get
()
template
=
disk
.
template_set
.
get
()
if
not
template
.
has_level
(
self
.
request
.
user
,
'owner'
):
if
not
template
.
has_level
(
self
.
request
.
user
,
'owner'
):
raise
PermissionDenied
()
raise
PermissionDenied
()
def
get_context_data
(
self
,
**
kwargs
):
disk
=
self
.
get_object
()
template
=
disk
.
template_set
.
get
()
context
=
super
(
DiskRemoveView
,
self
)
.
get_context_data
(
**
kwargs
)
context
[
'title'
]
=
_
(
"Disk remove confirmation"
)
context
[
'title'
]
=
_
(
"Disk remove confirmation"
)
context
[
'text'
]
=
_
(
"Are you sure you want to remove "
context
[
'text'
]
=
_
(
"Are you sure you want to remove "
"<strong>
%(disk)
s</strong> from "
"<strong>
%(disk)
s</strong> from "
...
@@ -360,29 +331,12 @@ class DiskRemoveView(DeleteView):
...
@@ -360,29 +331,12 @@ class DiskRemoveView(DeleteView):
)
)
return
context
return
context
def
delete
(
self
,
request
,
*
args
,
**
kwargs
):
def
delete
_obj
(
self
,
request
,
*
args
,
**
kwargs
):
disk
=
self
.
get_object
()
disk
=
self
.
get_object
()
template
=
disk
.
template_set
.
get
()
template
=
disk
.
template_set
.
get
()
template
.
remove_disk
(
disk
)
if
not
template
.
has_level
(
request
.
user
,
'owner'
):
raise
PermissionDenied
()
template
.
remove_disk
(
disk
=
disk
,
user
=
request
.
user
)
disk
.
destroy
()
disk
.
destroy
()
next_url
=
request
.
POST
.
get
(
"next"
)
success_url
=
next_url
if
next_url
else
template
.
get_absolute_url
()
success_message
=
_
(
"Disk successfully removed."
)
if
request
.
is_ajax
():
return
HttpResponse
(
json
.
dumps
({
'message'
:
success_message
}),
content_type
=
"application/json"
,
)
else
:
messages
.
success
(
request
,
success_message
)
return
HttpResponseRedirect
(
"
%
s#resources"
%
success_url
)
class
LeaseCreate
(
LoginRequiredMixin
,
PermissionRequiredMixin
,
class
LeaseCreate
(
LoginRequiredMixin
,
PermissionRequiredMixin
,
SuccessMessageMixin
,
CreateView
):
SuccessMessageMixin
,
CreateView
):
...
@@ -435,18 +389,13 @@ class LeaseDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
...
@@ -435,18 +389,13 @@ class LeaseDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
return
super
(
LeaseDetail
,
self
)
.
post
(
request
,
*
args
,
**
kwargs
)
return
super
(
LeaseDetail
,
self
)
.
post
(
request
,
*
args
,
**
kwargs
)
class
LeaseDelete
(
LoginRequiredMixin
,
DeleteView
):
class
LeaseDelete
(
DeleteViewBase
):
model
=
Lease
model
=
Lease
success_message
=
_
(
"Lease successfully deleted."
)
def
get_success_url
(
self
):
def
get_success_url
(
self
):
return
reverse
(
"dashboard.views.template-list"
)
return
reverse
(
"dashboard.views.template-list"
)
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
return
[
'dashboard/confirm/ajax-delete.html'
]
else
:
return
[
'dashboard/confirm/base-delete.html'
]
def
get_context_data
(
self
,
*
args
,
**
kwargs
):
def
get_context_data
(
self
,
*
args
,
**
kwargs
):
c
=
super
(
LeaseDelete
,
self
)
.
get_context_data
(
*
args
,
**
kwargs
)
c
=
super
(
LeaseDelete
,
self
)
.
get_context_data
(
*
args
,
**
kwargs
)
lease
=
self
.
get_object
()
lease
=
self
.
get_object
()
...
@@ -461,36 +410,11 @@ class LeaseDelete(LoginRequiredMixin, DeleteView):
...
@@ -461,36 +410,11 @@ class LeaseDelete(LoginRequiredMixin, DeleteView):
c
[
'disable_submit'
]
=
True
c
[
'disable_submit'
]
=
True
return
c
return
c
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
def
delete_obj
(
self
,
request
,
*
args
,
**
kwargs
):
if
not
self
.
get_object
()
.
has_level
(
request
.
user
,
"owner"
):
message
=
_
(
"Only the owners can delete the selected lease."
)
if
request
.
is_ajax
():
raise
PermissionDenied
()
else
:
messages
.
warning
(
request
,
message
)
return
redirect
(
self
.
get_success_url
())
return
super
(
LeaseDelete
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
delete
(
self
,
request
,
*
args
,
**
kwargs
):
object
=
self
.
get_object
()
object
=
self
.
get_object
()
if
not
object
.
has_level
(
request
.
user
,
"owner"
):
raise
PermissionDenied
()
if
object
.
instancetemplate_set
.
count
()
>
0
:
if
object
.
instancetemplate_set
.
count
()
>
0
:
raise
SuspiciousOperation
()
raise
SuspiciousOperation
()
object
.
delete
()
object
.
delete
()
success_url
=
self
.
get_success_url
()
success_message
=
_
(
"Lease successfully deleted."
)
if
request
.
is_ajax
():
return
HttpResponse
(
json
.
dumps
({
'message'
:
success_message
}),
content_type
=
"application/json"
,
)
else
:
messages
.
success
(
request
,
success_message
)
return
HttpResponseRedirect
(
success_url
)
class
TransferTemplateOwnershipConfirmView
(
TransferOwnershipConfirmView
):
class
TransferTemplateOwnershipConfirmView
(
TransferOwnershipConfirmView
):
...
...
circle/dashboard/views/user.py
View file @
7fed7d2c
...
@@ -35,7 +35,7 @@ from django.shortcuts import redirect, get_object_or_404
...
@@ -35,7 +35,7 @@ from django.shortcuts import redirect, get_object_or_404
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
django.views.decorators.http
import
require_POST
from
django.views.decorators.http
import
require_POST
from
django.views.generic
import
(
from
django.views.generic
import
(
TemplateView
,
DetailView
,
View
,
DeleteView
,
UpdateView
,
CreateView
,
TemplateView
,
DetailView
,
View
,
UpdateView
,
CreateView
,
)
)
from
django_sshkey.models
import
UserKey
from
django_sshkey.models
import
UserKey
...
@@ -50,7 +50,7 @@ from ..forms import (
...
@@ -50,7 +50,7 @@ from ..forms import (
from
..models
import
Profile
,
GroupProfile
,
ConnectCommand
,
create_profile
from
..models
import
Profile
,
GroupProfile
,
ConnectCommand
,
create_profile
from
..tables
import
UserKeyListTable
,
ConnectCommandListTable
from
..tables
import
UserKeyListTable
,
ConnectCommandListTable
from
.util
import
saml_available
from
.util
import
saml_available
,
DeleteViewBase
logger
=
logging
.
getLogger
(
__name__
)
logger
=
logging
.
getLogger
(
__name__
)
...
@@ -385,36 +385,17 @@ class UserKeyDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
...
@@ -385,36 +385,17 @@ class UserKeyDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
return
super
(
UserKeyDetail
,
self
)
.
post
(
self
,
request
,
args
,
kwargs
)
return
super
(
UserKeyDetail
,
self
)
.
post
(
self
,
request
,
args
,
kwargs
)
class
UserKeyDelete
(
LoginRequiredMixin
,
DeleteView
):
class
UserKeyDelete
(
DeleteViewBase
):
model
=
UserKey
model
=
UserKey
success_message
=
_
(
"SSH key successfully deleted."
)
def
get_success_url
(
self
):
def
get_success_url
(
self
):
return
reverse
(
"dashboard.views.profile-preferences"
)
return
reverse
(
"dashboard.views.profile-preferences"
)
def
get_template_names
(
self
):
def
check_auth
(
self
):
if
self
.
request
.
is_ajax
():
if
self
.
get_object
()
.
user
!=
self
.
request
.
user
:
return
[
'dashboard/confirm/ajax-delete.html'
]
else
:
return
[
'dashboard/confirm/base-delete.html'
]
def
delete
(
self
,
request
,
*
args
,
**
kwargs
):
object
=
self
.
get_object
()
if
object
.
user
!=
request
.
user
:
raise
PermissionDenied
()
raise
PermissionDenied
()
object
.
delete
()
success_url
=
self
.
get_success_url
()
success_message
=
_
(
"SSH key successfully deleted."
)
if
request
.
is_ajax
():
return
HttpResponse
(
json
.
dumps
({
'message'
:
success_message
}),
content_type
=
"application/json"
,
)
else
:
messages
.
success
(
request
,
success_message
)
return
HttpResponseRedirect
(
success_url
)
class
UserKeyCreate
(
LoginRequiredMixin
,
SuccessMessageMixin
,
CreateView
):
class
UserKeyCreate
(
LoginRequiredMixin
,
SuccessMessageMixin
,
CreateView
):
model
=
UserKey
model
=
UserKey
...
@@ -460,36 +441,17 @@ class ConnectCommandDetail(LoginRequiredMixin, SuccessMessageMixin,
...
@@ -460,36 +441,17 @@ class ConnectCommandDetail(LoginRequiredMixin, SuccessMessageMixin,
return
kwargs
return
kwargs
class
ConnectCommandDelete
(
LoginRequiredMixin
,
DeleteView
):
class
ConnectCommandDelete
(
DeleteViewBase
):
model
=
ConnectCommand
model
=
ConnectCommand
success_message
=
_
(
"Command template successfully deleted."
)
def
get_success_url
(
self
):
def
get_success_url
(
self
):
return
reverse
(
"dashboard.views.profile-preferences"
)
return
reverse
(
"dashboard.views.profile-preferences"
)
def
get_template_names
(
self
):
def
check_auth
(
self
):
if
self
.
request
.
is_ajax
():
if
self
.
get_object
()
.
user
!=
self
.
request
.
user
:
return
[
'dashboard/confirm/ajax-delete.html'
]
else
:
return
[
'dashboard/confirm/base-delete.html'
]
def
delete
(
self
,
request
,
*
args
,
**
kwargs
):
object
=
self
.
get_object
()
if
object
.
user
!=
request
.
user
:
raise
PermissionDenied
()
raise
PermissionDenied
()
object
.
delete
()
success_url
=
self
.
get_success_url
()
success_message
=
_
(
"Command template successfully deleted."
)
if
request
.
is_ajax
():
return
HttpResponse
(
json
.
dumps
({
'message'
:
success_message
}),
content_type
=
"application/json"
,
)
else
:
messages
.
success
(
request
,
success_message
)
return
HttpResponseRedirect
(
success_url
)
class
ConnectCommandCreate
(
LoginRequiredMixin
,
SuccessMessageMixin
,
class
ConnectCommandCreate
(
LoginRequiredMixin
,
SuccessMessageMixin
,
CreateView
):
CreateView
):
...
...
circle/dashboard/views/util.py
View file @
7fed7d2c
...
@@ -33,7 +33,7 @@ from django.db.models import Q
...
@@ -33,7 +33,7 @@ from django.db.models import Q
from
django.http
import
HttpResponse
,
Http404
,
HttpResponseRedirect
from
django.http
import
HttpResponse
,
Http404
,
HttpResponseRedirect
from
django.shortcuts
import
redirect
,
render
from
django.shortcuts
import
redirect
,
render
from
django.utils.translation
import
ugettext_lazy
as
_
,
ugettext_noop
from
django.utils.translation
import
ugettext_lazy
as
_
,
ugettext_noop
from
django.views.generic
import
DetailView
,
View
from
django.views.generic
import
DetailView
,
View
,
DeleteView
from
django.views.generic.detail
import
SingleObjectMixin
from
django.views.generic.detail
import
SingleObjectMixin
from
braces.views
import
LoginRequiredMixin
from
braces.views
import
LoginRequiredMixin
...
@@ -694,3 +694,45 @@ class TransferOwnershipConfirmView(LoginRequiredMixin, View):
...
@@ -694,3 +694,45 @@ class TransferOwnershipConfirmView(LoginRequiredMixin, View):
unicode
(
user
),
user
.
pk
,
new_owner
,
key
)
unicode
(
user
),
user
.
pk
,
new_owner
,
key
)
raise
PermissionDenied
()
raise
PermissionDenied
()
return
(
instance
,
new_owner
)
return
(
instance
,
new_owner
)
class
DeleteViewBase
(
LoginRequiredMixin
,
DeleteView
):
level
=
'owner'
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
return
[
'dashboard/confirm/ajax-delete.html'
]
else
:
return
[
'dashboard/confirm/base-delete.html'
]
def
check_auth
(
self
):
if
not
self
.
get_object
()
.
has_level
(
self
.
request
.
user
,
self
.
level
):
raise
PermissionDenied
()
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
try
:
self
.
check_auth
()
except
PermissionDenied
:
message
=
_
(
"Only the owners can delete the selected object."
)
if
request
.
is_ajax
():
raise
PermissionDenied
()
else
:
messages
.
warning
(
request
,
message
)
return
redirect
(
self
.
get_success_url
())
return
super
(
DeleteViewBase
,
self
)
.
get
(
request
,
*
args
,
**
kwargs
)
def
delete_obj
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
get_object
()
.
delete
()
def
delete
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
check_auth
()
self
.
delete_obj
(
request
,
*
args
,
**
kwargs
)
if
request
.
is_ajax
():
return
HttpResponse
(
json
.
dumps
({
'message'
:
self
.
success_message
}),
content_type
=
"application/json"
,
)
else
:
messages
.
success
(
request
,
self
.
success_message
)
return
HttpResponseRedirect
(
self
.
get_success_url
())
circle/dashboard/views/vm.py
View file @
7fed7d2c
...
@@ -37,7 +37,7 @@ from django.utils.translation import (
...
@@ -37,7 +37,7 @@ from django.utils.translation import (
)
)
from
django.views.decorators.http
import
require_GET
from
django.views.decorators.http
import
require_GET
from
django.views.generic
import
(
from
django.views.generic
import
(
UpdateView
,
ListView
,
TemplateView
,
DeleteView
UpdateView
,
ListView
,
TemplateView
)
)
from
braces.views
import
SuperuserRequiredMixin
,
LoginRequiredMixin
from
braces.views
import
SuperuserRequiredMixin
,
LoginRequiredMixin
...
@@ -64,6 +64,7 @@ from ..forms import (
...
@@ -64,6 +64,7 @@ from ..forms import (
VmDiskResizeForm
,
RedeployForm
,
VmDiskRemoveForm
,
VmDiskResizeForm
,
RedeployForm
,
VmDiskRemoveForm
,
VmMigrateForm
,
VmDeployForm
,
VmMigrateForm
,
VmDeployForm
,
VmPortRemoveForm
,
VmPortAddForm
,
VmPortRemoveForm
,
VmPortAddForm
,
VmRemoveInterfaceForm
,
)
)
from
..models
import
Favourite
from
..models
import
Favourite
...
@@ -324,6 +325,32 @@ def get_operations(instance, user):
...
@@ -324,6 +325,32 @@ def get_operations(instance, user):
return
ops
return
ops
class
VmRemoveInterfaceView
(
FormOperationMixin
,
VmOperationView
):
op
=
'remove_interface'
form_class
=
VmRemoveInterfaceForm
show_in_toolbar
=
False
wait_for_result
=
0.5
icon
=
'times'
effect
=
"danger"
with_reload
=
True
def
get_form_kwargs
(
self
):
instance
=
self
.
get_op
()
.
instance
choices
=
instance
.
interface_set
.
all
()
interface_pk
=
self
.
request
.
GET
.
get
(
'interface'
)
if
interface_pk
:
try
:
default
=
choices
.
get
(
pk
=
interface_pk
)
except
(
ValueError
,
Interface
.
DoesNotExist
):
raise
Http404
()
else
:
default
=
None
val
=
super
(
VmRemoveInterfaceView
,
self
)
.
get_form_kwargs
()
val
.
update
({
'choices'
:
choices
,
'default'
:
default
})
return
val
class
VmAddInterfaceView
(
FormOperationMixin
,
VmOperationView
):
class
VmAddInterfaceView
(
FormOperationMixin
,
VmOperationView
):
op
=
'add_interface'
op
=
'add_interface'
...
@@ -707,6 +734,7 @@ vm_ops = OrderedDict([
...
@@ -707,6 +734,7 @@ vm_ops = OrderedDict([
op
=
'remove_disk'
,
form_class
=
VmDiskRemoveForm
,
op
=
'remove_disk'
,
form_class
=
VmDiskRemoveForm
,
icon
=
'times'
,
effect
=
"danger"
)),
icon
=
'times'
,
effect
=
"danger"
)),
(
'add_interface'
,
VmAddInterfaceView
),
(
'add_interface'
,
VmAddInterfaceView
),
(
'remove_interface'
,
VmRemoveInterfaceView
),
(
'remove_port'
,
VmPortRemoveView
),
(
'remove_port'
,
VmPortRemoveView
),
(
'add_port'
,
VmPortAddView
),
(
'add_port'
,
VmPortAddView
),
(
'renew'
,
VmRenewView
),
(
'renew'
,
VmRenewView
),
...
@@ -951,10 +979,21 @@ class VmCreate(LoginRequiredMixin, TemplateView):
...
@@ -951,10 +979,21 @@ class VmCreate(LoginRequiredMixin, TemplateView):
def
get_template_names
(
self
):
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
if
self
.
request
.
is_ajax
():
return
[
'dashboard/
modal-wrapper
.html'
]
return
[
'dashboard/
_modal
.html'
]
else
:
else
:
return
[
'dashboard/nojs-wrapper.html'
]
return
[
'dashboard/nojs-wrapper.html'
]
def
get_template
(
self
,
request
,
pk
):
try
:
template
=
InstanceTemplate
.
objects
.
get
(
pk
=
int
(
pk
))
except
(
ValueError
,
InstanceTemplate
.
DoesNotExist
):
raise
Http404
()
if
not
template
.
has_level
(
request
.
user
,
'user'
):
raise
PermissionDenied
()
return
template
def
get
(
self
,
request
,
form
=
None
,
*
args
,
**
kwargs
):
def
get
(
self
,
request
,
form
=
None
,
*
args
,
**
kwargs
):
if
not
request
.
user
.
has_perm
(
'vm.create_vm'
):
if
not
request
.
user
.
has_perm
(
'vm.create_vm'
):
raise
PermissionDenied
()
raise
PermissionDenied
()
...
@@ -965,9 +1004,7 @@ class VmCreate(LoginRequiredMixin, TemplateView):
...
@@ -965,9 +1004,7 @@ class VmCreate(LoginRequiredMixin, TemplateView):
template_pk
=
form
.
template
.
pk
template_pk
=
form
.
template
.
pk
if
template_pk
:
if
template_pk
:
template
=
get_object_or_404
(
InstanceTemplate
,
pk
=
template_pk
)
template
=
self
.
get_template
(
request
,
template_pk
)
if
not
template
.
has_level
(
request
.
user
,
'user'
):
raise
PermissionDenied
()
if
form
is
None
:
if
form
is
None
:
form
=
self
.
form_class
(
user
=
request
.
user
,
template
=
template
)
form
=
self
.
form_class
(
user
=
request
.
user
,
template
=
template
)
else
:
else
:
...
@@ -992,33 +1029,21 @@ class VmCreate(LoginRequiredMixin, TemplateView):
...
@@ -992,33 +1029,21 @@ class VmCreate(LoginRequiredMixin, TemplateView):
})
})
return
self
.
render_to_response
(
context
)
return
self
.
render_to_response
(
context
)
def
__create_normal
(
self
,
request
,
*
args
,
**
kwargs
):
def
__create_normal
(
self
,
request
,
template
,
*
args
,
**
kwargs
):
user
=
request
.
user
instances
=
[
Instance
.
create_from_template
(
template
=
InstanceTemplate
.
objects
.
get
(
template
=
template
,
pk
=
request
.
POST
.
get
(
"template"
))
owner
=
request
.
user
)]
# permission check
if
not
template
.
has_level
(
request
.
user
,
'user'
):
raise
PermissionDenied
()
args
=
{
"template"
:
template
,
"owner"
:
user
}
instances
=
[
Instance
.
create_from_template
(
**
args
)]
return
self
.
__deploy
(
request
,
instances
)
return
self
.
__deploy
(
request
,
instances
)
def
__create_customized
(
self
,
request
,
*
args
,
**
kwargs
):
def
__create_customized
(
self
,
request
,
template
,
*
args
,
**
kwargs
):
user
=
request
.
user
user
=
request
.
user
# no form yet, using POST directly:
# no form yet, using POST directly:
template
=
get_object_or_404
(
InstanceTemplate
,
pk
=
request
.
POST
.
get
(
"template"
))
form
=
self
.
form_class
(
form
=
self
.
form_class
(
request
.
POST
,
user
=
request
.
user
,
template
=
template
)
request
.
POST
,
user
=
request
.
user
,
template
=
template
)
if
not
form
.
is_valid
():
if
not
form
.
is_valid
():
return
self
.
get
(
request
,
form
,
*
args
,
**
kwargs
)
return
self
.
get
(
request
,
form
,
*
args
,
**
kwargs
)
post
=
form
.
cleaned_data
post
=
form
.
cleaned_data
if
not
template
.
has_level
(
user
,
'user'
):
raise
PermissionDenied
()
ikwargs
=
{
ikwargs
=
{
'name'
:
post
[
'name'
],
'name'
:
post
[
'name'
],
'template'
:
template
,
'template'
:
template
,
...
@@ -1071,6 +1096,8 @@ class VmCreate(LoginRequiredMixin, TemplateView):
...
@@ -1071,6 +1096,8 @@ class VmCreate(LoginRequiredMixin, TemplateView):
if
not
request
.
user
.
has_perm
(
'vm.create_vm'
):
if
not
request
.
user
.
has_perm
(
'vm.create_vm'
):
raise
PermissionDenied
()
raise
PermissionDenied
()
template
=
self
.
get_template
(
request
,
request
.
POST
.
get
(
"template"
))
# limit chekcs
# limit chekcs
try
:
try
:
limit
=
user
.
profile
.
instance_limit
limit
=
user
.
profile
.
instance_limit
...
@@ -1096,7 +1123,7 @@ class VmCreate(LoginRequiredMixin, TemplateView):
...
@@ -1096,7 +1123,7 @@ class VmCreate(LoginRequiredMixin, TemplateView):
request
.
POST
.
get
(
"customized"
)
is
None
else
request
.
POST
.
get
(
"customized"
)
is
None
else
self
.
__create_customized
)
self
.
__create_customized
)
return
create_func
(
request
,
*
args
,
**
kwargs
)
return
create_func
(
request
,
template
,
*
args
,
**
kwargs
)
@require_GET
@require_GET
...
@@ -1111,56 +1138,6 @@ def get_vm_screenshot(request, pk):
...
@@ -1111,56 +1138,6 @@ def get_vm_screenshot(request, pk):
return
HttpResponse
(
image
,
mimetype
=
"image/png"
)
return
HttpResponse
(
image
,
mimetype
=
"image/png"
)
class
InterfaceDeleteView
(
DeleteView
):
model
=
Interface
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
return
[
'dashboard/confirm/ajax-delete.html'
]
else
:
return
[
'dashboard/confirm/base-delete.html'
]
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
InterfaceDeleteView
,
self
)
.
get_context_data
(
**
kwargs
)
interface
=
self
.
get_object
()
context
[
'text'
]
=
_
(
"Are you sure you want to remove this interface "
"from <strong>
%(vm)
s</strong>?"
%
{
'vm'
:
interface
.
instance
.
name
})
return
context
def
delete
(
self
,
request
,
*
args
,
**
kwargs
):
self
.
object
=
self
.
get_object
()
instance
=
self
.
object
.
instance
if
not
instance
.
has_level
(
request
.
user
,
"owner"
):
raise
PermissionDenied
()
instance
.
remove_interface
(
interface
=
self
.
object
,
user
=
request
.
user
)
success_url
=
self
.
get_success_url
()
success_message
=
_
(
"Interface successfully deleted."
)
if
request
.
is_ajax
():
return
HttpResponse
(
json
.
dumps
(
{
'message'
:
success_message
,
'removed_network'
:
{
'vlan'
:
self
.
object
.
vlan
.
name
,
'vlan_pk'
:
self
.
object
.
vlan
.
pk
,
'managed'
:
self
.
object
.
host
is
not
None
,
}}),
content_type
=
"application/json"
,
)
else
:
messages
.
success
(
request
,
success_message
)
return
HttpResponseRedirect
(
"
%
s#network"
%
success_url
)
def
get_success_url
(
self
):
redirect
=
self
.
request
.
POST
.
get
(
"next"
)
if
redirect
:
return
redirect
self
.
object
.
instance
.
get_absolute_url
()
class
InstanceActivityDetail
(
CheckedDetailView
):
class
InstanceActivityDetail
(
CheckedDetailView
):
model
=
InstanceActivity
model
=
InstanceActivity
context_object_name
=
'instanceactivity'
# much simpler to mock object
context_object_name
=
'instanceactivity'
# much simpler to mock object
...
...
circle/vm/models/instance.py
View file @
7fed7d2c
...
@@ -354,6 +354,12 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
...
@@ -354,6 +354,12 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
def
create
(
cls
,
params
,
disks
,
networks
,
req_traits
,
tags
):
def
create
(
cls
,
params
,
disks
,
networks
,
req_traits
,
tags
):
""" Create new Instance object.
""" Create new Instance object.
"""
"""
# permission check
for
network
in
networks
:
if
not
network
.
vlan
.
has_level
(
params
[
'owner'
],
'user'
):
raise
PermissionDenied
()
# create instance and do additional setup
# create instance and do additional setup
inst
=
cls
(
**
params
)
inst
=
cls
(
**
params
)
...
@@ -408,10 +414,6 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
...
@@ -408,10 +414,6 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
networks
=
(
template
.
interface_set
.
all
()
if
networks
is
None
networks
=
(
template
.
interface_set
.
all
()
if
networks
is
None
else
networks
)
else
networks
)
for
network
in
networks
:
if
not
network
.
vlan
.
has_level
(
owner
,
'user'
):
raise
PermissionDenied
()
req_traits
=
(
template
.
req_traits
.
all
()
if
req_traits
is
None
req_traits
=
(
template
.
req_traits
.
all
()
if
req_traits
is
None
else
req_traits
)
else
req_traits
)
...
...
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