commit 4dddae298064ebcf0bbcc9579e179c3b5f6a5836
Author: Giorgos Verigakis <verigak@gmail.com>
Date:   Wed Aug 31 17:47:17 2011 +0300

    Add metadata support in image tab
    
    Refs #849

diff --git a/admin/static/main.js b/admin/static/main.js
index 17c5acf..7fbf53c 100644
--- a/admin/static/main.js
+++ b/admin/static/main.js
@@ -1,3 +1,17 @@
 $(function() {
-	$("table.id-sorted").tablesorter({ sortList: [[0, 0]] });
+	$('table.id-sorted').tablesorter({ sortList: [[0, 0]] });
+
+	$('tr.row-template').hide();
+});
+
+$('.add-row').live('click', function() {
+	template = $('tr.row-template');
+	row = template.clone();
+	row.removeClass('row-template');
+	row.show();
+	template.parent().append(row);
+});
+
+$('.delete-row').live('click', function() {
+	$(this).parents('tr').remove();
 });
diff --git a/admin/templates/images_info.html b/admin/templates/images_info.html
index b49b741..5873806 100644
--- a/admin/templates/images_info.html
+++ b/admin/templates/images_info.html
@@ -1,89 +1,120 @@
 {% extends "base.html" %}
 
 {% block body %}
-
 <form action="/admin/images/{{ image.id }}/modify" method="post">
-  <div class="clearfix">
-    <label for="image-id">ID</label>
-    <div class="input">
-      <span class="uneditable-input" id="image-id">{{ image.id }}</span>
-    </div>
-  </div>
+  <div class="row">
+    <div class="span7 columns">
 
-  <div class="clearfix">
-    <label for="image-name">Name</label>
-    <div class="input">
-      <input class="medium" id="image-name" name="name" value="{{ image.name }}" type="text" />
-    </div>
-  </div>
+      <div class="clearfix">
+        <label for="image-id">ID</label>
+        <div class="input">
+          <span class="uneditable-input" id="image-id">{{ image.id }}</span>
+        </div>
+      </div>
 
-  <div class="clearfix">
-    <label for="image-state">State</label>
-    <div class="input">
-      <select class="medium" id="image-state" name="state">
-        {% for state in states %}
-        <option{% ifequal state image.state %} selected{% endifequal %}>{{ state }}</option>
-        {% endfor %}
-      </select>
-    </div>
-  </div>
+      <div class="clearfix">
+        <label for="image-name">Name</label>
+        <div class="input">
+          <input class="medium" id="image-name" name="name" value="{{ image.name }}" type="text" />
+        </div>
+      </div>
 
-  <div class="clearfix">
-    <label for="image-owner">Owner ID</label>
-    <div class="input">
-      <input class="small" id="image-owner" name="owner" value="{{ image.owner.id }}" type="text" />
-    </div>
-  </div>
+      <div class="clearfix">
+        <label for="image-state">State</label>
+        <div class="input">
+          <select class="medium" id="image-state" name="state">
+            {% for state in states %}
+            <option{% ifequal state image.state %} selected{% endifequal %}>{{ state }}</option>
+            {% endfor %}
+          </select>
+        </div>
+      </div>
 
-  <div class="clearfix">
-    <label for="image-sourcevm">Virtual Machine ID</label>
-    <div class="input">
-      <input class="small" id="image-sourcevm" name="sourcevm" value="{{ image.sourcevm.id }}" type="text" />
-    </div>
-  </div>
+      <div class="clearfix">
+        <label for="image-owner">Owner ID</label>
+        <div class="input">
+          <input class="small" id="image-owner" name="owner" value="{{ image.owner.id }}" type="text" />
+        </div>
+      </div>
 
-  <div class="clearfix">
-    <label for="image-backend">Backend ID</label>
-    <div class="input">
-      <input class="large" id="image-backend" name="backend" value="{{ image.backend_id }}" type="text" />
-    </div>
-  </div>
+      <div class="clearfix">
+        <label for="image-sourcevm">Virtual Machine ID</label>
+        <div class="input">
+          <input class="small" id="image-sourcevm" name="sourcevm" value="{{ image.sourcevm.id }}" type="text" />
+        </div>
+      </div>
 
-  <div class="clearfix">
-    <label for="image-format">Format</label>
-    <div class="input">
-      <select class="medium" id="image-format" name="format">
-        {% for format in formats %}
-        <option{% ifequal format image.format %} selected{% endifequal %}>{{ format }}</option>
-        {% endfor %}
-      </select>
-    </div>
-  </div>
+      <div class="clearfix">
+        <label for="image-backend">Backend ID</label>
+        <div class="input">
+          <input class="large" id="image-backend" name="backend" value="{{ image.backend_id }}" type="text" />
+        </div>
+      </div>
 
