Skip to content

Commit

Permalink
Merge pull request #966 from digitalocean/develop
Browse files Browse the repository at this point in the history
Release v1.9.2
  • Loading branch information
jeremystretch authored Mar 14, 2017
2 parents 097e0f3 + b22c6a0 commit 27eefd8
Show file tree
Hide file tree
Showing 17 changed files with 70 additions and 50 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sh text eol=lf
39 changes: 25 additions & 14 deletions netbox/dcim/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,13 +680,21 @@ def clean_face(self):


class ChildDeviceFromCSVForm(BaseDeviceFromCSVForm):
parent = FlexibleModelChoiceField(queryset=Device.objects.all(), to_field_name='name', required=False,
error_messages={'invalid_choice': 'Parent device not found.'})
parent = FlexibleModelChoiceField(
queryset=Device.objects.all(),
to_field_name='name',
required=False,
error_messages={
'invalid_choice': 'Parent device not found.'
}
)
device_bay_name = forms.CharField(required=False)

class Meta(BaseDeviceFromCSVForm.Meta):
fields = ['name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'asset_tag',
'parent', 'device_bay_name']
fields = [
'name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'asset_tag', 'parent',
'device_bay_name',
]

def clean(self):

Expand Down Expand Up @@ -733,7 +741,7 @@ class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Device
q = forms.CharField(required=False, label='Search')
site = FilterChoiceField(
queryset=Site.objects.annotate(filter_count=Count('racks__devices')),
queryset=Site.objects.annotate(filter_count=Count('devices')),
to_field_name='slug',
)
rack_group_id = FilterChoiceField(
Expand Down Expand Up @@ -1610,20 +1618,23 @@ class DeviceBayCreateForm(DeviceComponentForm):


class PopulateDeviceBayForm(BootstrapMixin, forms.Form):
installed_device = forms.ModelChoiceField(queryset=Device.objects.all(), label='Child Device',
help_text="Child devices must first be created within the rack occupied "
"by the parent device. Then they can be assigned to a bay.")
installed_device = forms.ModelChoiceField(
queryset=Device.objects.all(),
label='Child Device',
help_text="Child devices must first be created and assigned to the site/rack of the parent device."
)

def __init__(self, device_bay, *args, **kwargs):

super(PopulateDeviceBayForm, self).__init__(*args, **kwargs)

children_queryset = Device.objects.filter(rack=device_bay.device.rack,
parent_bay__isnull=True,
device_type__u_height=0,
device_type__subdevice_role=SUBDEVICE_ROLE_CHILD)\
.exclude(pk=device_bay.device.pk)
self.fields['installed_device'].queryset = children_queryset
self.fields['installed_device'].queryset = Device.objects.filter(
site=device_bay.device.site,
rack=device_bay.device.rack,
parent_bay__isnull=True,
device_type__u_height=0,
device_type__subdevice_role=SUBDEVICE_ROLE_CHILD
).exclude(pk=device_bay.device.pk)


#
Expand Down
25 changes: 14 additions & 11 deletions netbox/dcim/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -975,25 +975,26 @@ def clean(self):
# Child devices cannot be assigned to a rack face/unit
if self.device_type.is_child_device and self.face is not None:
raise ValidationError({
'face': "Child device types cannot be assigned to a rack face. This is an attribute of the parent "
"device."
'face': "Child device types cannot be assigned to a rack face. This is an attribute of the "
"parent device."
})
if self.device_type.is_child_device and self.position:
raise ValidationError({
'position': "Child device types cannot be assigned to a rack position. This is an attribute of the "
"parent device."
'position': "Child device types cannot be assigned to a rack position. This is an attribute of "
"the parent device."
})

# Validate rack space
rack_face = self.face if not self.device_type.is_full_depth else None
exclude_list = [self.pk] if self.pk else []
try:
available_units = self.rack.get_available_units(u_height=self.device_type.u_height, rack_face=rack_face,
exclude=exclude_list)
available_units = self.rack.get_available_units(
u_height=self.device_type.u_height, rack_face=rack_face, exclude=exclude_list
)
if self.position and self.position not in available_units:
raise ValidationError({
'position': "U{} is already occupied or does not have sufficient space to accommodate a(n) {} "
"({}U).".format(self.position, self.device_type, self.device_type.u_height)
'position': "U{} is already occupied or does not have sufficient space to accommodate a(n) "
"{} ({}U).".format(self.position, self.device_type, self.device_type.u_height)
})
except Rack.DoesNotExist:
pass
Expand Down Expand Up @@ -1034,8 +1035,8 @@ def save(self, *args, **kwargs):
self.device_type.device_bay_templates.all()]
)

# Update Rack assignment for any child Devices
Device.objects.filter(parent_bay__device=self).update(rack=self.rack)
# Update Site and Rack assignment for any child Devices
Device.objects.filter(parent_bay__device=self).update(site=self.site, rack=self.rack)

