Skip to content

Commit

Permalink
Merge pull request #870 from digitalocean/develop
Browse files Browse the repository at this point in the history
Release v1.8.4
  • Loading branch information
jeremystretch authored Feb 3, 2017
2 parents c90cecc + 585e08e commit ce6796e
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 37 deletions.
12 changes: 5 additions & 7 deletions netbox/ipam/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,16 +635,14 @@ class IPAddressBulkImportView(PermissionRequiredMixin, BulkImportView):

def save_obj(self, obj):
obj.save()
# Update primary IP for device if needed

# Update primary IP for device if needed. The Device must be updated directly in the database; otherwise we risk
# overwriting a previous IP assignment from the same import (see #861).
try:
if obj.family == 4 and obj.primary_ip4_for:
device = obj.primary_ip4_for
device.primary_ip4 = obj
device.save()
Device.objects.filter(pk=obj.primary_ip4_for.pk).update(primary_ip4=obj)
elif obj.family == 6 and obj.primary_ip6_for:
device = obj.primary_ip6_for
device.primary_ip6 = obj
device.save()
Device.objects.filter(pk=obj.primary_ip6_for.pk).update(primary_ip6=obj)
except Device.DoesNotExist:
pass

Expand Down
7 changes: 1 addition & 6 deletions netbox/netbox/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"the documentation.")


VERSION = '1.8.3'
VERSION = '1.8.4'

# Import local configuration
for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']:
Expand Down Expand Up @@ -189,11 +189,6 @@
if LOGIN_REQUIRED:
REST_FRAMEWORK['DEFAULT_PERMISSION_CLASSES'] = ('rest_framework.permissions.IsAuthenticated',)

# Swagger settings (API docs)
SWAGGER_SETTINGS = {
'base_path': '{}/{}api/docs'.format(ALLOWED_HOSTS[0], BASE_PATH),
}

# Django debug toolbar
INTERNAL_IPS = (
'127.0.0.1',
Expand Down
5 changes: 3 additions & 2 deletions netbox/templates/dcim/device.html
Original file line number Diff line number Diff line change
Expand Up @@ -548,9 +548,10 @@
{% block javascript %}
<script type="text/javascript">
function toggleConnection(elem, api_url) {
var url = netbox_api_path + api_url + elem.attr('data') + "/";
if (elem.hasClass('connected')) {
$.ajax({
url: netbox_api_path + api_url + elem.attr('data') + "/",
url: url,
method: 'PATCH',
dataType: 'json',
beforeSend: function(xhr, settings) {
Expand All @@ -569,7 +570,7 @@
});
} else {
$.ajax({
url: api_url + elem.attr('data') + "/",
url: url,
method: 'PATCH',
dataType: 'json',
beforeSend: function(xhr, settings) {
Expand Down
13 changes: 6 additions & 7 deletions netbox/utilities/error_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,31 @@ def handle_protectederror(obj, request, e):
"""
Generate a user-friendly error message in response to a ProtectedError exception.
"""
dependent_objects = e[1]
try:
dep_class = dependent_objects[0]._meta.verbose_name_plural
dep_class = e.protected_objects[0]._meta.verbose_name_plural
except IndexError:
raise e

# Grammar for single versus multiple triggering objects
if type(obj) in (list, tuple):
err_message = "Unable to delete the requested {}. The following dependent {} were found: ".format(
err_message = u"Unable to delete the requested {}. The following dependent {} were found: ".format(
obj[0]._meta.verbose_name_plural,
dep_class,
)
else:
err_message = "Unable to delete {} {}. The following dependent {} were found: ".format(
err_message = u"Unable to delete {} {}. The following dependent {} were found: ".format(
obj._meta.verbose_name,
obj,
dep_class,
)

# Append dependent objects to error message
dependent_objects = []
for o in e[1]:
for o in e.protected_objects:
if hasattr(o, 'get_absolute_url'):
dependent_objects.append('<a href="{}">{}</a>'.format(o.get_absolute_url(), str(o)))
dependent_objects.append(u'<a href="{}">{}</a>'.format(o.get_absolute_url(), o))
else:
dependent_objects.append(str(o))
err_message += ', '.join(dependent_objects)
err_message += u', '.join(dependent_objects)

messages.error(request, err_message)
14 changes: 8 additions & 6 deletions netbox/utilities/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,14 +236,15 @@ def __init__(self, csv_form, *args, **kwargs):
if not self.help_text:
self.help_text = 'Enter one line per record in CSV format.'

def utf_8_encoder(self, unicode_csv_data):
for line in unicode_csv_data:
yield line.encode('utf-8')

def to_python(self, value):
# Return a list of dictionaries, each representing an individual record
"""
Return a list of dictionaries, each representing an individual record
"""
# Python 2's csv module has problems with Unicode
if not isinstance(value, str):
value = value.encode('utf-8')
records = []
reader = csv.reader(self.utf_8_encoder(value.splitlines()))
reader = csv.reader(value.splitlines())
for i, row in enumerate(reader, start=1):
if row:
if len(row) < len(self.columns):
Expand All @@ -252,6 +253,7 @@ def to_python(self, value):
elif len(row) > len(self.columns):
raise forms.ValidationError("Line {}: Too many fields (found {}; expected {})"
.format(i, len(row), len(self.columns)))
row = [col.strip() for col in row]
record = dict(zip(self.columns, row))
records.append(record)
return records
Expand Down
25 changes: 18 additions & 7 deletions netbox/utilities/utils.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
import six


def csv_format(data):
"""
Encapsulate any data which contains a comma within double quotes.
"""
csv = []
for d in data:
if d in [None, False]:
for value in data:

# Represent None or False with empty string
if value in [None, False]:
csv.append(u'')
elif type(d) not in (str, unicode):
csv.append(u'{}'.format(d))
elif u',' in d:
csv.append(u'"{}"'.format(d))
continue

# Force conversion to string first so we can check for any commas
if not isinstance(value, six.string_types):
value = u'{}'.format(value)

# Double-quote the value if it contains a comma
if u',' in value:
csv.append(u'"{}"'.format(value))
else:
csv.append(d)
csv.append(u'{}'.format(value))

return u','.join(csv)
4 changes: 2 additions & 2 deletions netbox/utilities/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def get_object(self, kwargs):
return get_object_or_404(self.model, pk=kwargs['pk'])

def get_return_url(self, obj):
if hasattr(obj, 'get_absolute_url'):
if obj.pk and hasattr(obj, 'get_absolute_url'):
return obj.get_absolute_url()
return reverse(self.default_return_url)

Expand Down Expand Up @@ -267,7 +267,7 @@ def post(self, request, **kwargs):
if return_url and is_safe_url(url=return_url, host=request.get_host()):
return redirect(return_url)
else:
return redirect(self.default_return_url)
return redirect(self.get_return_url(obj))

return render(request, self.template_name, {
'obj': obj,
Expand Down

0 comments on commit ce6796e

Please sign in to comment.