-  <div class="clearfix">
-    <label for="image-format">Public</label>
-    <div class="input">
-      <ul class="inputs-list">
-        <li>
-          <label>
-            <input type="checkbox" id="image-public" name="public"{% if image.public %} checked{% endif %}>
-          </label>
-        </li>
-      </ul>
-    </div>
-  </div>
+      <div class="clearfix">
+        <label for="image-format">Format</label>
+        <div class="input">
+          <select class="medium" id="image-format" name="format">
+            {% for format in formats %}
+            <option{% ifequal format image.format %} selected{% endifequal %}>{{ format }}</option>
+            {% endfor %}
+          </select>
+        </div>
+      </div>
+
+      <div class="clearfix">
+        <label for="image-format">Public</label>
+        <div class="input">
+          <ul class="inputs-list">
+            <li>
+              <label>
+                <input type="checkbox" id="image-public" name="public"{% if image.public %} checked{% endif %}>
+              </label>
+            </li>
+          </ul>
+        </div>
+      </div>
+
+      <div class="clearfix">
+        <label for="image-created">Created</label>
+        <div class="input">
+          <span class="uneditable-input" id="image-created">{{ image.created }}</span>
+        </div>
+      </div>
 
-  <div class="clearfix">
-    <label for="image-created">Created</label>
-    <div class="input">
-      <span class="uneditable-input" id="image-created">{{ image.created }}</span>
+      <div class="clearfix">
+        <label for="image-updated">Updated</label>
+        <div class="input">
+          <span class="uneditable-input" id="image-updated">{{ image.updated }}</span>
+        </div>
+      </div>
     </div>
-  </div>
 
-  <div class="clearfix">
-    <label for="image-updated">Updated</label>
-    <div class="input">
-      <span class="uneditable-input" id="image-updated">{{ image.updated }}</span>
+    <div class="span7 columns offset1">
+      <table>
+        <thead>
+          <tr>
+            <th>Key</th>
+            <th>Value</th>
+            <th></th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr class="row-template">
+            <td><input class="medium" type="text" name="key"></td>
+            <td><input class="medium" type="text" name="value"></td>
+            <td><a class="btn danger delete-row"><strong>-</strong></a></td>
+          </tr>
+          {% for meta in metadata %}
+          <tr>
+            <td><input type="text" class="medium" name="key" value="{{ meta.meta_key }}"></td>
+            <td><input type="text" class="medium" name="value" value="{{ meta.meta_value }}"></td>
+            <td><a class="btn danger delete-row"><strong>-</strong></a></td>
+          </tr>
+          {% endfor %}
+        </tbody>
+      </table>
+      <a class="btn success add-row"><strong>+</strong></a>
     </div>
   </div>
 
@@ -92,5 +123,4 @@
     <button type="reset" class="btn">Reset</button>
   </div>
 </form>
-
 {% endblock body %}
diff --git a/admin/views.py b/admin/views.py
index 351c2cf..1d8926a 100644
--- a/admin/views.py
+++ b/admin/views.py
@@ -27,7 +27,7 @@ def index(request):
     stats['ganeti_instances'] = len(backend.get_ganeti_instances())
     stats['ganeti_nodes'] = len(backend.get_ganeti_nodes())
     stats['ganeti_jobs'] = len(backend.get_ganeti_jobs())
-    
+
     images = []
     for image in models.Image.objects.exclude(state='DELETED'):
         vms = models.VirtualMachine.objects.filter(sourceimage=image)
@@ -103,8 +103,13 @@ def images_info(request, image_id):
     formats = [x[0] for x in models.Image.FORMATS]
     if not image.format:
         formats = [''] + formats
+    
+    metadata = image.imagemetadata_set.order_by('meta_key')
     html = render('images_info.html', 'images',
-                    image=image, states=states, formats=formats)
+                    image=image,
+                    states=states,
+                    formats=formats,
+                    metadata=metadata)
     return HttpResponse(html)
 
 def images_modify(request, image_id):
@@ -119,9 +124,17 @@ def images_modify(request, image_id):
     image.format = request.POST.get('format')
     image.public = True if request.POST.get('public') else False
     image.save()
+    
+    keys = request.POST.getlist('key')
+    vals = request.POST.getlist('value')
+    meta = dict(zip(keys, vals))
+    image.imagemetadata_set.all().delete()
+    for key, val in meta.items():
+        if key:
+            image.imagemetadata_set.create(meta_key=key, meta_value=val)
+    
     return redirect(images_info, image.id)
 
-
 def servers_list(request):
     vms = models.VirtualMachine.objects.order_by('id')
     html = render('servers_list.html', 'servers', vms=vms)