def to_csv(self):
return csv_format([
Expand All @@ -1059,8 +1060,10 @@ def display_name(self):
return self.name
elif self.position:
return u"{} ({} U{})".format(self.device_type, self.rack.name, self.position)
else:
elif self.rack:
return u"{} ({})".format(self.device_type, self.rack.name)
else:
return u"{} ({})".format(self.device_type, self.site.name)

@property
def identifier(self):
Expand Down
5 changes: 4 additions & 1 deletion netbox/dcim/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -763,9 +763,12 @@ class ChildDeviceBulkImportView(PermissionRequiredMixin, BulkImportView):
default_return_url = 'dcim:device_list'

def save_obj(self, obj):
# Inherent rack from parent device

# Inherit site and rack from parent device
obj.site = obj.parent_bay.device.site
obj.rack = obj.parent_bay.device.rack
obj.save()

# Save the reverse relation
device_bay = obj.parent_bay
device_bay.installed_device = obj
Expand Down
2 changes: 1 addition & 1 deletion netbox/netbox/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"the documentation.")


VERSION = '1.9.1'
VERSION = '1.9.2'

# Import local configuration
for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']:
Expand Down
2 changes: 1 addition & 1 deletion netbox/netbox/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
url(r'^ipam/', include('ipam.urls', namespace='ipam')),
url(r'^secrets/', include('secrets.urls', namespace='secrets')),
url(r'^tenancy/', include('tenancy.urls', namespace='tenancy')),
url(r'^profile/', include('users.urls', namespace='users')),
url(r'^user/', include('users.urls', namespace='user')),

# API
url(r'^api/circuits/', include('circuits.api.urls', namespace='circuits-api')),
Expand Down
4 changes: 2 additions & 2 deletions netbox/secrets/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ def wrapped_view(request, *args, **kwargs):
uk = UserKey.objects.get(user=request.user)
except UserKey.DoesNotExist:
messages.warning(request, u"This operation requires an active user key, but you don't have one.")
return redirect('users:userkey')
return redirect('user:userkey')
if not uk.is_active():
messages.warning(request, u"This operation is not available. Your user key has not been activated.")
return redirect('users:userkey')
return redirect('user:userkey')
return view(request, *args, **kwargs)
return wrapped_view
return _decorator
2 changes: 1 addition & 1 deletion netbox/templates/_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@
{% if request.user.is_staff %}
<li><a href="{% url 'admin:index' %}"><i class="fa fa-cogs" aria-hidden="true"></i> Admin</a></li>
{% endif %}
<li><a href="{% url 'users:profile' %}"><i class="fa fa-user" aria-hidden="true"></i> {{ request.user }}</a></li>
<li><a href="{% url 'user:profile' %}"><i class="fa fa-user" aria-hidden="true"></i> {{ request.user }}</a></li>
<li><a href="{% url 'logout' %}"><i class="fa fa-sign-out" aria-hidden="true"></i> Log out</a></li>
{% else %}
<li><a href="{% url 'login' %}?next={{ request.path }}"><i class="fa fa-sign-in" aria-hidden="true"></i> Log in</a></li>
Expand Down
6 changes: 4 additions & 2 deletions netbox/templates/dcim/device.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@
<td>
{% if device.parent_bay %}
{% with device.parent_bay.device as parent %}
<span>U{{ parent.position }} / {{ parent.get_face_display }}
(<a href="{{ parent.get_absolute_url }}">{{ parent }}</a> - {{ device.parent_bay.name }})</span>
<a href="{{ parent.get_absolute_url }}">{{ parent }}</a> <i class="fa fa-angle-right"></i> {{ device.parent_bay.name }}
{% if parent.position %}
(U{{ parent.position }} / {{ parent.get_face_display }})
{% endif %}
{% endwith %}
{% elif device.rack and device.position %}
<span>U{{ device.position }} / {{ device.get_face_display }}</span>
Expand Down
8 changes: 4 additions & 4 deletions netbox/templates/users/_user.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ <h1>{% block title %}{% endblock %}</h1>
<div class="row">
<div class="col-sm-3 col-md-2 col-md-offset-2">
<ul class="nav nav-pills nav-stacked">
<li{% ifequal active_tab "profile" %} class="active"{% endifequal %}><a href="{% url 'users:profile' %}">Profile</a></li>
<li{% ifequal active_tab "change_password" %} class="active"{% endifequal %}><a href="{% url 'users:change_password' %}">Change Password</a></li>
<li{% ifequal active_tab "userkey" %} class="active"{% endifequal %}><a href="{% url 'users:userkey' %}">User Key</a></li>
<li{% ifequal active_tab "recent_activity" %} class="active"{% endifequal %}><a href="{% url 'users:recent_activity' %}">Recent Activity</a></li>
<li{% ifequal active_tab "profile" %} class="active"{% endifequal %}><a href="{% url 'user:profile' %}">Profile</a></li>
<li{% ifequal active_tab "change_password" %} class="active"{% endifequal %}><a href="{% url 'user:change_password' %}">Change Password</a></li>
<li{% ifequal active_tab "userkey" %} class="active"{% endifequal %}><a href="{% url 'user:userkey' %}">User Key</a></li>
<li{% ifequal active_tab "recent_activity" %} class="active"{% endifequal %}><a href="{% url 'user:recent_activity' %}">Recent Activity</a></li>
</ul>
</div>
<div class="col-sm-9 col-md-6">
Expand Down
2 changes: 1 addition & 1 deletion netbox/templates/users/change_password.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
</div>
<div class="text-right">
<button type="submit" name="_update" class="btn btn-primary">Update</button>
<a href="{% url 'users:profile' %}" class="btn btn-default">Cancel</a>
<a href="{% url 'user:profile' %}" class="btn btn-default">Cancel</a>
</div>
</form>
{% endblock %}
4 changes: 2 additions & 2 deletions netbox/templates/users/userkey.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ <h4>
<p>Your public key is below.</p>
<pre>{{ userkey.public_key }}</pre>
<div class="pull-right">
<a href="{% url 'users:userkey_edit' %}" class="btn btn-warning">
<a href="{% url 'user:userkey_edit' %}" class="btn btn-warning">
<span class="fa fa-pencil" aria-hidden="true"></span>
Edit user key
</a>
Expand All @@ -24,7 +24,7 @@ <h4>
{% else %}
<p>You don't have a user key on file.</p>
<p>
<a href="{% url 'users:userkey_edit' %}" class="btn btn-primary">
<a href="{% url 'user:userkey_edit' %}" class="btn btn-primary">
<span class="fa fa-plus" aria-hidden="true"></span>
Create a User Key
</a>
Expand Down
2 changes: 1 addition & 1 deletion netbox/templates/users/userkey_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</div>
<div class="col-sm-6 col-md-6 text-right">
<button type="submit" name="_update" class="btn btn-primary">Save</button>
<a href="{% url 'users:userkey' %}" class="btn btn-default">Cancel</a>
<a href="{% url 'user:userkey' %}" class="btn btn-default">Cancel</a>
</div>
</div>
</div>
Expand Down
8 changes: 4 additions & 4 deletions netbox/users/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

# User profiles
url(r'^profile/$', views.profile, name='profile'),
url(r'^profile/password/$', views.change_password, name='change_password'),
url(r'^profile/user-key/$', views.userkey, name='userkey'),
url(r'^profile/user-key/edit/$', views.userkey_edit, name='userkey_edit'),
url(r'^profile/recent-activity/$', views.recent_activity, name='recent_activity'),
url(r'^password/$', views.change_password, name='change_password'),
url(r'^user-key/$', views.userkey, name='userkey'),
url(r'^user-key/edit/$', views.userkey_edit, name='userkey_edit'),
url(r'^recent-activity/$', views.recent_activity, name='recent_activity'),

]
4 changes: 2 additions & 2 deletions netbox/users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def change_password(request):
form.save()
update_session_auth_hash(request, form.user)
messages.success(request, u"Your password has been changed successfully.")
return redirect('users:profile')
return redirect('user:profile')

