Index: /trunk/exodus/models.py
===================================================================
--- /trunk/exodus/models.py	(revision 6323)
+++ /trunk/exodus/models.py	(revision 6324)
@@ -52,4 +52,7 @@
     Latitude = models.DecimalField(max_digits=8,decimal_places=6)
 
+    class Meta:
+        verbose_name = 'Location'
+
     def __str__(self):
         return self.description
@@ -69,4 +72,7 @@
 	netmask = models.IntegerField()
 
+    class Meta:
+        verbose_name = 'Network'
+
 	def __str__(self):
 		return self.name
@@ -81,5 +87,6 @@
  
     class Meta:
-         ordering = ['name']
+        ordering = ['name']
+        verbose_name = 'Node'
 
     def __str__(self):
@@ -103,4 +110,5 @@
 	class Meta:
 		unique_together = ('node', 'iface')
+		verbose_name = 'Interface'
 	
 	def __str__(self):
@@ -145,4 +153,7 @@
     PublicAP = models.ForeignKey(PublicAP)
 
+    class Meta:
+        verbose_name = "Static host"
+
     def __str__(self):
         return self.hostname
Index: /trunk/exodus/templates/addInterface.html
===================================================================
--- /trunk/exodus/templates/addInterface.html	(revision 6324)
+++ /trunk/exodus/templates/addInterface.html	(revision 6324)
@@ -0,0 +1,19 @@
+<script type="text/javascript">
+window.onload = function()
+{
+	document.getElementById('id_polar').disabled = 'true';
+	document.getElementById('id_antenna').disabled = 'true';
+	document.getElementById('id_type').onchange = function()
+	{
+	var newValue = document.getElementById('id_type').value;
+	document.getElementById('id_iface').value = newValue;
+	if (newValue == 'eth') {
+		newValue = 'true';
+	} else {
+		newValue = '';
+	}
+	document.getElementById('id_polar').disabled = newValue;
+	document.getElementById('id_antenna').disabled = newValue;
+	}
+}
+</script>
Index: unk/exodus/templates/addlocation.html
===================================================================
--- /trunk/exodus/templates/addlocation.html	(revision 6323)
+++ 	(revision )
@@ -1,12 +1,0 @@
-{% extends "exodus-template.html" %}
-
-{% block content %}
-<h1>Create a location</h1>
-
-
-<form method="post" action=".">
-<table>{{ form.as_table }}</table>
-<input type="submit" value="submit">
-</form>
-
-{% endblock %}
Index: unk/exodus/templates/addnic.html
===================================================================
--- /trunk/exodus/templates/addnic.html	(revision 6323)
+++ 	(revision )
@@ -1,33 +1,0 @@
-{% extends "exodus-template.html" %}
-
-{% block content %}
-<h1>Create a Interface</h1>
-{# XXX: Javascript to disable antenna details, when eth selected #}
-
-<form method="post" action=".">
-<table>{{ form.as_table }}</table>
-<input type="submit" value="submit">
-</form>
-
-<script type="text/javascript">
-window.onload = function()
-{
-	document.getElementById('id_polar').disabled = 'true';
-	document.getElementById('id_antenna').disabled = 'true';
-	document.getElementById('id_type').onchange = function()
-	{
-	var newValue = document.getElementById('id_type').value;
-	document.getElementById('id_iface').value = newValue;
-	if (newValue == 'eth') {
-		newValue = 'true';
-	} else {
-		newValue = '';
-	}
-	document.getElementById('id_polar').disabled = newValue;
-	document.getElementById('id_antenna').disabled = newValue;
-	}
-}
-</script>
-
-
-{% endblock %}
Index: unk/exodus/templates/addnode.html
===================================================================
--- /trunk/exodus/templates/addnode.html	(revision 6323)
+++ 	(revision )
@@ -1,13 +1,0 @@
-{% extends "exodus-template.html" %}
-
-{% block content %}
-
-<h1>Create a Node</h1>
-<h2><em> {{ message }} </em></h2>
-
-<form method="post" action=".">
-<table>{{ form.as_table }}</table>
-<input type="submit" value="submit">
-</form>
-
-{% endblock %}
Index: unk/exodus/templates/addomni.html
===================================================================
--- /trunk/exodus/templates/addomni.html	(revision 6323)
+++ 	(revision )
@@ -1,12 +1,0 @@
-{% extends "exodus-template.html" %}
-
-{% block content %}
-<h1>Add an public access point</h1>
-
-<form method="post" action=".">
-<table>{{ form.as_table }}</table>
-<input type="submit" name="cancel" value="NO, cancel">
-<input type="submit" name="proceed" value="OK, proceed">
-</form>
-
-{% endblock %}
Index: /trunk/exodus/templates/editInterface.html
===================================================================
--- /trunk/exodus/templates/editInterface.html	(revision 6324)
+++ /trunk/exodus/templates/editInterface.html	(revision 6324)
@@ -0,0 +1,1 @@
+{% include 'addInterface.html' %}
Index: /trunk/exodus/templates/exodus-template.html
===================================================================
--- /trunk/exodus/templates/exodus-template.html	(revision 6323)
+++ /trunk/exodus/templates/exodus-template.html	(revision 6324)
@@ -16,6 +16,6 @@
 	  &nbsp;&nbsp;<A class="menu" href="{% url root %}">Exodus</a><br>
 	  &nbsp;&nbsp;<A class="menu" href="{% url nodelist %}">Node List</a><br>
-	  &nbsp;&nbsp;<A class="menu" href="{% url exodus.views.addLocation %}">Add Location</a><br>
-	  &nbsp;&nbsp;<A class="menu" href="{% url exodus.views.addNode %}">Add Node</a><br>
+	  &nbsp;&nbsp;<A class="menu" href="{% url exodus.views.genericLocation "add" "new" %}">Add Location</a><br>
+	  &nbsp;&nbsp;<A class="menu" href="{% url exodus.views.genericNode "add" "new" %}">Add Node</a><br>
 	  </div>
 	</td>
Index: /trunk/exodus/templates/genericForm.html
===================================================================
--- /trunk/exodus/templates/genericForm.html	(revision 6323)
+++ /trunk/exodus/templates/genericForm.html	(revision 6324)
@@ -9,11 +9,21 @@
 
 <form method="post" action=".">
-{# On delete, make sure not to enable editing #}
+{# On delete, make sure not to enable editing, and view detail instead #}
 {% ifequal mode "delete" %}
+<table>
+{% for key, value in object.as_list %}
+<tr><th>{{ key }}</th><td>:</td><td>{{ value }}</td><tr>
+{% endfor %}
+</table>
 {% include delInclude %}
-
 <h3>Are you sure you want to <b>DELETE</b> this data <b>PERMANENTLY</b>?</h3>
 {% else %}
-<table>{{ form.as_table }}</table>
+	{# Include custom code, like the javascript code #}
+	{% ifequal mode "add" %}
+		{% include addInclude %}
+	{% else %}
+		{% include editInclude %}
+	{% endifequal %}
+	<table>{{ form.as_table }}</table>
 {% endifequal %}
 <input type="submit" name="cancel" value="NO, cancel">
Index: /trunk/exodus/templates/node-detail.html
===================================================================
--- /trunk/exodus/templates/node-detail.html	(revision 6323)
+++ /trunk/exodus/templates/node-detail.html	(revision 6324)
@@ -12,10 +12,10 @@
 
 Master ip: {{ node.masterip }} <br>
-<a href="{% url exodus.views.editNode node %}">EDIT</a>
-<a href="{% url exodus.views.delNode node %}">DELETE</a>
+<a href="{% url exodus.views.genericNode "edit" node.name %}">EDIT</a>
+<a href="{% url exodus.views.genericNode "delete" node.name %}">DELETE</a>
 </div>
 
 <h2>Interfaces</h2>
-<a href="{% url exodus.views.addInterface %}?node={{ node.name }}">Add new interface</a><p />
+<a href="{% url exodus.views.genericInterface "add" node.name "new" %}">Add new interface</a><p />
 
 {% for nic in node.interface_set.all %}
@@ -23,5 +23,5 @@
 	<div style="border:1px solid #000000;">
 	<h3>iface: {{ nic.iface }} </h3>
-	<a href="{% url exodus.views.genericPublicAP "add" node nic.iface "new" %}">Add new public access point</a><p />
+	<a href="{% url exodus.views.genericPublicAP "add" node.name nic.iface "new" %}">Add new public access point</a><p />
 	type: {{ nic.type }} <br>
 	description: {{ nic.shortdesc }} <br>
@@ -35,6 +35,6 @@
 		Mode: {{ nic.mode }} <br>
 	{% endifnotequal %}
-	<a href="{% url exodus.views.editInterface nic %}">EDIT</a>
-	<a href="{% url exodus.views.delInterface nic %}">DELETE</a>
+	<a href="{% url exodus.views.genericInterface "edit" node.name nic.iface %}">EDIT</a>
+	<a href="{% url exodus.views.genericInterface "delete" node.name nic.iface %}">DELETE</a>
 	</div>
 
Index: /trunk/exodus/urls.py
===================================================================
--- /trunk/exodus/urls.py	(revision 6323)
+++ /trunk/exodus/urls.py	(revision 6324)
@@ -39,19 +39,13 @@
 
 
-	# add urls
-	(r'^add/location/$', 'exodus.views.addLocation'),
-	(r'^add/node/$', 'exodus.views.addNode'),
-	(r'^add/nic/$', 'exodus.views.addInterface'),
 
-	# add urls
-	(r'^edit/location/(?P<object_id>.+)/$', 'exodus.views.addLocation'),
-	(r'^edit/node/(?P<objectId>.+)/$', 'exodus.views.editNode'),
-	(r'^edit/nic/(?P<objectId>.+)/$', 'exodus.views.editInterface'),
 	(r'^edit/link/(?P<object_id>.+)/$', 'exodus.views.addLink'),
-	(r'^(?P<mode>(add|edit|delete))/dhcp/(?P<node>.+)/(?P<interface>.+)/(?P<publicAP>.+)/$', 'exodus.views.genericPublicAP'),
 
-	# delete/remove urls
-	(r'^del/node/(?P<objectId>.+)/$', 'exodus.views.delNode'),
-	(r'^del/nic/(?P<objectId>.+)/$', 'exodus.views.delInterface'),
+	# Generic urls
+	(r'^location/(?P<mode>(add|edit|delete))/(?P<location>.+)/$', 'exodus.views.genericLocation'),
+	(r'^node/(?P<mode>(add|edit|delete))/(?P<node>.+)/$', 'exodus.views.genericNode'),
+	(r'^nic/(?P<mode>(add|edit|delete))/(?P<node>.+)/(?P<interface>.+)/$', 'exodus.views.genericInterface'),
+	(r'^dhcp/(?P<mode>(add|edit|delete))/(?P<node>.+)/(?P<interface>.+)/(?P<publicAP>.+)/$', 'exodus.views.genericPublicAP'),
+
 )
 
Index: /trunk/exodus/views.py
===================================================================
--- /trunk/exodus/views.py	(revision 6323)
+++ /trunk/exodus/views.py	(revision 6324)
@@ -13,22 +13,5 @@
 from exodus.wllogic import freeMasterIP, newSSIDName, addInterlinkIP, freeInterlinkIP, freePublicAPIP
 
-class AddLocationForm(forms.ModelForm):
-	class Meta:
-		model = Location
-
-def addLocation(request):
-	if request.POST:
-		form = AddLocationForm(request.POST)
-		if form.is_valid():
-			form.save()
-			return HttpResponseRedirect(reverse('exodus.views.addNode') + "?location=" + request.POST['description'])
-	else:
-		form = AddLocationForm()
-	return render_to_response('addlocation.html', {'form': form })
-
-class AddNodeForm(forms.ModelForm):
-	class Meta:
-		model = Node
-		exclude = ( 'masterip' )
+
 
 def node(request, node):
@@ -36,118 +19,4 @@
 	return render_to_response('node-detail.html', {'node': object})
 
-def addNode(request):
-	if request.POST:
-		form = AddNodeForm(request.POST)
-		if form.is_valid():
-			# input a valid master ip into new_data
-			instance  = form.save(commit=False)
-			instance.masterip = freeMasterIP(instance)
-			instance.save()
-			return HttpResponseRedirect(reverse('node-detail', args=[instance.name]))
-	else:
-		if 'location' in request.GET:
-			newNode = Node()
-			newNode.location = Location.objects.get(description=request.GET['location'])
-			form = AddNodeForm(instance=newNode)
-		else:
-			form = AddNodeForm()
-	return render_to_response('addnode.html', {'form': form })
-
-def editNode(request, objectId):
-	node = Node.objects.get(name=objectId)
-	if request.POST:
-		form = AddNodeForm(request.POST, instance=node)
-		if form.is_valid():
-			form.save()
-			#Properly redirect to view/<Node> needed
-			message = 'Node Updated succesfully'
-			return HttpResponseRedirect(reverse('node-detail', args=[objectId]))
-		else:
-			message = 'Form error, please edit and resubmit'
-	else:
-		message = 'Please edit and submit'
-		form = AddNodeForm(instance=node)
-	return render_to_response('addnode.html', {'form': form, 'message' : message })
-
-
-def delNode(request, objectId):
-	node = Node.objects.get(name=objectId)
-	if request.POST.has_key('cancel'):
-		return HttpResponseRedirect(reverse('node-detail', args=[objectId]))
-	elif request.POST.has_key('proceed'):
-		for master in Interface.objects.filter(node=node):
-			if master.link == master:
-				for makeMaster in Interface.objects.filter(link=master):
-					makeMaster.link = makeMaster
-					makeMaster.save()
-		node.delete()
-		return HttpResponseRedirect(reverse('nodelist'))
-	else:
-		return render_to_response('delnode.html', {'object': node })
-
-def delInterface(request, objectId):
-	if request.POST:
-		form = AddNodeForm(request.POST)
-		if form.is_valid():
-			# input a valid master ip into new_data
-			instance  = form.save(commit=False)
-			instance.masterip = freeMasterIP(instance)
-			instance.save()
-			return HttpResponseRedirect(reverse('nodelist'))
-	else:
-		form = AddNodeForm()
-	return render_to_response('delnode.html', {'form': form })
-
-class addInterfaceForm(forms.ModelForm):
-	class Meta:
-		model = Interface
-		exclude = ( 'ip', 'ssid', 'mode', 'channel', 'shortdesc' )
-
-def saveInterface(form):
-	#XXX: Should have checking wether form has actually been changed to avoid creation of IPs every time
-	instance  = form.save(commit=False)
-	if str(instance.type) != "eth":
-		instance.ssid = newSSIDName(instance.node, instance.iface, 'unused')
-		instance.channel = '1'
-		instance.mode = 1 # set to master
-	if not instance.link:
-		instance.ip = freeInterlinkIP(instance)
-	else:
-		instance.ip = addInterlinkIP(instance.link)
-	instance.save()
-	#Dirty to hack to get reference to self working
-	if not instance.link:
-		instance.link = instance
-		instance.save()
-
-def addInterface(request):
-	if request.POST:
-		form = addInterfaceForm(request.POST)
-		if form.is_valid():
-			saveInterface(form)
-			nodeName = Node.objects.get(pk=request.POST['node' ]).name
-			return HttpResponseRedirect(reverse('node-detail', args=[nodeName]))
-	else:
-		#XXX: Link, master interfaces only
-		if 'node' in request.GET:
-			newInterface = Interface()
-			newInterface.node = Node.objects.get(name=request.GET['node'])
-			form = addInterfaceForm(instance=newInterface)
-		else:
-			form = addInterfaceForm()
-	return render_to_response('addnic.html', {'form': form })
-
-def editInterface(request, objectId):
-	nodeName, interfaceName = objectId.split(':')
-	interface = Interface.objects.get(iface=interfaceName, node=nodename2id(nodeName))
-	if request.POST:
-		form = addInterfaceForm(request.POST, instance=interface)
-		if form.is_valid():
-			saveInterface(form)
-			return HttpResponseRedirect(reverse('node-detail', args=[nodeName]))
-	else:
-		#XXX: Link, master interfaces only
-		form = addInterfaceForm(instance = interface)
-	return render_to_response('addnic.html', {'form': form })
 
 class addLinkForm(forms.Form):
@@ -204,49 +73,84 @@
 	return render_to_response('addinterlink.html',{'form': form})
 
-class PublicAPForm(forms.ModelForm):
-	class Meta:
-		model = PublicAP
-		exclude = ('shortdesc', 'desc', 'ip', 'dhcpstart', 'dhcpstop')
 
 class GenericHandler():
 	"""Conventions used: type has to to the same name as the dependency object, delet template is named delete<type>.html"""
-	def __init__(self, request, node, interface, publicAP, mode, type):
-		# Find dependencies
-		node = Node.objects.get(name=node)
-		iface = Interface.objects.get(node=node, iface=interface)
-		publicAP = PublicAP(iface=iface) if mode == 'add' else PublicAP.objects.get(iface=iface, pk=publicAP)
-		
-		delInclude = 'delete' + type + '.html'
-		
+	def __init__(self, request, mode):
+		# Strip 'Handler' of name
+		type = self.__class__.__name__[:-7:]
 		formClass = eval(type + 'Form')
-		self.object = eval(type[0].lower() + type[1::])
-		title = self.object._meta.verbose_name
+
+		self.object = eval('self.' + type[0].lower() + type[1::])
+		self.title = self.object._meta.verbose_name
+		self.request = request
 		
 		if request.POST.has_key('cancel'):
-			self.response = HttpResponseRedirect(reverse('node-detail', args=[node]))
+			self.response = HttpResponseRedirect(reverse('node-detail', args=[self.node.name]))
 		elif request.POST.has_key('proceed'):
 			if mode == 'delete':
-				self._delete()
-				self.response = HttpResponseRedirect(reverse('node-detail', args=[node]))
+				self._deleteete()
+				self.response = HttpResponseRedirect(reverse('node-detail', args=[self.node.name]))
 			else:
 				# First checking whether form is valid, then add/edit actions
 				self.form = formClass(request.POST, instance=self.object)
 				if self.form.is_valid():
+					# Set response on forehand, to allow override in procedure
+					self.response = HttpResponseRedirect(reverse('node-detail', args=[self.node.name]))
 					if mode == 'add':
 						self._add()
 					elif mode == 'edit':
 						self._edit()
-					self.response = HttpResponseRedirect(reverse('node-detail', args=[node]))
 				else:
 					message = 'Form error, please edit and resubmit'
 					self.response = render_to_response('genericForm.html', {'form': self.form,
-						'message' : message, 'title' : title, 'mode' : mode,
-						'delInclude' : delInclude, 'object': self.object })
+						'message' : message, 'title' : self.title, 'mode' : mode,
+						'type' : type, 'object': self.object })
 		else:
 			message = 'Please edit and submit'
-			self.form = formClass(instance=self.object)
-			self.response = render_to_response('genericForm.html', {'form': self.form,
-				'message' : message, 'title' : title, 'mode' : mode,
-				'delInclude' : delInclude, 'object': self.object })
+			
+			# Dirty? hack to allow initial form to be filled with date for GET request, no errors raised
+			if request.GET and mode == 'add':
+				self.form = formClass(request.GET, instance=self.object)
+				self.form._errors = {}
+			else:
+				self.form = formClass(instance=self.object)
+
+			self.response = render_to_response('genericForm.html', {
+				'form': self.form, 'message' : message, 'title' : self.title,
+				'mode' : mode, 'type' : type, 'object': self.object,
+				'delInclude' : "delete" + type.capitalize() + ".html",
+				'addInclude' : "add" + type.capitalize() + ".html",
+				'editInclude' : "edit" + type.capitalize() + ".html" })
+
+	def _add(self):
+		self.form.save()
+
+	def _edit(self):
+		self.form.save()
+
+	def _deleteete(self):
+		self.object.delete()
+	
+	def render_to_response(self):
+		return self.response
+
+
+#
+# PublicAP
+class PublicAPForm(forms.ModelForm):
+	class Meta:
+		model = PublicAP
+		exclude = ('shortdesc', 'desc', 'ip', 'dhcpstart', 'dhcpstop')
+
+class PublicAPHandler(GenericHandler):
+	def __init__(self, request, node, interface, publicAP, mode):
+		self.node = Node.objects.get(name=node)
+		self.interface = Interface.objects.get(node=self.node, iface=interface)
+		if mode == 'add':
+			self.publicAP = PublicAP(iface=self.interface)
+		else:
+			self.publicAP =  PublicAP.objects.get(iface=self.interface, pk=publicAP)
+		GenericHandler.__init__(self, request, mode)
+
 
 	def _add(self):
@@ -260,16 +164,118 @@
 		_instance.save()
 
+def genericPublicAP(request, node, interface, publicAP, mode):
+	handler = PublicAPHandler(request, node, interface, publicAP, mode)
+	return handler.render_to_response()
+
+
+
+#
+# Interface 
+class InterfaceForm(forms.ModelForm):
+	class Meta:
+		model = Interface
+		exclude = ( 'ip', 'ssid', 'mode', 'channel', 'shortdesc' )
+
+class InterfaceHandler(GenericHandler):
+	def __init__(self, request, node, interface, mode):
+		self.node = Node.objects.get(name=node)
+		if mode == 'add':
+			self.interface = Interface(node=self.node)
+		else:
+			self.interface = Interface.objects.get(node=self.node, iface=interface)
+		GenericHandler.__init__(self, request, mode)
+
+	def _add(self):
+		self._saveInterface()
+
 	def _edit(self):
-		self.form.save()
+		self._saveInterface()
+
+	def _saveInterface(self):
+		#XXX: Should have checking wether form has actually been changed to avoid creation of IPs every time
+		_instance  = self.form.save(commit=False)
+		if str(_instance.type) != "eth":
+			_instance.ssid = newSSIDName(_instance.node, _instance.iface, 'unused')
+			_instance.channel = '1'
+			_instance.mode = 1 # set to master
+		if not _instance.link:
+			_instance.ip = freeInterlinkIP(_instance)
+		else:
+			_instance.ip = addInterlinkIP(_instance.link)
+		_instance.save()
+		#Dirty to hack to get reference to self working
+		if not _instance.link:
+			_instance.link = _instance
+			_instance.save()
+
+
+def genericInterface(request, node, interface, mode):
+	handler = InterfaceHandler(request, node, interface, mode)
+	return handler.render_to_response()
+
+#
+# Node
+class NodeForm(forms.ModelForm):
+	class Meta:
+		model = Node
+		exclude = ( 'masterip' )
+
+class NodeHandler(GenericHandler):
+	def __init__(self, request, node, mode):
+		if mode == 'add':
+			self.node = Node()
+		else:
+			self.node = Node.objects.get(name=node)
+		GenericHandler.__init__(self, request, mode)
+
+	def _add(self):
+		# input a valid master ip into new_data
+		_instance  = self.form.save(commit=False)
+		_instance.masterip = freeMasterIP(_instance)
+		_instance.save()
+
+	def _delete(self):
+		for _master in Interface.objects.filter(node=_instance):
+			if _master.link == _master:
+				for _makeMaster in Interface.objects.filter(link=_master):
+					_makeMaster.link = _makeMaster
+					_makeMaster.save()
+		_instance.delete()
+		# As node is deleted, goto overview page
+		self.response = HttpResponseRedirect(reverse('node-overview'))
+
+def genericNode(request, node, mode):
+	handler = NodeHandler(request, node, mode)
+	return handler.render_to_response()
+
+#
+# Location
+class LocationForm(forms.ModelForm):
+	class Meta:
+		model = Location
+
+class LocationHandler(GenericHandler):
+	def __init__(self, request, location, mode):
+		if mode == 'add':
+			self.location = Location()
+		else:
+			self.location = Location.objects.get(description=location)
+		GenericHandler.__init__(self, request, mode)
+
+	def _add(self):
+		self._saveInterface()
+		# After adding a location, allow adding a Node with this location
+		self.response = HttpResponseRedirect(reverse('exodus.views.genericNode', args=["add", "new"]) + "?location=%i" % self._instance.pk)
 
 	def _delete(self):
 		self.object.delete()
-	
-	def render_to_response(self):
-		return self.response
-
-def genericPublicAP(request, node, interface, publicAP, mode):
-	handler = GenericHandler(request, node, interface, publicAP, mode, 'PublicAP')
+		self.response = HttpResponseRedirect(reverse('node-overview'))
+
+def genericLocation(request, location, mode):
+	handler = LocationHandler(request, location, mode)
 	return handler.render_to_response()
+
+
+
 
 def nodename2id(node):
