Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Gelencsér Szabolcs
/
circlestack
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
fa12edb4
authored
Oct 30, 2014
by
Bach Dániel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dashboard: move TransferOwnership views to utils.py
parent
f5a446ed
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
166 additions
and
141 deletions
+166
-141
circle/dashboard/templates/dashboard/confirm/transfer-instance-ownership.html
+0
-0
circle/dashboard/urls.py
+7
-4
circle/dashboard/views/util.py
+136
-5
circle/dashboard/views/vm.py
+23
-132
No files found.
circle/dashboard/templates/dashboard/confirm/
base-transfer
-ownership.html
→
circle/dashboard/templates/dashboard/confirm/
transfer-instance
-ownership.html
View file @
fa12edb4
File moved
circle/dashboard/urls.py
View file @
fa12edb4
...
@@ -27,8 +27,8 @@ from .views import (
...
@@ -27,8 +27,8 @@ from .views import (
MyPreferencesView
,
NodeAddTraitView
,
NodeCreate
,
NodeDelete
,
MyPreferencesView
,
NodeAddTraitView
,
NodeCreate
,
NodeDelete
,
NodeDetailView
,
NodeList
,
NodeStatus
,
NodeDetailView
,
NodeList
,
NodeStatus
,
NotificationView
,
PortDelete
,
TemplateAclUpdateView
,
TemplateCreate
,
NotificationView
,
PortDelete
,
TemplateAclUpdateView
,
TemplateCreate
,
TemplateDelete
,
TemplateDetail
,
TemplateList
,
TransferOwnershipConfirmView
,
TemplateDelete
,
TemplateDetail
,
TemplateList
,
TransferOwnershipView
,
vm_activity
,
VmCreate
,
VmDetailView
,
vm_activity
,
VmCreate
,
VmDetailView
,
VmDetailVncTokenView
,
VmList
,
VmDetailVncTokenView
,
VmList
,
DiskRemoveView
,
get_disk_download_status
,
InterfaceDeleteView
,
DiskRemoveView
,
get_disk_download_status
,
InterfaceDeleteView
,
GroupRemoveUserView
,
GroupRemoveUserView
,
...
@@ -48,6 +48,8 @@ from .views import (
...
@@ -48,6 +48,8 @@ from .views import (
toggle_template_tutorial
,
toggle_template_tutorial
,
ClientCheck
,
TokenLogin
,
ClientCheck
,
TokenLogin
,
VmGraphView
,
NodeGraphView
,
NodeListGraphView
,
VmGraphView
,
NodeGraphView
,
NodeListGraphView
,
TransferInstanceOwnershipView
,
TransferInstanceOwnershipConfirmView
,
TransferTemplateOwnershipView
,
TransferTemplateOwnershipConfirmView
,
)
)
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
...
@@ -86,7 +88,7 @@ urlpatterns = patterns(
...
@@ -86,7 +88,7 @@ urlpatterns = patterns(
name
=
'dashboard.views.detail-vnc'
),
name
=
'dashboard.views.detail-vnc'
),
url
(
r'^vm/(?P<pk>\d+)/acl/$'
,
AclUpdateView
.
as_view
(
model
=
Instance
),
url
(
r'^vm/(?P<pk>\d+)/acl/$'
,
AclUpdateView
.
as_view
(
model
=
Instance
),
name
=
'dashboard.views.vm-acl'
),
name
=
'dashboard.views.vm-acl'
),
url
(
r'^vm/(?P<pk>\d+)/tx/$'
,
TransferOwnershipView
.
as_view
(),
url
(
r'^vm/(?P<pk>\d+)/tx/$'
,
Transfer
Instance
OwnershipView
.
as_view
(),
name
=
'dashboard.views.vm-transfer-ownership'
),
name
=
'dashboard.views.vm-transfer-ownership'
),
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
(),
...
@@ -108,7 +110,8 @@ urlpatterns = patterns(
...
@@ -108,7 +110,8 @@ urlpatterns = patterns(
name
=
'dashboard.views.node-detail'
),
name
=
'dashboard.views.node-detail'
),
url
(
r'^node/(?P<pk>\d+)/add-trait/$'
,
NodeAddTraitView
.
as_view
(),
url
(
r'^node/(?P<pk>\d+)/add-trait/$'
,
NodeAddTraitView
.
as_view
(),
name
=
'dashboard.views.node-addtrait'
),
name
=
'dashboard.views.node-addtrait'
),
url
(
r'^tx/(?P<key>.*)/?$'
,
TransferOwnershipConfirmView
.
as_view
(),
url
(
r'^vm/tx/(?P<key>.*)/?$'
,
TransferInstanceOwnershipConfirmView
.
as_view
(),
name
=
'dashboard.views.vm-transfer-ownership-confirm'
),
name
=
'dashboard.views.vm-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"
),
...
...
circle/dashboard/views/util.py
View file @
fa12edb4
...
@@ -24,14 +24,15 @@ from urlparse import urljoin
...
@@ -24,14 +24,15 @@ from urlparse import urljoin
from
django.conf
import
settings
from
django.conf
import
settings
from
django.contrib.auth.models
import
User
,
Group
from
django.contrib.auth.models
import
User
,
Group
from
django.core.exceptions
import
PermissionDenied
from
django.core
import
signing
from
django.core.exceptions
import
PermissionDenied
,
SuspiciousOperation
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.contrib
import
messages
from
django.contrib
import
messages
from
django.contrib.auth.views
import
redirect_to_login
from
django.contrib.auth.views
import
redirect_to_login
from
django.db.models
import
Q
from
django.db.models
import
Q
from
django.http
import
HttpResponse
,
HttpResponseRedirect
from
django.http
import
HttpResponse
,
Http
404
,
Http
ResponseRedirect
from
django.shortcuts
import
redirect
from
django.shortcuts
import
redirect
,
render
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
,
ugettext_noop
from
django.views.generic
import
DetailView
,
View
from
django.views.generic
import
DetailView
,
View
from
django.views.generic.detail
import
SingleObjectMixin
from
django.views.generic.detail
import
SingleObjectMixin
...
@@ -40,7 +41,8 @@ from braces.views._access import AccessMixin
...
@@ -40,7 +41,8 @@ from braces.views._access import AccessMixin
from
celery.exceptions
import
TimeoutError
from
celery.exceptions
import
TimeoutError
from
common.models
import
HumanReadableException
,
HumanReadableObject
from
common.models
import
HumanReadableException
,
HumanReadableObject
from
..models
import
GroupProfile
from
..models
import
GroupProfile
,
Profile
from
..forms
import
TransferOwnershipForm
logger
=
logging
.
getLogger
(
__name__
)
logger
=
logging
.
getLogger
(
__name__
)
saml_available
=
hasattr
(
settings
,
"SAML_CONFIG"
)
saml_available
=
hasattr
(
settings
,
"SAML_CONFIG"
)
...
@@ -563,3 +565,132 @@ class GraphMixin(object):
...
@@ -563,3 +565,132 @@ class GraphMixin(object):
def
absolute_url
(
url
):
def
absolute_url
(
url
):
return
urljoin
(
settings
.
DJANGO_URL
,
url
)
return
urljoin
(
settings
.
DJANGO_URL
,
url
)
class
TransferOwnershipView
(
CheckedDetailView
,
DetailView
):
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
return
[
'dashboard/_modal.html'
]
else
:
return
[
'dashboard/nojs-wrapper.html'
]
def
get_context_data
(
self
,
*
args
,
**
kwargs
):
context
=
super
(
TransferOwnershipView
,
self
)
.
get_context_data
(
*
args
,
**
kwargs
)
context
[
'form'
]
=
TransferOwnershipForm
()
context
.
update
({
'box_title'
:
_
(
"Transfer ownership"
),
'ajax_title'
:
True
,
'template'
:
self
.
template
,
})
return
context
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
form
=
TransferOwnershipForm
(
request
.
POST
)
if
not
form
.
is_valid
():
return
self
.
get
(
request
)
try
:
new_owner
=
search_user
(
request
.
POST
[
'name'
])
except
User
.
DoesNotExist
:
messages
.
error
(
request
,
_
(
'Can not find specified user.'
))
return
self
.
get
(
request
,
*
args
,
**
kwargs
)
except
KeyError
:
raise
SuspiciousOperation
()
obj
=
self
.
get_object
()
if
not
(
obj
.
owner
==
request
.
user
or
request
.
user
.
is_superuser
):
raise
PermissionDenied
()
token
=
signing
.
dumps
(
(
obj
.
pk
,
new_owner
.
pk
),
salt
=
self
.
confirm_view
.
get_salt
())
token_path
=
reverse
(
self
.
token_url
,
args
=
[
token
])
try
:
new_owner
.
profile
.
notify
(
ugettext_noop
(
'Ownership offer'
),
self
.
notification_msg
,
{
'instance'
:
obj
,
'token'
:
token_path
})
except
Profile
.
DoesNotExist
:
messages
.
error
(
request
,
_
(
'Can not notify selected user.'
))
else
:
messages
.
success
(
request
,
_
(
'User
%
s is notified about the offer.'
)
%
(
unicode
(
new_owner
),
))
return
redirect
(
obj
.
get_absolute_url
())
class
TransferOwnershipConfirmView
(
LoginRequiredMixin
,
View
):
"""User can accept an ownership offer."""
max_age
=
3
*
24
*
3600
success_message
=
_
(
"Ownership successfully transferred to you."
)
@classmethod
def
get_salt
(
cls
):
return
unicode
(
cls
)
+
unicode
(
cls
.
model
)
def
get
(
self
,
request
,
key
,
*
args
,
**
kwargs
):
"""Confirm ownership transfer based on token.
"""
logger
.
debug
(
'Confirm dialog for token
%
s.'
,
key
)
try
:
instance
,
new_owner
=
self
.
get_instance
(
key
,
request
.
user
)
except
PermissionDenied
:
messages
.
error
(
request
,
_
(
'This token is for an other user.'
))
raise
except
SuspiciousOperation
:
messages
.
error
(
request
,
_
(
'This token is invalid or has expired.'
))
raise
PermissionDenied
()
return
render
(
request
,
self
.
template
,
dictionary
=
{
'instance'
:
instance
,
'key'
:
key
})
def
change_owner
(
self
,
instance
,
new_owner
):
instance
.
owner
=
new_owner
instance
.
clean
()
instance
.
save
()
def
post
(
self
,
request
,
key
,
*
args
,
**
kwargs
):
"""Really transfer ownership based on token.
"""
instance
,
owner
=
self
.
get_instance
(
key
,
request
.
user
)
old
=
instance
.
owner
self
.
change_owner
(
instance
,
request
.
user
)
messages
.
success
(
request
,
self
.
success_message
)
logger
.
info
(
'Ownership of
%
s transferred from
%
s to
%
s.'
,
unicode
(
instance
),
unicode
(
old
),
unicode
(
request
.
user
))
if
old
.
profile
:
old
.
profile
.
notify
(
ugettext_noop
(
'Ownership accepted'
),
ugettext_noop
(
'Your ownership offer of
%(instance)
s has been '
'accepted by
%(user)
s.'
),
{
'instance'
:
instance
})
return
redirect
(
instance
.
get_absolute_url
())
def
get_instance
(
self
,
key
,
user
):
"""Get object based on signed token.
"""
try
:
instance
,
new_owner
=
(
signing
.
loads
(
key
,
max_age
=
self
.
max_age
,
salt
=
self
.
get_salt
()))
except
(
signing
.
BadSignature
,
ValueError
,
TypeError
)
as
e
:
logger
.
error
(
'Tried invalid token. Token:
%
s, user:
%
s.
%
s'
,
key
,
unicode
(
user
),
unicode
(
e
))
raise
SuspiciousOperation
()
try
:
instance
=
self
.
model
.
objects
.
get
(
id
=
instance
)
except
self
.
model
.
DoesNotExist
as
e
:
logger
.
error
(
'Tried token to nonexistent instance
%
d. '
'Token:
%
s, user:
%
s.
%
s'
,
instance
,
key
,
unicode
(
user
),
unicode
(
e
))
raise
Http404
()
if
new_owner
!=
user
.
pk
:
logger
.
error
(
'
%
s (
%
d) tried the token for
%
s. Token:
%
s.'
,
unicode
(
user
),
user
.
pk
,
new_owner
,
key
)
raise
PermissionDenied
()
return
(
instance
,
new_owner
)
circle/dashboard/views/vm.py
View file @
fa12edb4
...
@@ -29,7 +29,7 @@ from django.core import signing
...
@@ -29,7 +29,7 @@ from django.core import signing
from
django.core.exceptions
import
PermissionDenied
,
SuspiciousOperation
from
django.core.exceptions
import
PermissionDenied
,
SuspiciousOperation
from
django.core.urlresolvers
import
reverse
,
reverse_lazy
from
django.core.urlresolvers
import
reverse
,
reverse_lazy
from
django.http
import
HttpResponse
,
Http404
,
HttpResponseRedirect
from
django.http
import
HttpResponse
,
Http404
,
HttpResponseRedirect
from
django.shortcuts
import
redirect
,
get_object_or_404
,
render
from
django.shortcuts
import
redirect
,
get_object_or_404
from
django.template
import
RequestContext
from
django.template
import
RequestContext
from
django.template.loader
import
render_to_string
from
django.template.loader
import
render_to_string
from
django.utils.translation
import
(
from
django.utils.translation
import
(
...
@@ -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
,
DetailView
,
View
,
UpdateView
,
ListView
,
TemplateView
,
DeleteView
)
)
from
braces.views
import
SuperuserRequiredMixin
,
LoginRequiredMixin
from
braces.views
import
SuperuserRequiredMixin
,
LoginRequiredMixin
...
@@ -54,16 +54,17 @@ from vm.models import (
...
@@ -54,16 +54,17 @@ from vm.models import (
)
)
from
.util
import
(
from
.util
import
(
CheckedDetailView
,
AjaxOperationMixin
,
OperationView
,
AclUpdateView
,
CheckedDetailView
,
AjaxOperationMixin
,
OperationView
,
AclUpdateView
,
FormOperationMixin
,
FilterMixin
,
search_user
,
GraphMixin
,
FormOperationMixin
,
FilterMixin
,
GraphMixin
,
TransferOwnershipConfirmView
,
TransferOwnershipView
,
)
)
from
..forms
import
(
from
..forms
import
(
AclUserOrGroupAddForm
,
VmResourcesForm
,
TraitsForm
,
RawDataForm
,
AclUserOrGroupAddForm
,
VmResourcesForm
,
TraitsForm
,
RawDataForm
,
VmAddInterfaceForm
,
VmCreateDiskForm
,
VmDownloadDiskForm
,
VmSaveForm
,
VmAddInterfaceForm
,
VmCreateDiskForm
,
VmDownloadDiskForm
,
VmSaveForm
,
VmRenewForm
,
VmStateChangeForm
,
VmListSearchForm
,
VmCustomizeForm
,
VmRenewForm
,
VmStateChangeForm
,
VmListSearchForm
,
VmCustomizeForm
,
TransferOwnershipForm
,
VmDiskResizeForm
,
RedeployForm
,
VmDiskRemoveForm
,
VmDiskResizeForm
,
RedeployForm
,
VmDiskRemoveForm
,
VmMigrateForm
,
VmDeployForm
,
VmMigrateForm
,
VmDeployForm
,
)
)
from
..models
import
Favourite
,
Profile
from
..models
import
Favourite
logger
=
logging
.
getLogger
(
__name__
)
logger
=
logging
.
getLogger
(
__name__
)
...
@@ -1306,139 +1307,29 @@ class FavouriteView(TemplateView):
...
@@ -1306,139 +1307,29 @@ class FavouriteView(TemplateView):
return
HttpResponse
(
"Added."
)
return
HttpResponse
(
"Added."
)
class
TransferOwnershipView
(
CheckedDetailView
,
DetailView
):
class
TransferInstanceOwnershipConfirmView
(
TransferOwnershipConfirmView
):
template
=
"dashboard/confirm/transfer-instance-ownership.html"
model
=
Instance
model
=
Instance
def
get_template_names
(
self
):
def
change_owner
(
self
,
instance
,
new_owner
):
if
self
.
request
.
is_ajax
():
with
instance
.
activity
(
return
[
'dashboard/_modal.html'
]
code_suffix
=
'ownership-transferred'
,
else
:
readable_name
=
ugettext_noop
(
"transfer ownership"
),
return
[
'dashboard/nojs-wrapper.html'
]
concurrency_check
=
False
,
user
=
new_owner
):
super
(
TransferInstanceOwnershipConfirmView
,
self
)
.
change_owner
(
def
get_context_data
(
self
,
*
args
,
**
kwargs
):
instance
,
new_owner
)
context
=
super
(
TransferOwnershipView
,
self
)
.
get_context_data
(
*
args
,
**
kwargs
)
context
[
'form'
]
=
TransferOwnershipForm
()
context
.
update
({
'box_title'
:
_
(
"Transfer ownership"
),
'ajax_title'
:
True
,
'template'
:
"dashboard/vm-detail/tx-owner.html"
,
})
return
context
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
form
=
TransferOwnershipForm
(
request
.
POST
)
if
not
form
.
is_valid
():
return
self
.
get
(
request
)
try
:
new_owner
=
search_user
(
request
.
POST
[
'name'
])
except
User
.
DoesNotExist
:
messages
.
error
(
request
,
_
(
'Can not find specified user.'
))
return
self
.
get
(
request
,
*
args
,
**
kwargs
)
except
KeyError
:
raise
SuspiciousOperation
()
obj
=
self
.
get_object
()
if
not
(
obj
.
owner
==
request
.
user
or
request
.
user
.
is_superuser
):
raise
PermissionDenied
()
token
=
signing
.
dumps
((
obj
.
pk
,
new_owner
.
pk
),
class
TransferInstanceOwnershipView
(
TransferOwnershipView
):
salt
=
TransferOwnershipConfirmView
.
get_salt
())
confirm_view
=
TransferInstanceOwnershipConfirmView
token_path
=
reverse
(
model
=
Instance
'dashboard.views.vm-transfer-ownership-confirm'
,
args
=
[
token
])
notification_msg
=
ugettext_noop
(
try
:
'
%(user)
s offered you to take the ownership of '
new_owner
.
profile
.
notify
(
ugettext_noop
(
'Ownership offer'
),
ugettext_noop
(
'
%(user)
s offered you to take the ownership of '
'his/her virtual machine called
%(instance)
s. '
'his/her virtual machine called
%(instance)
s. '
'<a href="
%(token)
s" '
'<a href="
%(token)
s" '
'class="btn btn-success btn-small">Accept</a>'
),
'class="btn btn-success btn-small">Accept</a>'
)
{
'instance'
:
obj
,
'token'
:
token_path
})
token_url
=
'dashboard.views.vm-transfer-ownership-confirm'
except
Profile
.
DoesNotExist
:
template
=
"dashboard/vm-detail/tx-owner.html"
messages
.
error
(
request
,
_
(
'Can not notify selected user.'
))
else
:
messages
.
success
(
request
,
_
(
'User
%
s is notified about the offer.'
)
%
(
unicode
(
new_owner
),
))
return
redirect
(
reverse_lazy
(
"dashboard.views.detail"
,
kwargs
=
{
'pk'
:
obj
.
pk
}))
class
TransferOwnershipConfirmView
(
LoginRequiredMixin
,
View
):
"""User can accept an ownership offer."""
max_age
=
3
*
24
*
3600
success_message
=
_
(
"Ownership successfully transferred to you."
)
@classmethod
def
get_salt
(
cls
):
return
unicode
(
cls
)
def
get
(
self
,
request
,
key
,
*
args
,
**
kwargs
):
"""Confirm ownership transfer based on token.
"""
logger
.
debug
(
'Confirm dialog for token
%
s.'
,
key
)
try
:
instance
,
new_owner
=
self
.
get_instance
(
key
,
request
.
user
)
except
PermissionDenied
:
messages
.
error
(
request
,
_
(
'This token is for an other user.'
))
raise
except
SuspiciousOperation
:
messages
.
error
(
request
,
_
(
'This token is invalid or has expired.'
))
raise
PermissionDenied
()
return
render
(
request
,
"dashboard/confirm/base-transfer-ownership.html"
,
dictionary
=
{
'instance'
:
instance
,
'key'
:
key
})
def
post
(
self
,
request
,
key
,
*
args
,
**
kwargs
):
"""Really transfer ownership based on token.
"""
instance
,
owner
=
self
.
get_instance
(
key
,
request
.
user
)
old
=
instance
.
owner
with
instance
.
activity
(
code_suffix
=
'ownership-transferred'
,
concurrency_check
=
False
,
user
=
request
.
user
):
instance
.
owner
=
request
.
user
instance
.
clean
()
instance
.
save
()
messages
.
success
(
request
,
self
.
success_message
)
logger
.
info
(
'Ownership of
%
s transferred from
%
s to
%
s.'
,
unicode
(
instance
),
unicode
(
old
),
unicode
(
request
.
user
))
if
old
.
profile
:
old
.
profile
.
notify
(
ugettext_noop
(
'Ownership accepted'
),
ugettext_noop
(
'Your ownership offer of
%(instance)
s has been '
'accepted by
%(user)
s.'
),
{
'instance'
:
instance
})
return
redirect
(
instance
.
get_absolute_url
())
def
get_instance
(
self
,
key
,
user
):
"""Get object based on signed token.
"""
try
:
instance
,
new_owner
=
(
signing
.
loads
(
key
,
max_age
=
self
.
max_age
,
salt
=
self
.
get_salt
()))
except
(
signing
.
BadSignature
,
ValueError
,
TypeError
)
as
e
:
logger
.
error
(
'Tried invalid token. Token:
%
s, user:
%
s.
%
s'
,
key
,
unicode
(
user
),
unicode
(
e
))
raise
SuspiciousOperation
()
try
:
instance
=
Instance
.
objects
.
get
(
id
=
instance
)
except
Instance
.
DoesNotExist
as
e
:
logger
.
error
(
'Tried token to nonexistent instance
%
d. '
'Token:
%
s, user:
%
s.
%
s'
,
instance
,
key
,
unicode
(
user
),
unicode
(
e
))
raise
Http404
()
if
new_owner
!=
user
.
pk
:
logger
.
error
(
'
%
s (
%
d) tried the token for
%
s. Token:
%
s.'
,
unicode
(
user
),
user
.
pk
,
new_owner
,
key
)
raise
PermissionDenied
()
return
(
instance
,
new_owner
)
@login_required
@login_required
...
...
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