Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
CIRCLE
/
cloud
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
94
Merge Requests
10
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
482c59f5
authored
Jul 10, 2014
by
Kálmán Viktor
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into feature-store
Conflicts: circle/dashboard/static/dashboard/dashboard.css circle/dashboard/urls.py
parents
9fabdf4b
61b90140
Show whitespace changes
Inline
Side-by-side
Showing
48 changed files
with
1467 additions
and
191 deletions
+1467
-191
circle/circle/__init__.py
+20
-0
circle/circle/settings/base.py
+1
-0
circle/common/operations.py
+5
-2
circle/dashboard/fixtures/test-vm-fixture.json
+18
-0
circle/dashboard/forms.py
+110
-15
circle/dashboard/migrations/0010_auto__add_futuremember__add_unique_futuremember_org_id_group.py
+273
-0
circle/dashboard/models.py
+16
-0
circle/dashboard/static/dashboard/bootstrap-slider/bootstrap-slider.js
+3
-0
circle/dashboard/static/dashboard/dashboard.css
+30
-0
circle/dashboard/static/dashboard/dashboard.js
+4
-1
circle/dashboard/static/dashboard/vm-common.js
+52
-0
circle/dashboard/static/dashboard/vm-details.js
+27
-3
circle/dashboard/templates/base.html
+1
-2
circle/dashboard/templates/dashboard/_base.html
+5
-0
circle/dashboard/templates/dashboard/_modal.html
+4
-0
circle/dashboard/templates/dashboard/_template-choose.html
+2
-0
circle/dashboard/templates/dashboard/confirm/base-remove.html
+14
-0
circle/dashboard/templates/dashboard/group-detail.html
+35
-5
circle/dashboard/templates/dashboard/operate.html
+5
-3
circle/dashboard/templates/dashboard/vm-detail.html
+5
-4
circle/dashboard/templates/dashboard/vm-detail/_activity-timeline.html
+6
-4
circle/dashboard/templates/dashboard/vm-detail/_disk-operations.html
+10
-0
circle/dashboard/templates/dashboard/vm-detail/_operations.html
+13
-3
circle/dashboard/templates/dashboard/vm-detail/console.html
+6
-0
circle/dashboard/templates/dashboard/vm-detail/network.html
+10
-3
circle/dashboard/templates/dashboard/vm-detail/resources.html
+39
-13
circle/dashboard/templates/dashboard/vm-list/column-admin.html
+1
-1
circle/dashboard/templatetags/network_tags.py
+12
-4
circle/dashboard/tests/test_mockedviews.py
+6
-4
circle/dashboard/tests/test_views.py
+6
-0
circle/dashboard/urls.py
+15
-4
circle/dashboard/views.py
+195
-78
circle/firewall/fields.py
+12
-0
circle/firewall/models.py
+5
-7
circle/manager/mancelery.py
+21
-1
circle/monitor/__init__.py
+0
-0
circle/monitor/client.py
+109
-0
circle/monitor/tasks/__init__.py
+0
-0
circle/monitor/tasks/local_periodic_tasks.py
+102
-0
circle/storage/models.py
+27
-10
circle/storage/tasks/storage_tasks.py
+5
-0
circle/vm/migrations/0023_auto__del_unique_instancetemplate_n.py
+8
-0
circle/vm/models/instance.py
+37
-12
circle/vm/models/node.py
+6
-2
circle/vm/operations.py
+157
-10
circle/vm/tasks/local_agent_tasks.py
+23
-0
circle/vm/tests/test_models.py
+5
-0
requirements/base.txt
+1
-0
No files found.
circle/circle/__init__.py
View file @
482c59f5
# register a signal do update permissions every migration.
# This is based on app django_extensions update_permissions command
from
south.signals
import
post_migrate
def
update_permissions_after_migration
(
app
,
**
kwargs
):
"""
Update app permission just after every migration.
This is based on app django_extensions update_permissions
management command.
"""
from
django.conf
import
settings
from
django.db.models
import
get_app
,
get_models
from
django.contrib.auth.management
import
create_permissions
create_permissions
(
get_app
(
app
),
get_models
(),
2
if
settings
.
DEBUG
else
0
)
post_migrate
.
connect
(
update_permissions_after_migration
)
circle/circle/settings/base.py
View file @
482c59f5
...
...
@@ -271,6 +271,7 @@ LOCAL_APPS = (
'dashboard'
,
'manager'
,
'acl'
,
'monitor'
,
)
# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
...
...
circle/common/operations.py
View file @
482c59f5
...
...
@@ -20,7 +20,7 @@ from logging import getLogger
from
.models
import
activity_context
,
has_suffix
from
django.core.exceptions
import
PermissionDenied
from
django.core.exceptions
import
PermissionDenied
,
ImproperlyConfigured
logger
=
getLogger
(
__name__
)
...
...
@@ -30,7 +30,7 @@ class Operation(object):
"""Base class for VM operations.
"""
async_queue
=
'localhost.man'
required_perms
=
()
required_perms
=
None
do_not_call_in_templates
=
True
abortable
=
False
has_percentage
=
False
...
...
@@ -141,6 +141,9 @@ class Operation(object):
pass
def
check_auth
(
self
,
user
):
if
self
.
required_perms
is
None
:
raise
ImproperlyConfigured
(
"Set required_perms to () if none needed."
)
if
not
user
.
has_perms
(
self
.
required_perms
):
raise
PermissionDenied
(
"
%
s doesn't have the required permissions."
%
user
)
...
...
circle/dashboard/fixtures/test-vm-fixture.json
View file @
482c59f5
...
...
@@ -1240,6 +1240,24 @@
}
},
{
"pk"
:
1367
,
"model"
:
"auth.permission"
,
"fields"
:
{
"codename"
:
"create_vm"
,
"name"
:
"Can create a new VM."
,
"content_type"
:
28
}
},
{
"pk"
:
1368
,
"model"
:
"auth.permission"
,
"fields"
:
{
"codename"
:
"access_console"
,
"name"
:
"Can access the graphical console of a VM."
,
"content_type"
:
28
}
},
{
"pk"
:
1
,
"model"
:
"auth.group"
,
"fields"
:
{
...
...
circle/dashboard/forms.py
View file @
482c59f5
...
...
@@ -25,6 +25,7 @@ from django.contrib.auth.forms import (
)
from
django.contrib.auth.models
import
User
,
Group
from
django.core.validators
import
URLValidator
from
django.core.exceptions
import
PermissionDenied
,
ValidationError
from
crispy_forms.helper
import
FormHelper
from
crispy_forms.layout
import
(
...
...
@@ -39,13 +40,16 @@ from django.template import Context
from
django.template.loader
import
render_to_string
from
django.utils.translation
import
ugettext
as
_
from
sizefield.widgets
import
FileSizeWidget
from
django.core.urlresolvers
import
reverse_lazy
from
django_sshkey.models
import
UserKey
from
firewall.models
import
Vlan
,
Host
from
storage.models
import
Disk
from
vm.models
import
(
InstanceTemplate
,
Lease
,
InterfaceTemplate
,
Node
,
Trait
InstanceTemplate
,
Lease
,
InterfaceTemplate
,
Node
,
Trait
,
Instance
)
from
django.contrib.admin.widgets
import
FilteredSelectMultiple
from
django.contrib.auth.models
import
Permission
from
.models
import
Profile
,
GroupProfile
from
circle.settings.base
import
LANGUAGES
from
django.utils.translation
import
string_concat
...
...
@@ -592,6 +596,17 @@ class TemplateForm(forms.ModelForm):
n
=
self
.
instance
.
interface_set
.
values_list
(
"vlan"
,
flat
=
True
)
self
.
initial
[
'networks'
]
=
n
self
.
allowed_fields
=
(
'name'
,
'access_method'
,
'description'
,
'system'
,
'tags'
)
if
self
.
user
.
has_perm
(
'vm.change_template_resources'
):
self
.
allowed_fields
+=
tuple
(
set
(
self
.
fields
.
keys
())
-
set
([
'raw_data'
]))
if
self
.
user
.
is_superuser
:
self
.
allowed_fields
+=
(
'raw_data'
,
)
for
name
,
field
in
self
.
fields
.
items
():
if
name
not
in
self
.
allowed_fields
:
field
.
widget
.
attrs
[
'disabled'
]
=
'disabled'
if
not
self
.
instance
.
pk
and
len
(
self
.
errors
)
<
1
:
self
.
instance
.
priority
=
20
self
.
instance
.
ram_size
=
512
...
...
@@ -602,14 +617,35 @@ class TemplateForm(forms.ModelForm):
return
User
.
objects
.
get
(
pk
=
self
.
instance
.
owner
.
pk
)
return
self
.
user
def
clean_raw_data
(
self
):
# if raw_data has changed and the user is not superuser
if
"raw_data"
in
self
.
changed_data
and
not
self
.
user
.
is_superuser
:
old_raw_data
=
InstanceTemplate
.
objects
.
get
(
pk
=
self
.
instance
.
pk
)
.
raw_data
return
old_raw_data
def
_clean_fields
(
self
):
try
:
old
=
InstanceTemplate
.
objects
.
get
(
pk
=
self
.
instance
.
pk
)
except
InstanceTemplate
.
DoesNotExist
:
old
=
None
for
name
,
field
in
self
.
fields
.
items
():
if
name
in
self
.
allowed_fields
:
value
=
field
.
widget
.
value_from_datadict
(
self
.
data
,
self
.
files
,
self
.
add_prefix
(
name
))
try
:
if
isinstance
(
field
,
forms
.
FileField
):
initial
=
self
.
initial
.
get
(
name
,
field
.
initial
)
value
=
field
.
clean
(
value
,
initial
)
else
:
value
=
field
.
clean
(
value
)
self
.
cleaned_data
[
name
]
=
value
if
hasattr
(
self
,
'clean_
%
s'
%
name
):
value
=
getattr
(
self
,
'clean_
%
s'
%
name
)()
self
.
cleaned_data
[
name
]
=
value
except
ValidationError
as
e
:
self
.
_errors
[
name
]
=
self
.
error_class
(
e
.
messages
)
if
name
in
self
.
cleaned_data
:
del
self
.
cleaned_data
[
name
]
elif
old
:
if
name
==
'networks'
:
self
.
cleaned_data
[
name
]
=
[
i
.
vlan
for
i
in
self
.
instance
.
interface_set
.
all
()]
else
:
return
self
.
cleaned_data
[
'raw_data'
]
self
.
cleaned_data
[
name
]
=
getattr
(
old
,
name
)
def
save
(
self
,
commit
=
True
):
data
=
self
.
cleaned_data
...
...
@@ -623,6 +659,8 @@ class TemplateForm(forms.ModelForm):
networks
=
InterfaceTemplate
.
objects
.
filter
(
template
=
self
.
instance
)
.
values_list
(
"vlan"
,
flat
=
True
)
for
m
in
data
[
'networks'
]:
if
not
m
.
has_level
(
self
.
user
,
"user"
):
raise
PermissionDenied
()
if
m
.
pk
not
in
networks
:
InterfaceTemplate
(
vlan
=
m
,
managed
=
m
.
managed
,
template
=
self
.
instance
)
.
save
()
...
...
@@ -634,10 +672,6 @@ class TemplateForm(forms.ModelForm):
@property
def
helper
(
self
):
kwargs_raw_data
=
{}
if
not
self
.
user
.
is_superuser
:
kwargs_raw_data
[
'readonly'
]
=
None
helper
=
FormHelper
()
helper
.
layout
=
Layout
(
Field
(
"name"
),
...
...
@@ -689,7 +723,7 @@ class TemplateForm(forms.ModelForm):
_
(
"Virtual machine settings"
),
Field
(
'access_method'
),
Field
(
'boot_menu'
),
Field
(
'raw_data'
,
**
kwargs_raw_data
),
Field
(
'raw_data'
),
Field
(
'req_traits'
),
Field
(
'description'
),
Field
(
"parent"
,
type
=
"hidden"
),
...
...
@@ -882,8 +916,6 @@ class VmDownloadDiskForm(forms.Form):
@property
def
helper
(
self
):
helper
=
FormHelper
(
self
)
helper
.
add_input
(
Submit
(
"submit"
,
_
(
"Create"
),
css_class
=
"btn btn-success"
))
helper
.
form_tag
=
False
return
helper
...
...
@@ -1147,3 +1179,66 @@ class UserKeyForm(forms.ModelForm):
if
self
.
user
:
self
.
instance
.
user
=
self
.
user
return
super
(
UserKeyForm
,
self
)
.
clean
()
class
TraitsForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
Instance
fields
=
(
'req_traits'
,
)
@property
def
helper
(
self
):
helper
=
FormHelper
()
helper
.
form_show_labels
=
False
helper
.
form_action
=
reverse_lazy
(
"dashboard.views.vm-traits"
,
kwargs
=
{
'pk'
:
self
.
instance
.
pk
})
helper
.
add_input
(
Submit
(
"submit"
,
_
(
"Save"
),
css_class
=
"btn btn-success"
,
))
return
helper
class
RawDataForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
Instance
fields
=
(
'raw_data'
,
)
@property
def
helper
(
self
):
helper
=
FormHelper
()
helper
.
form_show_labels
=
False
helper
.
form_action
=
reverse_lazy
(
"dashboard.views.vm-raw-data"
,
kwargs
=
{
'pk'
:
self
.
instance
.
pk
})
helper
.
add_input
(
Submit
(
"submit"
,
_
(
"Save"
),
css_class
=
"btn btn-success"
,
css_id
=
"submit-password-button"
))
return
helper
permissions_filtered
=
Permission
.
objects
.
exclude
(
codename__startswith
=
"add_"
)
.
exclude
(
codename__startswith
=
"delete_"
)
.
exclude
(
codename__startswith
=
"change_"
)
class
GroupPermissionForm
(
forms
.
ModelForm
):
permissions
=
forms
.
ModelMultipleChoiceField
(
queryset
=
permissions_filtered
,
widget
=
FilteredSelectMultiple
(
_
(
"permissions"
),
is_stacked
=
False
)
)
class
Meta
:
model
=
Group
fields
=
(
'permissions'
,
)
@property
def
helper
(
self
):
helper
=
FormHelper
()
helper
.
form_show_labels
=
False
helper
.
form_action
=
reverse_lazy
(
"dashboard.views.group-permissions"
,
kwargs
=
{
'group_pk'
:
self
.
instance
.
pk
})
helper
.
add_input
(
Submit
(
"submit"
,
_
(
"Save"
),
css_class
=
"btn btn-success"
,
))
return
helper
circle/dashboard/migrations/0010_auto__add_futuremember__add_unique_futuremember_org_id_group.py
0 → 100644
View file @
482c59f5
# -*- coding: utf-8 -*-
from
south.utils
import
datetime_utils
as
datetime
from
south.db
import
db
from
south.v2
import
SchemaMigration
from
django.db
import
models
class
Migration
(
SchemaMigration
):
def
forwards
(
self
,
orm
):
# Adding model 'FutureMember'
db
.
create_table
(
u'dashboard_futuremember'
,
(
(
u'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'org_id'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
64
)),
(
'group'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'auth.Group'
])),
))
db
.
send_create_signal
(
u'dashboard'
,
[
'FutureMember'
])
# Adding unique constraint on 'FutureMember', fields ['org_id', 'group']
db
.
create_unique
(
u'dashboard_futuremember'
,
[
'org_id'
,
'group_id'
])
def
backwards
(
self
,
orm
):
# Removing unique constraint on 'FutureMember', fields ['org_id', 'group']
db
.
delete_unique
(
u'dashboard_futuremember'
,
[
'org_id'
,
'group_id'
])
# Deleting model 'FutureMember'
db
.
delete_table
(
u'dashboard_futuremember'
)
models
=
{
u'auth.group'
:
{
'Meta'
:
{
'object_name'
:
'Group'
},
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'80'
}),
'permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
})
},
u'auth.permission'
:
{
'Meta'
:
{
'ordering'
:
"(u'content_type__app_label', u'content_type__model', u'codename')"
,
'unique_together'
:
"((u'content_type', u'codename'),)"
,
'object_name'
:
'Permission'
},
'codename'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'content_type'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['contenttypes.ContentType']"
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
},
u'auth.user'
:
{
'Meta'
:
{
'object_name'
:
'User'
},
'date_joined'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'email'
:
(
'django.db.models.fields.EmailField'
,
[],
{
'max_length'
:
'75'
,
'blank'
:
'True'
}),
'first_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'symmetrical'
:
'False'
,
'related_name'
:
"u'user_set'"
,
'blank'
:
'True'
,
'to'
:
u"orm['auth.Group']"
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'is_active'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'is_staff'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'is_superuser'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'last_login'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'last_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'password'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'user_permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'symmetrical'
:
'False'
,
'related_name'
:
"u'user_set'"
,
'blank'
:
'True'
,
'to'
:
u"orm['auth.Permission']"
}),
'username'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'30'
})
},
u'contenttypes.contenttype'
:
{
'Meta'
:
{
'ordering'
:
"('name',)"
,
'unique_together'
:
"(('app_label', 'model'),)"
,
'object_name'
:
'ContentType'
,
'db_table'
:
"'django_content_type'"
},
'app_label'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'model'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
})
},
u'dashboard.favourite'
:
{
'Meta'
:
{
'object_name'
:
'Favourite'
},
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'instance'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['vm.Instance']"
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
})
},
u'dashboard.futuremember'
:
{
'Meta'
:
{
'unique_together'
:
"(('org_id', 'group'),)"
,
'object_name'
:
'FutureMember'
},
'group'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.Group']"
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'org_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'64'
})
},
u'dashboard.groupprofile'
:
{
'Meta'
:
{
'object_name'
:
'GroupProfile'
},
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'group'
:
(
'django.db.models.fields.related.OneToOneField'
,
[],
{
'to'
:
u"orm['auth.Group']"
,
'unique'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'org_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'64'
,
'unique'
:
'True'
,
'null'
:
'True'
,
'blank'
:
'True'
})
},
u'dashboard.notification'
:
{
'Meta'
:
{
'ordering'
:
"['-created']"
,
'object_name'
:
'Notification'
},
'created'
:
(
'model_utils.fields.AutoCreatedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'message'
:
(
'django.db.models.fields.TextField'
,
[],
{}),
'modified'
:
(
'model_utils.fields.AutoLastModifiedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'status'
:
(
'model_utils.fields.StatusField'
,
[],
{
'default'
:
"'new'"
,
'max_length'
:
'100'
,
u'no_check_for_status'
:
'True'
}),
'subject'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'to'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
}),
'valid_until'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'None'
,
'null'
:
'True'
})
},
u'dashboard.profile'
:
{
'Meta'
:
{
'object_name'
:
'Profile'
},
'email_notifications'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'instance_limit'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'5'
}),
'org_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'64'
,
'unique'
:
'True'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'preferred_language'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'en'"
,
'max_length'
:
'32'
}),
'use_gravatar'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.OneToOneField'
,
[],
{
'to'
:
u"orm['auth.User']"
,
'unique'
:
'True'
})
},
u'firewall.domain'
:
{
'Meta'
:
{
'object_name'
:
'Domain'
},
'created_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'blank'
:
'True'
}),
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'modified_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'blank'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'40'
}),
'owner'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
}),
'ttl'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'600'
})
},
u'firewall.group'
:
{
'Meta'
:
{
'object_name'
:
'Group'
},
'created_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'blank'
:
'True'
}),
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'modified_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'blank'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'20'
}),
'owner'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
,
'null'
:
'True'
,
'blank'
:
'True'
})
},
u'firewall.host'
:
{
'Meta'
:
{
'ordering'
:
"('normalized_hostname', 'vlan')"
,
'unique_together'
:
"(('hostname', 'vlan'),)"
,
'object_name'
:
'Host'
},
'comment'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'created_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'blank'
:
'True'
}),
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'external_ipv4'
:
(
'firewall.fields.IPAddressField'
,
[],
{
'max_length'
:
'100'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'symmetrical'
:
'False'
,
'to'
:
u"orm['firewall.Group']"
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'hostname'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'40'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'ipv4'
:
(
'firewall.fields.IPAddressField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'100'
}),
'ipv6'
:
(
'firewall.fields.IPAddressField'
,
[],
{
'max_length'
:
'100'
,
'unique'
:
'True'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'location'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'mac'
:
(
'firewall.fields.MACAddressField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'17'
}),
'modified_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'blank'
:
'True'
}),
'normalized_hostname'
:
(
'common.models.HumanSortField'
,
[],
{
'default'
:
"''"
,
'maximum_number_length'
:
'4'
,
'max_length'
:
'80'
,
'monitor'
:
"'hostname'"
,
'blank'
:
'True'
}),
'owner'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
}),
'reverse'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'40'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'shared_ip'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'vlan'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['firewall.Vlan']"
})
},
u'firewall.vlan'
:
{
'Meta'
:
{
'object_name'
:
'Vlan'
},
'comment'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'created_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'blank'
:
'True'
}),
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'dhcp_pool'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'domain'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['firewall.Domain']"
}),
'host_ipv6_prefixlen'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'112'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'ipv6_template'
:
(
'django.db.models.fields.TextField'
,
[],
{
'default'
:
"'2001:738:2001:4031:
%(b)
d:
%(c)
d:
%(d)
d:0'"
}),
'managed'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'modified_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'blank'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'20'
}),
'network4'
:
(
'firewall.fields.IPNetworkField'
,
[],
{
'max_length'
:
'100'
}),
'network6'
:
(
'firewall.fields.IPNetworkField'
,
[],
{
'max_length'
:
'100'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'network_type'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'portforward'"
,
'max_length'
:
'20'
}),
'owner'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'reverse_domain'
:
(
'django.db.models.fields.TextField'
,
[],
{
'default'
:
"'
%(d)
d.
%(c)
d.
%(b)
d.
%(a)
d.in-addr.arpa'"
}),
'snat_ip'
:
(
'django.db.models.fields.GenericIPAddressField'
,
[],
{
'max_length'
:
'39'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'snat_to'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'symmetrical'
:
'False'
,
'to'
:
u"orm['firewall.Vlan']"
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'vid'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'unique'
:
'True'
})
},
u'storage.datastore'
:
{
'Meta'
:
{
'ordering'
:
"[u'name']"
,
'object_name'
:
'DataStore'
},
'hostname'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'40'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'100'
}),
'path'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'200'
})
},
u'storage.disk'
:
{
'Meta'
:
{
'ordering'
:
"[u'name']"
,
'object_name'
:
'Disk'
},
'base'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"u'derivatives'"
,
'null'
:
'True'
,
'to'
:
u"orm['storage.Disk']"
}),
'created'
:
(
'model_utils.fields.AutoCreatedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'datastore'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['storage.DataStore']"
}),
'destroyed'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'None'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'dev_num'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"u'a'"
,
'max_length'
:
'1'
}),
'filename'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'256'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'is_ready'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'modified'
:
(
'model_utils.fields.AutoLastModifiedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
,
'blank'
:
'True'
}),
'size'
:
(
'sizefield.models.FileSizeField'
,
[],
{
'default'
:
'None'
,
'null'
:
'True'
}),
'type'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'10'
})
},
u'vm.instance'
:
{
'Meta'
:
{
'ordering'
:
"(u'pk',)"
,
'object_name'
:
'Instance'
},
'access_method'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'10'
}),
'active_since'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'arch'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'10'
}),
'boot_menu'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'created'
:
(
'model_utils.fields.AutoCreatedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'destroyed_at'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'disks'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'related_name'
:
"u'instance_set'"
,
'symmetrical'
:
'False'
,
'to'
:
u"orm['storage.Disk']"
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'is_base'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'lease'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['vm.Lease']"
}),
'max_ram_size'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'modified'
:
(
'model_utils.fields.AutoLastModifiedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
,
'blank'
:
'True'
}),
'node'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"u'instance_set'"
,
'null'
:
'True'
,
'to'
:
u"orm['vm.Node']"
}),
'num_cores'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'owner'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
}),
'priority'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'pw'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'20'
}),
'ram_size'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'raw_data'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'req_traits'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['vm.Trait']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'status'
:
(
'model_utils.fields.StatusField'
,
[],
{
'default'
:
"u'NOSTATE'"
,
'max_length'
:
'100'
,
u'no_check_for_status'
:
'True'
}),
'status_changed'
:
(
'model_utils.fields.MonitorField'
,
[],
{
'default'
:
'datetime.datetime.now'
,
u'monitor'
:
"u'status'"
}),
'system'
:
(
'django.db.models.fields.TextField'
,
[],
{}),
'template'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"u'instance_set'"
,
'null'
:
'True'
,
'on_delete'
:
'models.SET_NULL'
,
'to'
:
u"orm['vm.InstanceTemplate']"
}),
'time_of_delete'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'None'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'time_of_suspend'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'None'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'vnc_port'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'None'
,
'unique'
:
'True'
,
'null'
:
'True'
,
'blank'
:
'True'
})
},
u'vm.instancetemplate'
:
{
'Meta'
:
{
'ordering'
:
"(u'name',)"
,
'object_name'
:
'InstanceTemplate'
},
'access_method'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'10'
}),
'arch'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'10'
}),
'boot_menu'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'created'
:
(
'model_utils.fields.AutoCreatedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'description'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'disks'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'related_name'
:
"u'template_set'"
,
'symmetrical'
:
'False'
,
'to'
:
u"orm['storage.Disk']"
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'lease'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['vm.Lease']"
}),
'max_ram_size'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'modified'
:
(
'model_utils.fields.AutoLastModifiedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'num_cores'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'owner'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['auth.User']"
}),
'parent'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['vm.InstanceTemplate']"
,
'null'
:
'True'
,
'on_delete'
:
'models.SET_NULL'
,
'blank'
:
'True'
}),
'priority'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'ram_size'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'raw_data'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'req_traits'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['vm.Trait']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'system'
:
(
'django.db.models.fields.TextField'
,
[],
{})
},
u'vm.lease'
:
{
'Meta'
:
{
'ordering'
:
"[u'name']"
,
'object_name'
:
'Lease'
},
'delete_interval_seconds'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'100'
}),
'suspend_interval_seconds'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
})
},
u'vm.node'
:
{
'Meta'
:
{
'ordering'
:
"(u'-enabled', u'normalized_name')"
,
'object_name'
:
'Node'
},
'created'
:
(
'model_utils.fields.AutoCreatedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'enabled'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'host'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
u"orm['firewall.Host']"
}),
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'modified'
:
(
'model_utils.fields.AutoLastModifiedField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'50'
}),
'normalized_name'
:
(
'common.models.HumanSortField'
,
[],
{
'default'
:
"''"
,
'maximum_number_length'
:
'4'
,
'max_length'
:
'100'
,
'monitor'
:
"u'name'"
,
'blank'
:
'True'
}),
'overcommit'
:
(
'django.db.models.fields.FloatField'
,
[],
{
'default'
:
'1.0'
}),
'priority'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'traits'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
u"orm['vm.Trait']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
})
},
u'vm.trait'
:
{
'Meta'
:
{
'object_name'
:
'Trait'
},
u'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
}
}
complete_apps
=
[
'dashboard'
]
\ No newline at end of file
circle/dashboard/models.py
View file @
482c59f5
...
...
@@ -140,6 +140,18 @@ class Profile(Model):
return
self
.
get_display_name
()
class
FutureMember
(
Model
):
org_id
=
CharField
(
max_length
=
64
,
help_text
=
_
(
'Unique identifier of the person, e.g. a student number.'
))
group
=
ForeignKey
(
Group
)
class
Meta
:
unique_together
=
(
'org_id'
,
'group'
)
def
__unicode__
(
self
):
return
u"
%
s (
%
s)"
%
(
self
.
org_id
,
self
.
group
)
class
GroupProfile
(
AclBase
):
ACL_LEVELS
=
(
(
'operator'
,
_
(
'operator'
)),
...
...
@@ -224,6 +236,10 @@ if hasattr(settings, 'SAML_ORG_ID_ATTRIBUTE'):
group
,
unicode
(
g
))
g
.
user_set
.
add
(
sender
)
for
i
in
FutureMember
.
objects
.
filter
(
org_id
=
value
):
i
.
group
.
user_set
.
add
(
sender
)
i
.
delete
()
owneratrs
=
getattr
(
settings
,
'SAML_GROUP_OWNER_ATTRIBUTES'
,
[])
for
group
in
chain
(
*
[
attributes
[
i
]
for
i
in
owneratrs
if
i
in
attributes
]):
...
...
circle/dashboard/static/dashboard/bootstrap-slider/bootstrap-slider.js
View file @
482c59f5
...
...
@@ -192,6 +192,9 @@
},
mousedown
:
function
(
ev
)
{
if
(
this
.
element
[
0
].
disabled
)
{
return
false
;
}
// Touch: Get the original event:
if
(
this
.
touchCapable
&&
ev
.
type
===
'touchstart'
)
{
...
...
circle/dashboard/static/dashboard/dashboard.css
View file @
482c59f5
...
...
@@ -723,6 +723,7 @@ textarea[name="list-new-namelist"] {
}
<<<<<<<
HEAD
#store-list-list
{
list-style
:
none
;
}
...
...
@@ -792,3 +793,32 @@ textarea[name="list-new-namelist"] {
.no-hover
:hover
{
background
:
none
!important
;
}
#group-detail-permissions
.filtered
{
margin
:
2px
0
;
padding
:
2px
3px
;
vertical-align
:
middle
;
font-family
:
"Lucida Grande"
,
Verdana
,
Arial
,
sans-serif
;
font-weight
:
normal
;
font-size
:
11px
;
border
:
1px
solid
#ccc
;
}
#group-detail-permissions
.selector-available
h2
,
#group-detail-permissions
.selector-chosen
h2
{
margin
:
0
;
padding
:
5px
8px
5px
8px
;
font-size
:
12px
;
text-align
:
left
;
font-weight
:
bold
;
background
:
#7CA0C7
;
color
:
white
;
}
#group-detail-user-table
{
margin-top
:
20px
;
}
#group-detail-permissions
input
[
type
=
"submit"
]
{
margin-top
:
-6px
;
}
circle/dashboard/static/dashboard/dashboard.js
View file @
482c59f5
...
...
@@ -512,7 +512,10 @@ function addMessage(text, type) {
$
(
'body'
).
animate
({
scrollTop
:
0
});
div
=
'<div style="display: none;" class="alert alert-'
+
type
+
'">'
+
text
+
'</div>'
;
$
(
'.messagelist'
).
html
(
''
).
append
(
div
);
$
(
'.messagelist div'
).
fadeIn
();
var
div
=
$
(
'.messagelist div'
).
fadeIn
();
setTimeout
(
function
()
{
$
(
div
).
fadeOut
();
},
9000
);
}
...
...
circle/dashboard/static/dashboard/vm-common.js
View file @
482c59f5
...
...
@@ -30,4 +30,56 @@ $(function() {
});
return
false
;
});
/* if the operation fails show the modal again */
$
(
"body"
).
on
(
"click"
,
"#op-form-send"
,
function
()
{
var
url
=
$
(
this
).
closest
(
"form"
).
prop
(
"action"
);
$
.
ajax
({
url
:
url
,
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
type
:
'POST'
,
data
:
$
(
this
).
closest
(
'form'
).
serialize
(),
success
:
function
(
data
,
textStatus
,
xhr
)
{
/* hide the modal we just submitted */
$
(
'#confirmation-modal'
).
modal
(
"hide"
);
/* if it was successful trigger a click event on activity, this will
* - go to that tab
* - starts refreshing the activity
*/
if
(
data
.
success
)
{
$
(
'a[href="#activity"]'
).
trigger
(
"click"
);
/* if there are messages display them */
if
(
data
.
messages
&&
data
.
messages
.
length
>
0
)
{
addMessage
(
data
.
messages
.
join
(
"<br />"
),
"danger"
);
}
}