else:
form = PasswordChangeForm(user=request.user)
Expand Down Expand Up @@ -109,7 +109,7 @@ def userkey_edit(request):
uk.user = request.user
uk.save()
messages.success(request, u"Your user key has been saved.")
return redirect('users:userkey')
return redirect('user:userkey')

else:
form = UserKeyForm(instance=userkey)
Expand Down
2 changes: 1 addition & 1 deletion netbox/utilities/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def parse_numeric_range(string, base=10):
begin, end = dash_range.split('-')
except ValueError:
begin, end = dash_range, dash_range
begin, end = int(begin.strip()), int(end.strip(), base=base) + 1
begin, end = int(begin.strip(), base=base), int(end.strip(), base=base) + 1
values.extend(range(begin, end))
return list(set(values))

Expand Down
4 changes: 2 additions & 2 deletions netbox/utilities/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ def post(self, request, **kwargs):

# Are we editing *all* objects in the queryset or just a selected subset?
if request.POST.get('_all') and self.filter is not None:
pk_list = [obj.pk for obj in self.filter(request.GET, self.cls.objects.only('pk'))]
pk_list = [obj.pk for obj in self.filter(request.GET, self.cls.objects.only('pk')).qs]
else:
pk_list = [int(pk) for pk in request.POST.getlist('pk')]

Expand Down Expand Up @@ -572,7 +572,7 @@ def post(self, request, **kwargs):

# Are we deleting *all* objects in the queryset or just a selected subset?
if request.POST.get('_all') and self.filter is not None:
pk_list = [obj.pk for obj in self.filter(request.GET, self.cls.objects.only('pk'))]
pk_list = [obj.pk for obj in self.filter(request.GET, self.cls.objects.only('pk')).qs]
else:
pk_list = [int(pk) for pk in request.POST.getlist('pk')]

Expand Down

0 comments on commit 27eefd8

Please sign in to comment.