Flatten project hierarchy, moving djano applications out of htsworkflow.frontend...
authorDiane Trout <diane@ghic.org>
Thu, 24 Jul 2014 20:56:08 +0000 (13:56 -0700)
committerDiane Trout <diane@ghic.org>
Thu, 24 Jul 2014 20:56:08 +0000 (13:56 -0700)
Unsuprisingly this also required updates to large chunks of
code to change the import paths for things.

I was motivated by the idea of trying to make my django applications more
portable. I tried some hacks with the python path to make it so they
could live in htsworkflow.appname, but django 1.7 seemed to want the app
to have only one import path, and this was the easiest way I could see to
solve that.

242 files changed:
bcmagic/__init__.py [new file with mode: 0644]
bcmagic/admin.py [new file with mode: 0644]
bcmagic/fixtures/initial_data.json [new file with mode: 0644]
bcmagic/fixtures/woldlab.json [new file with mode: 0644]
bcmagic/forms.py [new file with mode: 0644]
bcmagic/models.py [new file with mode: 0644]
bcmagic/plugin.py [new file with mode: 0644]
bcmagic/urls.py [new file with mode: 0644]
bcmagic/utils.py [new file with mode: 0644]
bcmagic/views.py [new file with mode: 0644]
eland_config/__init__.py [new file with mode: 0644]
eland_config/admin.py [new file with mode: 0644]
eland_config/forms.py [new file with mode: 0644]
eland_config/models.py [new file with mode: 0644]
eland_config/urls.py [new file with mode: 0644]
eland_config/views.py [new file with mode: 0644]
experiments/__init__.py [new file with mode: 0644]
experiments/admin.py [new file with mode: 0644]
experiments/experiments.py [new file with mode: 0644]
experiments/fixtures/initial_data.json [new file with mode: 0644]
experiments/fixtures/test_flowcells.json [new file with mode: 0644]
experiments/fixtures/woldlab.json [new file with mode: 0644]
experiments/models.py [new file with mode: 0644]
experiments/test_experiments.py [new file with mode: 0644]
experiments/urls.py [new file with mode: 0644]
experiments/views.py [new file with mode: 0644]
htsworkflow/auth.py [new file with mode: 0644]
htsworkflow/frontend/auth.py [deleted file]
htsworkflow/frontend/bcmagic/__init__.py [deleted file]
htsworkflow/frontend/bcmagic/admin.py [deleted file]
htsworkflow/frontend/bcmagic/fixtures/initial_data.json [deleted file]
htsworkflow/frontend/bcmagic/fixtures/woldlab.json [deleted file]
htsworkflow/frontend/bcmagic/forms.py [deleted file]
htsworkflow/frontend/bcmagic/models.py [deleted file]
htsworkflow/frontend/bcmagic/plugin.py [deleted file]
htsworkflow/frontend/bcmagic/urls.py [deleted file]
htsworkflow/frontend/bcmagic/utils.py [deleted file]
htsworkflow/frontend/bcmagic/views.py [deleted file]
htsworkflow/frontend/eland_config/__init__.py [deleted file]
htsworkflow/frontend/eland_config/admin.py [deleted file]
htsworkflow/frontend/eland_config/forms.py [deleted file]
htsworkflow/frontend/eland_config/models.py [deleted file]
htsworkflow/frontend/eland_config/urls.py [deleted file]
htsworkflow/frontend/eland_config/views.py [deleted file]
htsworkflow/frontend/experiments/__init__.py [deleted file]
htsworkflow/frontend/experiments/admin.py [deleted file]
htsworkflow/frontend/experiments/experiments.py [deleted file]
htsworkflow/frontend/experiments/fixtures/initial_data.json [deleted file]
htsworkflow/frontend/experiments/fixtures/test_flowcells.json [deleted file]
htsworkflow/frontend/experiments/fixtures/woldlab.json [deleted file]
htsworkflow/frontend/experiments/models.py [deleted file]
htsworkflow/frontend/experiments/test_experiments.py [deleted file]
htsworkflow/frontend/experiments/urls.py [deleted file]
htsworkflow/frontend/experiments/views.py [deleted file]
htsworkflow/frontend/inventory/__init__.py [deleted file]
htsworkflow/frontend/inventory/admin.py [deleted file]
htsworkflow/frontend/inventory/bcmagic.py [deleted file]
htsworkflow/frontend/inventory/fixtures/initial_data.json [deleted file]
htsworkflow/frontend/inventory/fixtures/test_harddisks.json [deleted file]
htsworkflow/frontend/inventory/fixtures/test_user.json [deleted file]
htsworkflow/frontend/inventory/fixtures/woldlab.json [deleted file]
htsworkflow/frontend/inventory/models.py [deleted file]
htsworkflow/frontend/inventory/test_inventory.py [deleted file]
htsworkflow/frontend/inventory/urls.py [deleted file]
htsworkflow/frontend/inventory/views.py [deleted file]
htsworkflow/frontend/labels/__init__.py [deleted file]
htsworkflow/frontend/labels/admin.py [deleted file]
htsworkflow/frontend/labels/models.py [deleted file]
htsworkflow/frontend/labels/test_labels.py [deleted file]
htsworkflow/frontend/labels/views.py [deleted file]
htsworkflow/frontend/samples/__init__.py [deleted file]
htsworkflow/frontend/samples/admin.py [deleted file]
htsworkflow/frontend/samples/auth_backend.py [deleted file]
htsworkflow/frontend/samples/changelist.py [deleted file]
htsworkflow/frontend/samples/fixtures/initial_data.json [deleted file]
htsworkflow/frontend/samples/fixtures/test_samples.json [deleted file]
htsworkflow/frontend/samples/models.py [deleted file]
htsworkflow/frontend/samples/results.py [deleted file]
htsworkflow/frontend/samples/test_samples.py [deleted file]
htsworkflow/frontend/samples/urls.py [deleted file]
htsworkflow/frontend/samples/views.py [deleted file]
htsworkflow/frontend/static/css/admin_flowcell.css [deleted file]
htsworkflow/frontend/static/css/app.css [deleted file]
htsworkflow/frontend/static/css/base.css [deleted file]
htsworkflow/frontend/static/css/changelists.css [deleted file]
htsworkflow/frontend/static/css/click-table.css [deleted file]
htsworkflow/frontend/static/css/dashboard.css [deleted file]
htsworkflow/frontend/static/css/data-browse-index.css [deleted file]
htsworkflow/frontend/static/css/forms.css [deleted file]
htsworkflow/frontend/static/css/global.css [deleted file]
htsworkflow/frontend/static/css/htsw.css [deleted file]
htsworkflow/frontend/static/css/layout.css [deleted file]
htsworkflow/frontend/static/css/null.css [deleted file]
htsworkflow/frontend/static/css/patch-iewin.css [deleted file]
htsworkflow/frontend/static/css/wide_account_number.css [deleted file]
htsworkflow/frontend/static/img/changelist-bg.gif [deleted file]
htsworkflow/frontend/static/img/default-bg.gif [deleted file]
htsworkflow/frontend/static/img/dna80.png [deleted file]
htsworkflow/frontend/static/img/hdd_unmount.png [deleted file]
htsworkflow/frontend/static/img/icon_searchbox.png [deleted file]
htsworkflow/frontend/static/img/layout-browser-hd-bg.gif [deleted file]
htsworkflow/frontend/static/img/nav-bg-reverse.gif [deleted file]
htsworkflow/frontend/static/img/nav-bg.gif [deleted file]
htsworkflow/frontend/static/img/readme.txt [deleted file]
htsworkflow/frontend/static/img/s.gif [deleted file]
htsworkflow/frontend/static/js/bcmagic-ext.js [deleted file]
htsworkflow/frontend/static/js/htsw-inventory.js [deleted file]
htsworkflow/frontend/static/js/htsw.js [deleted file]
htsworkflow/frontend/static/js/jquery.timers-1.0.0.js [deleted file]
htsworkflow/frontend/static/js/magicbc.js [deleted file]
htsworkflow/frontend/templates/404.html [deleted file]
htsworkflow/frontend/templates/admin/auth/user/add_form.html [deleted file]
htsworkflow/frontend/templates/admin/base_site.html [deleted file]
htsworkflow/frontend/templates/admin/experiments/flowcell/change_form.html [deleted file]
htsworkflow/frontend/templates/admin/index.html [deleted file]
htsworkflow/frontend/templates/admin/pagination.html [deleted file]
htsworkflow/frontend/templates/base.html [deleted file]
htsworkflow/frontend/templates/base_site.html [deleted file]
htsworkflow/frontend/templates/bcmagic/magic.html [deleted file]
htsworkflow/frontend/templates/experiments/detail.html [deleted file]
htsworkflow/frontend/templates/experiments/email_preview.html [deleted file]
htsworkflow/frontend/templates/experiments/flowcellSheet.html [deleted file]
htsworkflow/frontend/templates/experiments/flowcell_detail.html [deleted file]
htsworkflow/frontend/templates/experiments/flowcell_header.html [deleted file]
htsworkflow/frontend/templates/experiments/flowcell_lane_detail.html [deleted file]
htsworkflow/frontend/templates/experiments/index.html [deleted file]
htsworkflow/frontend/templates/experiments/sequencer.html [deleted file]
htsworkflow/frontend/templates/experiments/started_email.html [deleted file]
htsworkflow/frontend/templates/experiments/started_email.txt [deleted file]
htsworkflow/frontend/templates/inventory/default.zpl [deleted file]
htsworkflow/frontend/templates/inventory/hard_drive_shell.zpl [deleted file]
htsworkflow/frontend/templates/inventory/inventory_all_index.html [deleted file]
htsworkflow/frontend/templates/inventory/inventory_index.html [deleted file]
htsworkflow/frontend/templates/inventory/inventory_itemtype_index.html [deleted file]
htsworkflow/frontend/templates/inventory/inventory_summary.html [deleted file]
htsworkflow/frontend/templates/registration/login.html [deleted file]
htsworkflow/frontend/templates/registration/profile.html [deleted file]
htsworkflow/frontend/templates/reports/report.html [deleted file]
htsworkflow/frontend/templates/sample_header.html [deleted file]
htsworkflow/frontend/templates/samples/antibody_index.html [deleted file]
htsworkflow/frontend/templates/samples/lanes_for.html [deleted file]
htsworkflow/frontend/templates/samples/library_detail.html [deleted file]
htsworkflow/frontend/templates/samples/library_index.html [deleted file]
htsworkflow/frontend/templates/samples/species_detail.html [deleted file]
htsworkflow/frontend/templates/search_form.html [deleted file]
htsworkflow/frontend/urls.py [deleted file]
htsworkflow/pipelines/retrieve_config.py
htsworkflow/pipelines/test/test_retrive_config.py
htsworkflow/settings.py
htsworkflow/static/css/admin_flowcell.css [new file with mode: 0644]
htsworkflow/static/css/app.css [new file with mode: 0644]
htsworkflow/static/css/base.css [new file with mode: 0644]
htsworkflow/static/css/changelists.css [new file with mode: 0644]
htsworkflow/static/css/click-table.css [new file with mode: 0644]
htsworkflow/static/css/dashboard.css [new file with mode: 0644]
htsworkflow/static/css/data-browse-index.css [new file with mode: 0644]
htsworkflow/static/css/forms.css [new file with mode: 0644]
htsworkflow/static/css/global.css [new file with mode: 0644]
htsworkflow/static/css/htsw.css [new file with mode: 0644]
htsworkflow/static/css/layout.css [new file with mode: 0644]
htsworkflow/static/css/null.css [new file with mode: 0644]
htsworkflow/static/css/patch-iewin.css [new file with mode: 0644]
htsworkflow/static/css/wide_account_number.css [new file with mode: 0644]
htsworkflow/static/img/changelist-bg.gif [new file with mode: 0644]
htsworkflow/static/img/default-bg.gif [new file with mode: 0644]
htsworkflow/static/img/dna80.png [new file with mode: 0644]
htsworkflow/static/img/hdd_unmount.png [new file with mode: 0755]
htsworkflow/static/img/icon_searchbox.png [new file with mode: 0644]
htsworkflow/static/img/layout-browser-hd-bg.gif [new file with mode: 0644]
htsworkflow/static/img/nav-bg-reverse.gif [new file with mode: 0644]
htsworkflow/static/img/nav-bg.gif [new file with mode: 0644]
htsworkflow/static/img/readme.txt [new file with mode: 0644]
htsworkflow/static/img/s.gif [new file with mode: 0644]
htsworkflow/static/js/bcmagic-ext.js [new file with mode: 0644]
htsworkflow/static/js/htsw-inventory.js [new file with mode: 0644]
htsworkflow/static/js/htsw.js [new file with mode: 0644]
htsworkflow/static/js/jquery.timers-1.0.0.js [new file with mode: 0644]
htsworkflow/static/js/magicbc.js [new file with mode: 0644]
htsworkflow/templates/404.html [new file with mode: 0644]
htsworkflow/templates/admin/auth/user/add_form.html [new file with mode: 0644]
htsworkflow/templates/admin/base_site.html [new file with mode: 0644]
htsworkflow/templates/admin/experiments/flowcell/change_form.html [new file with mode: 0644]
htsworkflow/templates/admin/index.html [new file with mode: 0644]
htsworkflow/templates/admin/pagination.html [new file with mode: 0644]
htsworkflow/templates/base.html [new file with mode: 0644]
htsworkflow/templates/base_site.html [new file with mode: 0644]
htsworkflow/templates/bcmagic/magic.html [new file with mode: 0644]
htsworkflow/templates/experiments/detail.html [new file with mode: 0644]
htsworkflow/templates/experiments/email_preview.html [new file with mode: 0644]
htsworkflow/templates/experiments/flowcellSheet.html [new file with mode: 0644]
htsworkflow/templates/experiments/flowcell_detail.html [new file with mode: 0644]
htsworkflow/templates/experiments/flowcell_header.html [new file with mode: 0644]
htsworkflow/templates/experiments/flowcell_lane_detail.html [new file with mode: 0644]
htsworkflow/templates/experiments/index.html [new file with mode: 0644]
htsworkflow/templates/experiments/sequencer.html [new file with mode: 0644]
htsworkflow/templates/experiments/started_email.html [new file with mode: 0644]
htsworkflow/templates/experiments/started_email.txt [new file with mode: 0644]
htsworkflow/templates/inventory/default.zpl [new file with mode: 0644]
htsworkflow/templates/inventory/hard_drive_shell.zpl [new file with mode: 0644]
htsworkflow/templates/inventory/inventory_all_index.html [new file with mode: 0644]
htsworkflow/templates/inventory/inventory_index.html [new file with mode: 0644]
htsworkflow/templates/inventory/inventory_itemtype_index.html [new file with mode: 0644]
htsworkflow/templates/inventory/inventory_summary.html [new file with mode: 0644]
htsworkflow/templates/registration/login.html [new file with mode: 0644]
htsworkflow/templates/registration/profile.html [new file with mode: 0644]
htsworkflow/templates/reports/report.html [new file with mode: 0644]
htsworkflow/templates/sample_header.html [new file with mode: 0644]
htsworkflow/templates/samples/antibody_index.html [new file with mode: 0644]
htsworkflow/templates/samples/lanes_for.html [new file with mode: 0644]
htsworkflow/templates/samples/library_detail.html [new file with mode: 0644]
htsworkflow/templates/samples/library_index.html [new file with mode: 0644]
htsworkflow/templates/samples/species_detail.html [new file with mode: 0644]
htsworkflow/templates/search_form.html [new file with mode: 0644]
htsworkflow/urls.py [new file with mode: 0644]
htsworkflow/util/makebed.py
inventory/__init__.py [new file with mode: 0644]
inventory/admin.py [new file with mode: 0644]
inventory/bcmagic.py [new file with mode: 0644]
inventory/fixtures/initial_data.json [new file with mode: 0644]
inventory/fixtures/test_harddisks.json [new file with mode: 0644]
inventory/fixtures/test_user.json [new file with mode: 0644]
inventory/fixtures/woldlab.json [new file with mode: 0644]
inventory/models.py [new file with mode: 0644]
inventory/test_inventory.py [new file with mode: 0644]
inventory/urls.py [new file with mode: 0644]
inventory/views.py [new file with mode: 0644]
labels/__init__.py [new file with mode: 0644]
labels/admin.py [new file with mode: 0644]
labels/models.py [new file with mode: 0644]
labels/test_labels.py [new file with mode: 0644]
labels/views.py [new file with mode: 0644]
samples/__init__.py [new file with mode: 0644]
samples/admin.py [new file with mode: 0644]
samples/auth_backend.py [new file with mode: 0644]
samples/changelist.py [new file with mode: 0644]
samples/fixtures/initial_data.json [new file with mode: 0644]
samples/fixtures/test_samples.json [new file with mode: 0644]
samples/models.py [new file with mode: 0644]
samples/results.py [new file with mode: 0644]
samples/test_samples.py [new file with mode: 0644]
samples/urls.py [new file with mode: 0644]
samples/views.py [new file with mode: 0644]

diff --git a/bcmagic/__init__.py b/bcmagic/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/bcmagic/admin.py b/bcmagic/admin.py
new file mode 100644 (file)
index 0000000..5241ab0
--- /dev/null
@@ -0,0 +1,11 @@
+from django.contrib import admin
+from .models import KeywordMap, Printer
+
+class KeywordMapAdmin(admin.ModelAdmin):
+    list_display = ('keyword','regex', 'url_template')
+
+class PrinterAdmin(admin.ModelAdmin):
+    list_display = ('name', 'model', 'ip_address', 'label_shape', 'label_width', 'label_height', 'notes')
+    
+admin.site.register(KeywordMap, KeywordMapAdmin)
+admin.site.register(Printer, PrinterAdmin)
\ No newline at end of file
diff --git a/bcmagic/fixtures/initial_data.json b/bcmagic/fixtures/initial_data.json
new file mode 100644 (file)
index 0000000..99decf2
--- /dev/null
@@ -0,0 +1,36 @@
+[{"pk": 1,
+  "model": "bcmagic.keywordmap",
+  "fields": {"regex": "(?P<uuid>[A-Fa-f0-9]+)",
+             "url_template": "/samples/freezer/{{ uuid }}/",
+             "keyword": "frzr"}},
+ {"pk": 2,
+  "model": "bcmagic.keywordmap",
+  "fields": {"regex": "(?P<uuid>[A-Fa-f0-9]+)",
+             "url_template": "/samples/container/{{ uuid }}/",
+             "keyword": "cntr"}},
+ {"pk": 3,
+  "model": "bcmagic.keywordmap",
+  "fields": {"regex": "(?P<sampleid>\\d+)\\|(?P<owner>[A-Za-z0-9_\\- ]+)",
+             "url_template": "/samples/sample/{{ sampleid }}/",
+             "keyword": "s"}},
+ {"pk": 4,
+  "model": "bcmagic.keywordmap",
+  "fields": {"regex": "(?P<search>[\\S\\s]+)",
+             "url_template": "http://www.google.com/search?q={{ search }}",
+             "keyword": "gg"}},
+ {"pk": 5,
+  "model": "bcmagic.keywordmap",
+  "fields": {"regex": "(?P<search>[\\S\\s]+)",
+             "url_template": "http://www.flickr.com/search/?q={{ search }}",
+             "keyword": "flickr"}},
+ {"pk": 6,
+  "model": "bcmagic.keywordmap",
+  "fields": {"regex": "(?P<uuid>[A-Fa-f0-9]+)",
+             "url_template": "/inventory/{{ uuid }}/",
+             "keyword": "invu"}},
+ {"pk": 7,
+  "model": "bcmagic.keywordmap",
+  "fields": {"regex": "(?P<barcode_id>.+)",
+             "url_template": "/inventory/{{barcode_id}}/",
+             "keyword": "invb"}}
+]
diff --git a/bcmagic/fixtures/woldlab.json b/bcmagic/fixtures/woldlab.json
new file mode 100644 (file)
index 0000000..51fdaa2
--- /dev/null
@@ -0,0 +1,18 @@
+[{"pk": 1,
+  "model": "bcmagic.printer",
+  "fields": {"name": "ZM400 1.25x1",
+             "label_height": 1.0,
+             "notes": "Everyday use labels",
+             "label_width": 1.25,
+             "label_shape": "Square",
+             "model": "Zebra ZM400",
+             "ip_address": "131.215.34.116"}},
+ {"pk": 2,
+  "model": "bcmagic.printer",
+  "fields": {"name": "ZM400 3x3",
+             "label_height": 3.0,
+             "notes": "Larger everyday use labels",
+             "label_width": 3.0,
+             "label_shape": "Square",
+             "model": "Zebra ZM400",
+             "ip_address": "131.215.34.117"}}]
diff --git a/bcmagic/forms.py b/bcmagic/forms.py
new file mode 100644 (file)
index 0000000..000acd9
--- /dev/null
@@ -0,0 +1,9 @@
+from django import forms
+
+class BarcodeMagicForm(forms.Form):
+    magic = forms.CharField(label="Barcode Magic", required=False)
+    bcm_mode = forms.CharField(widget=forms.HiddenInput, initial="default")
+    
+    class Media:
+        js = ('js/jquery.timers-1.0.0.js',
+              'js/bcmagic-ext.js')
diff --git a/bcmagic/models.py b/bcmagic/models.py
new file mode 100644 (file)
index 0000000..4db58a3
--- /dev/null
@@ -0,0 +1,31 @@
+from django.db import models
+
+#FIXME: Should be made more generic and probably pre-populated supported list
+#   but for now, since we only have a ZM400, this will do.
+PRINTER_MODELS=[ ('Zebra ZM400', 'Zebra ZM400'),
+                 ('Zebra ZM600', 'Zebra ZM600')]
+
+LABEL_SHAPES = [ ('Square', 'Square'), ('Circle', 'Circle') ]
+
+class KeywordMap(models.Model):
+    """
+    Mapper object maps keyword|arg1|arg2|...|argN to REST urls
+    """
+    keyword = models.CharField(max_length=64)
+    regex = models.CharField(max_length=1024)
+    url_template = models.TextField()
+
+class Printer(models.Model):
+    """
+    Barcode Printer Information
+    """
+    name = models.CharField(max_length=256)
+    model = models.CharField(max_length=64, choices=PRINTER_MODELS)
+    ip_address = models.IPAddressField()
+    label_shape = models.CharField(max_length=32, choices=LABEL_SHAPES)
+    label_width = models.FloatField(help_text='width or diameter in inches')
+    label_height = models.FloatField(help_text='height in inches')
+    notes = models.TextField()
+
+    def __unicode__(self):
+        return u'%s, %s, %s, %s, %sx%s' % (self.name, self.model, self.ip_address, self.label_shape, self.label_width, self.label_width)
\ No newline at end of file
diff --git a/bcmagic/plugin.py b/bcmagic/plugin.py
new file mode 100644 (file)
index 0000000..d701cf3
--- /dev/null
@@ -0,0 +1,34 @@
+#from htsworkflow.frontend.samples import bcm_cmds
+
+#BCM_PLUGINS = {'cmd_move_sample': bcm_cmds.cmd_move_sample}
+
+_SEARCH_FUNCTIONS = {}
+
+def bcm_plugin_processor(keyword, text, bcm_mode):
+    """
+    Fixme should be made generic plugable, but am hard coding values for proof
+    of concept.
+    """
+    d = {}
+    
+    if bcm_mode not in BCM_PLUGINS:
+        d['mode'] = 'Error'
+        d['status'] = 'bcm_mode plugin called "%s" was not found' % (bcm_mode)
+        return d
+    
+    return BCM_PLUGINS[bcm_mode](keyword, text, bcm_mode)
+    
+
+def register_search_plugin(label, search_function):
+    """
+    Registers a group label and search_function
+    
+    search_function(search_string) --> (text_display, obj_url)
+    """
+    
+    if label in _SEARCH_FUNCTIONS:
+        msg = "search function for label (%s) already registered." % (label)
+        raise ValueError, msg
+    
+    _SEARCH_FUNCTIONS[label] = search_function
+    
\ No newline at end of file
diff --git a/bcmagic/urls.py b/bcmagic/urls.py
new file mode 100644 (file)
index 0000000..9133391
--- /dev/null
@@ -0,0 +1,7 @@
+from django.conf.urls import patterns
+
+urlpatterns = patterns('',
+    (r'^json_test/$', 'bcmagic.views.json_test'),
+    (r'^magic/$', 'bcmagic.views.magic'),
+    (r'^$', 'bcmagic.views.index'),
+)
diff --git a/bcmagic/utils.py b/bcmagic/utils.py
new file mode 100644 (file)
index 0000000..ace241f
--- /dev/null
@@ -0,0 +1,64 @@
+from django.conf import settings
+
+import ftplib
+import socket
+import StringIO
+
+
+def print_zpl(zpl_text, host=None):
+    """
+    Sends zpl_text to printer
+    """
+    if not host:
+        host = settings.BCPRINTER_PRINTER1_HOST
+    ftp = ftplib.FTP(host=host, user='blank', passwd='')
+    ftp.login()
+    ftp.storlines("STOR printme.txt", StringIO.StringIO(zpl_text))
+    ftp.quit()
+
+
+def print_zpl_socket(zpl_text, host=None, port=None):
+    """
+    Sends zpl_text to printer via a socket
+
+    if zpl_text is a list of zpl_texts, it will print each one
+    in that list.
+    """
+    
+    if not host:
+        host=settings.BCPRINTER_PRINTER1_HOST
+    if not port:
+        port=settings.BCPRINTER_PRINTER1_PORT
+
+    # Process anyway if zpl_text is a list.
+    if type(zpl_text) is list:
+        zpl_text = '\n'.join(zpl_text)
+
+    s = socket.socket()
+    # PORT 9100 is default for Zebra tabletop/desktop printers
+    # PORT 6101 is default for Zebra mobile printers
+    s.connect((host, port))
+    s.sendall(zpl_text)
+    s.close()
+
+
+def report_error(message):
+    """
+    Return a dictionary with a command to display 'message'
+    """
+    return {'mode': 'Error', 'status': message}
+
+
+def redirect_to_url(url):
+    """
+    Return a bcm dictionary with a command to redirect to 'url'
+    """
+    return {'mode': 'redirect', 'url': url}
+
+
+def autofill(field, value):
+    """
+    Return a bcm dictionary with a command to automatically fill the
+    corresponding "field" with "value"
+    """
+    return {'mode': 'autofill', 'field': field, 'value': value}
diff --git a/bcmagic/views.py b/bcmagic/views.py
new file mode 100644 (file)
index 0000000..6825aed
--- /dev/null
@@ -0,0 +1,177 @@
+from django.http import HttpResponse
+from django.template import RequestContext, Template, Context
+from django.shortcuts import render_to_response
+from django.core.exceptions import ObjectDoesNotExist
+
+from . import models
+from .utils import report_error, redirect_to_url
+from .plugin import bcm_plugin_processor
+from . import plugin
+#from htsworkflow.util.jsonutil import encode_json
+
+try:
+    import json
+except ImportError, e:
+    import simplejson as json
+
+import re
+
+from htsworkflow.frontend.bcmagic import forms
+
+def index(request):
+    """
+    Display a barcode magic input box
+    """
+    form = forms.BarcodeMagicForm()
+    
+    return render_to_response('bcmagic/magic.html', {'bcmagic': form},
+                              context_instance=RequestContext(request))
+
+
+def __plugin_search(text):
+    """
+    Runs registered plugins to search for results
+    """
+    
+    hits = []
+    for label, search_func in plugin._SEARCH_FUNCTIONS.items():
+        result = search_func(text)
+        if result is not None:
+            hits.extend(result)
+            
+    n = len(hits)
+    if n == 0:
+        msg = 'No hits found for: %s' % (text)
+        return report_error(msg)
+    elif n == 1:
+        return redirect_to_url(hits[0][1])
+    else:
+        msg = "%d hits found for (%s); multi-hit not implemented yet." % (n, text)
+        return report_error(msg)
+    
+    
+    #return json.dumps(hits)
+    
+
+def __magic_process(text):
+    """
+    Based on scanned text, check to see if there is map object to use
+    for a useful redirect.
+    """
+    # Split text on |
+    split_text = text.split('|')
+    
+    # There should always be at least one | in a valid scan.
+    if len(split_text) <= 1:
+        #return report_error('Invalid text: %s' % (text))
+        return __plugin_search(text)
+    
+    # Keyword is the first element in the list
+    keyword = split_text[0]
+    
+    # Attempt to find a KeywordMap based on keyword
+    try:
+        keymap = models.KeywordMap.objects.get(keyword=keyword)
+    except ObjectDoesNotExist, e:
+        return report_error('Keyword (%s) is not defined' % (keyword))
+    
+    # Remove keyword and only scan the content
+    content = '|'.join(split_text[1:])
+    
+    #FIXME: would be faster to cache compiled regex
+    search = re.compile(keymap.regex)
+    
+    mo = search.search(content)
+    
+    # if the search was invalid
+    if not mo:
+        return report_error('(%s) failed to match (%s)' % (keymap.regex, content))
+    
+    t = Template(keymap.url_template)
+    c = Context(mo.groupdict())
+    
+    return redirect_to_url(str(t.render(c)))
+    
+    
+    
+    
+
+def magic(request):
+    """
+    Let the magic begin
+    """
+    d = {}
+    
+    #Retrieve posted text from processing
+    if 'text' in request.POST:
+        text = request.POST['text']
+    else:
+        text = None
+        
+    #Retrieve bmc_mode for processing
+    if 'bcm_mode' in request.POST:
+        bcm_mode = request.POST['bcm_mode']
+    else:
+        bcm_mode = None
+        
+    ################################
+    # Handle some errors
+    ################################
+    
+    # Did not receive text error
+    if text is None or text.strip() == '':
+        d['mode'] = 'Error'
+        d['status'] = 'Did not recieve text'
+        
+        return HttpResponse(json.dumps(d), 'text/plain')
+    
+    # Did not receive bcm_mode error
+    if bcm_mode is None or bcm_mode.strip() == '':
+        d['mode'] = 'Error'
+        d['status'] = 'Missing bcm_mode information'
+    
+    
+    ################################
+    # Figure out which mode to use
+    ################################
+    keyword = text.split('|')[0]
+    
+    # Handle URL mode by default
+    if keyword == 'url':
+        d['mode'] = 'redirect'
+        d['url'] = text.split('|')[1]
+        
+    # Pass off processing to plugins
+    elif bcm_mode != 'default':
+        d = bcm_plugin_processor(keyword, text, bcm_mode)
+    
+    # Try keyword mapper
+    else:
+        d = __magic_process(text)
+    
+    return HttpResponse(json.dumps(d), 'text/plain')
+
+
+
+def json_test(request):
+    d = {}
+    
+    if 'text' in request.POST:
+        text = request.POST['text']
+    else:
+        text = None
+    
+    #return HttpResponse(json.dumps(request.POST.items()), 'text/plain')
+    if text is None or text.strip() == '':
+        d['mode'] = 'Error'
+        d['status'] = 'Did not recieve text'
+        return HttpResponse(json.dumps(d), 'text/plain')
+    
+    if text.split('|')[0] == 'url':
+        d['mode'] = 'redirect'
+        d['url'] = text.split('|')[1]
+    else:
+        d['msg'] = 'Recieved text: %s' % (text)
+        d['mode'] = 'clear'
+    
+    return HttpResponse(json.dumps(d), 'text/plain')
diff --git a/eland_config/__init__.py b/eland_config/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/eland_config/admin.py b/eland_config/admin.py
new file mode 100644 (file)
index 0000000..56107ff
--- /dev/null
@@ -0,0 +1,4 @@
+from django.contrib import admin
+from django.utils.translation import ugettext_lazy as _
+
+
diff --git a/eland_config/forms.py b/eland_config/forms.py
new file mode 100644 (file)
index 0000000..a2245f9
--- /dev/null
@@ -0,0 +1,163 @@
+from django import forms
+from django.forms.util import ErrorList
+
+
+SPECIES_LIST = [#('--choose--', '--Choose--'),
+                ('hg18', 'Homo sapiens (Hg18)'),
+                ('Mm8', 'Mus musculus (Mm8)'),
+                ('arabv6', 'Arabadopsis Thaliana v6'),
+                ('other', 'Other species (Include in description)')]
+
+
+class DivErrorList(ErrorList):
+  def __unicode__(self):
+    return self.as_divs()
+  
+  def as_divs(self):
+    if not self: return u''
+    return u'<div class="errorlist">%s</div>' % (''.join([u'<div class="error">%s</div>' % e for e in self]))
+
+
+
+class ConfigForm(forms.Form):
+  
+  flow_cell_number = forms.CharField(min_length=2)
+  run_date = forms.DateTimeField()
+  advanced_run = forms.BooleanField(required=False)
+  read_length = forms.IntegerField(min_value=1, initial=32)
+  #eland_repeat = forms.BooleanField()
+  
+  #needs a for loop or something to allow for n configurations
+  #analysis_type = forms.ChoiceField(choices=[('eland','eland')])
+  lane1_species = forms.ChoiceField(choices=SPECIES_LIST)
+  lane1_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
+  
+  lane2_species = forms.ChoiceField(choices=SPECIES_LIST)
+  lane2_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
+  
+  lane3_species = forms.ChoiceField(choices=SPECIES_LIST)
+  lane3_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
+  
+  lane4_species = forms.ChoiceField(choices=SPECIES_LIST)
+  lane4_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
+  
+  lane5_species = forms.ChoiceField(choices=SPECIES_LIST)
+  lane5_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
+  
+  lane6_species = forms.ChoiceField(choices=SPECIES_LIST)
+  lane6_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
+  
+  lane7_species = forms.ChoiceField(choices=SPECIES_LIST)
+  lane7_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
+  
+  lane8_species = forms.ChoiceField(choices=SPECIES_LIST)
+  lane8_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
+  
+  notes = forms.CharField(widget=forms.Textarea(attrs={'cols':'70'}), required=False)
+  
+  #lane_specific_read_length = forms.IntegerField(min_value=1)
+  
+  #eland_genome_lanes = forms.MultipleChoiceField(choices=[('lane1','1'),
+  #                                              ('lane2','2'),
+  #                                              ('lane3','3'),
+  #                                              ('lane4','4'),
+  #                                              ('lane5','5'),
+  #                                              ('lane6','6'),
+  #                                              ('lane7','7'),
+  #                                              ('lane8','8') ])
+  
+  #eland_genome = forms.ChoiceField(choices=)
+  
+  #use_bases_lanes = forms.MultipleChoiceField(choices=[('lane1','1'),
+  #                                              ('lane2','2'),
+  #                                              ('lane3','3'),
+  #                                              ('lane4','4'),
+  #                                              ('lane5','5'),
+  #                                              ('lane6','6'),
+  #                                              ('lane7','7'),
+  #                                              ('lane8','8') ])
+  
+  #use_bases_mask = forms.CharField()
+  
+  #sequence_format = forms.ChoiceField(choices=[('scarf', 'scarf')])
+  
+  
+  
+  #subject = forms.CharField(max_length=100)
+  #message = forms.CharField()
+  #sender = forms.EmailField()
+  #cc_myself = forms.BooleanField()
+  
+  def as_custom(self):
+    """
+    Displays customized html output
+    """
+    html = []
+    
+    fcn = self['flow_cell_number']
+    
+    html.append(fcn.label_tag() + ': ' + str(fcn) + str(fcn.errors) + '<br />')
+    
+    run_date = self['run_date']
+    html.append(run_date.label_tag() + ': ' + str(run_date) + str(run_date.errors) + '<br />')
+    
+    arun = self['advanced_run']
+    html.append(arun.label_tag() + ': ' + str(arun) + str(arun.errors) + '<br />')
+    
+    rl = self['read_length']
+    html.append(rl.label_tag() + ': ' + str(rl) + str(rl.errors) + '<br /><br />')
+    
+    html.append('<table border="0">')
+    html.append(' <tr><td>%s</td><td>%s</td><td>%s</td></tr>' \
+                % ('Lane', 'Species', 'Description'))
+    
+    l1s = self['lane1_species']
+    l1d = self['lane1_description']
+    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
+                % ('1', str(l1s), str(l1s.errors), str(l1d), str(l1d.errors)))
+    
+    l2s = self['lane2_species']
+    l2d = self['lane2_description']
+    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
+                % ('2', str(l2s), str(l2s.errors), str(l2d), str(l2d.errors)))
+    
+    l3s = self['lane3_species']
+    l3d = self['lane3_description']
+    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
+                % ('3', str(l3s), str(l3s.errors), str(l3d), str(l3d.errors)))
+    
+    l4s = self['lane4_species']
+    l4d = self['lane4_description']
+    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
+                % ('4', str(l4s), str(l4s.errors), str(l4d), str(l4d.errors)))
+    
+    l5s = self['lane5_species']
+    l5d = self['lane5_description']
+    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
+                % ('5', str(l5s), str(l5s.errors), str(l5d), str(l5d.errors)))
+    
+    l6s = self['lane6_species']
+    l6d = self['lane6_description']
+    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
+                % ('6', str(l6s), str(l6s.errors), str(l6d), str(l6d.errors)))
+    
+    l7s = self['lane7_species']
+    l7d = self['lane7_description']
+    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
+                % ('7', str(l7s), str(l7s.errors), str(l7d), str(l7d.errors)))
+    
+    l8s = self['lane8_species']
+    l8d = self['lane8_description']
+    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
+                % ('8', str(l8s), str(l8s.errors), str(l8d), str(l8d.errors)))
+    
+    html.append('</table><br />')
+    
+    notes = self['notes']
+    html.append('<p>Notes:</p>')
+    html.append(' %s<br />' % (str(notes)))
+    
+    return '\n'.join(html)
+    
+    
+    
diff --git a/eland_config/models.py b/eland_config/models.py
new file mode 100644 (file)
index 0000000..71a8362
--- /dev/null
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/eland_config/urls.py b/eland_config/urls.py
new file mode 100644 (file)
index 0000000..eff1477
--- /dev/null
@@ -0,0 +1,10 @@
+from django.conf.urls import patterns, url
+
+urlpatterns = patterns('',
+    ## Example:
+
+    url(r'^(?P<flowcell>\w+)/$', 'eland_config.views.config'),
+    url(r'^$', 'eland_config.views.config'),
+    #url(r'^$', 'htsworkflow.frontend.eland_config.views.index')
+
+)
diff --git a/eland_config/views.py b/eland_config/views.py
new file mode 100644 (file)
index 0000000..f4d765e
--- /dev/null
@@ -0,0 +1,119 @@
+from __future__ import absolute_import, print_function
+
+from django.conf import settings
+from django.http import HttpResponse
+from django.core.exceptions import ObjectDoesNotExist
+
+from experiments import models
+
+import os
+
+
+def _validate_input(data):
+    return data.replace('..', '').replace('/', '_').replace('\\', '_')
+
+
+def getElandConfig(flowcell, regenerate=False):
+
+    if hasattr(settings, 'UPLOADTO_CONFIG_FILE'):
+        dest = settings.UPLOADTO_CONFIG_FILE
+    else:
+        dest = '/tmp'
+    file_path = os.path.join(dest, flowcell)
+
+    #If we are regenerating the config file, skip
+    # reading of existing file. If the file doesn't
+    # exist, try to generate it form the DB.
+    if not regenerate and os.path.isfile(file_path):
+        f = open(file_path, 'r')
+        data = f.read()
+        f.close()
+        return data
+
+    try:
+        fcObj = models.FlowCell.objects.get(flowcell_id__iexact=flowcell)
+    except ObjectDoesNotExist:
+        return None
+
+    data = []
+
+    #form = form.cleaned_data
+
+    data.append("# FLOWCELL: %s" % (fcObj.flowcell_id))
+    data.append("#")
+
+    notes = fcObj.notes.replace('\r\n', '\n').replace('\r', '\n')
+    notes = notes.replace('\n', '\n#  ')
+    data.append("# NOTES:")
+    data.append("#  %s\n#" % (notes))
+
+    #Convert all newline conventions to unix style
+    for lane in fcObj.lane_set.all():
+        data.append("# Lane%d: %s | %s" %
+                    (lane.lane_number, unicode(lane.library.id),
+                     lane.library.library_name.replace('%', '%%')))
+
+    read_length = fcObj.read_length
+    #data.append("ELAND_REPEAT")
+    data.append("ELAND_MULTIPLE_INSTANCES 8")
+
+    #Construct genome dictionary to figure out what lanes to put
+    # in the config file.
+    genome_dict = {}
+
+    #l1s = form['lane1_species']
+    for lane in fcObj.lane_set.all():
+        species = lane.library.library_species.scientific_name
+        genome_dict.setdefault(species, []).append(unicode(lane.lane_number))
+
+    genome_list = genome_dict.keys()
+    genome_list.sort()
+
+    #Loop through and create entries for each species.
+    for genome in genome_list:
+        lanes = ''.join(genome_dict[genome])
+        if fcObj.paired_end:
+            data.append('%s:ANALYSIS eland_pair' % (lanes))
+        else:
+            data.append('%s:ANALYSIS eland_extended' % (lanes))
+        data.append('%s:READ_LENGTH %s' % (lanes, read_length))
+        data.append('%s:ELAND_GENOME %s' % (lanes, '%%(%s)s' % (genome)))
+        data.append('%s:USE_BASES %s' % (lanes, 'Y'*int(read_length)))
+
+    data.append('SEQUENCE_FORMAT --fastq')
+    data.append('')  # want a trailing newline
+
+    data = '\n'.join(data)
+
+    f = open(file_path, 'w')
+    f.write(data)
+    f.close()
+
+    return data
+
+
+def config(request, flowcell=None):
+    """
+    Returns eland config file for a given flowcell number,
+    or returns a list of available flowcell numbers.
+    """
+
+    # Provide INDEX of available Flowcell config files.
+    if flowcell is None:
+        fc_list = [fc.flowcell_id for fc in models.FlowCell.objects.all()]
+
+        #Convert FC* list to html links
+        fc_html = ['<a href="/eland_config/%s/">%s</a>' % (fc_name, fc_name)
+                   for fc_name in fc_list]
+
+        return HttpResponse('<br />'.join(fc_html))
+
+    #FIXME: Should validate flowcell input before using.
+    flowcell = _validate_input(flowcell)
+    cfg = getElandConfig(flowcell, regenerate=True)
+
+    if not cfg:
+        return HttpResponse(
+            "Hmm, config file for %s does not seem to exist." % (flowcell))
+
+    return HttpResponse(cfg, mimetype="text/plain")
diff --git a/experiments/__init__.py b/experiments/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/experiments/admin.py b/experiments/admin.py
new file mode 100644 (file)
index 0000000..6290dbf
--- /dev/null
@@ -0,0 +1,203 @@
+from __future__ import absolute_import, print_function
+
+from itertools import chain
+
+from django.contrib import admin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.forms import ModelForm
+from django.forms.fields import Field, CharField
+from django.forms.widgets import TextInput, Select
+from django.utils.encoding import force_unicode
+from django.utils.html import escape, conditional_escape
+from django.utils.translation import ugettext_lazy as _
+
+from .models import \
+     FlowCell, DataRun, DataFile, FileType, ClusterStation, Sequencer, Lane
+
+class DataFileForm(ModelForm):
+    class Meta:
+        model = DataFile
+        fields = ('random_key', 'data_run', 'library', 'file_type', 'relative_pathname')
+
+class DataFileInline(admin.TabularInline):
+    model = DataFile
+    form = DataFileForm
+    raw_id_fields = ('library',)
+    extra = 0
+
+class DataRunOptions(admin.ModelAdmin):
+  search_fields = [
+      'flowcell_id',
+      'run_folder',
+      'run_note',
+      ]
+  list_display = [
+      'runfolder_name',
+      'result_dir',
+      'run_start_time',
+  ]
+  fieldsets = (
+      (None, {
+        'fields': (('flowcell', 'run_status'),
+                   ('runfolder_name', 'cycle_start', 'cycle_stop'),
+                   ('result_dir',),
+                   ('last_update_time'),
+                   ('image_software', 'image_version'),
+                   ('basecall_software', 'basecall_version'),
+                   ('alignment_software', 'alignment_version'),
+                   ('comment',))
+      }),
+    )
+  inlines = [ DataFileInline ]
+  #list_filter = ('run_status', 'run_start_time')
+admin.site.register(DataRun, DataRunOptions)
+
+
+class FileTypeAdmin(admin.ModelAdmin):
+    list_display = ('name', 'mimetype', 'regex')
+admin.site.register(FileType, FileTypeAdmin)
+
+# lane form setup needs to come before Flowcell form config
+# as flowcell refers to the LaneInline class
+class LaneForm(ModelForm):
+    comment = CharField(widget=TextInput(attrs={'size':'80'}), required=False)
+
+    class Meta:
+        model = Lane
+        fields = ('flowcell', 'lane_number', 'library', 'pM', 'cluster_estimate',
+                  'status', 'comment')
+
+class LaneInline(admin.StackedInline):
+    """
+    Controls display of Lanes on the Flowcell form.
+    """
+    model = Lane
+    extra = 8
+    form = LaneForm
+    raw_id_fields = ('library',)
+    fieldsets = (
+      (None, {
+        'fields': ('lane_number', 'flowcell',
+                   ('library',),
+                   ('pM', 'cluster_estimate', 'status'),
+                   'comment',)
+      }),
+    )
+
+class LaneOptions(admin.ModelAdmin):
+    """
+    Controls display of Lane browser
+    """
+    search_fields = ('=flowcell__flowcell_id', 'library__id', 'library__library_name' )
+    list_display = ('flowcell', 'lane_number', 'library', 'comment')
+    fieldsets = (
+      (None, {
+        'fields': ('lane_number', 'flowcell',
+                   ('library'),
+                   ('pM', 'cluster_estimate'))
+      }),
+      ('Optional', {
+        'classes': ('collapse', ),
+        'fields': ('comment', )
+      }),
+    )
+admin.site.register(Lane, LaneOptions)
+
+class FlowCellOptions(admin.ModelAdmin):
+    class Media:
+        css = { 'all': ('css/admin_flowcell.css',) }
+    date_hierarchy = "run_date"
+    save_on_top = True
+    search_fields = ('flowcell_id',
+        'sequencer__name',
+        'cluster_station__name',
+        '=lane__library__id',
+        'lane__library__library_name')
+    list_display = ('flowcell_id','run_date','Lanes')
+    list_filter = ('sequencer','cluster_station', 'paired_end')
+    fieldsets = (
+        (None, {
+          'fields': ('run_date', ('flowcell_id','cluster_station','sequencer'),
+                    ('read_length', 'control_lane', 'paired_end'),)
+        }),
+        ('Notes:', { 'fields': ('notes',),}),
+    )
+    inlines = [
+      LaneInline,
+    ]
+
+    def formfield_for_dbfield(self, db_field, **kwargs):
+        field = super(FlowCellOptions, self).formfield_for_dbfield(db_field,
+                                                                   **kwargs)
+
+        # Override field attributes
+        if db_field.name == 'sequencer':
+            # seems kind of clunky.
+            # the goal is to replace the default select/combo box with one
+            # that can strike out disabled options.
+            attrs = field.widget.widget.attrs
+            field.widget.widget = SequencerSelect(attrs=attrs, queryset=field.queryset)
+        elif db_field.name == "notes":
+            field.widget.attrs["rows"] = "3"
+        return field
+admin.site.register(FlowCell, FlowCellOptions)
+
+class ClusterStationOptions(admin.ModelAdmin):
+    list_display = ('name', 'isdefault',)
+    fieldsets = ( ( None, { 'fields': ( 'name', 'isdefault') } ), )
+admin.site.register(ClusterStation, ClusterStationOptions)
+
+class SequencerSelect(Select):
+    def __init__(self, queryset=None, *args, **kwargs):
+        super(SequencerSelect, self).__init__(*args, **kwargs)
+        self.queryset = queryset
+
+    def render_options(self, choices, selected_choices):
+        # Normalize to strings.
+        selected_choices = set([force_unicode(v) for v in selected_choices])
+        output = []
+        for option_value, option_label in chain(self.choices, choices):
+            if isinstance(option_label, (list, tuple)):
+                output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
+                for option in option_label:
+                    output.append(self.render_option(selected_choices, *option))
+                output.append(u'</optgroup>')
+            else:
+                output.append(self.render_option(selected_choices, option_value, option_label))
+        return u'\n'.join(output)
+
+    # render_options blatently grabbed from 1.3.1 as the 1.2 version
+    # has render_option, which is what I needed to overload as a
+    # nested function in render_options
+    def render_options(self, choices, selected_choices):
+        # Normalize to strings.
+        selected_choices = set([force_unicode(v) for v in selected_choices])
+        output = []
+        for option_value, option_label in chain(self.choices, choices):
+            if isinstance(option_label, (list, tuple)):
+                output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
+                for option in option_label:
+                    output.append(self.render_option(selected_choices, *option))
+                output.append(u'</optgroup>')
+            else:
+                output.append(self.render_option(selected_choices, option_value, option_label))
+        return u'\n'.join(output)
+
+
+    def render_option(self, selected_choices, option_value, option_label):
+        disabled_sequencers = [ unicode(s.id) for s in self.queryset.filter(active=False) ]
+        option_value = unicode(option_value)
+        selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
+        cssclass = "strikeout" if option_value in disabled_sequencers else ''
+        return u'<option class="%s" value="%s"%s>%s</option>' % (
+            cssclass, escape(option_value), selected_html,
+            conditional_escape(force_unicode(option_label)))
+
+class SequencerOptions(admin.ModelAdmin):
+    list_display = ('name', 'active', 'isdefault', 'instrument_name', 'model')
+    fieldsets = ( ( None,
+                    { 'fields': (
+                        'name', ('active', 'isdefault'), 'instrument_name', 'serial_number',
+                        'model', 'comment') } ), )
+
+admin.site.register(Sequencer, SequencerOptions)
diff --git a/experiments/experiments.py b/experiments/experiments.py
new file mode 100644 (file)
index 0000000..bdf7919
--- /dev/null
@@ -0,0 +1,406 @@
+from __future__ import absolute_import, print_function
+
+# some core functions of the exp tracker module
+from datetime import datetime, timedelta
+try:
+    import json
+except ImportError, e:
+    import simplejson as json
+
+import os
+import re
+
+from django.contrib.auth.decorators import login_required
+from django.views.decorators.csrf import csrf_exempt
+from django.core.exceptions import ObjectDoesNotExist
+from django.core.mail import send_mail, mail_admins
+from django.http import HttpResponse, Http404
+from django.conf import settings
+from django.utils import timezone
+
+from htsworkflow.auth import require_api_key
+from .models import FlowCell, DataRun, Lane, LANE_STATUS_MAP
+from samples.models import Library, MultiplexIndex, HTSUser
+
+def flowcell_information(flowcell_id):
+    """
+    Return a dictionary describing a flowcell
+    """
+    try:
+        fc = FlowCell.objects.get(flowcell_id__startswith=flowcell_id)
+    except FlowCell.DoesNotExist, e:
+        return None
+
+    lane_set = {}
+    for lane in fc.lane_set.all():
+        lane_item = {
+            'cluster_estimate': lane.cluster_estimate,
+            'comment': lane.comment,
+            'experiment_type': lane.library.experiment_type.name,
+            'experiment_type_id': lane.library.experiment_type_id,
+            'flowcell': lane.flowcell.flowcell_id,
+            'lane_number': lane.lane_number,
+            'library_name': lane.library.library_name,
+            'library_id': lane.library.id,
+            'library_species': lane.library.library_species.scientific_name,
+            'pM': unicode(lane.pM),
+            'read_length': lane.flowcell.read_length,
+            'status_code': lane.status,
+            'status': LANE_STATUS_MAP[lane.status]
+        }
+        sequences = lane.library.index_sequences()
+        if sequences is not None:
+            lane_item['index_sequence'] = sequences
+
+        lane_set.setdefault(lane.lane_number,[]).append(lane_item)
+
+    if fc.control_lane is None:
+        control_lane = None
+    else:
+        control_lane = int(fc.control_lane)
+
+    info = {
+        'advanced_run': fc.advanced_run,
+        'cluster_station_id': fc.cluster_station_id,
+        'cluster_station': fc.cluster_station.name,
+        'control_lane': control_lane,
+        # 'datarun_set': how should this be represented?,
+        'flowcell_id': fc.flowcell_id,
+        'id': fc.id,
+        'lane_set': lane_set,
+        'notes': fc.notes,
+        'paired_end': fc.paired_end,
+        'read_length': fc.read_length,
+        'run_date': fc.run_date.isoformat(),
+        'sequencer_id': fc.sequencer_id,
+        'sequencer': fc.sequencer.name,
+    }
+
+    return info
+
+@csrf_exempt
+def flowcell_json(request, fc_id):
+    """
+    Return a JSON blob containing enough information to generate a config file.
+    """
+    require_api_key(request)
+
+    fc_dict = flowcell_information(fc_id)
+
+    if fc_dict is None:
+        raise Http404
+
+    fc_json = json.dumps(fc_dict)
+    return HttpResponse(fc_json, content_type = 'application/json')
+
+def lanes_for(username=None):
+    """
+    Given a user id try to return recent lanes as a list of dictionaries
+    """
+    query = {}
+    if username is not None:
+        user = HTSUser.objects.get(username=username)
+        query.update({'library__affiliations__users__id': user.id})
+
+    lanes = Lane.objects.filter(**query).order_by('-flowcell__run_date')
+
+
+    result = []
+    for l in lanes:
+        affiliations = l.library.affiliations.all()
+        affiliations_list = [(a.id, a.name) for a in affiliations]
+        result.append({ 'flowcell': l.flowcell.flowcell_id,
+                        'run_date': l.flowcell.run_date.isoformat(),
+                        'lane_number': l.lane_number,
+                        'library': l.library.id,
+                        'library_name': l.library.library_name,
+                        'comment': l.comment,
+                        'affiliations': affiliations_list})
+    return result
+
+@csrf_exempt
+def lanes_for_json(request, username):
+    """
+    Format lanes for a user
+    """
+    require_api_key(request)
+
+    try:
+        result = lanes_for(username)
+    except ObjectDoesNotExist, e:
+        raise Http404
+
+    #convert query set to python structure
+
+    result_json = json.dumps(result)
+    return HttpResponse(result_json, content_type='application/json')
+
+
+def updStatus(request):
+    output=''
+    user = 'none'
+    pswd = ''
+    UpdatedStatus = 'unknown'
+    fcid = 'none'
+    runfolder = 'unknown'
+    ClIP = request.META['REMOTE_ADDR']
+
+    if hasattr(request, 'user'):
+      user = request.user
+
+    #Check access permission
+    if not (user.is_superuser and settings.ALLOWED_IPS.has_key(ClIP)):
+        return HttpResponse("%s access denied from %s." % (user, ClIP))
+
+    # ~~~~~~Parameters for the job ~~~~
+    if request.REQUEST.has_key('fcid'):
+      fcid = request.REQUEST['fcid']
+    else:
+      return HttpResponse('missing fcid')
+
+    if request.REQUEST.has_key('runf'):
+      runfolder = request.REQUEST['runf']
+    else:
+      return HttpResponse('missing runf')
+
+
+    if request.REQUEST.has_key('updst'):
+      UpdatedStatus = request.REQUEST['updst']
+    else:
+      return HttpResponse('missing status')
+
+    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    # Update Data Run status in DB
+    # Try get rec. If not found return 'entry not found + <fcid><runfolder>', if found try update and return updated
+    try:
+      rec = DataRun.objects.get(run_folder=runfolder)
+      rec.run_status = UpdatedStatus
+
+      #if there's a message update that too
+      mytimestamp = timezone.now().__str__()
+      mytimestamp = re.sub(pattern=":[^:]*$",repl="",string=mytimestamp)
+      if request.REQUEST.has_key('msg'):
+        rec.run_note += ", "+request.REQUEST['msg']+" ("+mytimestamp+")"
+      else :
+        if UpdatedStatus == '1':
+          rec.run_note = "Started ("+mytimestamp+")"
+
+      rec.save()
+      output = "Hello "+settings.ALLOWED_IPS[ClIP]+". Updated to:'"+DataRun.RUN_STATUS_CHOICES[int(UpdatedStatus)][1].__str__()+"'"
+    except ObjectDoesNotExist:
+      output = "entry not found: "+fcid+", "+runfolder
+
+
+    #Notify researcher by email
+    # Doesn't work
+    #send_mail('Exp Tracker', 'Data Run Status '+output, 'rrauch@stanford.edu', ['rrrami@gmail.com'], fail_silently=False)
+    #mail_admins("test subject", "testing , testing", fail_silently=False)
+    # gives error: (49, "Can't assign requested address")
+    return HttpResponse(output)
+
+def generateConfile(request,fcid):
+    #granted = False
+    #ClIP = request.META['REMOTE_ADDR']
+    #if (settings.ALLOWED_IPS.has_key(ClIP)):  granted = True
+
+    #if not granted: return HttpResponse("access denied.")
+
+    config = ['READ_LENGTH 25']
+    config += ['ANALYSIS eland']
+    config += ['GENOME_FILE all_chr.fa']
+    config += ['ELAND_MULTIPLE_INSTANCES 8']
+    genome_dir = 'GENOME_DIR /Volumes/Genomes/'
+    eland_genome = 'ELAND_GENOME /Volumes/Genomes/'
+
+    try:
+      fc = FlowCell.objects.get(flowcell_id=fcid)
+      for lane in fc.lane_set.all():
+          config += [ str(lane.lane_number) +":" + \
+                      genome_dir + lane.library.library_species.scientific_name ]
+          config += [ str(lane.lane_number) +":" + \
+                      eland_genome + lane.library.library_species.scientific_name ]
+
+    except ObjectDoesNotExist:
+      config = 'Entry not found for fcid  = '+fcid
+
+    return os.linesep.join(config)
+
+def getConfile(req):
+    granted = False
+    ClIP = req.META['REMOTE_ADDR']
+    if (settings.ALLOWED_IPS.has_key(ClIP)):  granted = True
+
+    if not granted: return HttpResponse("access denied. IP: "+ClIP)
+
+    fcid = 'none'
+    cnfgfile = 'Nothing found'
+    runfolder = 'unknown'
+    request = req.REQUEST
+    if request.has_key('fcid'):
+      fcid = request['fcid']
+      if request.has_key('runf'):
+        runfolder = request['runf']
+        try:
+          rec = DataRun.objects.get(run_folder=runfolder) #,flowcell_id=fcid)
+          cnfgfile = rec.config_params
+          #match_str = re.compile(r"READ_LENGTH.+$")
+          match_str = re.compile('^READ_LENGTH.+')
+          if not match_str.search(cnfgfile):
+            cnfgfile = generateConfile(request,fcid)
+            if match_str.search(cnfgfile):
+              rec = DataRun.objects.get(run_folder=runfolder) #,flowcell_id=fcid)
+              rec.config_params = cnfgfile
+              rec.save()
+            else:
+              cnfgfile = 'Failed generating config params for RunFolder = '+runfolder +', Flowcell id = '+ fcid+ ' Config Text:\n'+cnfgfile
+
+        except ObjectDoesNotExist:
+          cnfgfile = 'Entry not found for RunFolder = '+runfolder
+
+    return HttpResponse(cnfgfile, content_type='text/plain')
+
+def getLaneLibs(req):
+    granted = False
+    ClIP = req.META['REMOTE_ADDR']
+    if (settings.ALLOWED_IPS.has_key(ClIP)):  granted = True
+
+    if not granted: return HttpResponse("access denied.")
+
+    request = req.REQUEST
+    fcid = 'none'
+    outputfile = ''
+    if request.has_key('fcid'):
+      fcid = request['fcid']
+      try:
+        rec = FlowCell.objects.get(flowcell_id=fcid)
+        #Ex: 071211
+        year = datetime.today().year.__str__()
+        year = replace(year,'20','')
+        month = datetime.today().month
+        if month < 10: month = "0"+month.__str__()
+        else: month = month.__str__()
+        day = datetime.today().day
+        if day < 10: day = "0"+day.__str__()
+        else: day = day.__str__()
+        mydate = year+month+day
+        outputfile = '<?xml version="1.0" ?>'
+        outputfile += '\n<SolexaResult Date="'+mydate+'" Flowcell="'+fcid+'" Client="'+settings.ALLOWED_IPS[ClIP]+'">'
+        outputfile += '\n<Lane Index="1" Name="'+rec.lane_1_library.library_name+'" Library="'+rec.lane_1_library.id+'" Genome="'+rec.lane_1_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
+        outputfile += '\n<Lane Index="2" Name="'+rec.lane_2_library.library_name+'" Library="'+rec.lane_2_library.id+'" Genome="'+rec.lane_2_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
+        outputfile += '\n<Lane Index="3" Name="'+rec.lane_3_library.library_name+'" Library="'+rec.lane_3_library.id+'" Genome="'+rec.lane_3_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
+        outputfile += '\n<Lane Index="4" Name="'+rec.lane_4_library.library_name+'" Library="'+rec.lane_4_library.id+'" Genome="'+rec.lane_4_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
+        outputfile += '\n<Lane Index="5" Name="'+rec.lane_5_library.library_name+'" Library="'+rec.lane_5_library.id+'" Genome="'+rec.lane_5_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
+        outputfile += '\n<Lane Index="6" Name="'+rec.lane_6_library.library_name+'" Library="'+rec.lane_6_library.id+'" Genome="'+rec.lane_6_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
+        outputfile += '\n<Lane Index="7" Name="'+rec.lane_7_library.library_name+'" Library="'+rec.lane_7_library.id+'" Genome="'+rec.lane_7_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
+        outputfile += '\n<Lane Index="8" Name="'+rec.lane_8_library.library_name+'" Library="'+rec.lane_8_library.id+'" Genome="'+rec.lane_8_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
+        outputfile += '\n</SolexaResult>'
+      except ObjectDoesNotExist:
+        outputfile = 'Flowcell entry not found for: '+fcid
+    else: outputfile = 'Missing input: flowcell id'
+
+    return HttpResponse(outputfile, content_type='text/plain')
+
+def estimateFlowcellDuration(flowcell):
+    """
+    Attempt to estimate how long it will take to run a flowcell
+
+    """
+    # (3600 seconds * 1.5 hours per cycle )
+    sequencing_seconds_per_cycle= 3600 * 1.5
+    # 800 is a rough guess
+    pipeline_seconds_per_cycle = 800
+
+    cycles = flowcell.read_length
+    if flowcell.paired_end:
+        cycles *= 2
+    sequencing_time = timedelta(0, cycles * sequencing_seconds_per_cycle)
+    analysis_time = timedelta(0, cycles * pipeline_seconds_per_cycle)
+    estimate_mid = sequencing_time + analysis_time
+
+    return estimate_mid
+
+def estimateFlowcellTimeRemaining(flowcell):
+    estimate_mid = estimateFlowcellDuration(flowcell)
+
+    # offset for how long we've been running
+    running_time = timezone.now() - flowcell.run_date
+    estimate_mid -= running_time
+
+    return estimate_mid
+
+def roundToDays(estimate):
+    """
+    Given a time estimate round up and down in days
+    """
+    # floor estimate_mid
+    estimate_low = timedelta(estimate.days, 0)
+    # floor estimate_mid and add a day
+    estimate_high = timedelta(estimate.days+1, 0)
+
+    return (estimate_low, estimate_high)
+
+
+def makeUserLaneMap(flowcell):
+    """
+    Given a flowcell return a mapping of users interested in
+    the libraries on those lanes.
+    """
+    users = {}
+
+    for lane in flowcell.lane_set.all():
+        for affiliation in lane.library.affiliations.all():
+            for user in affiliation.users.all():
+                users.setdefault(user,[]).append(lane)
+
+    return users
+
+def getUsersForFlowcell(flowcell):
+    users = set()
+
+    for lane in flowcell.lane_set.all():
+        for affiliation in lane.library.affiliations.all():
+            for user in affiliation.users.all():
+                users.add(user)
+
+    return users
+
+def makeUserLibraryMap(libraries):
+    """
+    Given an interable set of libraries return a mapping or
+    users interested in those libraries.
+    """
+    users = {}
+
+    for library in libraries:
+        for affiliation in library.affiliations.all():
+            for user in affiliation.users.all():
+                users.setdefault(user,[]).append(library)
+
+    return users
+
+def makeAffiliationLaneMap(flowcell):
+    affs = {}
+
+    for lane in flowcell.lane_set.all():
+        for affiliation in lane.library.affiliations.all():
+            affs.setdefault(affiliation,[]).append(lane)
+
+    return affs
+
+def makeEmailLaneMap(flowcell):
+    """
+    Create a list of email addresses and the lanes associated with those users.
+
+    The email addresses can come from both the "users" table and the "affiliations" table.
+    """
+    emails = {}
+    for lane in flowcell.lane_set.all():
+        for affiliation in lane.library.affiliations.all():
+            if affiliation.email is not None and len(affiliation.email) > 0:
+                emails.setdefault(affiliation.email,set()).add(lane)
+            for user in affiliation.users.all():
+                if user.email is not None and len(user.email) > 0:
+                    emails.setdefault(user.email,set()).add(lane)
+
+    return emails
diff --git a/experiments/fixtures/initial_data.json b/experiments/fixtures/initial_data.json
new file mode 100644 (file)
index 0000000..f364502
--- /dev/null
@@ -0,0 +1,122 @@
+[
+  { "model": "experiments.FileType",
+    "pk": 1,
+    "fields": {
+      "name": "run_xml",
+      "mimetype": "application/vnd.htsworkflow-run-xml",
+      "regex": "run.*\\.xml\\Z(?ms)"
+    }
+  },
+  { "model": "experiments.FileType",
+    "pk": 2,
+    "fields": {
+      "name": "Summary.htm",
+      "mimetype": "text/html",
+      "regex": "Summary\\.htm\\Z(?ms)"
+    }
+  },
+
+  { "model": "experiments.FileType",
+    "pk": 3,
+    "fields": {
+      "name": "IVC All",
+      "mimetype": "image/png",
+      "regex": "s_(?P<lane>[0-9])_all\\.png\\Z(?ms)"
+    }
+  },
+  { "model": "experiments.FileType",
+    "pk": 4,
+    "fields": {
+      "name": "IVC Call",
+      "mimetype": "image/png",
+      "regex": "s_(?P<lane>[0-9])_call\\.png\\Z(?ms)"
+    }
+  },
+  { "model": "experiments.FileType",
+    "pk": 5,
+    "fields": {
+      "name": "IVC Percent All",
+      "mimetype": "image/png",
+      "regex": "s_(?P<lane>[0-9])_percent_all\\.png\\Z(?ms)"
+    }
+  },
+  { "model": "experiments.FileType",
+    "pk": 6,
+    "fields": {
+      "name": "IVC Percent Base",
+      "mimetype": "image/png",
+      "regex": "s_(?P<lane>[0-9])_percent_base\\.png\\Z(?ms)"
+    }
+  },
+  { "model": "experiments.FileType",
+    "pk": 7,
+    "fields": {
+      "name": "IVC Percent Call",
+      "mimetype": "image/png",
+      "regex": "s_(?P<lane>[0-9])_percent_call\\.png\\Z(?ms)"
+    }
+  },
+  { "model": "experiments.FileType",
+    "pk": 8,
+    "fields": {
+      "name": "GERALD Scores",
+      "regex": "scores\\.tar\\.bz2\\Z(?ms)"
+    }
+  },
+  { "model": "experiments.FileType",
+    "pk": 9,
+    "fields": {
+      "name": "ELAND Result",
+      "mimetype": "chemical/seq-na-eland",
+      "regex": "s_(?P<lane>[0-9])((?P<end>[1-4])_)?_eland_result\\.txt\\.bz2\\Z(?ms)"
+    }
+  },
+  { "model": "experiments.FileType",
+    "pk": 10,
+    "fields": {
+      "name": "ELAND Multi",
+      "mimetype": "chemical/seq-na-eland",
+      "regex": "s_(?P<lane>[0-9])((?P<end>[1-4])_)?_eland_multi\\.txt\\.bz2\\Z(?ms)"
+    }
+  },
+  { "model": "experiments.FileType",
+    "pk": 11,
+    "fields": {
+      "name": "ELAND Extended",
+      "mimetype": "chemical/seq-na-eland",
+      "regex": "s_(?P<lane>[0-9])((?P<end>[1-4])_)?_eland_extended\\.txt\\.bz2\\Z(?ms)"
+    }
+  },
+  { "model": "experiments.FileType",
+    "pk": 12,
+    "fields": {
+      "name": "ELAND Export",
+      "mimetype": "chemical/seq-na-eland",
+      "regex": "s_(?P<lane>[0-9])((?P<end>[1-4])_)?_export\\.txt\\.bz2\\Z(?ms)"
+    }
+  },
+  { "model": "experiments.FileType",
+    "pk": 13,
+    "fields": {
+      "name": "SRF",
+      "mimetype": "chemical/seq-na-srf",
+      "regex": ".*_(?P<lane>[1-8])\\.srf\\Z(?ms)"
+    }
+  },
+  { "model": "experiments.FileType",
+    "pk": 14,
+    "fields": {
+      "name": "QSEQ tarfile",
+      "mimetype": "chemical/seq-na-qseq",
+      "regex": ".*_l(?P<lane>[1-8])_r(?P<end>[1-4])\\.tar\\.bz2\\Z(?ms)"
+    }
+  },
+  { "model": "experiments.FileType",
+    "pk": 15,
+    "fields": {
+      "name": "HiSeq Fastq",
+      "mimetype": "chemical/seq-na-fastq",
+      "regex": "(?P<library>[0-9]+)_(NoIndex|[AGCT]+)_L(?P<lane>[0-9]+)_R(?P<end>[12])_(?P<split>[0-9]+)\\.fastq\\.gz"
+    }
+  }
+]
diff --git a/experiments/fixtures/test_flowcells.json b/experiments/fixtures/test_flowcells.json
new file mode 100644 (file)
index 0000000..15d00c6
--- /dev/null
@@ -0,0 +1,1273 @@
+[
+    {"pk": 5, "model": "auth.user",
+   "fields": {
+       "username": "test",
+       "first_name": "",
+       "last_name": "",
+       "is_active": true,
+       "is_superuser": false,
+       "is_staff": false,
+       "last_login": "2009-01-01T00:00:01-0800",
+       "groups": [],
+       "user_permissions": [],
+       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
+       "email": "",
+       "date_joined": "2009-01-01T00:01:01-0800"
+       }
+   },
+   {"pk": 5, "model": "samples.htsuser",
+    "fields" : {}
+   },
+   {"pk": 6, "model": "auth.user",
+   "fields": {
+       "username": "admintest",
+       "first_name": "",
+       "last_name": "",
+       "is_active": true,
+       "is_superuser": false,
+       "is_staff": true,
+       "last_login": "2009-01-01T00:00:01-0800",
+       "groups": [],
+       "user_permissions": [],
+       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
+       "email": "",
+       "date_joined": "2009-01-01T00:01:01-0800"
+       }
+   },
+   {"pk": 6, "model": "samples.htsuser",
+    "fields" : {}
+   },
+   {"pk": 7, "model": "auth.user",
+   "fields": {
+       "username": "supertest",
+       "first_name": "",
+       "last_name": "",
+       "is_active": true,
+       "is_superuser": true,
+       "is_staff": true,
+       "last_login": "2009-01-01T00:00:01-0800",
+       "groups": [],
+       "user_permissions": [],
+       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
+       "email": "",
+       "date_joined": "2009-01-01T00:01:01-0800"
+       }
+   },
+   {"pk": 7, "model": "samples.htsuser",
+    "fields" : {}
+   },
+   {"pk": 1, "model": "samples.affiliation",
+     "fields": {
+         "users": [5],
+         "contact": "group 1",
+         "name": "affiliation 1",
+         "email": "pk1@example.com"
+         }
+     },
+    {"pk": 2, "model": "samples.affiliation",
+     "fields": {
+         "users": [6],
+         "contact": "group 2",
+         "name": "affiliation 2",
+         "email": "pk2@example.com"
+         }
+     },
+    {"pk": 3, "model": "samples.affiliation",
+     "fields": {
+         "users": [],
+         "contact": "group 3",
+         "name": "affiliation 3",
+         "email": "pk3@example.com"
+         }
+     },
+    {"pk": 4, "model": "samples.affiliation",
+     "fields": {
+         "users": [],
+         "contact": "group 4",
+         "name": "affiliation 4",
+         "email": "pk1@example.com"
+         }
+     },
+    {"pk": 5, "model": "samples.affiliation",
+     "fields": {
+         "users": [],
+         "contact": "group 5",
+         "name": "affiliation 5",
+         "email": "pk5@example.com"
+         }
+     },
+ {"pk": 1, "model": "experiments.clusterstation",
+  "fields": {"name": "old", "isdefault": false}},
+ {"pk": 2, "model": "experiments.clusterstation",
+  "fields": {"name": "loaner", "isdefault": true}},
+ {"pk": 3, "model": "experiments.clusterstation",
+  "fields": {"name": "new", "isdefault": false}},
+ {"pk": 1, "model": "experiments.sequencer",
+  "fields": { "name": "Rotifer (HWI-EAS229)",
+              "model": "Illumina Genome Analyzer I",
+              "active": false,
+              "isdefault": false }},
+ {"pk": 2, "model": "experiments.sequencer",
+  "fields": {"name": "Tardigrade",
+             "instrument_name": "ILLUMINA-EC5D15",
+             "model": "Illumina Genome Analyzer IIx",
+             "active": true,
+             "isdefault": true}
+ },
+ {"pk": 3, "model": "experiments.sequencer",
+  "fields": {"name": "Sequenced somewhere else.",
+             "model": "Unknown",
+             "active": true,
+             "isdefault": false}},
+ {"pk": 153, "model": "experiments.flowcell",
+  "fields": {
+      "paired_end": true,
+      "run_date": "2007-09-27T22:12:13-0800",
+      "read_length": 36,
+      "notes": "",
+      "advanced_run": false,
+      "control_lane": 2,
+      "cluster_station": 3,
+      "sequencer": 2,
+      "flowcell_id": "FC12150"
+      }
+  },
+  {"pk": 1193, "model": "experiments.lane",
+   "fields": {
+       "comment": "No change in cluster numbers, despite slight increase in pM",
+       "library": "10981",
+       "cluster_estimate": 129000,
+       "flowcell": 153,
+       "lane_number": 1,
+       "pM": "8"
+       }
+   },
+   {"pk": 1192, "model": "experiments.lane",
+    "fields": {
+        "comment": "Other library",
+        "library": "11070",
+        "cluster_estimate": 132000,
+        "flowcell": 153,
+        "lane_number": 1,
+        "pM": "7"
+        }
+    },
+
+  {"pk": "10981", "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 400,
+            "library_name": "Paired End Multiplexed Sp-BAC",
+            "creation_date": "2009-07-21",
+            "cell_line": 1,
+            "library_species": 10,
+            "library_type": null,
+            "made_by": "Igor",
+            "affiliations": [
+                1,2
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "Done",
+            "tags": [],
+            "made_for": "Andy Cameron",
+            "amplified_from_sample": null,
+            "notes": "Combined 10957-10968",
+            "undiluted_concentration": "5.1",
+            "successful_pM": null,
+            "experiment_type": 10,
+            "antibody": null
+        }
+    },
+  {"pk": 1194, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11016",
+       "cluster_estimate": 152000,
+       "flowcell": 153,
+       "lane_number": 2,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11006",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 325,
+            "library_name": "Paired End Pfl #3 MP 7/24/9",
+            "creation_date": "2009-08-05",
+            "cell_line": 1,
+            "library_species": 8,
+            "library_type": 2,
+            "made_by": "Lorian",
+            "affiliations": [
+                3
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": true,
+            "stopping_point": "1A",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "7/31/2009 16:08:22\tColor: Blue",
+            "undiluted_concentration": null,
+            "successful_pM": null,
+            "experiment_type": 8,
+            "antibody": null
+        }
+    },
+    {
+        "pk": "11016",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 325,
+            "library_name": "Paired End Pfl #3 MP 7/24/9 a",
+            "creation_date": "2009-08-06",
+            "cell_line": 1,
+            "library_species": 2,
+            "library_type": 2,
+            "made_by": "Lorian",
+            "affiliations": [
+                2
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": 11006,
+            "notes": "7/31/2009 16:08:22\tColor: Blue",
+            "undiluted_concentration": "35.5",
+            "successful_pM": null,
+            "experiment_type": 8,
+            "antibody": null
+        }
+    },
+  {"pk": 1195, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "SL039",
+       "cluster_estimate": 162000,
+       "flowcell": 153,
+       "lane_number": 3,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "SL039",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired ends 99 GM12892",
+            "creation_date": "2009-08-25",
+            "cell_line": 1,
+            "library_species": 8,
+            "library_type": 2,
+            "made_by": "Brian Williams",
+            "affiliations": [
+                3,4
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "Brian Williams",
+            "amplified_from_sample": 11006,
+            "notes": "fragment size = 300 bp, Amicon filtered\r\nnanodrop: 56.3",
+            "undiluted_concentration": "28.7",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+    },
+  {"pk": 1196, "model": "experiments.lane",
+   "fields": {
+       "comment": "This lane's library had the second lowest concentration of all the libraries built at the same time (2.05ng/ul)",
+       "library": "11060",
+       "cluster_estimate": 24000,
+       "flowcell": 153,
+       "lane_number": 4,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11060",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired ends 100 VC_CN_4_M_MBB1185_s1",
+            "creation_date": "2009-09-01",
+            "cell_line": 1,
+            "library_species": 8,
+            "library_type": 2,
+            "made_by": "Brian Williams",
+            "affiliations": [
+                5
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "Brian Williams",
+            "amplified_from_sample": 11006,
+            "notes": "300 bp gel fragment, Amicon filtered\r\nnanodrop: 24.2",
+            "undiluted_concentration": "2.05",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+    },
+  {"pk": 1197, "model": "experiments.lane",
+   "fields": {
+       "comment": "stuff",
+       "library": "11061",
+       "cluster_estimate": 140000,
+       "flowcell": 153,
+       "lane_number": 5,
+       "pM": "7",
+       "status": 2
+       }
+   },
+    {
+        "pk": "11061",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired ends 101 VC_CN_4_M_MBB1185_s2",
+            "creation_date": "2009-09-01",
+            "cell_line": 1,
+            "library_species": 8,
+            "library_type": 2,
+            "made_by": "Brian Williams",
+            "affiliations": [
+                2,4
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "Brian Williams",
+            "amplified_from_sample": null,
+            "notes": "300 bp gel fragment, Amicon filtered\r\nnanodrop: 33.1",
+            "undiluted_concentration": "12.9",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+    },
+  {"pk": 1198, "model": "experiments.lane",
+   "fields": {
+       "comment": "This lane's library had the lowest concentration of all the libraries built at the same time (1.2ng/ul)",
+       "library": "11062",
+       "cluster_estimate": 2000,
+       "flowcell": 153,
+       "lane_number": 6,
+       "pM": "7",
+       "status": 0
+       }
+   },
+    {
+        "pk": "11062",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired ends 102 VC_AU_8_M_MBB4721_s1",
+            "creation_date": "2009-09-01",
+            "cell_line": 1,
+            "library_species": 8,
+            "library_type": 2,
+            "made_by": "Brian Williams",
+            "affiliations": [
+                4,5
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "Brian Williams",
+            "amplified_from_sample": null,
+            "notes": "300 bp gel fragment, Amicon filtered\r\nnanodrop: 13.9",
+            "undiluted_concentration": "1.2",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+    },
+  {"pk": 1199, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11063",
+       "cluster_estimate": 120000,
+       "flowcell": 153,
+       "lane_number": 7,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11063",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired ends 103 VC_AU_8_M_MBB4721_s2",
+            "creation_date": "2009-09-01",
+            "cell_line": 1,
+            "library_species": 8,
+            "library_type": 2,
+            "made_by": "Brian Williams",
+            "affiliations": [
+                1,3
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "Brian Williams",
+            "amplified_from_sample": null,
+            "notes": "300 bp gel fragment, Amicon filtered\r\nnanodrop: 46.9",
+            "undiluted_concentration": "24.5",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+    },
+  {"pk": 1200, "model": "experiments.lane",
+   "fields": {
+       "comment": "This lane's library had the third lowest concentration of all the libraries built at the same time (5.21ng/ul), but gave perfectly normal cluster numbers",
+       "library": "11064",
+       "cluster_estimate": 157000,
+       "flowcell": 153,
+       "lane_number": 8,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11064",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired ends 104 VC_CN_7_M_MBB4898_s1",
+            "creation_date": "2009-09-01",
+            "cell_line": 1,
+            "library_species": 8,
+            "library_type": 2,
+            "made_by": "Brian Williams",
+            "affiliations": [
+                3,5
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "Brian Williams",
+            "amplified_from_sample": null,
+            "notes": "300 bp gel fragment, Amicon filtered\r\nnanodrop: 20.4",
+            "undiluted_concentration": "5.21",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+    },
+   {"pk": 152, "model": "experiments.flowcell",
+   "fields": {
+       "paired_end": false,
+       "run_date": "2009-09-10T18:30:15-0800",
+       "read_length": 38,
+       "notes": "328461 4897273 RGT-0248815\r\n328479 4897265 RGT-0249274\r\n330421 4822845 SR-0005496",
+       "advanced_run": false,
+       "control_lane": 4,
+       "cluster_station": 3,
+       "sequencer": 1,
+       "flowcell_id": "42JTNAAXX"
+       }
+   },
+  {"pk": 1185, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11035",
+       "cluster_estimate": 174000,
+       "flowcell": 152,
+       "lane_number": 1,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11035",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired ends 95 Gilberto_d3_control_LTA",
+            "creation_date": "2009-08-25",
+            "cell_line": 1,
+            "library_species": 9,
+            "library_type": 2,
+            "made_by": "Brian Williams",
+            "affiliations": [
+                3
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "Brian Williams",
+            "amplified_from_sample": null,
+            "notes": "fragment size = 300 bp, Amicon filtered\r\nnanodrop: 67.1",
+            "undiluted_concentration": "28.5",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+    },
+  {"pk": 1186, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11037",
+       "cluster_estimate": 173000,
+       "flowcell": 152,
+       "lane_number": 2,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11037",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired ends 97 Kuntz_PDHT",
+            "creation_date": "2009-08-25",
+            "cell_line": 1,
+            "library_species": 3,
+            "library_type": 2,
+            "made_by": "Brian Williams",
+            "affiliations": [
+                4
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "Brian Williams",
+            "amplified_from_sample": null,
+            "notes": "fragment size = 300 bp, Amicon filtered\r\nnanodrop: 52.7",
+            "undiluted_concentration": "25.5",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+    },
+  {"pk": 1187, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11045",
+       "cluster_estimate": 198000,
+       "flowcell": 152,
+       "lane_number": 3,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11045",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 250,
+            "library_name": "FLDN1 8/3/9 anti-AcH3 chip B6 a",
+            "creation_date": "2009-08-26",
+            "cell_line": null,
+            "library_species": 9,
+            "library_type": 1,
+            "made_by": "Lorian",
+            "affiliations": [
+                5
+            ],
+            "replicate": 1,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "2A",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "8/21/2009 11:57:54\tColor: Yellow",
+            "undiluted_concentration": "20.5",
+            "successful_pM": null,
+            "experiment_type": 2,
+            "antibody": null
+        }
+    },
+  {"pk": 1188, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11046",
+       "cluster_estimate": 212000,
+       "flowcell": 152,
+       "lane_number": 4,
+       "pM": "7"}
+   },
+    {
+        "pk": "11046",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 250,
+            "library_name": "FLDN1 7/8/9 anti-DiMeH3K4 chip B6 a",
+            "creation_date": "2009-08-26",
+            "cell_line": null,
+            "library_species": 9,
+            "library_type": 1,
+            "made_by": "Lorian",
+            "affiliations": [
+                4
+            ],
+            "replicate": 1,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "2A",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "8/21/2009 11:57:54\tColor: Blue",
+            "undiluted_concentration": "23.9",
+            "successful_pM": null,
+            "experiment_type": 2,
+            "antibody": null
+        }
+    },
+  {"pk": 1189, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11054",
+       "cluster_estimate": 49000,
+       "flowcell": 152,
+       "lane_number": 5,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11054",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 225,
+            "library_name": "HNDHT HLH hnd-1 strain HT115 fed anti-hlh-1 2% fix plate a",
+            "creation_date": "2009-08-31",
+            "cell_line": null,
+            "library_species": 3,
+            "library_type": 1,
+            "made_by": "Lorian",
+            "affiliations": [
+                1
+            ],
+            "replicate": 1,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "8/26/2009 14:46:56\tColor: Purple",
+            "undiluted_concentration": "1.47",
+            "successful_pM": null,
+            "experiment_type": 2,
+            "antibody": null
+        }
+    },
+  {"pk": 1190, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11056",
+       "cluster_estimate": 48000,
+       "flowcell": 152,
+       "lane_number": 6,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11056",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 225,
+            "library_name": "HNDM3 HLH hnd-1 strain mex-3 fed anti-hlh-1 2% fix plate a",
+            "creation_date": "2009-08-31",
+            "cell_line": null,
+            "library_species": 3,
+            "library_type": 1,
+            "made_by": "Lorian",
+            "affiliations": [
+                2
+            ],
+            "replicate": 1,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "8/26/2009 14:46:56\tColor: Black",
+            "undiluted_concentration": "1.42",
+            "successful_pM": null,
+            "experiment_type": 2,
+            "antibody": null
+        }
+    },
+  {"pk": 1191, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11057",
+       "cluster_estimate": 4000,
+       "flowcell": 152,
+       "lane_number": 7,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11057",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 225,
+            "library_name": "HNDM3 4H8 hnd-1 strain mex-3 fed 4H8 2% fix plate a",
+            "creation_date": "2009-08-31",
+            "cell_line": null,
+            "library_species": 3,
+            "library_type": 1,
+            "made_by": "Lorian",
+            "affiliations": [
+                3
+            ],
+            "replicate": 1,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "8/26/2009 14:46:56\tColor: Orange.",
+            "undiluted_concentration": "1.3",
+            "successful_pM": null,
+            "experiment_type": 2,
+            "antibody": null
+        }
+    },
+  {"pk": 1192, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11065",
+       "cluster_estimate": 5000,
+       "flowcell": 152,
+       "lane_number": 8,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11065",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired ends 105 Kuntz PDM3",
+            "creation_date": "2009-09-01",
+            "cell_line": 1,
+            "library_species": 3,
+            "library_type": 2,
+            "made_by": "Brian Williams",
+            "affiliations": [
+                4
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "Brian Williams",
+            "amplified_from_sample": null,
+            "notes": "300 bp gel fragment, Amicon filtered\r\nnanodrop: 30.5",
+            "undiluted_concentration": "2.47",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+    },
+  {"pk": 151, "model": "experiments.flowcell",
+   "fields": {
+       "paired_end": false,
+       "run_date": "2009-09-08T15:39:28-0800",
+       "read_length": 38,
+       "notes": "Rebuild of broken flowcell\r\n\r\n328461 4820241 RGT-0215719\r\n328479 4897265 RGT-0249510\r\n330421 4822845 SR-0005402\r\n",
+       "advanced_run": false,
+       "control_lane": 5,
+       "cluster_station": 3,
+       "sequencer": 2,
+       "flowcell_id": "42JU1AAXX"
+       }
+   },
+  {"pk": 1177, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11034",
+       "cluster_estimate": 177000,
+       "flowcell": 151,
+       "lane_number": 1,
+       "pM": "7"
+       }
+   },
+  {"pk": 1178, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11036",
+       "cluster_estimate": 169000,
+       "flowcell": 151,
+       "lane_number": 2,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11036",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired ends 96 Kuntz_PDE1",
+            "creation_date": "2009-08-25",
+            "cell_line": 1,
+            "library_species": 3,
+            "library_type": 2,
+            "made_by": "Brian Williams",
+            "affiliations": [
+                5
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "Brian Williams",
+            "amplified_from_sample": null,
+            "notes": "fragment size = 300 bp",
+            "undiluted_concentration": "30.6",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+    },
+    {
+        "pk": "11034",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired ends 94 Gilberto_d3_denerv_LTA",
+            "creation_date": "2009-08-25",
+            "cell_line": 1,
+            "library_species": 9,
+            "library_type": 2,
+            "made_by": "Brian Williams",
+            "affiliations": [
+                1
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "Brian Williams",
+            "amplified_from_sample": null,
+            "notes": "fragment size = 300 bp",
+            "undiluted_concentration": "27",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+    },
+    {
+        "pk": "12044",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 225,
+            "library_name": "Pooled Indexed Test",
+            "creation_date": "2009-08-26",
+            "cell_line": null,
+            "library_species": 9,
+            "library_type": 5,
+            "multiplex_id": "1,2,3",
+            "made_by": "Lorian",
+            "affiliations": [
+                2
+            ],
+            "replicate": 1,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "2A",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "8/21/2009 11:57:54\tColor: Orange",
+            "undiluted_concentration": "22.4",
+            "successful_pM": null,
+            "experiment_type": 2,
+            "antibody": null
+        }
+    },
+    {
+        "pk": "13044",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 225,
+            "library_name": "Dual Indexed Test",
+            "creation_date": "2009-08-26",
+            "cell_line": null,
+            "library_species": 9,
+            "library_type": 9,
+            "multiplex_id": "N701-N501",
+            "made_by": "Lorian",
+            "affiliations": [
+                2
+            ],
+            "replicate": 1,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "2A",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "8/21/2009 11:57:54\tColor: Orange",
+            "undiluted_concentration": "22.4",
+            "successful_pM": null,
+            "experiment_type": 2,
+            "antibody": null
+        }
+    },
+    {
+        "pk": "11045",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 225,
+            "library_name": "Simple Indexed Test",
+            "creation_date": "2009-08-26",
+            "cell_line": null,
+            "library_species": 9,
+            "library_type": 5,
+            "multiplex_id": "1",
+            "made_by": "Lorian",
+            "affiliations": [
+                2
+            ],
+            "replicate": 2,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "2A",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "8/21/2009 11:57:54\tColor: Orange",
+            "undiluted_concentration": "22.4",
+            "successful_pM": null,
+            "experiment_type": 2,
+            "antibody": null
+        }
+    },
+  {"pk": 1179,
+   "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "12044",
+       "cluster_estimate": 196000,
+       "flowcell": 151,
+       "lane_number": 3,
+       "pM": "7"
+       }
+   },
+  {"pk": 1279,
+   "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11045",
+       "cluster_estimate": 196000,
+       "flowcell": 151,
+       "lane_number": 3,
+       "pM": "7"
+       }
+   },
+  {"pk": 1379,
+   "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "13044",
+       "cluster_estimate": 196000,
+       "flowcell": 151,
+       "lane_number": 4,
+       "pM": "7"
+       }
+   },
+
+    {
+        "pk": "11044",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 225,
+            "library_name": "p300 60h C2 FA KF 12/22/8 a",
+            "creation_date": "2009-08-26",
+            "cell_line": null,
+            "library_species": 9,
+            "library_type": 1,
+            "made_by": "Lorian",
+            "affiliations": [
+                3
+            ],
+            "replicate": 1,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "2A",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "8/21/2009 11:57:54\tColor: Orange.",
+            "undiluted_concentration": "22.4",
+            "successful_pM": null,
+            "experiment_type": 2,
+            "antibody": null
+        }
+    },
+  {"pk": 1180, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11047",
+       "cluster_estimate": 200000,
+       "flowcell": 151,
+       "lane_number": 4,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11047",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 250,
+            "library_name": "FLDN1 7/8/9 anti-TriMeH3K27 chip B6 a",
+            "creation_date": "2009-08-26",
+            "cell_line": null,
+            "library_species": 9,
+            "library_type": 1,
+            "made_by": "Lorian",
+            "affiliations": [
+                4
+            ],
+            "replicate": 1,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "2A",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "8/21/2009 11:57:54\tColor: Green",
+            "undiluted_concentration": "24.9",
+            "successful_pM": null,
+            "experiment_type": 2,
+            "antibody": null
+        }
+    },
+  {"pk": 1181, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11055",
+       "cluster_estimate": 104000,
+       "flowcell": 151,
+       "lane_number": 5,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11055",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 225,
+            "library_name": "HNDHT 4H8 hnd-1 strain HT115 fed 4H8 2% fix plate a",
+            "creation_date": "2009-08-31",
+            "cell_line": null,
+            "library_species": 3,
+            "library_type": 1,
+            "made_by": "Lorian",
+            "affiliations": [
+                5
+            ],
+            "replicate": 1,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "8/26/2009 14:46:56\tColor: White.",
+            "undiluted_concentration": "2.17",
+            "successful_pM": null,
+            "experiment_type": 2,
+            "antibody": null
+        }
+    },
+  {"pk": 1182, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11067",
+       "cluster_estimate": 168000,
+       "flowcell": 151,
+       "lane_number": 6,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11067",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 325,
+            "library_name": "Paired End SP-BAC Barcoding test 250-300 bp",
+            "creation_date": "2009-09-03",
+            "cell_line": 1,
+            "library_species": 10,
+            "library_type": 2,
+            "made_by": "Igor",
+            "affiliations": [
+                1
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "Done",
+            "tags": [],
+            "made_for": "Andy Cameron",
+            "amplified_from_sample": null,
+            "notes": "12 SP BACs",
+            "undiluted_concentration": "1.45",
+            "successful_pM": null,
+            "experiment_type": 8,
+            "antibody": null
+        }
+    },
+  {"pk": 1183, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11069",
+       "cluster_estimate": 184000,
+       "flowcell": 151,
+       "lane_number": 7,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11069",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired End AG-3d-1 AG domain of floral meristem day 3, rep 1",
+            "creation_date": "2009-09-02",
+            "cell_line": null,
+            "library_species": 6,
+            "library_type": 2,
+            "made_by": "Yuling Jiao",
+            "affiliations": [
+                2
+            ],
+            "replicate": 1,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "Done",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "nanodrop: Xng/ul.",
+            "undiluted_concentration": "18.3",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+    },
+  {"pk": 1184, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11070",
+       "cluster_estimate": 182000,
+       "flowcell": 151,
+       "lane_number": 8,
+       "pM": "7"
+       }
+   },
+    {
+        "pk": "11070",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired End AG-5d-1 AG domain of floral meristem day 5, rep 1",
+            "creation_date": "2009-09-02",
+            "cell_line": null,
+            "library_species": 6,
+            "library_type": 2,
+            "made_by": "Yuling Jiao",
+            "affiliations": [
+                3
+            ],
+            "replicate": 1,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "Done",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "nanodrop: 40ng/ul\r\nCalibrated qbit with standards.\r\nMeasured 2ul library with qbit using HS kit.\r\n",
+            "undiluted_concentration": "20.3",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+     },
+ {"pk": 200, "model": "experiments.flowcell",
+  "fields": {
+      "paired_end": true,
+      "run_date": "2007-09-27T22:12:13-0800",
+      "read_length": 36,
+      "notes": "",
+      "advanced_run": false,
+      "control_lane": 2,
+      "cluster_station": 3,
+      "sequencer": 2,
+      "flowcell_id": "30012AAXX (failed)"
+      }
+  },
+  {"pk": 201, "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "11070",
+       "cluster_estimate": 182000,
+       "flowcell": 200,
+       "lane_number": 8,
+       "pM": "7"
+       }
+   }
+]
diff --git a/experiments/fixtures/woldlab.json b/experiments/fixtures/woldlab.json
new file mode 100644 (file)
index 0000000..b058925
--- /dev/null
@@ -0,0 +1,89 @@
+[ { "model": "experiments.Sequencer",
+    "pk": 1,
+    "fields": {
+      "name": "Rotifer",
+      "instrument_name": "ILLUMINA-33A494",
+      "serial_number": "",
+      "model": "Illumina Genome Analyzer II",
+      "active": false,
+      "isdefault": false,
+      "comment": "after 2010 pipeline name, was exchanged for hiseq"
+    }
+  },
+  { "model": "experiments.Sequencer",
+    "pk": 2,
+    "fields": {
+      "name": "Tardigrade",
+      "instrument_name": "ILLUMINA-EC5D15",
+      "serial_number": "",
+      "model": "Illumina Genome Analyzer IIx",
+      "active": true,
+      "isdefault": false,
+      "comment": "after 2010 pipeline name"
+    }
+  },
+  { "model": "experiments.Sequencer",
+    "pk": 3,
+    "fields": {
+      "name": "Elsewhere",
+      "instrument_name": "",
+      "serial_number": "",
+      "model": "Unknown",
+      "active": false,
+      "isdefault": false,
+      "comment": "Sequenced somewhere else"
+    }
+  },
+  { "model": "experiments.Sequencer",
+    "pk": 4,
+    "fields": {
+      "name": "Volvox",
+      "instrument_name": "HWI-ST0787",
+      "serial_number": "",
+      "model": "Illumina HiSeq 2000",
+      "active": true,
+      "isdefault": true,
+      "comment": ""
+    }
+  },
+  { "model": "experiments.Sequencer",
+    "pk": 5,
+    "fields": {
+      "name": "Tardigrade (older)",
+      "instrument_name": "HWUSI-EAS627",
+      "serial_number": "",
+      "model": "Illumina Genome Analyzer II",
+      "active": false,
+      "isdefault": false,
+      "comment": "earlier version of tardigrade"
+    }
+  },
+  { "model": "experiments.Sequencer",
+    "pk": 6,
+    "fields": {
+      "name": "Rotifer (older)",
+      "instrument_name": "HWUSI-EAS229",
+      "serial_number": "",
+      "model": "Illumina Genome Analyzer II",
+      "active": false,
+      "isdefault": false,
+      "comment": "earlier rotifer name"
+    }
+  },
+  { "model": "experiments.Sequencer",
+    "pk": 7,
+    "fields": {
+      "name": "First sequencer",
+      "instrument_name": "USI-EAS44",
+      "serial_number": "",
+      "model": "Illumina Genome Analyzer I",
+      "active": false,
+      "isdefault": false,
+      "comment": "our first sequencer"
+    }
+  },
+  { "model": "experiments.ClusterStation",
+    "pk": 3,
+    "fields": { "name": "new", "isdefault": false }
+  }
+]
diff --git a/experiments/models.py b/experiments/models.py
new file mode 100644 (file)
index 0000000..38411ef
--- /dev/null
@@ -0,0 +1,484 @@
+from __future__ import absolute_import, print_function
+
+import datetime
+import glob
+import logging
+import os
+import re
+import types
+import uuid
+
+from django.conf import settings
+from django.core.exceptions import ObjectDoesNotExist
+from django.core import urlresolvers
+from django.utils import timezone
+from django.db import models
+from django.db.models.signals import post_init, pre_save
+
+from samples.models import Library
+from htsworkflow.util.conversion import parse_flowcell_id
+from htsworkflow.pipelines import runfolder
+
+import pytz
+
+LOGGER = logging.getLogger(__name__)
+default_pM = 5
+try:
+    default_pM = int(settings.DEFAULT_PM)
+except AttributeError, e:
+    LOGGER.error("invalid value for default_pm")
+
+# how many days to wait before trying to re-import a runfolder
+RESCAN_DELAY = 1
+try:
+    RESCAN_DELAY = int(settings.RESCAN_DELAY)
+except (ValueError, AttributeError):
+    LOGGER.error("Missing or invalid settings.RESCAN_DELAY, "\
+                 "defaulting to %s" % (RESCAN_DELAY,))
+
+RUN_STATUS_CHOICES = (
+    (0, 'Sequencer running'),  # Solexa Data Pipeline Not Yet Started'),
+    (1, 'Data Pipeline Started'),
+    (2, 'Data Pipeline Interrupted'),
+    (3, 'Data Pipeline Finished'),
+    (4, 'Collect Results Started'),
+    (5, 'Collect Results Finished'),
+    (6, 'QC Started'),
+    (7, 'QC Finished'),
+    (255, 'DONE'),
+  )
+RUN_STATUS_REVERSE_MAP = dict(((v, k) for k, v in RUN_STATUS_CHOICES))
+
+
+class ClusterStation(models.Model):
+    """List of cluster stations"""
+    name = models.CharField(max_length=50, unique=True)
+    isdefault = models.BooleanField(default=False, null=False)
+
+    class Meta:
+        ordering = ["-isdefault", "name"]
+
+    def __unicode__(self):
+        return unicode(self.name)
+
+    @classmethod
+    def default(cls):
+        d = cls.objects.filter(isdefault=True).all()
+        if len(d) > 0:
+            return d[0]
+        d = cls.objects.order_by('-id').all()
+        if len(d) > 0:
+            return d[0]
+        return None
+
+    @staticmethod
+    def update_isdefault(sender, instance, **kwargs):
+        """Clear default if needed
+        """
+        if instance.isdefault:
+            for c in ClusterStation.objects.filter(isdefault=True).all():
+                if c.id != instance.id:
+                    c.isdefault = False
+                    c.save()
+
+pre_save.connect(ClusterStation.update_isdefault, sender=ClusterStation)
+
+class Sequencer(models.Model):
+    """Sequencers we've owned
+    """
+    name = models.CharField(max_length=50, db_index=True)
+    instrument_name = models.CharField(max_length=50, db_index=True)
+    serial_number = models.CharField(max_length=50, db_index=True)
+    model = models.CharField(max_length=255)
+    active = models.BooleanField(default=True, null=False)
+    isdefault = models.BooleanField(default=False, null=False)
+    comment = models.CharField(max_length=255)
+
+    class Meta:
+        ordering = ["-isdefault", "-active", "name"]
+
+    def __unicode__(self):
+        name = [unicode(self.name)]
+        if self.instrument_name is not None:
+            name.append("(%s)" % (unicode(self.instrument_name),))
+        return " ".join(name)
+
+    @models.permalink
+    def get_absolute_url(self):
+        return ('experiments.views.sequencer',
+                [self.id])
+
+    @classmethod
+    def default(cls):
+        d = cls.objects.filter(isdefault=True).all()
+        if len(d) > 0:
+            return d[0]
+        d = cls.objects.order_by('active', '-id').all()
+        if len(d) > 0:
+            return d[0]
+        return None
+
+    @staticmethod
+    def update_isdefault(sender, instance, **kwargs):
+        """Clear default if needed
+        """
+        if instance.isdefault:
+            for s in Sequencer.objects.filter(isdefault=True).all():
+                if s.id != instance.id:
+                    s.isdefault = False
+                    s.save()
+
+pre_save.connect(Sequencer.update_isdefault, sender=Sequencer)
+
+
+class FlowCell(models.Model):
+    flowcell_id = models.CharField(max_length=20, unique=True, db_index=True)
+    run_date = models.DateTimeField()
+    advanced_run = models.BooleanField(default=False)
+    paired_end = models.BooleanField(default=False)
+    read_length = models.IntegerField(default=32)  # Stanford is currenlty 25
+    control_lane = models.IntegerField(choices=[(1, 1),
+                                                (2, 2),
+                                                (3, 3),
+                                                (4, 4),
+                                                (5, 5),
+                                                (6, 6),
+                                                (7, 7),
+                                                (8, 8),
+                                                (0, 'All Lanes')],
+                                       null=True,
+                                       blank=True)
+
+    cluster_station = models.ForeignKey(ClusterStation, default=ClusterStation.default)
+    sequencer = models.ForeignKey(Sequencer, default=Sequencer.default)
+
+    notes = models.TextField(blank=True)
+
+    def __unicode__(self):
+        return unicode(self.flowcell_id)
+
+    def Lanes(self):
+        html = ['<table>']
+        for lane in self.lane_set.order_by('lane_number'):
+            cluster_estimate = lane.cluster_estimate
+            if cluster_estimate is not None:
+                cluster_estimate = "%s k" % ((int(cluster_estimate) / 1000), )
+            else:
+                cluster_estimate = 'None'
+            library_id = lane.library_id
+            library = lane.library
+            element = '<tr><td>%d</td>'\
+                      '<td><a href="%s">%s</a></td><td>%s</td></tr>'
+            html.append(element % (lane.lane_number,
+                                   library.get_admin_url(),
+                                   library,
+                                   cluster_estimate))
+        html.append('</table>')
+        return "\n".join(html)
+    Lanes.allow_tags = True
+
+    class Meta:
+        ordering = ["-run_date"]
+
+    def get_admin_url(self):
+        # that's the django way... except it didn't work
+        return urlresolvers.reverse('admin:experiments_flowcell_change',
+                                    args=(self.id,))
+
+    def flowcell_type(self):
+        """Convert our boolean 'is paired' flag to a name
+        """
+        if self.paired_end:
+            return u"Paired"
+        else:
+            return u"Single"
+
+    @models.permalink
+    def get_absolute_url(self):
+        flowcell_id, status = parse_flowcell_id(self.flowcell_id)
+        return ('experiments.views.flowcell_detail',
+                [str(flowcell_id)])
+
+    def get_raw_data_directory(self):
+        """Return location of where the raw data is stored"""
+        flowcell_id, status = parse_flowcell_id(self.flowcell_id)
+
+        return os.path.join(settings.RESULT_HOME_DIR, flowcell_id)
+
+    def update_data_runs(self):
+        result_root = self.get_raw_data_directory()
+        LOGGER.debug("Update data runs flowcell root: %s" % (result_root,))
+        if result_root is None:
+            return
+
+        result_home_dir = os.path.join(settings.RESULT_HOME_DIR, '')
+        run_xml_re = re.compile(glob.fnmatch.translate('run*.xml'))
+
+        result_dirs = []
+        for dirpath, dirnames, filenames in os.walk(result_root):
+            for filename in filenames:
+                if run_xml_re.match(filename):
+                    # we have a run directory
+                    relative_pathname = get_relative_pathname(dirpath)
+                    self.import_data_run(relative_pathname, filename)
+
+    def import_data_run(self, relative_pathname, run_xml_name, force=False):
+        """Given a result directory import files"""
+        now = timezone.now()
+        run_dir = get_absolute_pathname(relative_pathname)
+        run_xml_path = os.path.join(run_dir, run_xml_name)
+
+        runs = DataRun.objects.filter(result_dir = relative_pathname)
+        if len(runs) == 0:
+            run = DataRun()
+            created = True
+        elif len(runs) > 1:
+            raise RuntimeError("Too many data runs for %s" % (
+                relative_pathname,))
+        else:
+            run = runs[0]
+            created = False
+
+        if created or force or (now-run.last_update_time).days > RESCAN_DELAY:
+            LOGGER.debug("Importing run from %s" % (relative_pathname,))
+            run_xml_data = runfolder.load_pipeline_run_xml(run_xml_path)
+            run.flowcell = self
+            run.status = RUN_STATUS_REVERSE_MAP['DONE']
+            run.result_dir = relative_pathname
+            run.runfolder_name = run_xml_data.runfolder_name
+            run.cycle_start = run_xml_data.image_analysis.start
+            run.cycle_stop = run_xml_data.image_analysis.stop
+            naive_run_start_time = datetime.datetime.fromordinal(run_xml_data.image_analysis.date.toordinal())
+            run.run_start_time = pytz.timezone(settings.TIME_ZONE).localize(naive_run_start_time)
+            run.image_software = run_xml_data.image_analysis.software
+            run.image_version = run_xml_data.image_analysis.version
+            run.basecall_software = run_xml_data.bustard.software
+            run.basecall_version = run_xml_data.bustard.version
+            # we're frequently not running alignments
+            if run_xml_data.gerald:
+                run.alignment_software = run_xml_data.gerald.software
+                run.alignment_version = run_xml_data.gerald.version
+
+            run.last_update_time = timezone.now()
+            run.save()
+
+            run.update_result_files()
+
+
+# FIXME: should we automatically update dataruns?
+#        Or should we expect someone to call update_data_runs?
+#def update_flowcell_dataruns(sender, instance, *args, **kwargs):
+#    """Update our dataruns
+#    """
+#    if not os.path.exists(settings.RESULT_HOME_DIR):
+#       return
+#
+#    instance.update_data_runs()
+#post_init.connect(update_flowcell_dataruns, sender=FlowCell)
+
+
+LANE_STATUS_CODES = [(0, 'Failed'),
+                     (1, 'Marginal'),
+                     (2, 'Good'), ]
+LANE_STATUS_MAP = dict((int(k), v) for k, v in LANE_STATUS_CODES)
+LANE_STATUS_MAP[None] = "Unknown"
+
+
+def is_valid_lane(value):
+    if value >= 1 and value <= 8:
+        return True
+    else:
+        return False
+
+
+class Lane(models.Model):
+    flowcell = models.ForeignKey(FlowCell)
+    lane_number = models.IntegerField()
+    library = models.ForeignKey(Library)
+    pM = models.DecimalField(max_digits=5,
+                             decimal_places=2,
+                             blank=False,
+                             null=False,
+                             default=default_pM)
+    cluster_estimate = models.IntegerField(blank=True, null=True)
+    status = models.IntegerField(choices=LANE_STATUS_CODES,
+                                 null=True,
+                                 blank=True)
+    comment = models.TextField(null=True, blank=True)
+
+    @models.permalink
+    def get_absolute_url(self):
+        return ('experiments.views.flowcell_lane_detail',
+                [str(self.id)])
+
+    def __unicode__(self):
+        return self.flowcell.flowcell_id + ':' + unicode(self.lane_number)
+
+
+class DataRun(models.Model):
+    flowcell = models.ForeignKey(FlowCell, verbose_name="Flowcell Id")
+    runfolder_name = models.CharField(max_length=50)
+    result_dir = models.CharField(max_length=255)
+    last_update_time = models.DateTimeField()
+    run_start_time = models.DateTimeField()
+    cycle_start = models.IntegerField(null=True, blank=True)
+    cycle_stop = models.IntegerField(null=True, blank=True)
+    run_status = models.IntegerField(choices=RUN_STATUS_CHOICES,
+                                     null=True, blank=True)
+    image_software = models.CharField(max_length=50)
+    image_version = models.CharField(max_length=50)
+    basecall_software = models.CharField(max_length=50)
+    basecall_version = models.CharField(max_length=50)
+    alignment_software = models.CharField(max_length=50)
+    alignment_version = models.CharField(max_length=50)
+    comment = models.TextField(blank=True)
+
+    def update_result_files(self):
+        abs_result_dir = get_absolute_pathname(self.result_dir)
+
+        for dirname, dirnames, filenames in os.walk(abs_result_dir):
+            for filename in filenames:
+                pathname = os.path.join(dirname, filename)
+                relative_pathname = get_relative_pathname(pathname)
+                datafiles = self.datafile_set.filter(
+                    data_run=self,
+                    relative_pathname=relative_pathname)
+                if len(datafiles) > 0:
+                    continue
+
+                metadata = find_file_type_metadata_from_filename(filename)
+                if metadata is not None:
+                    metadata['filename'] = filename
+                    newfile = DataFile()
+                    newfile.data_run = self
+                    newfile.file_type = metadata['file_type']
+                    newfile.relative_pathname = relative_pathname
+
+                    lane_number = metadata.get('lane', None)
+                    if lane_number is not None:
+                        lane = self.flowcell.lane_set.get(
+                            lane_number=lane_number)
+                        newfile.library = lane.library
+
+                    self.datafile_set.add(newfile)
+
+        self.last_update_time = timezone.now()
+
+    def lane_files(self):
+        lanes = {}
+
+        for datafile in self.datafile_set.all():
+            metadata = datafile.attributes
+            if metadata is not None:
+                lane = metadata.get('lane', None)
+                if lane is not None:
+                    lane_file_set = lanes.setdefault(lane, {})
+                    normalized_name = datafile.file_type.normalized_name
+                    lane_file_set[normalized_name] = datafile
+        return lanes
+
+    def ivc_plots(self, lane):
+        ivc_name = ['IVC All', 'IVC Call',
+                    'IVC Percent Base', 'IVC Percent All', 'IVC Percent Call']
+
+        plots = {}
+        for rel_filename, metadata in self.get_result_files():
+            if metadata.file_type.name in ivc_name:
+                plots[metadata.file_type.name] = (rel_filename, metadata)
+
+
+class FileType(models.Model):
+    """Represent potential file types
+
+    regex is a pattern used to detect if a filename matches this type
+    data run currently assumes that there may be a (?P<lane>) and
+    (?P<end>) pattern in the regular expression.
+    """
+    name = models.CharField(max_length=50)
+    mimetype = models.CharField(max_length=50, null=True, blank=True)
+    # regular expression from glob.fnmatch.translate
+    regex = models.TextField(null=True, blank=True)
+
+    def parse_filename(self, pathname):
+        """Does filename match our pattern?
+
+        Returns None if not, or dictionary of match variables if we do.
+        """
+        path, filename = os.path.split(pathname)
+        if len(self.regex) > 0:
+            match = re.match(self.regex, filename)
+            if match is not None:
+                # These are (?P<>) names we know about from our
+                # default regexes.
+                results = match.groupdict()
+
+                # convert int parameters
+                for attribute_name in ['lane', 'end']:
+                    value = results.get(attribute_name, None)
+                    if value is not None:
+                        results[attribute_name] = int(value)
+
+                return results
+
+    def _get_normalized_name(self):
+        """Crush data file name into identifier friendly name"""
+        return self.name.replace(' ', '_').lower()
+    normalized_name = property(_get_normalized_name)
+
+    def __unicode__(self):
+        #return u"<FileType: %s>" % (self.name,)
+        return self.name
+
+
+def str_uuid():
+    """Helper function to set default UUID in DataFile"""
+    return str(uuid.uuid1())
+
+
+class DataFile(models.Model):
+    """Store map from random ID to filename"""
+    random_key = models.CharField(max_length=64,
+                                  db_index=True,
+                                  default=str_uuid)
+    data_run = models.ForeignKey(DataRun, db_index=True)
+    library = models.ForeignKey(Library, db_index=True, null=True, blank=True)
+    file_type = models.ForeignKey(FileType)
+    relative_pathname = models.CharField(max_length=255, db_index=True)
+
+    def _get_attributes(self):
+        return self.file_type.parse_filename(self.relative_pathname)
+    attributes = property(_get_attributes)
+
+    def _get_pathname(self):
+        return get_absolute_pathname(self.relative_pathname)
+    pathname = property(_get_pathname)
+
+    @models.permalink
+    def get_absolute_url(self):
+        return ('experiments.views.read_result_file',
+                (), {'key': self.random_key})
+
+
+def find_file_type_metadata_from_filename(pathname):
+    path, filename = os.path.split(pathname)
+    result = None
+    for file_type in FileType.objects.all():
+        result = file_type.parse_filename(filename)
+        if result is not None:
+            result['file_type'] = file_type
+            return result
+
+    return None
+
+
+def get_relative_pathname(abspath):
+    """Strip off the result home directory from a path
+    """
+    result_home_dir = os.path.join(settings.RESULT_HOME_DIR, '')
+    relative_pathname = abspath.replace(result_home_dir, '')
+    return relative_pathname
+
+
+def get_absolute_pathname(relative_pathname):
+    """Attach relative path to  results home directory"""
+    return os.path.join(settings.RESULT_HOME_DIR, relative_pathname)
diff --git a/experiments/test_experiments.py b/experiments/test_experiments.py
new file mode 100644 (file)
index 0000000..6dce585
--- /dev/null
@@ -0,0 +1,708 @@
+from __future__ import absolute_import, print_function
+
+import re
+from lxml.html import fromstring
+try:
+    import json
+except ImportError, e:
+    import simplejson as json
+import os
+import shutil
+import sys
+import tempfile
+from urlparse import urljoin
+
+from django.conf import settings
+from django.core import mail
+from django.core.exceptions import ObjectDoesNotExist
+from django.test import TestCase
+from django.test.utils import setup_test_environment, teardown_test_environment
+from django.db import connection
+from django.conf import settings
+
+from .models import ClusterStation, DataRun, Sequencer, FlowCell, FileType, \
+    find_file_type_metadata_from_filename
+from .experiments import flowcell_information, lanes_for
+from htsworkflow.auth import apidata
+from htsworkflow.util.ethelp import validate_xhtml
+
+from htsworkflow.pipelines.test.simulate_runfolder import TESTDATA_DIR
+
+LANE_SET = range(1,9)
+
+NSMAP = {'libns':'http://jumpgate.caltech.edu/wiki/LibraryOntology#'}
+
+from django.db import connection
+
+class ClusterStationTestCases(TestCase):
+    fixtures = ['initial_data.json',
+                'test_flowcells.json']
+
+    def test_default(self):
+        c = ClusterStation.default()
+        self.assertEqual(c.id, 2)
+
+        c.isdefault = False
+        c.save()
+
+        total = ClusterStation.objects.filter(isdefault=True).count()
+        self.assertEqual(total, 0)
+
+        other_default = ClusterStation.default()
+        self.assertEqual(other_default.id, 3)
+
+
+    def test_update_default(self):
+        old_default = ClusterStation.default()
+
+        c = ClusterStation.objects.get(pk=3)
+        c.isdefault = True
+        c.save()
+
+        new_default = ClusterStation.default()
+
+        self.assertNotEqual(old_default, new_default)
+        self.assertEqual(new_default, c)
+
+        total = ClusterStation.objects.filter(isdefault=True).count()
+        self.assertEqual(total, 1)
+
+    def test_update_other(self):
+        old_default = ClusterStation.default()
+        total = ClusterStation.objects.filter(isdefault=True).count()
+        self.assertEqual(total, 1)
+
+        c = ClusterStation.objects.get(pk=1)
+        c.name = "Primary Key 1"
+        c.save()
+
+        total = ClusterStation.objects.filter(isdefault=True).count()
+        self.assertEqual(total, 1)
+
+        new_default = ClusterStation.default()
+        self.assertEqual(old_default, new_default)
+
+
+class SequencerTestCases(TestCase):
+    fixtures = ['initial_data.json',
+                'woldlab.json',
+                'test_flowcells.json']
+
+    def test_default(self):
+        # starting with no default
+        s = Sequencer.default()
+        self.assertEqual(s.id, 2)
+
+        total = Sequencer.objects.filter(isdefault=True).count()
+        self.assertEqual(total, 1)
+
+        s.isdefault = False
+        s.save()
+
+        total = Sequencer.objects.filter(isdefault=True).count()
+        self.assertEqual(total, 0)
+
+        other_default = Sequencer.default()
+        self.assertEqual(other_default.id, 7)
+
+    def test_update_default(self):
+        old_default = Sequencer.default()
+
+        s = Sequencer.objects.get(pk=1)
+        s.isdefault = True
+        s.save()
+
+        new_default = Sequencer.default()
+
+        self.assertNotEqual(old_default, new_default)
+        self.assertEqual(new_default, s)
+
+        total = Sequencer.objects.filter(isdefault=True).count()
+        self.assertEqual(total, 1)
+
+
+    def test_update_other(self):
+        old_default = Sequencer.default()
+        total = Sequencer.objects.filter(isdefault=True).count()
+        self.assertEqual(total, 1)
+
+        s = Sequencer.objects.get(pk=1)
+        s.name = "Primary Key 1"
+        s.save()
+
+        total = Sequencer.objects.filter(isdefault=True).count()
+        self.assertEqual(total, 1)
+
+        new_default = Sequencer.default()
+        self.assertEqual(old_default, new_default)
+
+
+class ExperimentsTestCases(TestCase):
+    fixtures = ['initial_data.json',
+                'test_flowcells.json',
+                ]
+
+    def setUp(self):
+        self.tempdir = tempfile.mkdtemp(prefix='htsw-test-experiments-')
+        settings.RESULT_HOME_DIR = self.tempdir
+
+        self.fc1_id = 'FC12150'
+        self.fc1_root = os.path.join(self.tempdir, self.fc1_id)
+        os.mkdir(self.fc1_root)
+        self.fc1_dir = os.path.join(self.fc1_root, 'C1-37')
+        os.mkdir(self.fc1_dir)
+        runxml = 'run_FC12150_2007-09-27.xml'
+        shutil.copy(os.path.join(TESTDATA_DIR, runxml),
+                    os.path.join(self.fc1_dir, runxml))
+        for i in range(1,9):
+            shutil.copy(
+                os.path.join(TESTDATA_DIR,
+                             'woldlab_070829_USI-EAS44_0017_FC11055_1.srf'),
+                os.path.join(self.fc1_dir,
+                             'woldlab_070829_SERIAL_FC12150_%d.srf' %(i,))
+                )
+
+        self.fc2_dir = os.path.join(self.tempdir, '42JTNAAXX')
+        os.mkdir(self.fc2_dir)
+        os.mkdir(os.path.join(self.fc2_dir, 'C1-25'))
+        os.mkdir(os.path.join(self.fc2_dir, 'C1-37'))
+        os.mkdir(os.path.join(self.fc2_dir, 'C1-37', 'Plots'))
+
+    def tearDown(self):
+        shutil.rmtree(self.tempdir)
+
+    def test_flowcell_information(self):
+        """
+        Check the code that packs the django objects into simple types.
+        """
+        for fc_id in [u'FC12150', u"42JTNAAXX", "42JU1AAXX"]:
+            fc_dict = flowcell_information(fc_id)
+            fc_django = FlowCell.objects.get(flowcell_id=fc_id)
+            self.assertEqual(fc_dict['flowcell_id'], fc_id)
+            self.assertEqual(fc_django.flowcell_id, fc_id)
+            self.assertEqual(fc_dict['sequencer'], fc_django.sequencer.name)
+            self.assertEqual(fc_dict['read_length'], fc_django.read_length)
+            self.assertEqual(fc_dict['notes'], fc_django.notes)
+            self.assertEqual(fc_dict['cluster_station'], fc_django.cluster_station.name)
+
+            for lane in fc_django.lane_set.all():
+                lane_contents = fc_dict['lane_set'][lane.lane_number]
+                lane_dict = multi_lane_to_dict(lane_contents)[lane.library_id]
+                self.assertEqual(lane_dict['cluster_estimate'], lane.cluster_estimate)
+                self.assertEqual(lane_dict['comment'], lane.comment)
+                self.assertEqual(lane_dict['flowcell'], lane.flowcell.flowcell_id)
+                self.assertEqual(lane_dict['lane_number'], lane.lane_number)
+                self.assertEqual(lane_dict['library_name'], lane.library.library_name)
+                self.assertEqual(lane_dict['library_id'], lane.library.id)
+                self.assertAlmostEqual(float(lane_dict['pM']), float(lane.pM))
+                self.assertEqual(lane_dict['library_species'],
+                                     lane.library.library_species.scientific_name)
+
+            response = self.client.get('/experiments/config/%s/json' % (fc_id,), apidata)
+            # strptime isoformat string = '%Y-%m-%dT%H:%M:%S'
+            fc_json = json.loads(response.content)
+            self.assertEqual(fc_json['flowcell_id'], fc_id)
+            self.assertEqual(fc_json['sequencer'], fc_django.sequencer.name)
+            self.assertEqual(fc_json['read_length'], fc_django.read_length)
+            self.assertEqual(fc_json['notes'], fc_django.notes)
+            self.assertEqual(fc_json['cluster_station'], fc_django.cluster_station.name)
+
+
+            for lane in fc_django.lane_set.all():
+                lane_contents = fc_json['lane_set'][unicode(lane.lane_number)]
+                lane_dict = multi_lane_to_dict(lane_contents)[lane.library_id]
+
+                self.assertEqual(lane_dict['cluster_estimate'], lane.cluster_estimate)
+                self.assertEqual(lane_dict['comment'], lane.comment)
+                self.assertEqual(lane_dict['flowcell'], lane.flowcell.flowcell_id)
+                self.assertEqual(lane_dict['lane_number'], lane.lane_number)
+                self.assertEqual(lane_dict['library_name'], lane.library.library_name)
+                self.assertEqual(lane_dict['library_id'], lane.library.id)
+                self.assertAlmostEqual(float(lane_dict['pM']), float(lane.pM))
+                self.assertEqual(lane_dict['library_species'],
+                                     lane.library.library_species.scientific_name)
+
+    def test_invalid_flowcell(self):
+        """
+        Make sure we get a 404 if we request an invalid flowcell ID
+        """
+        response = self.client.get('/experiments/config/nottheone/json', apidata)
+        self.assertEqual(response.status_code, 404)
+
+    def test_no_key(self):
+        """
+        Require logging in to retrieve meta data
+        """
+        response = self.client.get(u'/experiments/config/FC12150/json')
+        self.assertEqual(response.status_code, 403)
+
+    def test_library_id(self):
+        """
+        Library IDs should be flexible, so make sure we can retrive a non-numeric ID
+        """
+        response = self.client.get('/experiments/config/FC12150/json', apidata)
+        self.assertEqual(response.status_code, 200)
+        flowcell = json.loads(response.content)
+
+        lane_contents = flowcell['lane_set']['3']
+        lane_library = lane_contents[0]
+        self.assertEqual(lane_library['library_id'], 'SL039')
+
+        response = self.client.get('/samples/library/SL039/json', apidata)
+        self.assertEqual(response.status_code, 200)
+        library_sl039 = json.loads(response.content)
+
+        self.assertEqual(library_sl039['library_id'], 'SL039')
+
+    def test_raw_id_field(self):
+        """
+        Test ticket:147
+
+        Library's have IDs, libraries also have primary keys,
+        we eventually had enough libraries that the drop down combo box was too
+        hard to filter through, unfortnately we want a field that uses our library
+        id and not the internal primary key, and raw_id_field uses primary keys.
+
+        This tests to make sure that the value entered in the raw library id field matches
+        the library id looked up.
+        """
+        expected_ids = [u'10981',u'11016',u'SL039',u'11060',
+                        u'11061',u'11062',u'11063',u'11064']
+        self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5')
+        response = self.client.get('/admin/experiments/flowcell/153/')
+
+        tree = fromstring(response.content)
+        for i in range(0,8):
+            xpath_expression = '//input[@id="id_lane_set-%d-library"]'
+            input_field = tree.xpath(xpath_expression % (i,))[0]
+            library_field = input_field.find('../strong')
+            library_id, library_name = library_field.text.split(':')
+            # strip leading '#' sign from name
+            library_id = library_id[1:]
+            self.assertEqual(library_id, expected_ids[i])
+            self.assertEqual(input_field.attrib['value'], library_id)
+
+    def test_library_to_flowcell_link(self):
+        """
+        Make sure the library page includes links to the flowcell pages.
+        That work with flowcell IDs that have parenthetical comments.
+        """
+        self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5')
+        response = self.client.get('/library/11070/')
+        self.assertEqual(response.status_code, 200)
+        status = validate_xhtml(response.content)
+        if status is not None: self.assertTrue(status)
+
+        tree = fromstring(response.content)
+        flowcell_spans = tree.xpath('//span[@property="libns:flowcell_id"]',
+                                    namespaces=NSMAP)
+        self.assertEqual(flowcell_spans[1].text, '30012AAXX (failed)')
+        failed_fc_span = flowcell_spans[1]
+        failed_fc_a = failed_fc_span.getparent()
+        # make sure some of our RDF made it.
+        self.assertEqual(failed_fc_a.get('typeof'), 'libns:IlluminaFlowcell')
+        self.assertEqual(failed_fc_a.get('href'), '/flowcell/30012AAXX/')
+        fc_response = self.client.get(failed_fc_a.get('href'))
+        self.assertEqual(fc_response.status_code, 200)
+        status = validate_xhtml(response.content)
+        if status is not None: self.assertTrue(status)
+
+        fc_lane_response = self.client.get('/flowcell/30012AAXX/8/')
+        self.assertEqual(fc_lane_response.status_code, 200)
+        status = validate_xhtml(response.content)
+        if status is not None: self.assertTrue(status)
+
+
+    def test_pooled_multiplex_id(self):
+        fc_dict = flowcell_information('42JU1AAXX')
+        lane_contents = fc_dict['lane_set'][3]
+        self.assertEqual(len(lane_contents), 2)
+        lane_dict = multi_lane_to_dict(lane_contents)
+
+        self.assertEqual(lane_dict['12044']['index_sequence'],
+                         {u'1': u'ATCACG',
+                          u'2': u'CGATGT',
+                          u'3': u'TTAGGC'})
+        self.assertEqual(lane_dict['11045']['index_sequence'],
+                         {u'1': u'ATCACG'})
+
+
+
+    def test_lanes_for(self):
+        """
+        Check the code that packs the django objects into simple types.
+        """
+        user = 'test'
+        lanes = lanes_for(user)
+        self.assertEqual(len(lanes), 5)
+
+        response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
+        lanes_json = json.loads(response.content)
+        self.assertEqual(len(lanes), len(lanes_json))
+        for i in range(len(lanes)):
+            self.assertEqual(lanes[i]['comment'], lanes_json[i]['comment'])
+            self.assertEqual(lanes[i]['lane_number'], lanes_json[i]['lane_number'])
+            self.assertEqual(lanes[i]['flowcell'], lanes_json[i]['flowcell'])
+            self.assertEqual(lanes[i]['run_date'], lanes_json[i]['run_date'])
+
+    def test_lanes_for_no_lanes(self):
+        """
+        Do we get something meaningful back when the user isn't attached to anything?
+        """
+        user = 'supertest'
+        lanes = lanes_for(user)
+        self.assertEqual(len(lanes), 0)
+
+        response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
+        lanes_json = json.loads(response.content)
+
+    def test_lanes_for_no_user(self):
+        """
+        Do we get something meaningful back when its the wrong user
+        """
+        user = 'not a real user'
+        self.assertRaises(ObjectDoesNotExist, lanes_for, user)
+
+        response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
+        self.assertEqual(response.status_code, 404)
+
+
+    def test_raw_data_dir(self):
+        """Raw data path generator check"""
+        flowcell_id = self.fc1_id
+        raw_dir = os.path.join(settings.RESULT_HOME_DIR, flowcell_id)
+
+        fc = FlowCell.objects.get(flowcell_id=flowcell_id)
+        self.assertEqual(fc.get_raw_data_directory(), raw_dir)
+
+        fc.flowcell_id = flowcell_id + " (failed)"
+        self.assertEqual(fc.get_raw_data_directory(), raw_dir)
+
+
+    def test_data_run_import(self):
+        srf_file_type = FileType.objects.get(name='SRF')
+        runxml_file_type = FileType.objects.get(name='run_xml')
+        flowcell_id = self.fc1_id
+        flowcell = FlowCell.objects.get(flowcell_id=flowcell_id)
+        flowcell.update_data_runs()
+        self.assertEqual(len(flowcell.datarun_set.all()), 1)
+
+        run = flowcell.datarun_set.all()[0]
+        result_files = run.datafile_set.all()
+        result_dict = dict(((rf.relative_pathname, rf) for rf in result_files))
+
+        srf4 = result_dict['FC12150/C1-37/woldlab_070829_SERIAL_FC12150_4.srf']
+        self.assertEqual(srf4.file_type, srf_file_type)
+        self.assertEqual(srf4.library_id, '11060')
+        self.assertEqual(srf4.data_run.flowcell.flowcell_id, 'FC12150')
+        self.assertEqual(
+            srf4.data_run.flowcell.lane_set.get(lane_number=4).library_id,
+            '11060')
+        self.assertEqual(
+            srf4.pathname,
+            os.path.join(settings.RESULT_HOME_DIR, srf4.relative_pathname))
+
+        lane_files = run.lane_files()
+        self.assertEqual(lane_files[4]['srf'], srf4)
+
+        runxml= result_dict['FC12150/C1-37/run_FC12150_2007-09-27.xml']
+        self.assertEqual(runxml.file_type, runxml_file_type)
+        self.assertEqual(runxml.library_id, None)
+
+        import1 = len(DataRun.objects.filter(result_dir='FC12150/C1-37'))
+        # what happens if we import twice?
+        flowcell.import_data_run('FC12150/C1-37',
+                                 'run_FC12150_2007-09-27.xml')
+        self.assertEqual(
+            len(DataRun.objects.filter(result_dir='FC12150/C1-37')),
+            import1)
+
+    def test_read_result_file(self):
+        """make sure we can return a result file
+        """
+        flowcell_id = self.fc1_id
+        flowcell = FlowCell.objects.get(flowcell_id=flowcell_id)
+        flowcell.update_data_runs()
+
+        #self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5')
+
+        result_files = flowcell.datarun_set.all()[0].datafile_set.all()
+        for f in result_files:
+            url = '/experiments/file/%s' % ( f.random_key,)
+            response = self.client.get(url)
+            self.assertEqual(response.status_code, 200)
+            mimetype = f.file_type.mimetype
+            if mimetype is None:
+                mimetype = 'application/octet-stream'
+
+            self.assertEqual(mimetype, response['content-type'])
+
+    def test_flowcell_rdf(self):
+        import RDF
+        from htsworkflow.util.rdfhelp import get_model, \
+             fromTypedNode, \
+             load_string_into_model, \
+             rdfNS, \
+             libraryOntology, \
+             dump_model
+
+        model = get_model()
+
+        expected = {'1': ['11034'],
+                    '2': ['11036'],
+                    '3': ['12044','11045'],
+                    '4': ['11047','13044'],
+                    '5': ['11055'],
+                    '6': ['11067'],
+                    '7': ['11069'],
+                    '8': ['11070']}
+        url = '/flowcell/42JU1AAXX/'
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, 200)
+        status = validate_xhtml(response.content)
+        if status is not None: self.assertTrue(status)
+
+        ns = urljoin('http://localhost', url)
+        load_string_into_model(model, 'rdfa', response.content, ns=ns)
+        body = """prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+        prefix libns: <http://jumpgate.caltech.edu/wiki/LibraryOntology#>
+
+        select ?flowcell ?flowcell_id ?lane_id ?library_id
+        where {
+          ?flowcell a libns:IlluminaFlowcell ;
+                    libns:flowcell_id ?flowcell_id ;
+                    libns:has_lane ?lane .
+          ?lane libns:lane_number ?lane_id ;
+                libns:library ?library .
+          ?library libns:library_id ?library_id .
+        }"""
+        query = RDF.SPARQLQuery(body)
+        count = 0
+        for r in query.execute(model):
+            count += 1
+            self.assertEqual(fromTypedNode(r['flowcell_id']), u'42JU1AAXX')
+            lane_id = fromTypedNode(r['lane_id'])
+            library_id = fromTypedNode(r['library_id'])
+            self.assertTrue(library_id in expected[lane_id])
+        self.assertEqual(count, 10)
+
+
+class TestFileType(TestCase):
+    fixtures = ['initial_data.json',
+                'test_flowcells.json',
+                ]
+
+    def test_file_type_unicode(self):
+        file_type_objects = FileType.objects
+        name = 'QSEQ tarfile'
+        file_type_object = file_type_objects.get(name=name)
+        self.assertEqual(u"QSEQ tarfile",
+                             unicode(file_type_object))
+
+    def test_find_file_type(self):
+        file_type_objects = FileType.objects
+        cases = [('woldlab_090921_HWUSI-EAS627_0009_42FC3AAXX_l7_r1.tar.bz2',
+                  'QSEQ tarfile', 7, 1),
+                 ('woldlab_091005_HWUSI-EAS627_0010_42JT2AAXX_1.srf',
+                  'SRF', 1, None),
+                 ('s_1_eland_extended.txt.bz2','ELAND Extended', 1, None),
+                 ('s_7_eland_multi.txt.bz2', 'ELAND Multi', 7, None),
+                 ('s_3_eland_result.txt.bz2','ELAND Result', 3, None),
+                 ('s_1_export.txt.bz2','ELAND Export', 1, None),
+                 ('s_1_percent_call.png', 'IVC Percent Call', 1, None),
+                 ('s_2_percent_base.png', 'IVC Percent Base', 2, None),
+                 ('s_3_percent_all.png', 'IVC Percent All', 3, None),
+                 ('s_4_call.png', 'IVC Call', 4, None),
+                 ('s_5_all.png', 'IVC All', 5, None),
+                 ('Summary.htm', 'Summary.htm', None, None),
+                 ('run_42JT2AAXX_2009-10-07.xml', 'run_xml', None, None),
+         ]
+        for filename, typename, lane, end in cases:
+            ft = find_file_type_metadata_from_filename(filename)
+            self.assertEqual(ft['file_type'],
+                                 file_type_objects.get(name=typename))
+            self.assertEqual(ft.get('lane', None), lane)
+            self.assertEqual(ft.get('end', None), end)
+
+    def test_assign_file_type_complex_path(self):
+        file_type_objects = FileType.objects
+        cases = [('/a/b/c/woldlab_090921_HWUSI-EAS627_0009_42FC3AAXX_l7_r1.tar.bz2',
+                  'QSEQ tarfile', 7, 1),
+                 ('foo/woldlab_091005_HWUSI-EAS627_0010_42JT2AAXX_1.srf',
+                  'SRF', 1, None),
+                 ('../s_1_eland_extended.txt.bz2','ELAND Extended', 1, None),
+                 ('/bleem/s_7_eland_multi.txt.bz2', 'ELAND Multi', 7, None),
+                 ('/qwer/s_3_eland_result.txt.bz2','ELAND Result', 3, None),
+                 ('/ty///1/s_1_export.txt.bz2','ELAND Export', 1, None),
+                 ('/help/s_1_percent_call.png', 'IVC Percent Call', 1, None),
+                 ('/bored/s_2_percent_base.png', 'IVC Percent Base', 2, None),
+                 ('/example1/s_3_percent_all.png', 'IVC Percent All', 3, None),
+                 ('amonkey/s_4_call.png', 'IVC Call', 4, None),
+                 ('fishie/s_5_all.png', 'IVC All', 5, None),
+                 ('/random/Summary.htm', 'Summary.htm', None, None),
+                 ('/notrandom/run_42JT2AAXX_2009-10-07.xml', 'run_xml', None, None),
+         ]
+        for filename, typename, lane, end in cases:
+            result = find_file_type_metadata_from_filename(filename)
+            self.assertEqual(result['file_type'],
+                                 file_type_objects.get(name=typename))
+            self.assertEqual(result.get('lane',None), lane)
+            self.assertEqual(result.get('end', None), end)
+
+class TestEmailNotify(TestCase):
+    fixtures = ['initial_data.json',
+                'test_flowcells.json']
+
+    def test_started_email_not_logged_in(self):
+        response = self.client.get('/experiments/started/153/')
+        self.assertEqual(response.status_code, 302)
+
+    def test_started_email_logged_in_user(self):
+        self.client.login(username='test', password='BJOKL5kAj6aFZ6A5')
+        response = self.client.get('/experiments/started/153/')
+        self.assertEqual(response.status_code, 302)
+
+    def test_started_email_logged_in_staff(self):
+        self.client.login(username='admintest', password='BJOKL5kAj6aFZ6A5')
+        response = self.client.get('/experiments/started/153/')
+        self.assertEqual(response.status_code, 200)
+
+    def test_started_email_send(self):
+        self.client.login(username='admintest', password='BJOKL5kAj6aFZ6A5')
+        response = self.client.get('/experiments/started/153/')
+        self.assertEqual(response.status_code, 200)
+
+        self.assertTrue('pk1@example.com' in response.content)
+        self.assertTrue('Lane #8 : (11064) Paired ends 104' in response.content)
+
+        response = self.client.get('/experiments/started/153/', {'send':'1','bcc':'on'})
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(len(mail.outbox), 4)
+        bcc = set(settings.NOTIFICATION_BCC).copy()
+        bcc.update(set(settings.MANAGERS))
+        for m in mail.outbox:
+            self.assertTrue(len(m.body) > 0)
+            self.assertEqual(set(m.bcc), bcc)
+
+    def test_email_navigation(self):
+        """
+        Can we navigate between the flowcell and email forms properly?
+        """
+        self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5')
+        response = self.client.get('/experiments/started/153/')
+        self.assertEqual(response.status_code, 200)
+        self.assertTrue(re.search('Flowcell FC12150', response.content))
+        # require that navigation back to the admin page exists
+        self.assertTrue(re.search('<a href="/admin/experiments/flowcell/153/">[^<]+</a>', response.content))
+
+def multi_lane_to_dict(lane):
+    """Convert a list of lane entries into a dictionary indexed by library ID
+    """
+    return dict( ((x['library_id'],x) for x in lane) )
+
+class TestSequencer(TestCase):
+    fixtures = ['initial_data.json',
+                'test_flowcells.json',
+                ]
+
+    def test_name_generation(self):
+        seq = Sequencer()
+        seq.name = "Seq1"
+        seq.instrument_name = "HWI-SEQ1"
+        seq.model = "Imaginary 5000"
+
+        self.assertEqual(unicode(seq), "Seq1 (HWI-SEQ1)")
+
+    def test_lookup(self):
+        fc = FlowCell.objects.get(pk=153)
+        self.assertEqual(fc.sequencer.model,
+                             "Illumina Genome Analyzer IIx")
+        self.assertEqual(fc.sequencer.instrument_name,
+                             "ILLUMINA-EC5D15")
+        # well actually we let the browser tack on the host name
+        url = fc.get_absolute_url()
+        self.assertEqual(url, '/flowcell/FC12150/')
+
+    def test_rdf(self):
+        response = self.client.get('/flowcell/FC12150/', apidata)
+        tree = fromstring(response.content)
+        seq_by = tree.xpath('//div[@rel="libns:sequenced_by"]',
+                            namespaces=NSMAP)
+        self.assertEqual(len(seq_by), 1)
+        self.assertEqual(seq_by[0].attrib['rel'], 'libns:sequenced_by')
+        seq = seq_by[0].getchildren()
+        self.assertEqual(len(seq), 1)
+        self.assertEqual(seq[0].attrib['about'], '/sequencer/2')
+        self.assertEqual(seq[0].attrib['typeof'], 'libns:Sequencer')
+
+        name = seq[0].xpath('./span[@property="libns:sequencer_name"]')
+        self.assertEqual(len(name), 1)
+        self.assertEqual(name[0].text, 'Tardigrade')
+        instrument = seq[0].xpath(
+            './span[@property="libns:sequencer_instrument"]')
+        self.assertEqual(len(instrument), 1)
+        self.assertEqual(instrument[0].text, 'ILLUMINA-EC5D15')
+        model = seq[0].xpath(
+            './span[@property="libns:sequencer_model"]')
+        self.assertEqual(len(model), 1)
+        self.assertEqual(model[0].text, 'Illumina Genome Analyzer IIx')
+
+    def test_flowcell_with_rdf_validation(self):
+        from htsworkflow.util.rdfhelp import add_default_schemas, \
+             dump_model, \
+             get_model, \
+             load_string_into_model
+        from htsworkflow.util.rdfinfer import Infer
+
+        model = get_model()
+        add_default_schemas(model)
+        inference = Infer(model)
+
+        url ='/flowcell/FC12150/'
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, 200)
+        status = validate_xhtml(response.content)
+        if status is not None: self.assertTrue(status)
+
+        load_string_into_model(model, 'rdfa', response.content)
+
+        errmsgs = list(inference.run_validation())
+        self.assertEqual(len(errmsgs), 0)
+
+    def test_lane_with_rdf_validation(self):
+        from htsworkflow.util.rdfhelp import add_default_schemas, \
+             dump_model, \
+             get_model, \
+             load_string_into_model
+        from htsworkflow.util.rdfinfer import Infer
+
+        model = get_model()
+        add_default_schemas(model)
+        inference = Infer(model)
+
+        url = '/lane/1193'
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, 200)
+        status = validate_xhtml(response.content)
+        if status is not None: self.assertTrue(status)
+
+        load_string_into_model(model, 'rdfa', response.content)
+
+        errmsgs = list(inference.run_validation())
+        self.assertEqual(len(errmsgs), 0)
+
+def suite():
+    from unittest import TestSuite, defaultTestLoader
+    suite = TestSuite()
+    for testcase in [ClusterStationTestCases,
+                     SequencerTestCases,
+                     ExerimentsTestCases,
+                     TestFileType,
+                     TestEmailNotify,
+                     TestSequencer]:
+        suite.addTests(defaultTestLoader.loadTestsFromTestCase(testcase))
+    return suite
+
+if __name__ == "__main__":
+    from unittest import main
+    main(defaultTest="suite")
diff --git a/experiments/urls.py b/experiments/urls.py
new file mode 100644 (file)
index 0000000..8330d91
--- /dev/null
@@ -0,0 +1,12 @@
+from django.conf.urls import patterns
+
+urlpatterns = patterns('',
+    (r'^$', 'experiments.views.index'),
+    #(r'^liblist$', 'htsworkflow.frontend.experiments.views.test_Libs'),
+    #(r'^(?P<run_folder>.+)/$', 'gaworkflow.frontend.experiments.views.detail'),
+    (r'^config/(?P<fc_id>.+)/json$', 'experiments.experiments.flowcell_json'),
+    (r'^lanes_for/(?P<username>.+)/json$', 'experiments.experiments.lanes_for_json'),
+    (r'^file/(?P<key>.+)/?$', 'experiments.views.read_result_file'),
+    (r'^started/(?P<pk>.+)/$', 'experiments.views.startedEmail'),
+    (r'^finished/(?P<pk>.+)/$', 'experiments.views.finishedEmail'),
+)
diff --git a/experiments/views.py b/experiments/views.py
new file mode 100644 (file)
index 0000000..294aff2
--- /dev/null
@@ -0,0 +1,189 @@
+from __future__ import absolute_import, print_function
+
+# Create your views here.
+from datetime import datetime
+import os
+
+#from django.template import Context, loader
+#shortcut to the above modules
+from django.contrib.auth.decorators import user_passes_test
+from django.conf import settings
+from django.core.exceptions import ObjectDoesNotExist
+from django.core.mail import EmailMessage, mail_managers
+from django.http import HttpResponse
+from django.shortcuts import render_to_response, get_object_or_404
+from django.template import RequestContext
+from django.template.loader import get_template
+
+from .models import DataRun, DataFile, FlowCell, Lane, Sequencer
+from .experiments import estimateFlowcellDuration, estimateFlowcellTimeRemaining, roundToDays, \
+     getUsersForFlowcell, \
+     makeEmailLaneMap
+
+def index(request):
+    all_runs = DataRun.objects.order_by('-run_start_time')
+    return render_to_response('experiments/index.html',{'data_run_list': all_runs})
+
+def detail(request, run_folder):
+    html_str = '<h2>Exp Track Details Page</h2>'
+    html_str += 'Run Folder: '+run_folder
+    r = get_object_or_404(DataRun,run_folder=run_folder)
+    return render_to_response('experiments/detail.html',{'run_f': r})
+
+def makeFCSheet(request,fcid):
+  # get Flowcell by input fcid
+  # ...
+  rec = None
+  try:
+    rec = FlowCell.objects.get(flowcell_id=fcid)
+  except ObjectDoesNotExist:
+    pass
+  lanes = ['1','2','3','4','5','6','7','8']
+  return render_to_response('experiments/flowcellSheet.html',{'fc': rec})
+
+
+@user_passes_test(lambda u: u.is_staff)
+def startedEmail(request, pk):
+    """
+    Create the we have started processing your samples email
+    """
+    fc = get_object_or_404(FlowCell, id=pk)
+
+    send = request.REQUEST.get('send',False)
+    if send in ('1', 'on', 'True', 'true', True):
+        send = True
+    else:
+        send = False
+
+    bcc_managers = request.REQUEST.get('bcc', False)
+    if bcc_managers in ('on', '1', 'True', 'true'):
+        bcc_managers = True
+    else:
+        bcc_managers = False
+
+    email_lane = makeEmailLaneMap(fc)
+    flowcell_users = getUsersForFlowcell(fc)
+    estimate = estimateFlowcellTimeRemaining(fc)
+    estimate_low, estimate_high = roundToDays(estimate)
+    email_verify = get_template('experiments/email_preview.html')
+    email_template = get_template('experiments/started_email.txt')
+    sender = settings.NOTIFICATION_SENDER
+
+    warnings = []
+    emails = []
+
+    emailless_users = []
+    for user in flowcell_users:
+        # provide warning
+        if user.email is None or len(user.email) == 0:
+            warnings.append((user.admin_url(), user.username))
+    user=None
+
+    for user_email in email_lane.keys():
+        sending = ""
+        # build body
+        context = RequestContext(request,
+                                 {u'flowcell': fc,
+                                  u'lanes': email_lane[user_email],
+                                  u'runfolder': 'blank',
+                                  u'finish_low': estimate_low,
+                                  u'finish_high': estimate_high,
+                                  u'now': datetime.now(),
+                                  })
+
+        # build view
+        subject = "Flowcell %s" % ( fc.flowcell_id )
+        body = email_template.render(context)
+
+        if send:
+            email = EmailMessage(subject, body, sender, to=[user_email])
+            notified = set()
+            if bcc_managers:
+                for manager in settings.MANAGERS:
+                    if len(manager) > 0:
+                        notified.add(manager)
+            for user in settings.NOTIFICATION_BCC:
+                if len(user) > 0:
+                    notified.add(user)
+            email.bcc = list(notified)
+            email.send()
+
+        emails.append((user_email, subject, body, sending))
+
+    verify_context = RequestContext(
+        request,
+        { 'emails': emails,
+          'flowcell': fc,
+          'from': sender,
+          'send': send,
+          'site_managers': settings.MANAGERS,
+          'title': fc.flowcell_id,
+          'warnings': warnings,
+        })
+    return HttpResponse(email_verify.render(verify_context))
+
+def finishedEmail(request, pk):
+    """
+    """
+    return HttpResponse("I've got nothing.")
+
+
+def flowcell_detail(request, flowcell_id, lane_number=None):
+    fc = get_object_or_404(FlowCell, flowcell_id__startswith=flowcell_id)
+    fc.update_data_runs()
+
+
+    if lane_number is not None:
+        lanes = fc.lane_set.filter(lane_number=lane_number)
+    else:
+        lanes = fc.lane_set.all()
+
+    context = RequestContext(request,
+                             {'flowcell': fc,
+                              'lanes': lanes})
+
+    return render_to_response('experiments/flowcell_detail.html',
+                              context)
+
+def flowcell_lane_detail(request, lane_pk):
+    lane = get_object_or_404(Lane, id=lane_pk)
+    lane.flowcell.update_data_runs()
+
+    dataruns = []
+    lane.flowcell.update_data_runs()
+    for run in lane.flowcell.datarun_set.all():
+        files = run.lane_files().get(lane.lane_number, None)
+        dataruns.append((run,
+                         lane.lane_number,
+                         files))
+
+    context = RequestContext(request,
+                             {'lib': lane.library,
+                              'lane': lane,
+                              'flowcell': lane.flowcell,
+                              'filtered_dataruns': dataruns})
+
+    return render_to_response('experiments/flowcell_lane_detail.html',
+                              context)
+
+def read_result_file(self, key):
+    """Return the contents of filename if everything is approved
+    """
+    data_file = get_object_or_404(DataFile, random_key = key)
+
+    content_type = 'application/octet-stream'
+    if data_file.file_type.mimetype is not None:
+        content_type = data_file.file_type.mimetype
+
+    if os.path.exists(data_file.pathname):
+        return HttpResponse(open(data_file.pathname,'r'),
+                            content_type=content_type)
+
+    raise Http404
+
+
+def sequencer(request, sequencer_id):
+    sequencer = get_object_or_404(Sequencer, id=sequencer_id)
+    context = RequestContext(request,
+                             {'sequencer': sequencer})
+    return render_to_response('experiments/sequencer.html', context)
diff --git a/htsworkflow/auth.py b/htsworkflow/auth.py
new file mode 100644 (file)
index 0000000..5688cc9
--- /dev/null
@@ -0,0 +1,19 @@
+"""
+Define some alternate authentication methods
+"""
+from django.core.exceptions import PermissionDenied
+from django.conf import settings
+
+apidata = {'apiid': u'0', 'apikey': settings.DEFAULT_API_KEY}
+
+def require_api_key(request):
+    # make sure we have the api component
+    if not (request.REQUEST.has_key('apiid') or request.REQUEST.has_key('apikey')):
+        raise PermissionDenied
+
+    # make sure the id and key are right
+    if request.REQUEST['apiid'] == apidata['apiid'] and \
+       request.REQUEST['apikey'] == apidata['apikey']:
+        return True
+    else:
+        raise PermissionDenied
diff --git a/htsworkflow/frontend/auth.py b/htsworkflow/frontend/auth.py
deleted file mode 100644 (file)
index 5688cc9..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-"""
-Define some alternate authentication methods
-"""
-from django.core.exceptions import PermissionDenied
-from django.conf import settings
-
-apidata = {'apiid': u'0', 'apikey': settings.DEFAULT_API_KEY}
-
-def require_api_key(request):
-    # make sure we have the api component
-    if not (request.REQUEST.has_key('apiid') or request.REQUEST.has_key('apikey')):
-        raise PermissionDenied
-
-    # make sure the id and key are right
-    if request.REQUEST['apiid'] == apidata['apiid'] and \
-       request.REQUEST['apikey'] == apidata['apikey']:
-        return True
-    else:
-        raise PermissionDenied
diff --git a/htsworkflow/frontend/bcmagic/__init__.py b/htsworkflow/frontend/bcmagic/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/htsworkflow/frontend/bcmagic/admin.py b/htsworkflow/frontend/bcmagic/admin.py
deleted file mode 100644 (file)
index 073c3e8..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-from django.contrib import admin
-from htsworkflow.frontend.bcmagic.models import KeywordMap, Printer
-
-class KeywordMapAdmin(admin.ModelAdmin):
-    list_display = ('keyword','regex', 'url_template')
-
-class PrinterAdmin(admin.ModelAdmin):
-    list_display = ('name', 'model', 'ip_address', 'label_shape', 'label_width', 'label_height', 'notes')
-    
-admin.site.register(KeywordMap, KeywordMapAdmin)
-admin.site.register(Printer, PrinterAdmin)
\ No newline at end of file
diff --git a/htsworkflow/frontend/bcmagic/fixtures/initial_data.json b/htsworkflow/frontend/bcmagic/fixtures/initial_data.json
deleted file mode 100644 (file)
index 99decf2..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-[{"pk": 1,
-  "model": "bcmagic.keywordmap",
-  "fields": {"regex": "(?P<uuid>[A-Fa-f0-9]+)",
-             "url_template": "/samples/freezer/{{ uuid }}/",
-             "keyword": "frzr"}},
- {"pk": 2,
-  "model": "bcmagic.keywordmap",
-  "fields": {"regex": "(?P<uuid>[A-Fa-f0-9]+)",
-             "url_template": "/samples/container/{{ uuid }}/",
-             "keyword": "cntr"}},
- {"pk": 3,
-  "model": "bcmagic.keywordmap",
-  "fields": {"regex": "(?P<sampleid>\\d+)\\|(?P<owner>[A-Za-z0-9_\\- ]+)",
-             "url_template": "/samples/sample/{{ sampleid }}/",
-             "keyword": "s"}},
- {"pk": 4,
-  "model": "bcmagic.keywordmap",
-  "fields": {"regex": "(?P<search>[\\S\\s]+)",
-             "url_template": "http://www.google.com/search?q={{ search }}",
-             "keyword": "gg"}},
- {"pk": 5,
-  "model": "bcmagic.keywordmap",
-  "fields": {"regex": "(?P<search>[\\S\\s]+)",
-             "url_template": "http://www.flickr.com/search/?q={{ search }}",
-             "keyword": "flickr"}},
- {"pk": 6,
-  "model": "bcmagic.keywordmap",
-  "fields": {"regex": "(?P<uuid>[A-Fa-f0-9]+)",
-             "url_template": "/inventory/{{ uuid }}/",
-             "keyword": "invu"}},
- {"pk": 7,
-  "model": "bcmagic.keywordmap",
-  "fields": {"regex": "(?P<barcode_id>.+)",
-             "url_template": "/inventory/{{barcode_id}}/",
-             "keyword": "invb"}}
-]
diff --git a/htsworkflow/frontend/bcmagic/fixtures/woldlab.json b/htsworkflow/frontend/bcmagic/fixtures/woldlab.json
deleted file mode 100644 (file)
index 51fdaa2..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-[{"pk": 1,
-  "model": "bcmagic.printer",
-  "fields": {"name": "ZM400 1.25x1",
-             "label_height": 1.0,
-             "notes": "Everyday use labels",
-             "label_width": 1.25,
-             "label_shape": "Square",
-             "model": "Zebra ZM400",
-             "ip_address": "131.215.34.116"}},
- {"pk": 2,
-  "model": "bcmagic.printer",
-  "fields": {"name": "ZM400 3x3",
-             "label_height": 3.0,
-             "notes": "Larger everyday use labels",
-             "label_width": 3.0,
-             "label_shape": "Square",
-             "model": "Zebra ZM400",
-             "ip_address": "131.215.34.117"}}]
diff --git a/htsworkflow/frontend/bcmagic/forms.py b/htsworkflow/frontend/bcmagic/forms.py
deleted file mode 100644 (file)
index 000acd9..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-from django import forms
-
-class BarcodeMagicForm(forms.Form):
-    magic = forms.CharField(label="Barcode Magic", required=False)
-    bcm_mode = forms.CharField(widget=forms.HiddenInput, initial="default")
-    
-    class Media:
-        js = ('js/jquery.timers-1.0.0.js',
-              'js/bcmagic-ext.js')
diff --git a/htsworkflow/frontend/bcmagic/models.py b/htsworkflow/frontend/bcmagic/models.py
deleted file mode 100644 (file)
index 4db58a3..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-from django.db import models
-
-#FIXME: Should be made more generic and probably pre-populated supported list
-#   but for now, since we only have a ZM400, this will do.
-PRINTER_MODELS=[ ('Zebra ZM400', 'Zebra ZM400'),
-                 ('Zebra ZM600', 'Zebra ZM600')]
-
-LABEL_SHAPES = [ ('Square', 'Square'), ('Circle', 'Circle') ]
-
-class KeywordMap(models.Model):
-    """
-    Mapper object maps keyword|arg1|arg2|...|argN to REST urls
-    """
-    keyword = models.CharField(max_length=64)
-    regex = models.CharField(max_length=1024)
-    url_template = models.TextField()
-
-class Printer(models.Model):
-    """
-    Barcode Printer Information
-    """
-    name = models.CharField(max_length=256)
-    model = models.CharField(max_length=64, choices=PRINTER_MODELS)
-    ip_address = models.IPAddressField()
-    label_shape = models.CharField(max_length=32, choices=LABEL_SHAPES)
-    label_width = models.FloatField(help_text='width or diameter in inches')
-    label_height = models.FloatField(help_text='height in inches')
-    notes = models.TextField()
-
-    def __unicode__(self):
-        return u'%s, %s, %s, %s, %sx%s' % (self.name, self.model, self.ip_address, self.label_shape, self.label_width, self.label_width)
\ No newline at end of file
diff --git a/htsworkflow/frontend/bcmagic/plugin.py b/htsworkflow/frontend/bcmagic/plugin.py
deleted file mode 100644 (file)
index d701cf3..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#from htsworkflow.frontend.samples import bcm_cmds
-
-#BCM_PLUGINS = {'cmd_move_sample': bcm_cmds.cmd_move_sample}
-
-_SEARCH_FUNCTIONS = {}
-
-def bcm_plugin_processor(keyword, text, bcm_mode):
-    """
-    Fixme should be made generic plugable, but am hard coding values for proof
-    of concept.
-    """
-    d = {}
-    
-    if bcm_mode not in BCM_PLUGINS:
-        d['mode'] = 'Error'
-        d['status'] = 'bcm_mode plugin called "%s" was not found' % (bcm_mode)
-        return d
-    
-    return BCM_PLUGINS[bcm_mode](keyword, text, bcm_mode)
-    
-
-def register_search_plugin(label, search_function):
-    """
-    Registers a group label and search_function
-    
-    search_function(search_string) --> (text_display, obj_url)
-    """
-    
-    if label in _SEARCH_FUNCTIONS:
-        msg = "search function for label (%s) already registered." % (label)
-        raise ValueError, msg
-    
-    _SEARCH_FUNCTIONS[label] = search_function
-    
\ No newline at end of file
diff --git a/htsworkflow/frontend/bcmagic/urls.py b/htsworkflow/frontend/bcmagic/urls.py
deleted file mode 100644 (file)
index d5c9627..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-from django.conf.urls import patterns
-
-urlpatterns = patterns('',
-    (r'^json_test/$', 'htsworkflow.frontend.bcmagic.views.json_test'),
-    (r'^magic/$', 'htsworkflow.frontend.bcmagic.views.magic'),
-    (r'^$', 'htsworkflow.frontend.bcmagic.views.index'),
-)
diff --git a/htsworkflow/frontend/bcmagic/utils.py b/htsworkflow/frontend/bcmagic/utils.py
deleted file mode 100644 (file)
index ace241f..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-from django.conf import settings
-
-import ftplib
-import socket
-import StringIO
-
-
-def print_zpl(zpl_text, host=None):
-    """
-    Sends zpl_text to printer
-    """
-    if not host:
-        host = settings.BCPRINTER_PRINTER1_HOST
-    ftp = ftplib.FTP(host=host, user='blank', passwd='')
-    ftp.login()
-    ftp.storlines("STOR printme.txt", StringIO.StringIO(zpl_text))
-    ftp.quit()
-
-
-def print_zpl_socket(zpl_text, host=None, port=None):
-    """
-    Sends zpl_text to printer via a socket
-
-    if zpl_text is a list of zpl_texts, it will print each one
-    in that list.
-    """
-    
-    if not host:
-        host=settings.BCPRINTER_PRINTER1_HOST
-    if not port:
-        port=settings.BCPRINTER_PRINTER1_PORT
-
-    # Process anyway if zpl_text is a list.
-    if type(zpl_text) is list:
-        zpl_text = '\n'.join(zpl_text)
-
-    s = socket.socket()
-    # PORT 9100 is default for Zebra tabletop/desktop printers
-    # PORT 6101 is default for Zebra mobile printers
-    s.connect((host, port))
-    s.sendall(zpl_text)
-    s.close()
-
-
-def report_error(message):
-    """
-    Return a dictionary with a command to display 'message'
-    """
-    return {'mode': 'Error', 'status': message}
-
-
-def redirect_to_url(url):
-    """
-    Return a bcm dictionary with a command to redirect to 'url'
-    """
-    return {'mode': 'redirect', 'url': url}
-
-
-def autofill(field, value):
-    """
-    Return a bcm dictionary with a command to automatically fill the
-    corresponding "field" with "value"
-    """
-    return {'mode': 'autofill', 'field': field, 'value': value}
diff --git a/htsworkflow/frontend/bcmagic/views.py b/htsworkflow/frontend/bcmagic/views.py
deleted file mode 100644 (file)
index f9fb793..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-from django.http import HttpResponse
-from django.template import RequestContext, Template, Context
-from django.shortcuts import render_to_response
-from django.core.exceptions import ObjectDoesNotExist
-
-from htsworkflow.frontend.bcmagic import models
-from htsworkflow.frontend.bcmagic.utils import report_error, redirect_to_url
-from htsworkflow.frontend.bcmagic.plugin import bcm_plugin_processor
-from htsworkflow.frontend.bcmagic import plugin
-#from htsworkflow.util.jsonutil import encode_json
-
-try:
-    import json
-except ImportError, e:
-    import simplejson as json
-
-import re
-
-from htsworkflow.frontend.bcmagic import forms
-
-def index(request):
-    """
-    Display a barcode magic input box
-    """
-    form = forms.BarcodeMagicForm()
-    
-    return render_to_response('bcmagic/magic.html', {'bcmagic': form},
-                              context_instance=RequestContext(request))
-
-
-def __plugin_search(text):
-    """
-    Runs registered plugins to search for results
-    """
-    
-    hits = []
-    for label, search_func in plugin._SEARCH_FUNCTIONS.items():
-        result = search_func(text)
-        if result is not None:
-            hits.extend(result)
-            
-    n = len(hits)
-    if n == 0:
-        msg = 'No hits found for: %s' % (text)
-        return report_error(msg)
-    elif n == 1:
-        return redirect_to_url(hits[0][1])
-    else:
-        msg = "%d hits found for (%s); multi-hit not implemented yet." % (n, text)
-        return report_error(msg)
-    
-    
-    #return json.dumps(hits)
-    
-
-def __magic_process(text):
-    """
-    Based on scanned text, check to see if there is map object to use
-    for a useful redirect.
-    """
-    # Split text on |
-    split_text = text.split('|')
-    
-    # There should always be at least one | in a valid scan.
-    if len(split_text) <= 1:
-        #return report_error('Invalid text: %s' % (text))
-        return __plugin_search(text)
-    
-    # Keyword is the first element in the list
-    keyword = split_text[0]
-    
-    # Attempt to find a KeywordMap based on keyword
-    try:
-        keymap = models.KeywordMap.objects.get(keyword=keyword)
-    except ObjectDoesNotExist, e:
-        return report_error('Keyword (%s) is not defined' % (keyword))
-    
-    # Remove keyword and only scan the content
-    content = '|'.join(split_text[1:])
-    
-    #FIXME: would be faster to cache compiled regex
-    search = re.compile(keymap.regex)
-    
-    mo = search.search(content)
-    
-    # if the search was invalid
-    if not mo:
-        return report_error('(%s) failed to match (%s)' % (keymap.regex, content))
-    
-    t = Template(keymap.url_template)
-    c = Context(mo.groupdict())
-    
-    return redirect_to_url(str(t.render(c)))
-    
-    
-    
-    
-
-def magic(request):
-    """
-    Let the magic begin
-    """
-    d = {}
-    
-    #Retrieve posted text from processing
-    if 'text' in request.POST:
-        text = request.POST['text']
-    else:
-        text = None
-        
-    #Retrieve bmc_mode for processing
-    if 'bcm_mode' in request.POST:
-        bcm_mode = request.POST['bcm_mode']
-    else:
-        bcm_mode = None
-        
-    ################################
-    # Handle some errors
-    ################################
-    
-    # Did not receive text error
-    if text is None or text.strip() == '':
-        d['mode'] = 'Error'
-        d['status'] = 'Did not recieve text'
-        
-        return HttpResponse(json.dumps(d), 'text/plain')
-    
-    # Did not receive bcm_mode error
-    if bcm_mode is None or bcm_mode.strip() == '':
-        d['mode'] = 'Error'
-        d['status'] = 'Missing bcm_mode information'
-    
-    
-    ################################
-    # Figure out which mode to use
-    ################################
-    keyword = text.split('|')[0]
-    
-    # Handle URL mode by default
-    if keyword == 'url':
-        d['mode'] = 'redirect'
-        d['url'] = text.split('|')[1]
-        
-    # Pass off processing to plugins
-    elif bcm_mode != 'default':
-        d = bcm_plugin_processor(keyword, text, bcm_mode)
-    
-    # Try keyword mapper
-    else:
-        d = __magic_process(text)
-    
-    return HttpResponse(json.dumps(d), 'text/plain')
-
-
-
-def json_test(request):
-    d = {}
-    
-    if 'text' in request.POST:
-        text = request.POST['text']
-    else:
-        text = None
-    
-    #return HttpResponse(json.dumps(request.POST.items()), 'text/plain')
-    if text is None or text.strip() == '':
-        d['mode'] = 'Error'
-        d['status'] = 'Did not recieve text'
-        return HttpResponse(json.dumps(d), 'text/plain')
-    
-    if text.split('|')[0] == 'url':
-        d['mode'] = 'redirect'
-        d['url'] = text.split('|')[1]
-    else:
-        d['msg'] = 'Recieved text: %s' % (text)
-        d['mode'] = 'clear'
-    
-    return HttpResponse(json.dumps(d), 'text/plain')
diff --git a/htsworkflow/frontend/eland_config/__init__.py b/htsworkflow/frontend/eland_config/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/htsworkflow/frontend/eland_config/admin.py b/htsworkflow/frontend/eland_config/admin.py
deleted file mode 100644 (file)
index 56107ff..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-from django.contrib import admin
-from django.utils.translation import ugettext_lazy as _
-
-
diff --git a/htsworkflow/frontend/eland_config/forms.py b/htsworkflow/frontend/eland_config/forms.py
deleted file mode 100644 (file)
index a2245f9..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-from django import forms
-from django.forms.util import ErrorList
-
-
-SPECIES_LIST = [#('--choose--', '--Choose--'),
-                ('hg18', 'Homo sapiens (Hg18)'),
-                ('Mm8', 'Mus musculus (Mm8)'),
-                ('arabv6', 'Arabadopsis Thaliana v6'),
-                ('other', 'Other species (Include in description)')]
-
-
-class DivErrorList(ErrorList):
-  def __unicode__(self):
-    return self.as_divs()
-  
-  def as_divs(self):
-    if not self: return u''
-    return u'<div class="errorlist">%s</div>' % (''.join([u'<div class="error">%s</div>' % e for e in self]))
-
-
-
-class ConfigForm(forms.Form):
-  
-  flow_cell_number = forms.CharField(min_length=2)
-  run_date = forms.DateTimeField()
-  advanced_run = forms.BooleanField(required=False)
-  read_length = forms.IntegerField(min_value=1, initial=32)
-  #eland_repeat = forms.BooleanField()
-  
-  #needs a for loop or something to allow for n configurations
-  #analysis_type = forms.ChoiceField(choices=[('eland','eland')])
-  lane1_species = forms.ChoiceField(choices=SPECIES_LIST)
-  lane1_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
-  
-  lane2_species = forms.ChoiceField(choices=SPECIES_LIST)
-  lane2_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
-  
-  lane3_species = forms.ChoiceField(choices=SPECIES_LIST)
-  lane3_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
-  
-  lane4_species = forms.ChoiceField(choices=SPECIES_LIST)
-  lane4_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
-  
-  lane5_species = forms.ChoiceField(choices=SPECIES_LIST)
-  lane5_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
-  
-  lane6_species = forms.ChoiceField(choices=SPECIES_LIST)
-  lane6_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
-  
-  lane7_species = forms.ChoiceField(choices=SPECIES_LIST)
-  lane7_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
-  
-  lane8_species = forms.ChoiceField(choices=SPECIES_LIST)
-  lane8_description = forms.CharField(widget=forms.TextInput(attrs={'size':'60'}))
-  
-  notes = forms.CharField(widget=forms.Textarea(attrs={'cols':'70'}), required=False)
-  
-  #lane_specific_read_length = forms.IntegerField(min_value=1)
-  
-  #eland_genome_lanes = forms.MultipleChoiceField(choices=[('lane1','1'),
-  #                                              ('lane2','2'),
-  #                                              ('lane3','3'),
-  #                                              ('lane4','4'),
-  #                                              ('lane5','5'),
-  #                                              ('lane6','6'),
-  #                                              ('lane7','7'),
-  #                                              ('lane8','8') ])
-  
-  #eland_genome = forms.ChoiceField(choices=)
-  
-  #use_bases_lanes = forms.MultipleChoiceField(choices=[('lane1','1'),
-  #                                              ('lane2','2'),
-  #                                              ('lane3','3'),
-  #                                              ('lane4','4'),
-  #                                              ('lane5','5'),
-  #                                              ('lane6','6'),
-  #                                              ('lane7','7'),
-  #                                              ('lane8','8') ])
-  
-  #use_bases_mask = forms.CharField()
-  
-  #sequence_format = forms.ChoiceField(choices=[('scarf', 'scarf')])
-  
-  
-  
-  #subject = forms.CharField(max_length=100)
-  #message = forms.CharField()
-  #sender = forms.EmailField()
-  #cc_myself = forms.BooleanField()
-  
-  def as_custom(self):
-    """
-    Displays customized html output
-    """
-    html = []
-    
-    fcn = self['flow_cell_number']
-    
-    html.append(fcn.label_tag() + ': ' + str(fcn) + str(fcn.errors) + '<br />')
-    
-    run_date = self['run_date']
-    html.append(run_date.label_tag() + ': ' + str(run_date) + str(run_date.errors) + '<br />')
-    
-    arun = self['advanced_run']
-    html.append(arun.label_tag() + ': ' + str(arun) + str(arun.errors) + '<br />')
-    
-    rl = self['read_length']
-    html.append(rl.label_tag() + ': ' + str(rl) + str(rl.errors) + '<br /><br />')
-    
-    html.append('<table border="0">')
-    html.append(' <tr><td>%s</td><td>%s</td><td>%s</td></tr>' \
-                % ('Lane', 'Species', 'Description'))
-    
-    l1s = self['lane1_species']
-    l1d = self['lane1_description']
-    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
-                % ('1', str(l1s), str(l1s.errors), str(l1d), str(l1d.errors)))
-    
-    l2s = self['lane2_species']
-    l2d = self['lane2_description']
-    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
-                % ('2', str(l2s), str(l2s.errors), str(l2d), str(l2d.errors)))
-    
-    l3s = self['lane3_species']
-    l3d = self['lane3_description']
-    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
-                % ('3', str(l3s), str(l3s.errors), str(l3d), str(l3d.errors)))
-    
-    l4s = self['lane4_species']
-    l4d = self['lane4_description']
-    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
-                % ('4', str(l4s), str(l4s.errors), str(l4d), str(l4d.errors)))
-    
-    l5s = self['lane5_species']
-    l5d = self['lane5_description']
-    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
-                % ('5', str(l5s), str(l5s.errors), str(l5d), str(l5d.errors)))
-    
-    l6s = self['lane6_species']
-    l6d = self['lane6_description']
-    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
-                % ('6', str(l6s), str(l6s.errors), str(l6d), str(l6d.errors)))
-    
-    l7s = self['lane7_species']
-    l7d = self['lane7_description']
-    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
-                % ('7', str(l7s), str(l7s.errors), str(l7d), str(l7d.errors)))
-    
-    l8s = self['lane8_species']
-    l8d = self['lane8_description']
-    html.append(' <tr><td>%s</td><td>%s %s</td><td>%s %s</td></tr>' \
-                % ('8', str(l8s), str(l8s.errors), str(l8d), str(l8d.errors)))
-    
-    html.append('</table><br />')
-    
-    notes = self['notes']
-    html.append('<p>Notes:</p>')
-    html.append(' %s<br />' % (str(notes)))
-    
-    return '\n'.join(html)
-    
-    
-    
diff --git a/htsworkflow/frontend/eland_config/models.py b/htsworkflow/frontend/eland_config/models.py
deleted file mode 100644 (file)
index 71a8362..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-from django.db import models
-
-# Create your models here.
diff --git a/htsworkflow/frontend/eland_config/urls.py b/htsworkflow/frontend/eland_config/urls.py
deleted file mode 100644 (file)
index b4bc42b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-from django.conf.urls import patterns, url
-
-urlpatterns = patterns('',
-    ## Example:
-
-    url(r'^(?P<flowcell>\w+)/$', 'htsworkflow.frontend.eland_config.views.config'),
-    url(r'^$', 'htsworkflow.frontend.eland_config.views.config'),
-    #url(r'^$', 'htsworkflow.frontend.eland_config.views.index')
-
-)
diff --git a/htsworkflow/frontend/eland_config/views.py b/htsworkflow/frontend/eland_config/views.py
deleted file mode 100644 (file)
index 7c3178b..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-from __future__ import absolute_import, print_function
-
-from django.conf import settings
-from django.http import HttpResponse
-from django.core.exceptions import ObjectDoesNotExist
-
-from htsworkflow.frontend.experiments import models
-
-import os
-
-
-def _validate_input(data):
-    return data.replace('..', '').replace('/', '_').replace('\\', '_')
-
-
-def getElandConfig(flowcell, regenerate=False):
-
-    if hasattr(settings, 'UPLOADTO_CONFIG_FILE'):
-        dest = settings.UPLOADTO_CONFIG_FILE
-    else:
-        dest = '/tmp'
-    file_path = os.path.join(dest, flowcell)
-
-    #If we are regenerating the config file, skip
-    # reading of existing file. If the file doesn't
-    # exist, try to generate it form the DB.
-    if not regenerate and os.path.isfile(file_path):
-        f = open(file_path, 'r')
-        data = f.read()
-        f.close()
-        return data
-
-    try:
-        fcObj = models.FlowCell.objects.get(flowcell_id__iexact=flowcell)
-    except ObjectDoesNotExist:
-        return None
-
-    data = []
-
-    #form = form.cleaned_data
-
-    data.append("# FLOWCELL: %s" % (fcObj.flowcell_id))
-    data.append("#")
-
-    notes = fcObj.notes.replace('\r\n', '\n').replace('\r', '\n')
-    notes = notes.replace('\n', '\n#  ')
-    data.append("# NOTES:")
-    data.append("#  %s\n#" % (notes))
-
-    #Convert all newline conventions to unix style
-    for lane in fcObj.lane_set.all():
-        data.append("# Lane%d: %s | %s" %
-                    (lane.lane_number, unicode(lane.library.id),
-                     lane.library.library_name.replace('%', '%%')))
-
-    read_length = fcObj.read_length
-    #data.append("ELAND_REPEAT")
-    data.append("ELAND_MULTIPLE_INSTANCES 8")
-
-    #Construct genome dictionary to figure out what lanes to put
-    # in the config file.
-    genome_dict = {}
-
-    #l1s = form['lane1_species']
-    for lane in fcObj.lane_set.all():
-        species = lane.library.library_species.scientific_name
-        genome_dict.setdefault(species, []).append(unicode(lane.lane_number))
-
-    genome_list = genome_dict.keys()
-    genome_list.sort()
-
-    #Loop through and create entries for each species.
-    for genome in genome_list:
-        lanes = ''.join(genome_dict[genome])
-        if fcObj.paired_end:
-            data.append('%s:ANALYSIS eland_pair' % (lanes))
-        else:
-            data.append('%s:ANALYSIS eland_extended' % (lanes))
-        data.append('%s:READ_LENGTH %s' % (lanes, read_length))
-        data.append('%s:ELAND_GENOME %s' % (lanes, '%%(%s)s' % (genome)))
-        data.append('%s:USE_BASES %s' % (lanes, 'Y'*int(read_length)))
-
-    data.append('SEQUENCE_FORMAT --fastq')
-    data.append('')  # want a trailing newline
-
-    data = '\n'.join(data)
-
-    f = open(file_path, 'w')
-    f.write(data)
-    f.close()
-
-    return data
-
-
-def config(request, flowcell=None):
-    """
-    Returns eland config file for a given flowcell number,
-    or returns a list of available flowcell numbers.
-    """
-
-    # Provide INDEX of available Flowcell config files.
-    if flowcell is None:
-        fc_list = [fc.flowcell_id for fc in models.FlowCell.objects.all()]
-
-        #Convert FC* list to html links
-        fc_html = ['<a href="/eland_config/%s/">%s</a>' % (fc_name, fc_name)
-                   for fc_name in fc_list]
-
-        return HttpResponse('<br />'.join(fc_html))
-
-    #FIXME: Should validate flowcell input before using.
-    flowcell = _validate_input(flowcell)
-    cfg = getElandConfig(flowcell, regenerate=True)
-
-    if not cfg:
-        return HttpResponse(
-            "Hmm, config file for %s does not seem to exist." % (flowcell))
-
-    return HttpResponse(cfg, mimetype="text/plain")
diff --git a/htsworkflow/frontend/experiments/__init__.py b/htsworkflow/frontend/experiments/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/htsworkflow/frontend/experiments/admin.py b/htsworkflow/frontend/experiments/admin.py
deleted file mode 100644 (file)
index f7c6396..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-from itertools import chain
-from htsworkflow.frontend.experiments.models import \
-     FlowCell, DataRun, DataFile, FileType, ClusterStation, Sequencer, Lane
-from django.contrib import admin
-from django.contrib.admin.widgets import FilteredSelectMultiple
-from django.forms import ModelForm
-from django.forms.fields import Field, CharField
-from django.forms.widgets import TextInput, Select
-from django.utils.encoding import force_unicode
-from django.utils.html import escape, conditional_escape
-from django.utils.translation import ugettext_lazy as _
-
-class DataFileForm(ModelForm):
-    class Meta:
-        model = DataFile
-        fields = ('random_key', 'data_run', 'library', 'file_type', 'relative_pathname')
-
-class DataFileInline(admin.TabularInline):
-    model = DataFile
-    form = DataFileForm
-    raw_id_fields = ('library',)
-    extra = 0
-
-class DataRunOptions(admin.ModelAdmin):
-  search_fields = [
-      'flowcell_id',
-      'run_folder',
-      'run_note',
-      ]
-  list_display = [
-      'runfolder_name',
-      'result_dir',
-      'run_start_time',
-  ]
-  fieldsets = (
-      (None, {
-        'fields': (('flowcell', 'run_status'),
-                   ('runfolder_name', 'cycle_start', 'cycle_stop'),
-                   ('result_dir',),
-                   ('last_update_time'),
-                   ('image_software', 'image_version'),
-                   ('basecall_software', 'basecall_version'),
-                   ('alignment_software', 'alignment_version'),
-                   ('comment',))
-      }),
-    )
-  inlines = [ DataFileInline ]
-  #list_filter = ('run_status', 'run_start_time')
-admin.site.register(DataRun, DataRunOptions)
-
-
-class FileTypeAdmin(admin.ModelAdmin):
-    list_display = ('name', 'mimetype', 'regex')
-admin.site.register(FileType, FileTypeAdmin)
-
-# lane form setup needs to come before Flowcell form config
-# as flowcell refers to the LaneInline class
-class LaneForm(ModelForm):
-    comment = CharField(widget=TextInput(attrs={'size':'80'}), required=False)
-
-    class Meta:
-        model = Lane
-        fields = ('flowcell', 'lane_number', 'library', 'pM', 'cluster_estimate',
-                  'status', 'comment')
-
-class LaneInline(admin.StackedInline):
-    """
-    Controls display of Lanes on the Flowcell form.
-    """
-    model = Lane
-    extra = 8
-    form = LaneForm
-    raw_id_fields = ('library',)
-    fieldsets = (
-      (None, {
-        'fields': ('lane_number', 'flowcell',
-                   ('library',),
-                   ('pM', 'cluster_estimate', 'status'),
-                   'comment',)
-      }),
-    )
-
-class LaneOptions(admin.ModelAdmin):
-    """
-    Controls display of Lane browser
-    """
-    search_fields = ('=flowcell__flowcell_id', 'library__id', 'library__library_name' )
-    list_display = ('flowcell', 'lane_number', 'library', 'comment')
-    fieldsets = (
-      (None, {
-        'fields': ('lane_number', 'flowcell',
-                   ('library'),
-                   ('pM', 'cluster_estimate'))
-      }),
-      ('Optional', {
-        'classes': ('collapse', ),
-        'fields': ('comment', )
-      }),
-    )
-admin.site.register(Lane, LaneOptions)
-
-class FlowCellOptions(admin.ModelAdmin):
-    class Media:
-        css = { 'all': ('css/admin_flowcell.css',) }
-    date_hierarchy = "run_date"
-    save_on_top = True
-    search_fields = ('flowcell_id',
-        'sequencer__name',
-        'cluster_station__name',
-        '=lane__library__id',
-        'lane__library__library_name')
-    list_display = ('flowcell_id','run_date','Lanes')
-    list_filter = ('sequencer','cluster_station', 'paired_end')
-    fieldsets = (
-        (None, {
-          'fields': ('run_date', ('flowcell_id','cluster_station','sequencer'),
-                    ('read_length', 'control_lane', 'paired_end'),)
-        }),
-        ('Notes:', { 'fields': ('notes',),}),
-    )
-    inlines = [
-      LaneInline,
-    ]
-
-    def formfield_for_dbfield(self, db_field, **kwargs):
-        field = super(FlowCellOptions, self).formfield_for_dbfield(db_field,
-                                                                   **kwargs)
-
-        # Override field attributes
-        if db_field.name == 'sequencer':
-            # seems kind of clunky.
-            # the goal is to replace the default select/combo box with one
-            # that can strike out disabled options.
-            attrs = field.widget.widget.attrs
-            field.widget.widget = SequencerSelect(attrs=attrs, queryset=field.queryset)
-        elif db_field.name == "notes":
-            field.widget.attrs["rows"] = "3"
-        return field
-admin.site.register(FlowCell, FlowCellOptions)
-
-class ClusterStationOptions(admin.ModelAdmin):
-    list_display = ('name', 'isdefault',)
-    fieldsets = ( ( None, { 'fields': ( 'name', 'isdefault') } ), )
-admin.site.register(ClusterStation, ClusterStationOptions)
-
-class SequencerSelect(Select):
-    def __init__(self, queryset=None, *args, **kwargs):
-        super(SequencerSelect, self).__init__(*args, **kwargs)
-        self.queryset = queryset
-
-    def render_options(self, choices, selected_choices):
-        # Normalize to strings.
-        selected_choices = set([force_unicode(v) for v in selected_choices])
-        output = []
-        for option_value, option_label in chain(self.choices, choices):
-            if isinstance(option_label, (list, tuple)):
-                output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
-                for option in option_label:
-                    output.append(self.render_option(selected_choices, *option))
-                output.append(u'</optgroup>')
-            else:
-                output.append(self.render_option(selected_choices, option_value, option_label))
-        return u'\n'.join(output)
-
-    # render_options blatently grabbed from 1.3.1 as the 1.2 version
-    # has render_option, which is what I needed to overload as a
-    # nested function in render_options
-    def render_options(self, choices, selected_choices):
-        # Normalize to strings.
-        selected_choices = set([force_unicode(v) for v in selected_choices])
-        output = []
-        for option_value, option_label in chain(self.choices, choices):
-            if isinstance(option_label, (list, tuple)):
-                output.append(u'<optgroup label="%s">' % escape(force_unicode(option_value)))
-                for option in option_label:
-                    output.append(self.render_option(selected_choices, *option))
-                output.append(u'</optgroup>')
-            else:
-                output.append(self.render_option(selected_choices, option_value, option_label))
-        return u'\n'.join(output)
-
-
-    def render_option(self, selected_choices, option_value, option_label):
-        disabled_sequencers = [ unicode(s.id) for s in self.queryset.filter(active=False) ]
-        option_value = unicode(option_value)
-        selected_html = (option_value in selected_choices) and u' selected="selected"' or ''
-        cssclass = "strikeout" if option_value in disabled_sequencers else ''
-        return u'<option class="%s" value="%s"%s>%s</option>' % (
-            cssclass, escape(option_value), selected_html,
-            conditional_escape(force_unicode(option_label)))
-
-class SequencerOptions(admin.ModelAdmin):
-    list_display = ('name', 'active', 'isdefault', 'instrument_name', 'model')
-    fieldsets = ( ( None,
-                    { 'fields': (
-                        'name', ('active', 'isdefault'), 'instrument_name', 'serial_number',
-                        'model', 'comment') } ), )
-
-admin.site.register(Sequencer, SequencerOptions)
diff --git a/htsworkflow/frontend/experiments/experiments.py b/htsworkflow/frontend/experiments/experiments.py
deleted file mode 100644 (file)
index 6dfd4b4..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-# some core functions of the exp tracker module
-from datetime import datetime, timedelta
-try:
-    import json
-except ImportError, e:
-    import simplejson as json
-
-import os
-import re
-
-from django.contrib.auth.decorators import login_required
-from django.views.decorators.csrf import csrf_exempt
-from django.core.exceptions import ObjectDoesNotExist
-from django.core.mail import send_mail, mail_admins
-from django.http import HttpResponse, Http404
-from django.conf import settings
-from django.utils import timezone
-
-from htsworkflow.frontend.auth import require_api_key
-from htsworkflow.frontend.experiments.models import \
-    FlowCell, \
-    DataRun, \
-    Lane, \
-    LANE_STATUS_MAP
-from htsworkflow.frontend.samples.models import Library, MultiplexIndex, HTSUser
-
-def flowcell_information(flowcell_id):
-    """
-    Return a dictionary describing a flowcell
-    """
-    try:
-        fc = FlowCell.objects.get(flowcell_id__startswith=flowcell_id)
-    except FlowCell.DoesNotExist, e:
-        return None
-
-    lane_set = {}
-    for lane in fc.lane_set.all():
-        lane_item = {
-            'cluster_estimate': lane.cluster_estimate,
-            'comment': lane.comment,
-            'experiment_type': lane.library.experiment_type.name,
-            'experiment_type_id': lane.library.experiment_type_id,
-            'flowcell': lane.flowcell.flowcell_id,
-            'lane_number': lane.lane_number,
-            'library_name': lane.library.library_name,
-            'library_id': lane.library.id,
-            'library_species': lane.library.library_species.scientific_name,
-            'pM': unicode(lane.pM),
-            'read_length': lane.flowcell.read_length,
-            'status_code': lane.status,
-            'status': LANE_STATUS_MAP[lane.status]
-        }
-        sequences = lane.library.index_sequences()
-        if sequences is not None:
-            lane_item['index_sequence'] = sequences
-
-        lane_set.setdefault(lane.lane_number,[]).append(lane_item)
-
-    if fc.control_lane is None:
-        control_lane = None
-    else:
-        control_lane = int(fc.control_lane)
-
-    info = {
-        'advanced_run': fc.advanced_run,
-        'cluster_station_id': fc.cluster_station_id,
-        'cluster_station': fc.cluster_station.name,
-        'control_lane': control_lane,
-        # 'datarun_set': how should this be represented?,
-        'flowcell_id': fc.flowcell_id,
-        'id': fc.id,
-        'lane_set': lane_set,
-        'notes': fc.notes,
-        'paired_end': fc.paired_end,
-        'read_length': fc.read_length,
-        'run_date': fc.run_date.isoformat(),
-        'sequencer_id': fc.sequencer_id,
-        'sequencer': fc.sequencer.name,
-    }
-
-    return info
-
-@csrf_exempt
-def flowcell_json(request, fc_id):
-    """
-    Return a JSON blob containing enough information to generate a config file.
-    """
-    require_api_key(request)
-
-    fc_dict = flowcell_information(fc_id)
-
-    if fc_dict is None:
-        raise Http404
-
-    fc_json = json.dumps(fc_dict)
-    return HttpResponse(fc_json, content_type = 'application/json')
-
-def lanes_for(username=None):
-    """
-    Given a user id try to return recent lanes as a list of dictionaries
-    """
-    query = {}
-    if username is not None:
-        user = HTSUser.objects.get(username=username)
-        query.update({'library__affiliations__users__id': user.id})
-
-    lanes = Lane.objects.filter(**query).order_by('-flowcell__run_date')
-
-
-    result = []
-    for l in lanes:
-        affiliations = l.library.affiliations.all()
-        affiliations_list = [(a.id, a.name) for a in affiliations]
-        result.append({ 'flowcell': l.flowcell.flowcell_id,
-                        'run_date': l.flowcell.run_date.isoformat(),
-                        'lane_number': l.lane_number,
-                        'library': l.library.id,
-                        'library_name': l.library.library_name,
-                        'comment': l.comment,
-                        'affiliations': affiliations_list})
-    return result
-
-@csrf_exempt
-def lanes_for_json(request, username):
-    """
-    Format lanes for a user
-    """
-    require_api_key(request)
-
-    try:
-        result = lanes_for(username)
-    except ObjectDoesNotExist, e:
-        raise Http404
-
-    #convert query set to python structure
-
-    result_json = json.dumps(result)
-    return HttpResponse(result_json, content_type='application/json')
-
-
-def updStatus(request):
-    output=''
-    user = 'none'
-    pswd = ''
-    UpdatedStatus = 'unknown'
-    fcid = 'none'
-    runfolder = 'unknown'
-    ClIP = request.META['REMOTE_ADDR']
-
-    if hasattr(request, 'user'):
-      user = request.user
-
-    #Check access permission
-    if not (user.is_superuser and settings.ALLOWED_IPS.has_key(ClIP)):
-        return HttpResponse("%s access denied from %s." % (user, ClIP))
-
-    # ~~~~~~Parameters for the job ~~~~
-    if request.REQUEST.has_key('fcid'):
-      fcid = request.REQUEST['fcid']
-    else:
-      return HttpResponse('missing fcid')
-
-    if request.REQUEST.has_key('runf'):
-      runfolder = request.REQUEST['runf']
-    else:
-      return HttpResponse('missing runf')
-
-
-    if request.REQUEST.has_key('updst'):
-      UpdatedStatus = request.REQUEST['updst']
-    else:
-      return HttpResponse('missing status')
-
-    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    # Update Data Run status in DB
-    # Try get rec. If not found return 'entry not found + <fcid><runfolder>', if found try update and return updated
-    try:
-      rec = DataRun.objects.get(run_folder=runfolder)
-      rec.run_status = UpdatedStatus
-
-      #if there's a message update that too
-      mytimestamp = timezone.now().__str__()
-      mytimestamp = re.sub(pattern=":[^:]*$",repl="",string=mytimestamp)
-      if request.REQUEST.has_key('msg'):
-        rec.run_note += ", "+request.REQUEST['msg']+" ("+mytimestamp+")"
-      else :
-        if UpdatedStatus == '1':
-          rec.run_note = "Started ("+mytimestamp+")"
-
-      rec.save()
-      output = "Hello "+settings.ALLOWED_IPS[ClIP]+". Updated to:'"+DataRun.RUN_STATUS_CHOICES[int(UpdatedStatus)][1].__str__()+"'"
-    except ObjectDoesNotExist:
-      output = "entry not found: "+fcid+", "+runfolder
-
-
-    #Notify researcher by email
-    # Doesn't work
-    #send_mail('Exp Tracker', 'Data Run Status '+output, 'rrauch@stanford.edu', ['rrrami@gmail.com'], fail_silently=False)
-    #mail_admins("test subject", "testing , testing", fail_silently=False)
-    # gives error: (49, "Can't assign requested address")
-    return HttpResponse(output)
-
-def generateConfile(request,fcid):
-    #granted = False
-    #ClIP = request.META['REMOTE_ADDR']
-    #if (settings.ALLOWED_IPS.has_key(ClIP)):  granted = True
-
-    #if not granted: return HttpResponse("access denied.")
-
-    config = ['READ_LENGTH 25']
-    config += ['ANALYSIS eland']
-    config += ['GENOME_FILE all_chr.fa']
-    config += ['ELAND_MULTIPLE_INSTANCES 8']
-    genome_dir = 'GENOME_DIR /Volumes/Genomes/'
-    eland_genome = 'ELAND_GENOME /Volumes/Genomes/'
-
-    try:
-      fc = FlowCell.objects.get(flowcell_id=fcid)
-      for lane in fc.lane_set.all():
-          config += [ str(lane.lane_number) +":" + \
-                      genome_dir + lane.library.library_species.scientific_name ]
-          config += [ str(lane.lane_number) +":" + \
-                      eland_genome + lane.library.library_species.scientific_name ]
-
-    except ObjectDoesNotExist:
-      config = 'Entry not found for fcid  = '+fcid
-
-    return os.linesep.join(config)
-
-def getConfile(req):
-    granted = False
-    ClIP = req.META['REMOTE_ADDR']
-    if (settings.ALLOWED_IPS.has_key(ClIP)):  granted = True
-
-    if not granted: return HttpResponse("access denied. IP: "+ClIP)
-
-    fcid = 'none'
-    cnfgfile = 'Nothing found'
-    runfolder = 'unknown'
-    request = req.REQUEST
-    if request.has_key('fcid'):
-      fcid = request['fcid']
-      if request.has_key('runf'):
-        runfolder = request['runf']
-        try:
-          rec = DataRun.objects.get(run_folder=runfolder) #,flowcell_id=fcid)
-          cnfgfile = rec.config_params
-          #match_str = re.compile(r"READ_LENGTH.+$")
-          match_str = re.compile('^READ_LENGTH.+')
-          if not match_str.search(cnfgfile):
-            cnfgfile = generateConfile(request,fcid)
-            if match_str.search(cnfgfile):
-              rec = DataRun.objects.get(run_folder=runfolder) #,flowcell_id=fcid)
-              rec.config_params = cnfgfile
-              rec.save()
-            else:
-              cnfgfile = 'Failed generating config params for RunFolder = '+runfolder +', Flowcell id = '+ fcid+ ' Config Text:\n'+cnfgfile
-
-        except ObjectDoesNotExist:
-          cnfgfile = 'Entry not found for RunFolder = '+runfolder
-
-    return HttpResponse(cnfgfile, content_type='text/plain')
-
-def getLaneLibs(req):
-    granted = False
-    ClIP = req.META['REMOTE_ADDR']
-    if (settings.ALLOWED_IPS.has_key(ClIP)):  granted = True
-
-    if not granted: return HttpResponse("access denied.")
-
-    request = req.REQUEST
-    fcid = 'none'
-    outputfile = ''
-    if request.has_key('fcid'):
-      fcid = request['fcid']
-      try:
-        rec = FlowCell.objects.get(flowcell_id=fcid)
-        #Ex: 071211
-        year = datetime.today().year.__str__()
-        year = replace(year,'20','')
-        month = datetime.today().month
-        if month < 10: month = "0"+month.__str__()
-        else: month = month.__str__()
-        day = datetime.today().day
-        if day < 10: day = "0"+day.__str__()
-        else: day = day.__str__()
-        mydate = year+month+day
-        outputfile = '<?xml version="1.0" ?>'
-        outputfile += '\n<SolexaResult Date="'+mydate+'" Flowcell="'+fcid+'" Client="'+settings.ALLOWED_IPS[ClIP]+'">'
-        outputfile += '\n<Lane Index="1" Name="'+rec.lane_1_library.library_name+'" Library="'+rec.lane_1_library.id+'" Genome="'+rec.lane_1_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
-        outputfile += '\n<Lane Index="2" Name="'+rec.lane_2_library.library_name+'" Library="'+rec.lane_2_library.id+'" Genome="'+rec.lane_2_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
-        outputfile += '\n<Lane Index="3" Name="'+rec.lane_3_library.library_name+'" Library="'+rec.lane_3_library.id+'" Genome="'+rec.lane_3_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
-        outputfile += '\n<Lane Index="4" Name="'+rec.lane_4_library.library_name+'" Library="'+rec.lane_4_library.id+'" Genome="'+rec.lane_4_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
-        outputfile += '\n<Lane Index="5" Name="'+rec.lane_5_library.library_name+'" Library="'+rec.lane_5_library.id+'" Genome="'+rec.lane_5_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
-        outputfile += '\n<Lane Index="6" Name="'+rec.lane_6_library.library_name+'" Library="'+rec.lane_6_library.id+'" Genome="'+rec.lane_6_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
-        outputfile += '\n<Lane Index="7" Name="'+rec.lane_7_library.library_name+'" Library="'+rec.lane_7_library.id+'" Genome="'+rec.lane_7_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
-        outputfile += '\n<Lane Index="8" Name="'+rec.lane_8_library.library_name+'" Library="'+rec.lane_8_library.id+'" Genome="'+rec.lane_8_library.library_species.use_genome_build+'" PrimerName="" PrimerSeq=""/>'
-        outputfile += '\n</SolexaResult>'
-      except ObjectDoesNotExist:
-        outputfile = 'Flowcell entry not found for: '+fcid
-    else: outputfile = 'Missing input: flowcell id'
-
-    return HttpResponse(outputfile, content_type='text/plain')
-
-def estimateFlowcellDuration(flowcell):
-    """
-    Attempt to estimate how long it will take to run a flowcell
-
-    """
-    # (3600 seconds * 1.5 hours per cycle )
-    sequencing_seconds_per_cycle= 3600 * 1.5
-    # 800 is a rough guess
-    pipeline_seconds_per_cycle = 800
-
-    cycles = flowcell.read_length
-    if flowcell.paired_end:
-        cycles *= 2
-    sequencing_time = timedelta(0, cycles * sequencing_seconds_per_cycle)
-    analysis_time = timedelta(0, cycles * pipeline_seconds_per_cycle)
-    estimate_mid = sequencing_time + analysis_time
-
-    return estimate_mid
-
-def estimateFlowcellTimeRemaining(flowcell):
-    estimate_mid = estimateFlowcellDuration(flowcell)
-
-    # offset for how long we've been running
-    running_time = timezone.now() - flowcell.run_date
-    estimate_mid -= running_time
-
-    return estimate_mid
-
-def roundToDays(estimate):
-    """
-    Given a time estimate round up and down in days
-    """
-    # floor estimate_mid
-    estimate_low = timedelta(estimate.days, 0)
-    # floor estimate_mid and add a day
-    estimate_high = timedelta(estimate.days+1, 0)
-
-    return (estimate_low, estimate_high)
-
-
-def makeUserLaneMap(flowcell):
-    """
-    Given a flowcell return a mapping of users interested in
-    the libraries on those lanes.
-    """
-    users = {}
-
-    for lane in flowcell.lane_set.all():
-        for affiliation in lane.library.affiliations.all():
-            for user in affiliation.users.all():
-                users.setdefault(user,[]).append(lane)
-
-    return users
-
-def getUsersForFlowcell(flowcell):
-    users = set()
-
-    for lane in flowcell.lane_set.all():
-        for affiliation in lane.library.affiliations.all():
-            for user in affiliation.users.all():
-                users.add(user)
-
-    return users
-
-def makeUserLibraryMap(libraries):
-    """
-    Given an interable set of libraries return a mapping or
-    users interested in those libraries.
-    """
-    users = {}
-
-    for library in libraries:
-        for affiliation in library.affiliations.all():
-            for user in affiliation.users.all():
-                users.setdefault(user,[]).append(library)
-
-    return users
-
-def makeAffiliationLaneMap(flowcell):
-    affs = {}
-
-    for lane in flowcell.lane_set.all():
-        for affiliation in lane.library.affiliations.all():
-            affs.setdefault(affiliation,[]).append(lane)
-
-    return affs
-
-def makeEmailLaneMap(flowcell):
-    """
-    Create a list of email addresses and the lanes associated with those users.
-
-    The email addresses can come from both the "users" table and the "affiliations" table.
-    """
-    emails = {}
-    for lane in flowcell.lane_set.all():
-        for affiliation in lane.library.affiliations.all():
-            if affiliation.email is not None and len(affiliation.email) > 0:
-                emails.setdefault(affiliation.email,set()).add(lane)
-            for user in affiliation.users.all():
-                if user.email is not None and len(user.email) > 0:
-                    emails.setdefault(user.email,set()).add(lane)
-
-    return emails
diff --git a/htsworkflow/frontend/experiments/fixtures/initial_data.json b/htsworkflow/frontend/experiments/fixtures/initial_data.json
deleted file mode 100644 (file)
index f364502..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-[
-  { "model": "experiments.FileType",
-    "pk": 1,
-    "fields": {
-      "name": "run_xml",
-      "mimetype": "application/vnd.htsworkflow-run-xml",
-      "regex": "run.*\\.xml\\Z(?ms)"
-    }
-  },
-  { "model": "experiments.FileType",
-    "pk": 2,
-    "fields": {
-      "name": "Summary.htm",
-      "mimetype": "text/html",
-      "regex": "Summary\\.htm\\Z(?ms)"
-    }
-  },
-
-  { "model": "experiments.FileType",
-    "pk": 3,
-    "fields": {
-      "name": "IVC All",
-      "mimetype": "image/png",
-      "regex": "s_(?P<lane>[0-9])_all\\.png\\Z(?ms)"
-    }
-  },
-  { "model": "experiments.FileType",
-    "pk": 4,
-    "fields": {
-      "name": "IVC Call",
-      "mimetype": "image/png",
-      "regex": "s_(?P<lane>[0-9])_call\\.png\\Z(?ms)"
-    }
-  },
-  { "model": "experiments.FileType",
-    "pk": 5,
-    "fields": {
-      "name": "IVC Percent All",
-      "mimetype": "image/png",
-      "regex": "s_(?P<lane>[0-9])_percent_all\\.png\\Z(?ms)"
-    }
-  },
-  { "model": "experiments.FileType",
-    "pk": 6,
-    "fields": {
-      "name": "IVC Percent Base",
-      "mimetype": "image/png",
-      "regex": "s_(?P<lane>[0-9])_percent_base\\.png\\Z(?ms)"
-    }
-  },
-  { "model": "experiments.FileType",
-    "pk": 7,
-    "fields": {
-      "name": "IVC Percent Call",
-      "mimetype": "image/png",
-      "regex": "s_(?P<lane>[0-9])_percent_call\\.png\\Z(?ms)"
-    }
-  },
-  { "model": "experiments.FileType",
-    "pk": 8,
-    "fields": {
-      "name": "GERALD Scores",
-      "regex": "scores\\.tar\\.bz2\\Z(?ms)"
-    }
-  },
-  { "model": "experiments.FileType",
-    "pk": 9,
-    "fields": {
-      "name": "ELAND Result",
-      "mimetype": "chemical/seq-na-eland",
-      "regex": "s_(?P<lane>[0-9])((?P<end>[1-4])_)?_eland_result\\.txt\\.bz2\\Z(?ms)"
-    }
-  },
-  { "model": "experiments.FileType",
-    "pk": 10,
-    "fields": {
-      "name": "ELAND Multi",
-      "mimetype": "chemical/seq-na-eland",
-      "regex": "s_(?P<lane>[0-9])((?P<end>[1-4])_)?_eland_multi\\.txt\\.bz2\\Z(?ms)"
-    }
-  },
-  { "model": "experiments.FileType",
-    "pk": 11,
-    "fields": {
-      "name": "ELAND Extended",
-      "mimetype": "chemical/seq-na-eland",
-      "regex": "s_(?P<lane>[0-9])((?P<end>[1-4])_)?_eland_extended\\.txt\\.bz2\\Z(?ms)"
-    }
-  },
-  { "model": "experiments.FileType",
-    "pk": 12,
-    "fields": {
-      "name": "ELAND Export",
-      "mimetype": "chemical/seq-na-eland",
-      "regex": "s_(?P<lane>[0-9])((?P<end>[1-4])_)?_export\\.txt\\.bz2\\Z(?ms)"
-    }
-  },
-  { "model": "experiments.FileType",
-    "pk": 13,
-    "fields": {
-      "name": "SRF",
-      "mimetype": "chemical/seq-na-srf",
-      "regex": ".*_(?P<lane>[1-8])\\.srf\\Z(?ms)"
-    }
-  },
-  { "model": "experiments.FileType",
-    "pk": 14,
-    "fields": {
-      "name": "QSEQ tarfile",
-      "mimetype": "chemical/seq-na-qseq",
-      "regex": ".*_l(?P<lane>[1-8])_r(?P<end>[1-4])\\.tar\\.bz2\\Z(?ms)"
-    }
-  },
-  { "model": "experiments.FileType",
-    "pk": 15,
-    "fields": {
-      "name": "HiSeq Fastq",
-      "mimetype": "chemical/seq-na-fastq",
-      "regex": "(?P<library>[0-9]+)_(NoIndex|[AGCT]+)_L(?P<lane>[0-9]+)_R(?P<end>[12])_(?P<split>[0-9]+)\\.fastq\\.gz"
-    }
-  }
-]
diff --git a/htsworkflow/frontend/experiments/fixtures/test_flowcells.json b/htsworkflow/frontend/experiments/fixtures/test_flowcells.json
deleted file mode 100644 (file)
index 15d00c6..0000000
+++ /dev/null
@@ -1,1273 +0,0 @@
-[
-    {"pk": 5, "model": "auth.user",
-   "fields": {
-       "username": "test",
-       "first_name": "",
-       "last_name": "",
-       "is_active": true,
-       "is_superuser": false,
-       "is_staff": false,
-       "last_login": "2009-01-01T00:00:01-0800",
-       "groups": [],
-       "user_permissions": [],
-       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
-       "email": "",
-       "date_joined": "2009-01-01T00:01:01-0800"
-       }
-   },
-   {"pk": 5, "model": "samples.htsuser",
-    "fields" : {}
-   },
-   {"pk": 6, "model": "auth.user",
-   "fields": {
-       "username": "admintest",
-       "first_name": "",
-       "last_name": "",
-       "is_active": true,
-       "is_superuser": false,
-       "is_staff": true,
-       "last_login": "2009-01-01T00:00:01-0800",
-       "groups": [],
-       "user_permissions": [],
-       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
-       "email": "",
-       "date_joined": "2009-01-01T00:01:01-0800"
-       }
-   },
-   {"pk": 6, "model": "samples.htsuser",
-    "fields" : {}
-   },
-   {"pk": 7, "model": "auth.user",
-   "fields": {
-       "username": "supertest",
-       "first_name": "",
-       "last_name": "",
-       "is_active": true,
-       "is_superuser": true,
-       "is_staff": true,
-       "last_login": "2009-01-01T00:00:01-0800",
-       "groups": [],
-       "user_permissions": [],
-       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
-       "email": "",
-       "date_joined": "2009-01-01T00:01:01-0800"
-       }
-   },
-   {"pk": 7, "model": "samples.htsuser",
-    "fields" : {}
-   },
-   {"pk": 1, "model": "samples.affiliation",
-     "fields": {
-         "users": [5],
-         "contact": "group 1",
-         "name": "affiliation 1",
-         "email": "pk1@example.com"
-         }
-     },
-    {"pk": 2, "model": "samples.affiliation",
-     "fields": {
-         "users": [6],
-         "contact": "group 2",
-         "name": "affiliation 2",
-         "email": "pk2@example.com"
-         }
-     },
-    {"pk": 3, "model": "samples.affiliation",
-     "fields": {
-         "users": [],
-         "contact": "group 3",
-         "name": "affiliation 3",
-         "email": "pk3@example.com"
-         }
-     },
-    {"pk": 4, "model": "samples.affiliation",
-     "fields": {
-         "users": [],
-         "contact": "group 4",
-         "name": "affiliation 4",
-         "email": "pk1@example.com"
-         }
-     },
-    {"pk": 5, "model": "samples.affiliation",
-     "fields": {
-         "users": [],
-         "contact": "group 5",
-         "name": "affiliation 5",
-         "email": "pk5@example.com"
-         }
-     },
- {"pk": 1, "model": "experiments.clusterstation",
-  "fields": {"name": "old", "isdefault": false}},
- {"pk": 2, "model": "experiments.clusterstation",
-  "fields": {"name": "loaner", "isdefault": true}},
- {"pk": 3, "model": "experiments.clusterstation",
-  "fields": {"name": "new", "isdefault": false}},
- {"pk": 1, "model": "experiments.sequencer",
-  "fields": { "name": "Rotifer (HWI-EAS229)",
-              "model": "Illumina Genome Analyzer I",
-              "active": false,
-              "isdefault": false }},
- {"pk": 2, "model": "experiments.sequencer",
-  "fields": {"name": "Tardigrade",
-             "instrument_name": "ILLUMINA-EC5D15",
-             "model": "Illumina Genome Analyzer IIx",
-             "active": true,
-             "isdefault": true}
- },
- {"pk": 3, "model": "experiments.sequencer",
-  "fields": {"name": "Sequenced somewhere else.",
-             "model": "Unknown",
-             "active": true,
-             "isdefault": false}},
- {"pk": 153, "model": "experiments.flowcell",
-  "fields": {
-      "paired_end": true,
-      "run_date": "2007-09-27T22:12:13-0800",
-      "read_length": 36,
-      "notes": "",
-      "advanced_run": false,
-      "control_lane": 2,
-      "cluster_station": 3,
-      "sequencer": 2,
-      "flowcell_id": "FC12150"
-      }
-  },
-  {"pk": 1193, "model": "experiments.lane",
-   "fields": {
-       "comment": "No change in cluster numbers, despite slight increase in pM",
-       "library": "10981",
-       "cluster_estimate": 129000,
-       "flowcell": 153,
-       "lane_number": 1,
-       "pM": "8"
-       }
-   },
-   {"pk": 1192, "model": "experiments.lane",
-    "fields": {
-        "comment": "Other library",
-        "library": "11070",
-        "cluster_estimate": 132000,
-        "flowcell": 153,
-        "lane_number": 1,
-        "pM": "7"
-        }
-    },
-
-  {"pk": "10981", "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 400,
-            "library_name": "Paired End Multiplexed Sp-BAC",
-            "creation_date": "2009-07-21",
-            "cell_line": 1,
-            "library_species": 10,
-            "library_type": null,
-            "made_by": "Igor",
-            "affiliations": [
-                1,2
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "Done",
-            "tags": [],
-            "made_for": "Andy Cameron",
-            "amplified_from_sample": null,
-            "notes": "Combined 10957-10968",
-            "undiluted_concentration": "5.1",
-            "successful_pM": null,
-            "experiment_type": 10,
-            "antibody": null
-        }
-    },
-  {"pk": 1194, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11016",
-       "cluster_estimate": 152000,
-       "flowcell": 153,
-       "lane_number": 2,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11006",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 325,
-            "library_name": "Paired End Pfl #3 MP 7/24/9",
-            "creation_date": "2009-08-05",
-            "cell_line": 1,
-            "library_species": 8,
-            "library_type": 2,
-            "made_by": "Lorian",
-            "affiliations": [
-                3
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": true,
-            "stopping_point": "1A",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "7/31/2009 16:08:22\tColor: Blue",
-            "undiluted_concentration": null,
-            "successful_pM": null,
-            "experiment_type": 8,
-            "antibody": null
-        }
-    },
-    {
-        "pk": "11016",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 325,
-            "library_name": "Paired End Pfl #3 MP 7/24/9 a",
-            "creation_date": "2009-08-06",
-            "cell_line": 1,
-            "library_species": 2,
-            "library_type": 2,
-            "made_by": "Lorian",
-            "affiliations": [
-                2
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": 11006,
-            "notes": "7/31/2009 16:08:22\tColor: Blue",
-            "undiluted_concentration": "35.5",
-            "successful_pM": null,
-            "experiment_type": 8,
-            "antibody": null
-        }
-    },
-  {"pk": 1195, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "SL039",
-       "cluster_estimate": 162000,
-       "flowcell": 153,
-       "lane_number": 3,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "SL039",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired ends 99 GM12892",
-            "creation_date": "2009-08-25",
-            "cell_line": 1,
-            "library_species": 8,
-            "library_type": 2,
-            "made_by": "Brian Williams",
-            "affiliations": [
-                3,4
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "Brian Williams",
-            "amplified_from_sample": 11006,
-            "notes": "fragment size = 300 bp, Amicon filtered\r\nnanodrop: 56.3",
-            "undiluted_concentration": "28.7",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-  {"pk": 1196, "model": "experiments.lane",
-   "fields": {
-       "comment": "This lane's library had the second lowest concentration of all the libraries built at the same time (2.05ng/ul)",
-       "library": "11060",
-       "cluster_estimate": 24000,
-       "flowcell": 153,
-       "lane_number": 4,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11060",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired ends 100 VC_CN_4_M_MBB1185_s1",
-            "creation_date": "2009-09-01",
-            "cell_line": 1,
-            "library_species": 8,
-            "library_type": 2,
-            "made_by": "Brian Williams",
-            "affiliations": [
-                5
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "Brian Williams",
-            "amplified_from_sample": 11006,
-            "notes": "300 bp gel fragment, Amicon filtered\r\nnanodrop: 24.2",
-            "undiluted_concentration": "2.05",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-  {"pk": 1197, "model": "experiments.lane",
-   "fields": {
-       "comment": "stuff",
-       "library": "11061",
-       "cluster_estimate": 140000,
-       "flowcell": 153,
-       "lane_number": 5,
-       "pM": "7",
-       "status": 2
-       }
-   },
-    {
-        "pk": "11061",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired ends 101 VC_CN_4_M_MBB1185_s2",
-            "creation_date": "2009-09-01",
-            "cell_line": 1,
-            "library_species": 8,
-            "library_type": 2,
-            "made_by": "Brian Williams",
-            "affiliations": [
-                2,4
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "Brian Williams",
-            "amplified_from_sample": null,
-            "notes": "300 bp gel fragment, Amicon filtered\r\nnanodrop: 33.1",
-            "undiluted_concentration": "12.9",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-  {"pk": 1198, "model": "experiments.lane",
-   "fields": {
-       "comment": "This lane's library had the lowest concentration of all the libraries built at the same time (1.2ng/ul)",
-       "library": "11062",
-       "cluster_estimate": 2000,
-       "flowcell": 153,
-       "lane_number": 6,
-       "pM": "7",
-       "status": 0
-       }
-   },
-    {
-        "pk": "11062",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired ends 102 VC_AU_8_M_MBB4721_s1",
-            "creation_date": "2009-09-01",
-            "cell_line": 1,
-            "library_species": 8,
-            "library_type": 2,
-            "made_by": "Brian Williams",
-            "affiliations": [
-                4,5
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "Brian Williams",
-            "amplified_from_sample": null,
-            "notes": "300 bp gel fragment, Amicon filtered\r\nnanodrop: 13.9",
-            "undiluted_concentration": "1.2",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-  {"pk": 1199, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11063",
-       "cluster_estimate": 120000,
-       "flowcell": 153,
-       "lane_number": 7,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11063",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired ends 103 VC_AU_8_M_MBB4721_s2",
-            "creation_date": "2009-09-01",
-            "cell_line": 1,
-            "library_species": 8,
-            "library_type": 2,
-            "made_by": "Brian Williams",
-            "affiliations": [
-                1,3
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "Brian Williams",
-            "amplified_from_sample": null,
-            "notes": "300 bp gel fragment, Amicon filtered\r\nnanodrop: 46.9",
-            "undiluted_concentration": "24.5",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-  {"pk": 1200, "model": "experiments.lane",
-   "fields": {
-       "comment": "This lane's library had the third lowest concentration of all the libraries built at the same time (5.21ng/ul), but gave perfectly normal cluster numbers",
-       "library": "11064",
-       "cluster_estimate": 157000,
-       "flowcell": 153,
-       "lane_number": 8,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11064",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired ends 104 VC_CN_7_M_MBB4898_s1",
-            "creation_date": "2009-09-01",
-            "cell_line": 1,
-            "library_species": 8,
-            "library_type": 2,
-            "made_by": "Brian Williams",
-            "affiliations": [
-                3,5
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "Brian Williams",
-            "amplified_from_sample": null,
-            "notes": "300 bp gel fragment, Amicon filtered\r\nnanodrop: 20.4",
-            "undiluted_concentration": "5.21",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-   {"pk": 152, "model": "experiments.flowcell",
-   "fields": {
-       "paired_end": false,
-       "run_date": "2009-09-10T18:30:15-0800",
-       "read_length": 38,
-       "notes": "328461 4897273 RGT-0248815\r\n328479 4897265 RGT-0249274\r\n330421 4822845 SR-0005496",
-       "advanced_run": false,
-       "control_lane": 4,
-       "cluster_station": 3,
-       "sequencer": 1,
-       "flowcell_id": "42JTNAAXX"
-       }
-   },
-  {"pk": 1185, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11035",
-       "cluster_estimate": 174000,
-       "flowcell": 152,
-       "lane_number": 1,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11035",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired ends 95 Gilberto_d3_control_LTA",
-            "creation_date": "2009-08-25",
-            "cell_line": 1,
-            "library_species": 9,
-            "library_type": 2,
-            "made_by": "Brian Williams",
-            "affiliations": [
-                3
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "Brian Williams",
-            "amplified_from_sample": null,
-            "notes": "fragment size = 300 bp, Amicon filtered\r\nnanodrop: 67.1",
-            "undiluted_concentration": "28.5",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-  {"pk": 1186, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11037",
-       "cluster_estimate": 173000,
-       "flowcell": 152,
-       "lane_number": 2,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11037",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired ends 97 Kuntz_PDHT",
-            "creation_date": "2009-08-25",
-            "cell_line": 1,
-            "library_species": 3,
-            "library_type": 2,
-            "made_by": "Brian Williams",
-            "affiliations": [
-                4
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "Brian Williams",
-            "amplified_from_sample": null,
-            "notes": "fragment size = 300 bp, Amicon filtered\r\nnanodrop: 52.7",
-            "undiluted_concentration": "25.5",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-  {"pk": 1187, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11045",
-       "cluster_estimate": 198000,
-       "flowcell": 152,
-       "lane_number": 3,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11045",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 250,
-            "library_name": "FLDN1 8/3/9 anti-AcH3 chip B6 a",
-            "creation_date": "2009-08-26",
-            "cell_line": null,
-            "library_species": 9,
-            "library_type": 1,
-            "made_by": "Lorian",
-            "affiliations": [
-                5
-            ],
-            "replicate": 1,
-            "condition": null,
-            "hidden": false,
-            "stopping_point": "2A",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "8/21/2009 11:57:54\tColor: Yellow",
-            "undiluted_concentration": "20.5",
-            "successful_pM": null,
-            "experiment_type": 2,
-            "antibody": null
-        }
-    },
-  {"pk": 1188, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11046",
-       "cluster_estimate": 212000,
-       "flowcell": 152,
-       "lane_number": 4,
-       "pM": "7"}
-   },
-    {
-        "pk": "11046",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 250,
-            "library_name": "FLDN1 7/8/9 anti-DiMeH3K4 chip B6 a",
-            "creation_date": "2009-08-26",
-            "cell_line": null,
-            "library_species": 9,
-            "library_type": 1,
-            "made_by": "Lorian",
-            "affiliations": [
-                4
-            ],
-            "replicate": 1,
-            "condition": null,
-            "hidden": false,
-            "stopping_point": "2A",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "8/21/2009 11:57:54\tColor: Blue",
-            "undiluted_concentration": "23.9",
-            "successful_pM": null,
-            "experiment_type": 2,
-            "antibody": null
-        }
-    },
-  {"pk": 1189, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11054",
-       "cluster_estimate": 49000,
-       "flowcell": 152,
-       "lane_number": 5,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11054",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 225,
-            "library_name": "HNDHT HLH hnd-1 strain HT115 fed anti-hlh-1 2% fix plate a",
-            "creation_date": "2009-08-31",
-            "cell_line": null,
-            "library_species": 3,
-            "library_type": 1,
-            "made_by": "Lorian",
-            "affiliations": [
-                1
-            ],
-            "replicate": 1,
-            "condition": null,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "8/26/2009 14:46:56\tColor: Purple",
-            "undiluted_concentration": "1.47",
-            "successful_pM": null,
-            "experiment_type": 2,
-            "antibody": null
-        }
-    },
-  {"pk": 1190, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11056",
-       "cluster_estimate": 48000,
-       "flowcell": 152,
-       "lane_number": 6,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11056",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 225,
-            "library_name": "HNDM3 HLH hnd-1 strain mex-3 fed anti-hlh-1 2% fix plate a",
-            "creation_date": "2009-08-31",
-            "cell_line": null,
-            "library_species": 3,
-            "library_type": 1,
-            "made_by": "Lorian",
-            "affiliations": [
-                2
-            ],
-            "replicate": 1,
-            "condition": null,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "8/26/2009 14:46:56\tColor: Black",
-            "undiluted_concentration": "1.42",
-            "successful_pM": null,
-            "experiment_type": 2,
-            "antibody": null
-        }
-    },
-  {"pk": 1191, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11057",
-       "cluster_estimate": 4000,
-       "flowcell": 152,
-       "lane_number": 7,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11057",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 225,
-            "library_name": "HNDM3 4H8 hnd-1 strain mex-3 fed 4H8 2% fix plate a",
-            "creation_date": "2009-08-31",
-            "cell_line": null,
-            "library_species": 3,
-            "library_type": 1,
-            "made_by": "Lorian",
-            "affiliations": [
-                3
-            ],
-            "replicate": 1,
-            "condition": null,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "8/26/2009 14:46:56\tColor: Orange.",
-            "undiluted_concentration": "1.3",
-            "successful_pM": null,
-            "experiment_type": 2,
-            "antibody": null
-        }
-    },
-  {"pk": 1192, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11065",
-       "cluster_estimate": 5000,
-       "flowcell": 152,
-       "lane_number": 8,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11065",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired ends 105 Kuntz PDM3",
-            "creation_date": "2009-09-01",
-            "cell_line": 1,
-            "library_species": 3,
-            "library_type": 2,
-            "made_by": "Brian Williams",
-            "affiliations": [
-                4
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "Brian Williams",
-            "amplified_from_sample": null,
-            "notes": "300 bp gel fragment, Amicon filtered\r\nnanodrop: 30.5",
-            "undiluted_concentration": "2.47",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-  {"pk": 151, "model": "experiments.flowcell",
-   "fields": {
-       "paired_end": false,
-       "run_date": "2009-09-08T15:39:28-0800",
-       "read_length": 38,
-       "notes": "Rebuild of broken flowcell\r\n\r\n328461 4820241 RGT-0215719\r\n328479 4897265 RGT-0249510\r\n330421 4822845 SR-0005402\r\n",
-       "advanced_run": false,
-       "control_lane": 5,
-       "cluster_station": 3,
-       "sequencer": 2,
-       "flowcell_id": "42JU1AAXX"
-       }
-   },
-  {"pk": 1177, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11034",
-       "cluster_estimate": 177000,
-       "flowcell": 151,
-       "lane_number": 1,
-       "pM": "7"
-       }
-   },
-  {"pk": 1178, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11036",
-       "cluster_estimate": 169000,
-       "flowcell": 151,
-       "lane_number": 2,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11036",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired ends 96 Kuntz_PDE1",
-            "creation_date": "2009-08-25",
-            "cell_line": 1,
-            "library_species": 3,
-            "library_type": 2,
-            "made_by": "Brian Williams",
-            "affiliations": [
-                5
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "Brian Williams",
-            "amplified_from_sample": null,
-            "notes": "fragment size = 300 bp",
-            "undiluted_concentration": "30.6",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-    {
-        "pk": "11034",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired ends 94 Gilberto_d3_denerv_LTA",
-            "creation_date": "2009-08-25",
-            "cell_line": 1,
-            "library_species": 9,
-            "library_type": 2,
-            "made_by": "Brian Williams",
-            "affiliations": [
-                1
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "Brian Williams",
-            "amplified_from_sample": null,
-            "notes": "fragment size = 300 bp",
-            "undiluted_concentration": "27",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-    {
-        "pk": "12044",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 225,
-            "library_name": "Pooled Indexed Test",
-            "creation_date": "2009-08-26",
-            "cell_line": null,
-            "library_species": 9,
-            "library_type": 5,
-            "multiplex_id": "1,2,3",
-            "made_by": "Lorian",
-            "affiliations": [
-                2
-            ],
-            "replicate": 1,
-            "condition": null,
-            "hidden": false,
-            "stopping_point": "2A",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "8/21/2009 11:57:54\tColor: Orange",
-            "undiluted_concentration": "22.4",
-            "successful_pM": null,
-            "experiment_type": 2,
-            "antibody": null
-        }
-    },
-    {
-        "pk": "13044",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 225,
-            "library_name": "Dual Indexed Test",
-            "creation_date": "2009-08-26",
-            "cell_line": null,
-            "library_species": 9,
-            "library_type": 9,
-            "multiplex_id": "N701-N501",
-            "made_by": "Lorian",
-            "affiliations": [
-                2
-            ],
-            "replicate": 1,
-            "condition": null,
-            "hidden": false,
-            "stopping_point": "2A",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "8/21/2009 11:57:54\tColor: Orange",
-            "undiluted_concentration": "22.4",
-            "successful_pM": null,
-            "experiment_type": 2,
-            "antibody": null
-        }
-    },
-    {
-        "pk": "11045",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 225,
-            "library_name": "Simple Indexed Test",
-            "creation_date": "2009-08-26",
-            "cell_line": null,
-            "library_species": 9,
-            "library_type": 5,
-            "multiplex_id": "1",
-            "made_by": "Lorian",
-            "affiliations": [
-                2
-            ],
-            "replicate": 2,
-            "condition": null,
-            "hidden": false,
-            "stopping_point": "2A",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "8/21/2009 11:57:54\tColor: Orange",
-            "undiluted_concentration": "22.4",
-            "successful_pM": null,
-            "experiment_type": 2,
-            "antibody": null
-        }
-    },
-  {"pk": 1179,
-   "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "12044",
-       "cluster_estimate": 196000,
-       "flowcell": 151,
-       "lane_number": 3,
-       "pM": "7"
-       }
-   },
-  {"pk": 1279,
-   "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11045",
-       "cluster_estimate": 196000,
-       "flowcell": 151,
-       "lane_number": 3,
-       "pM": "7"
-       }
-   },
-  {"pk": 1379,
-   "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "13044",
-       "cluster_estimate": 196000,
-       "flowcell": 151,
-       "lane_number": 4,
-       "pM": "7"
-       }
-   },
-
-    {
-        "pk": "11044",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 225,
-            "library_name": "p300 60h C2 FA KF 12/22/8 a",
-            "creation_date": "2009-08-26",
-            "cell_line": null,
-            "library_species": 9,
-            "library_type": 1,
-            "made_by": "Lorian",
-            "affiliations": [
-                3
-            ],
-            "replicate": 1,
-            "condition": null,
-            "hidden": false,
-            "stopping_point": "2A",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "8/21/2009 11:57:54\tColor: Orange.",
-            "undiluted_concentration": "22.4",
-            "successful_pM": null,
-            "experiment_type": 2,
-            "antibody": null
-        }
-    },
-  {"pk": 1180, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11047",
-       "cluster_estimate": 200000,
-       "flowcell": 151,
-       "lane_number": 4,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11047",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 250,
-            "library_name": "FLDN1 7/8/9 anti-TriMeH3K27 chip B6 a",
-            "creation_date": "2009-08-26",
-            "cell_line": null,
-            "library_species": 9,
-            "library_type": 1,
-            "made_by": "Lorian",
-            "affiliations": [
-                4
-            ],
-            "replicate": 1,
-            "condition": null,
-            "hidden": false,
-            "stopping_point": "2A",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "8/21/2009 11:57:54\tColor: Green",
-            "undiluted_concentration": "24.9",
-            "successful_pM": null,
-            "experiment_type": 2,
-            "antibody": null
-        }
-    },
-  {"pk": 1181, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11055",
-       "cluster_estimate": 104000,
-       "flowcell": 151,
-       "lane_number": 5,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11055",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 225,
-            "library_name": "HNDHT 4H8 hnd-1 strain HT115 fed 4H8 2% fix plate a",
-            "creation_date": "2009-08-31",
-            "cell_line": null,
-            "library_species": 3,
-            "library_type": 1,
-            "made_by": "Lorian",
-            "affiliations": [
-                5
-            ],
-            "replicate": 1,
-            "condition": null,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "8/26/2009 14:46:56\tColor: White.",
-            "undiluted_concentration": "2.17",
-            "successful_pM": null,
-            "experiment_type": 2,
-            "antibody": null
-        }
-    },
-  {"pk": 1182, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11067",
-       "cluster_estimate": 168000,
-       "flowcell": 151,
-       "lane_number": 6,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11067",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 325,
-            "library_name": "Paired End SP-BAC Barcoding test 250-300 bp",
-            "creation_date": "2009-09-03",
-            "cell_line": 1,
-            "library_species": 10,
-            "library_type": 2,
-            "made_by": "Igor",
-            "affiliations": [
-                1
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "Done",
-            "tags": [],
-            "made_for": "Andy Cameron",
-            "amplified_from_sample": null,
-            "notes": "12 SP BACs",
-            "undiluted_concentration": "1.45",
-            "successful_pM": null,
-            "experiment_type": 8,
-            "antibody": null
-        }
-    },
-  {"pk": 1183, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11069",
-       "cluster_estimate": 184000,
-       "flowcell": 151,
-       "lane_number": 7,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11069",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired End AG-3d-1 AG domain of floral meristem day 3, rep 1",
-            "creation_date": "2009-09-02",
-            "cell_line": null,
-            "library_species": 6,
-            "library_type": 2,
-            "made_by": "Yuling Jiao",
-            "affiliations": [
-                2
-            ],
-            "replicate": 1,
-            "condition": null,
-            "hidden": false,
-            "stopping_point": "Done",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "nanodrop: Xng/ul.",
-            "undiluted_concentration": "18.3",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-  {"pk": 1184, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11070",
-       "cluster_estimate": 182000,
-       "flowcell": 151,
-       "lane_number": 8,
-       "pM": "7"
-       }
-   },
-    {
-        "pk": "11070",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired End AG-5d-1 AG domain of floral meristem day 5, rep 1",
-            "creation_date": "2009-09-02",
-            "cell_line": null,
-            "library_species": 6,
-            "library_type": 2,
-            "made_by": "Yuling Jiao",
-            "affiliations": [
-                3
-            ],
-            "replicate": 1,
-            "condition": null,
-            "hidden": false,
-            "stopping_point": "Done",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "nanodrop: 40ng/ul\r\nCalibrated qbit with standards.\r\nMeasured 2ul library with qbit using HS kit.\r\n",
-            "undiluted_concentration": "20.3",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-     },
- {"pk": 200, "model": "experiments.flowcell",
-  "fields": {
-      "paired_end": true,
-      "run_date": "2007-09-27T22:12:13-0800",
-      "read_length": 36,
-      "notes": "",
-      "advanced_run": false,
-      "control_lane": 2,
-      "cluster_station": 3,
-      "sequencer": 2,
-      "flowcell_id": "30012AAXX (failed)"
-      }
-  },
-  {"pk": 201, "model": "experiments.lane",
-   "fields": {
-       "comment": "",
-       "library": "11070",
-       "cluster_estimate": 182000,
-       "flowcell": 200,
-       "lane_number": 8,
-       "pM": "7"
-       }
-   }
-]
diff --git a/htsworkflow/frontend/experiments/fixtures/woldlab.json b/htsworkflow/frontend/experiments/fixtures/woldlab.json
deleted file mode 100644 (file)
index b058925..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-[ { "model": "experiments.Sequencer",
-    "pk": 1,
-    "fields": {
-      "name": "Rotifer",
-      "instrument_name": "ILLUMINA-33A494",
-      "serial_number": "",
-      "model": "Illumina Genome Analyzer II",
-      "active": false,
-      "isdefault": false,
-      "comment": "after 2010 pipeline name, was exchanged for hiseq"
-    }
-  },
-  { "model": "experiments.Sequencer",
-    "pk": 2,
-    "fields": {
-      "name": "Tardigrade",
-      "instrument_name": "ILLUMINA-EC5D15",
-      "serial_number": "",
-      "model": "Illumina Genome Analyzer IIx",
-      "active": true,
-      "isdefault": false,
-      "comment": "after 2010 pipeline name"
-    }
-  },
-  { "model": "experiments.Sequencer",
-    "pk": 3,
-    "fields": {
-      "name": "Elsewhere",
-      "instrument_name": "",
-      "serial_number": "",
-      "model": "Unknown",
-      "active": false,
-      "isdefault": false,
-      "comment": "Sequenced somewhere else"
-    }
-  },
-  { "model": "experiments.Sequencer",
-    "pk": 4,
-    "fields": {
-      "name": "Volvox",
-      "instrument_name": "HWI-ST0787",
-      "serial_number": "",
-      "model": "Illumina HiSeq 2000",
-      "active": true,
-      "isdefault": true,
-      "comment": ""
-    }
-  },
-  { "model": "experiments.Sequencer",
-    "pk": 5,
-    "fields": {
-      "name": "Tardigrade (older)",
-      "instrument_name": "HWUSI-EAS627",
-      "serial_number": "",
-      "model": "Illumina Genome Analyzer II",
-      "active": false,
-      "isdefault": false,
-      "comment": "earlier version of tardigrade"
-    }
-  },
-  { "model": "experiments.Sequencer",
-    "pk": 6,
-    "fields": {
-      "name": "Rotifer (older)",
-      "instrument_name": "HWUSI-EAS229",
-      "serial_number": "",
-      "model": "Illumina Genome Analyzer II",
-      "active": false,
-      "isdefault": false,
-      "comment": "earlier rotifer name"
-    }
-  },
-  { "model": "experiments.Sequencer",
-    "pk": 7,
-    "fields": {
-      "name": "First sequencer",
-      "instrument_name": "USI-EAS44",
-      "serial_number": "",
-      "model": "Illumina Genome Analyzer I",
-      "active": false,
-      "isdefault": false,
-      "comment": "our first sequencer"
-    }
-  },
-  { "model": "experiments.ClusterStation",
-    "pk": 3,
-    "fields": { "name": "new", "isdefault": false }
-  }
-]
diff --git a/htsworkflow/frontend/experiments/models.py b/htsworkflow/frontend/experiments/models.py
deleted file mode 100644 (file)
index 6c952db..0000000
+++ /dev/null
@@ -1,482 +0,0 @@
-import datetime
-import glob
-import logging
-import os
-import re
-import types
-import uuid
-
-from django.conf import settings
-from django.core.exceptions import ObjectDoesNotExist
-from django.core import urlresolvers
-from django.utils import timezone
-from django.db import models
-from django.db.models.signals import post_init, pre_save
-
-from htsworkflow.frontend.samples.models import Library
-from htsworkflow.util.conversion import parse_flowcell_id
-from htsworkflow.pipelines import runfolder
-
-import pytz
-
-LOGGER = logging.getLogger(__name__)
-default_pM = 5
-try:
-    default_pM = int(settings.DEFAULT_PM)
-except AttributeError, e:
-    LOGGER.error("invalid value for frontend.default_pm")
-
-# how many days to wait before trying to re-import a runfolder
-RESCAN_DELAY = 1
-try:
-    RESCAN_DELAY = int(settings.RESCAN_DELAY)
-except (ValueError, AttributeError):
-    LOGGER.error("Missing or invalid settings.RESCAN_DELAY, "\
-                 "defaulting to %s" % (RESCAN_DELAY,))
-
-RUN_STATUS_CHOICES = (
-    (0, 'Sequencer running'),  # Solexa Data Pipeline Not Yet Started'),
-    (1, 'Data Pipeline Started'),
-    (2, 'Data Pipeline Interrupted'),
-    (3, 'Data Pipeline Finished'),
-    (4, 'Collect Results Started'),
-    (5, 'Collect Results Finished'),
-    (6, 'QC Started'),
-    (7, 'QC Finished'),
-    (255, 'DONE'),
-  )
-RUN_STATUS_REVERSE_MAP = dict(((v, k) for k, v in RUN_STATUS_CHOICES))
-
-
-class ClusterStation(models.Model):
-    """List of cluster stations"""
-    name = models.CharField(max_length=50, unique=True)
-    isdefault = models.BooleanField(default=False, null=False)
-
-    class Meta:
-        ordering = ["-isdefault", "name"]
-
-    def __unicode__(self):
-        return unicode(self.name)
-
-    @classmethod
-    def default(cls):
-        d = cls.objects.filter(isdefault=True).all()
-        if len(d) > 0:
-            return d[0]
-        d = cls.objects.order_by('-id').all()
-        if len(d) > 0:
-            return d[0]
-        return None
-
-    @staticmethod
-    def update_isdefault(sender, instance, **kwargs):
-        """Clear default if needed
-        """
-        if instance.isdefault:
-            for c in ClusterStation.objects.filter(isdefault=True).all():
-                if c.id != instance.id:
-                    c.isdefault = False
-                    c.save()
-
-pre_save.connect(ClusterStation.update_isdefault, sender=ClusterStation)
-
-class Sequencer(models.Model):
-    """Sequencers we've owned
-    """
-    name = models.CharField(max_length=50, db_index=True)
-    instrument_name = models.CharField(max_length=50, db_index=True)
-    serial_number = models.CharField(max_length=50, db_index=True)
-    model = models.CharField(max_length=255)
-    active = models.BooleanField(default=True, null=False)
-    isdefault = models.BooleanField(default=False, null=False)
-    comment = models.CharField(max_length=255)
-
-    class Meta:
-        ordering = ["-isdefault", "-active", "name"]
-
-    def __unicode__(self):
-        name = [unicode(self.name)]
-        if self.instrument_name is not None:
-            name.append("(%s)" % (unicode(self.instrument_name),))
-        return " ".join(name)
-
-    @models.permalink
-    def get_absolute_url(self):
-        return ('htsworkflow.frontend.experiments.views.sequencer',
-                [self.id])
-
-    @classmethod
-    def default(cls):
-        d = cls.objects.filter(isdefault=True).all()
-        if len(d) > 0:
-            return d[0]
-        d = cls.objects.order_by('active', '-id').all()
-        if len(d) > 0:
-            return d[0]
-        return None
-
-    @staticmethod
-    def update_isdefault(sender, instance, **kwargs):
-        """Clear default if needed
-        """
-        if instance.isdefault:
-            for s in Sequencer.objects.filter(isdefault=True).all():
-                if s.id != instance.id:
-                    s.isdefault = False
-                    s.save()
-
-pre_save.connect(Sequencer.update_isdefault, sender=Sequencer)
-
-
-class FlowCell(models.Model):
-    flowcell_id = models.CharField(max_length=20, unique=True, db_index=True)
-    run_date = models.DateTimeField()
-    advanced_run = models.BooleanField(default=False)
-    paired_end = models.BooleanField(default=False)
-    read_length = models.IntegerField(default=32)  # Stanford is currenlty 25
-    control_lane = models.IntegerField(choices=[(1, 1),
-                                                (2, 2),
-                                                (3, 3),
-                                                (4, 4),
-                                                (5, 5),
-                                                (6, 6),
-                                                (7, 7),
-                                                (8, 8),
-                                                (0, 'All Lanes')],
-                                       null=True,
-                                       blank=True)
-
-    cluster_station = models.ForeignKey(ClusterStation, default=ClusterStation.default)
-    sequencer = models.ForeignKey(Sequencer, default=Sequencer.default)
-
-    notes = models.TextField(blank=True)
-
-    def __unicode__(self):
-        return unicode(self.flowcell_id)
-
-    def Lanes(self):
-        html = ['<table>']
-        for lane in self.lane_set.order_by('lane_number'):
-            cluster_estimate = lane.cluster_estimate
-            if cluster_estimate is not None:
-                cluster_estimate = "%s k" % ((int(cluster_estimate) / 1000), )
-            else:
-                cluster_estimate = 'None'
-            library_id = lane.library_id
-            library = lane.library
-            element = '<tr><td>%d</td>'\
-                      '<td><a href="%s">%s</a></td><td>%s</td></tr>'
-            html.append(element % (lane.lane_number,
-                                   library.get_admin_url(),
-                                   library,
-                                   cluster_estimate))
-        html.append('</table>')
-        return "\n".join(html)
-    Lanes.allow_tags = True
-
-    class Meta:
-        ordering = ["-run_date"]
-
-    def get_admin_url(self):
-        # that's the django way... except it didn't work
-        return urlresolvers.reverse('admin:experiments_flowcell_change',
-                                    args=(self.id,))
-
-    def flowcell_type(self):
-        """Convert our boolean 'is paired' flag to a name
-        """
-        if self.paired_end:
-            return u"Paired"
-        else:
-            return u"Single"
-
-    @models.permalink
-    def get_absolute_url(self):
-        flowcell_id, status = parse_flowcell_id(self.flowcell_id)
-        return ('htsworkflow.frontend.experiments.views.flowcell_detail',
-                [str(flowcell_id)])
-
-    def get_raw_data_directory(self):
-        """Return location of where the raw data is stored"""
-        flowcell_id, status = parse_flowcell_id(self.flowcell_id)
-
-        return os.path.join(settings.RESULT_HOME_DIR, flowcell_id)
-
-    def update_data_runs(self):
-        result_root = self.get_raw_data_directory()
-        LOGGER.debug("Update data runs flowcell root: %s" % (result_root,))
-        if result_root is None:
-            return
-
-        result_home_dir = os.path.join(settings.RESULT_HOME_DIR, '')
-        run_xml_re = re.compile(glob.fnmatch.translate('run*.xml'))
-
-        result_dirs = []
-        for dirpath, dirnames, filenames in os.walk(result_root):
-            for filename in filenames:
-                if run_xml_re.match(filename):
-                    # we have a run directory
-                    relative_pathname = get_relative_pathname(dirpath)
-                    self.import_data_run(relative_pathname, filename)
-
-    def import_data_run(self, relative_pathname, run_xml_name, force=False):
-        """Given a result directory import files"""
-        now = timezone.now()
-        run_dir = get_absolute_pathname(relative_pathname)
-        run_xml_path = os.path.join(run_dir, run_xml_name)
-
-        runs = DataRun.objects.filter(result_dir = relative_pathname)
-        if len(runs) == 0:
-            run = DataRun()
-            created = True
-        elif len(runs) > 1:
-            raise RuntimeError("Too many data runs for %s" % (
-                relative_pathname,))
-        else:
-            run = runs[0]
-            created = False
-
-        if created or force or (now-run.last_update_time).days > RESCAN_DELAY:
-            LOGGER.debug("Importing run from %s" % (relative_pathname,))
-            run_xml_data = runfolder.load_pipeline_run_xml(run_xml_path)
-            run.flowcell = self
-            run.status = RUN_STATUS_REVERSE_MAP['DONE']
-            run.result_dir = relative_pathname
-            run.runfolder_name = run_xml_data.runfolder_name
-            run.cycle_start = run_xml_data.image_analysis.start
-            run.cycle_stop = run_xml_data.image_analysis.stop
-            naive_run_start_time = datetime.datetime.fromordinal(run_xml_data.image_analysis.date.toordinal())
-            run.run_start_time = pytz.timezone(settings.TIME_ZONE).localize(naive_run_start_time)
-            run.image_software = run_xml_data.image_analysis.software
-            run.image_version = run_xml_data.image_analysis.version
-            run.basecall_software = run_xml_data.bustard.software
-            run.basecall_version = run_xml_data.bustard.version
-            # we're frequently not running alignments
-            if run_xml_data.gerald:
-                run.alignment_software = run_xml_data.gerald.software
-                run.alignment_version = run_xml_data.gerald.version
-
-            run.last_update_time = timezone.now()
-            run.save()
-
-            run.update_result_files()
-
-
-# FIXME: should we automatically update dataruns?
-#        Or should we expect someone to call update_data_runs?
-#def update_flowcell_dataruns(sender, instance, *args, **kwargs):
-#    """Update our dataruns
-#    """
-#    if not os.path.exists(settings.RESULT_HOME_DIR):
-#       return
-#
-#    instance.update_data_runs()
-#post_init.connect(update_flowcell_dataruns, sender=FlowCell)
-
-
-LANE_STATUS_CODES = [(0, 'Failed'),
-                     (1, 'Marginal'),
-                     (2, 'Good'), ]
-LANE_STATUS_MAP = dict((int(k), v) for k, v in LANE_STATUS_CODES)
-LANE_STATUS_MAP[None] = "Unknown"
-
-
-def is_valid_lane(value):
-    if value >= 1 and value <= 8:
-        return True
-    else:
-        return False
-
-
-class Lane(models.Model):
-    flowcell = models.ForeignKey(FlowCell)
-    lane_number = models.IntegerField()
-    library = models.ForeignKey(Library)
-    pM = models.DecimalField(max_digits=5,
-                             decimal_places=2,
-                             blank=False,
-                             null=False,
-                             default=default_pM)
-    cluster_estimate = models.IntegerField(blank=True, null=True)
-    status = models.IntegerField(choices=LANE_STATUS_CODES,
-                                 null=True,
-                                 blank=True)
-    comment = models.TextField(null=True, blank=True)
-
-    @models.permalink
-    def get_absolute_url(self):
-        return ('htsworkflow.frontend.experiments.views.flowcell_lane_detail',
-                [str(self.id)])
-
-    def __unicode__(self):
-        return self.flowcell.flowcell_id + ':' + unicode(self.lane_number)
-
-
-class DataRun(models.Model):
-    flowcell = models.ForeignKey(FlowCell, verbose_name="Flowcell Id")
-    runfolder_name = models.CharField(max_length=50)
-    result_dir = models.CharField(max_length=255)
-    last_update_time = models.DateTimeField()
-    run_start_time = models.DateTimeField()
-    cycle_start = models.IntegerField(null=True, blank=True)
-    cycle_stop = models.IntegerField(null=True, blank=True)
-    run_status = models.IntegerField(choices=RUN_STATUS_CHOICES,
-                                     null=True, blank=True)
-    image_software = models.CharField(max_length=50)
-    image_version = models.CharField(max_length=50)
-    basecall_software = models.CharField(max_length=50)
-    basecall_version = models.CharField(max_length=50)
-    alignment_software = models.CharField(max_length=50)
-    alignment_version = models.CharField(max_length=50)
-    comment = models.TextField(blank=True)
-
-    def update_result_files(self):
-        abs_result_dir = get_absolute_pathname(self.result_dir)
-
-        for dirname, dirnames, filenames in os.walk(abs_result_dir):
-            for filename in filenames:
-                pathname = os.path.join(dirname, filename)
-                relative_pathname = get_relative_pathname(pathname)
-                datafiles = self.datafile_set.filter(
-                    data_run=self,
-                    relative_pathname=relative_pathname)
-                if len(datafiles) > 0:
-                    continue
-
-                metadata = find_file_type_metadata_from_filename(filename)
-                if metadata is not None:
-                    metadata['filename'] = filename
-                    newfile = DataFile()
-                    newfile.data_run = self
-                    newfile.file_type = metadata['file_type']
-                    newfile.relative_pathname = relative_pathname
-
-                    lane_number = metadata.get('lane', None)
-                    if lane_number is not None:
-                        lane = self.flowcell.lane_set.get(
-                            lane_number=lane_number)
-                        newfile.library = lane.library
-
-                    self.datafile_set.add(newfile)
-
-        self.last_update_time = timezone.now()
-
-    def lane_files(self):
-        lanes = {}
-
-        for datafile in self.datafile_set.all():
-            metadata = datafile.attributes
-            if metadata is not None:
-                lane = metadata.get('lane', None)
-                if lane is not None:
-                    lane_file_set = lanes.setdefault(lane, {})
-                    normalized_name = datafile.file_type.normalized_name
-                    lane_file_set[normalized_name] = datafile
-        return lanes
-
-    def ivc_plots(self, lane):
-        ivc_name = ['IVC All', 'IVC Call',
-                    'IVC Percent Base', 'IVC Percent All', 'IVC Percent Call']
-
-        plots = {}
-        for rel_filename, metadata in self.get_result_files():
-            if metadata.file_type.name in ivc_name:
-                plots[metadata.file_type.name] = (rel_filename, metadata)
-
-
-class FileType(models.Model):
-    """Represent potential file types
-
-    regex is a pattern used to detect if a filename matches this type
-    data run currently assumes that there may be a (?P<lane>) and
-    (?P<end>) pattern in the regular expression.
-    """
-    name = models.CharField(max_length=50)
-    mimetype = models.CharField(max_length=50, null=True, blank=True)
-    # regular expression from glob.fnmatch.translate
-    regex = models.TextField(null=True, blank=True)
-
-    def parse_filename(self, pathname):
-        """Does filename match our pattern?
-
-        Returns None if not, or dictionary of match variables if we do.
-        """
-        path, filename = os.path.split(pathname)
-        if len(self.regex) > 0:
-            match = re.match(self.regex, filename)
-            if match is not None:
-                # These are (?P<>) names we know about from our
-                # default regexes.
-                results = match.groupdict()
-
-                # convert int parameters
-                for attribute_name in ['lane', 'end']:
-                    value = results.get(attribute_name, None)
-                    if value is not None:
-                        results[attribute_name] = int(value)
-
-                return results
-
-    def _get_normalized_name(self):
-        """Crush data file name into identifier friendly name"""
-        return self.name.replace(' ', '_').lower()
-    normalized_name = property(_get_normalized_name)
-
-    def __unicode__(self):
-        #return u"<FileType: %s>" % (self.name,)
-        return self.name
-
-
-def str_uuid():
-    """Helper function to set default UUID in DataFile"""
-    return str(uuid.uuid1())
-
-
-class DataFile(models.Model):
-    """Store map from random ID to filename"""
-    random_key = models.CharField(max_length=64,
-                                  db_index=True,
-                                  default=str_uuid)
-    data_run = models.ForeignKey(DataRun, db_index=True)
-    library = models.ForeignKey(Library, db_index=True, null=True, blank=True)
-    file_type = models.ForeignKey(FileType)
-    relative_pathname = models.CharField(max_length=255, db_index=True)
-
-    def _get_attributes(self):
-        return self.file_type.parse_filename(self.relative_pathname)
-    attributes = property(_get_attributes)
-
-    def _get_pathname(self):
-        return get_absolute_pathname(self.relative_pathname)
-    pathname = property(_get_pathname)
-
-    @models.permalink
-    def get_absolute_url(self):
-        return ('htsworkflow.frontend.experiments.views.read_result_file',
-                (), {'key': self.random_key})
-
-
-def find_file_type_metadata_from_filename(pathname):
-    path, filename = os.path.split(pathname)
-    result = None
-    for file_type in FileType.objects.all():
-        result = file_type.parse_filename(filename)
-        if result is not None:
-            result['file_type'] = file_type
-            return result
-
-    return None
-
-
-def get_relative_pathname(abspath):
-    """Strip off the result home directory from a path
-    """
-    result_home_dir = os.path.join(settings.RESULT_HOME_DIR, '')
-    relative_pathname = abspath.replace(result_home_dir, '')
-    return relative_pathname
-
-
-def get_absolute_pathname(relative_pathname):
-    """Attach relative path to  results home directory"""
-    return os.path.join(settings.RESULT_HOME_DIR, relative_pathname)
diff --git a/htsworkflow/frontend/experiments/test_experiments.py b/htsworkflow/frontend/experiments/test_experiments.py
deleted file mode 100644 (file)
index 0a0c941..0000000
+++ /dev/null
@@ -1,704 +0,0 @@
-import re
-from lxml.html import fromstring
-try:
-    import json
-except ImportError, e:
-    import simplejson as json
-import os
-import shutil
-import sys
-import tempfile
-from urlparse import urljoin
-
-from django.conf import settings
-from django.core import mail
-from django.core.exceptions import ObjectDoesNotExist
-from django.test import TestCase
-from django.test.utils import setup_test_environment, teardown_test_environment
-from django.db import connection
-from django.conf import settings
-from htsworkflow.frontend.experiments import models
-from htsworkflow.frontend.experiments import experiments
-from htsworkflow.frontend.auth import apidata
-from htsworkflow.util.ethelp import validate_xhtml
-
-from htsworkflow.pipelines.test.simulate_runfolder import TESTDATA_DIR
-
-LANE_SET = range(1,9)
-
-NSMAP = {'libns':'http://jumpgate.caltech.edu/wiki/LibraryOntology#'}
-
-from django.db import connection
-
-class ClusterStationTestCases(TestCase):
-    fixtures = ['initial_data.json',
-                'test_flowcells.json']
-
-    def test_default(self):
-        c = models.ClusterStation.default()
-        self.assertEqual(c.id, 2)
-
-        c.isdefault = False
-        c.save()
-
-        total = models.ClusterStation.objects.filter(isdefault=True).count()
-        self.assertEqual(total, 0)
-
-        other_default = models.ClusterStation.default()
-        self.assertEqual(other_default.id, 3)
-
-
-    def test_update_default(self):
-        old_default = models.ClusterStation.default()
-
-        c = models.ClusterStation.objects.get(pk=3)
-        c.isdefault = True
-        c.save()
-
-        new_default = models.ClusterStation.default()
-
-        self.assertNotEqual(old_default, new_default)
-        self.assertEqual(new_default, c)
-
-        total = models.ClusterStation.objects.filter(isdefault=True).count()
-        self.assertEqual(total, 1)
-
-    def test_update_other(self):
-        old_default = models.ClusterStation.default()
-        total = models.ClusterStation.objects.filter(isdefault=True).count()
-        self.assertEqual(total, 1)
-
-        c = models.ClusterStation.objects.get(pk=1)
-        c.name = "Primary Key 1"
-        c.save()
-
-        total = models.ClusterStation.objects.filter(isdefault=True).count()
-        self.assertEqual(total, 1)
-
-        new_default = models.ClusterStation.default()
-        self.assertEqual(old_default, new_default)
-
-
-class SequencerTestCases(TestCase):
-    fixtures = ['initial_data.json',
-                'woldlab.json',
-                'test_flowcells.json']
-
-    def test_default(self):
-        # starting with no default
-        s = models.Sequencer.default()
-        self.assertEqual(s.id, 2)
-
-        total = models.Sequencer.objects.filter(isdefault=True).count()
-        self.assertEqual(total, 1)
-
-        s.isdefault = False
-        s.save()
-
-        total = models.Sequencer.objects.filter(isdefault=True).count()
-        self.assertEqual(total, 0)
-
-        other_default = models.Sequencer.default()
-        self.assertEqual(other_default.id, 7)
-
-    def test_update_default(self):
-        old_default = models.Sequencer.default()
-
-        s = models.Sequencer.objects.get(pk=1)
-        s.isdefault = True
-        s.save()
-
-        new_default = models.Sequencer.default()
-
-        self.assertNotEqual(old_default, new_default)
-        self.assertEqual(new_default, s)
-
-        total = models.Sequencer.objects.filter(isdefault=True).count()
-        self.assertEqual(total, 1)
-
-
-    def test_update_other(self):
-        old_default = models.Sequencer.default()
-        total = models.Sequencer.objects.filter(isdefault=True).count()
-        self.assertEqual(total, 1)
-
-        s = models.Sequencer.objects.get(pk=1)
-        s.name = "Primary Key 1"
-        s.save()
-
-        total = models.Sequencer.objects.filter(isdefault=True).count()
-        self.assertEqual(total, 1)
-
-        new_default = models.Sequencer.default()
-        self.assertEqual(old_default, new_default)
-
-
-class ExperimentsTestCases(TestCase):
-    fixtures = ['initial_data.json',
-                'test_flowcells.json',
-                ]
-
-    def setUp(self):
-        self.tempdir = tempfile.mkdtemp(prefix='htsw-test-experiments-')
-        settings.RESULT_HOME_DIR = self.tempdir
-
-        self.fc1_id = 'FC12150'
-        self.fc1_root = os.path.join(self.tempdir, self.fc1_id)
-        os.mkdir(self.fc1_root)
-        self.fc1_dir = os.path.join(self.fc1_root, 'C1-37')
-        os.mkdir(self.fc1_dir)
-        runxml = 'run_FC12150_2007-09-27.xml'
-        shutil.copy(os.path.join(TESTDATA_DIR, runxml),
-                    os.path.join(self.fc1_dir, runxml))
-        for i in range(1,9):
-            shutil.copy(
-                os.path.join(TESTDATA_DIR,
-                             'woldlab_070829_USI-EAS44_0017_FC11055_1.srf'),
-                os.path.join(self.fc1_dir,
-                             'woldlab_070829_SERIAL_FC12150_%d.srf' %(i,))
-                )
-
-        self.fc2_dir = os.path.join(self.tempdir, '42JTNAAXX')
-        os.mkdir(self.fc2_dir)
-        os.mkdir(os.path.join(self.fc2_dir, 'C1-25'))
-        os.mkdir(os.path.join(self.fc2_dir, 'C1-37'))
-        os.mkdir(os.path.join(self.fc2_dir, 'C1-37', 'Plots'))
-
-    def tearDown(self):
-        shutil.rmtree(self.tempdir)
-
-    def test_flowcell_information(self):
-        """
-        Check the code that packs the django objects into simple types.
-        """
-        for fc_id in [u'FC12150', u"42JTNAAXX", "42JU1AAXX"]:
-            fc_dict = experiments.flowcell_information(fc_id)
-            fc_django = models.FlowCell.objects.get(flowcell_id=fc_id)
-            self.assertEqual(fc_dict['flowcell_id'], fc_id)
-            self.assertEqual(fc_django.flowcell_id, fc_id)
-            self.assertEqual(fc_dict['sequencer'], fc_django.sequencer.name)
-            self.assertEqual(fc_dict['read_length'], fc_django.read_length)
-            self.assertEqual(fc_dict['notes'], fc_django.notes)
-            self.assertEqual(fc_dict['cluster_station'], fc_django.cluster_station.name)
-
-            for lane in fc_django.lane_set.all():
-                lane_contents = fc_dict['lane_set'][lane.lane_number]
-                lane_dict = multi_lane_to_dict(lane_contents)[lane.library_id]
-                self.assertEqual(lane_dict['cluster_estimate'], lane.cluster_estimate)
-                self.assertEqual(lane_dict['comment'], lane.comment)
-                self.assertEqual(lane_dict['flowcell'], lane.flowcell.flowcell_id)
-                self.assertEqual(lane_dict['lane_number'], lane.lane_number)
-                self.assertEqual(lane_dict['library_name'], lane.library.library_name)
-                self.assertEqual(lane_dict['library_id'], lane.library.id)
-                self.assertAlmostEqual(float(lane_dict['pM']), float(lane.pM))
-                self.assertEqual(lane_dict['library_species'],
-                                     lane.library.library_species.scientific_name)
-
-            response = self.client.get('/experiments/config/%s/json' % (fc_id,), apidata)
-            # strptime isoformat string = '%Y-%m-%dT%H:%M:%S'
-            fc_json = json.loads(response.content)
-            self.assertEqual(fc_json['flowcell_id'], fc_id)
-            self.assertEqual(fc_json['sequencer'], fc_django.sequencer.name)
-            self.assertEqual(fc_json['read_length'], fc_django.read_length)
-            self.assertEqual(fc_json['notes'], fc_django.notes)
-            self.assertEqual(fc_json['cluster_station'], fc_django.cluster_station.name)
-
-
-            for lane in fc_django.lane_set.all():
-                lane_contents = fc_json['lane_set'][unicode(lane.lane_number)]
-                lane_dict = multi_lane_to_dict(lane_contents)[lane.library_id]
-
-                self.assertEqual(lane_dict['cluster_estimate'], lane.cluster_estimate)
-                self.assertEqual(lane_dict['comment'], lane.comment)
-                self.assertEqual(lane_dict['flowcell'], lane.flowcell.flowcell_id)
-                self.assertEqual(lane_dict['lane_number'], lane.lane_number)
-                self.assertEqual(lane_dict['library_name'], lane.library.library_name)
-                self.assertEqual(lane_dict['library_id'], lane.library.id)
-                self.assertAlmostEqual(float(lane_dict['pM']), float(lane.pM))
-                self.assertEqual(lane_dict['library_species'],
-                                     lane.library.library_species.scientific_name)
-
-    def test_invalid_flowcell(self):
-        """
-        Make sure we get a 404 if we request an invalid flowcell ID
-        """
-        response = self.client.get('/experiments/config/nottheone/json', apidata)
-        self.assertEqual(response.status_code, 404)
-
-    def test_no_key(self):
-        """
-        Require logging in to retrieve meta data
-        """
-        response = self.client.get(u'/experiments/config/FC12150/json')
-        self.assertEqual(response.status_code, 403)
-
-    def test_library_id(self):
-        """
-        Library IDs should be flexible, so make sure we can retrive a non-numeric ID
-        """
-        response = self.client.get('/experiments/config/FC12150/json', apidata)
-        self.assertEqual(response.status_code, 200)
-        flowcell = json.loads(response.content)
-
-        lane_contents = flowcell['lane_set']['3']
-        lane_library = lane_contents[0]
-        self.assertEqual(lane_library['library_id'], 'SL039')
-
-        response = self.client.get('/samples/library/SL039/json', apidata)
-        self.assertEqual(response.status_code, 200)
-        library_sl039 = json.loads(response.content)
-
-        self.assertEqual(library_sl039['library_id'], 'SL039')
-
-    def test_raw_id_field(self):
-        """
-        Test ticket:147
-
-        Library's have IDs, libraries also have primary keys,
-        we eventually had enough libraries that the drop down combo box was too
-        hard to filter through, unfortnately we want a field that uses our library
-        id and not the internal primary key, and raw_id_field uses primary keys.
-
-        This tests to make sure that the value entered in the raw library id field matches
-        the library id looked up.
-        """
-        expected_ids = [u'10981',u'11016',u'SL039',u'11060',
-                        u'11061',u'11062',u'11063',u'11064']
-        self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5')
-        response = self.client.get('/admin/experiments/flowcell/153/')
-
-        tree = fromstring(response.content)
-        for i in range(0,8):
-            xpath_expression = '//input[@id="id_lane_set-%d-library"]'
-            input_field = tree.xpath(xpath_expression % (i,))[0]
-            library_field = input_field.find('../strong')
-            library_id, library_name = library_field.text.split(':')
-            # strip leading '#' sign from name
-            library_id = library_id[1:]
-            self.assertEqual(library_id, expected_ids[i])
-            self.assertEqual(input_field.attrib['value'], library_id)
-
-    def test_library_to_flowcell_link(self):
-        """
-        Make sure the library page includes links to the flowcell pages.
-        That work with flowcell IDs that have parenthetical comments.
-        """
-        self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5')
-        response = self.client.get('/library/11070/')
-        self.assertEqual(response.status_code, 200)
-        status = validate_xhtml(response.content)
-        if status is not None: self.assertTrue(status)
-
-        tree = fromstring(response.content)
-        flowcell_spans = tree.xpath('//span[@property="libns:flowcell_id"]',
-                                    namespaces=NSMAP)
-        self.assertEqual(flowcell_spans[1].text, '30012AAXX (failed)')
-        failed_fc_span = flowcell_spans[1]
-        failed_fc_a = failed_fc_span.getparent()
-        # make sure some of our RDF made it.
-        self.assertEqual(failed_fc_a.get('typeof'), 'libns:IlluminaFlowcell')
-        self.assertEqual(failed_fc_a.get('href'), '/flowcell/30012AAXX/')
-        fc_response = self.client.get(failed_fc_a.get('href'))
-        self.assertEqual(fc_response.status_code, 200)
-        status = validate_xhtml(response.content)
-        if status is not None: self.assertTrue(status)
-
-        fc_lane_response = self.client.get('/flowcell/30012AAXX/8/')
-        self.assertEqual(fc_lane_response.status_code, 200)
-        status = validate_xhtml(response.content)
-        if status is not None: self.assertTrue(status)
-
-
-    def test_pooled_multiplex_id(self):
-        fc_dict = experiments.flowcell_information('42JU1AAXX')
-        lane_contents = fc_dict['lane_set'][3]
-        self.assertEqual(len(lane_contents), 2)
-        lane_dict = multi_lane_to_dict(lane_contents)
-
-        self.assertEqual(lane_dict['12044']['index_sequence'],
-                         {u'1': u'ATCACG',
-                          u'2': u'CGATGT',
-                          u'3': u'TTAGGC'})
-        self.assertEqual(lane_dict['11045']['index_sequence'],
-                         {u'1': u'ATCACG'})
-
-
-
-    def test_lanes_for(self):
-        """
-        Check the code that packs the django objects into simple types.
-        """
-        user = 'test'
-        lanes = experiments.lanes_for(user)
-        self.assertEqual(len(lanes), 5)
-
-        response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
-        lanes_json = json.loads(response.content)
-        self.assertEqual(len(lanes), len(lanes_json))
-        for i in range(len(lanes)):
-            self.assertEqual(lanes[i]['comment'], lanes_json[i]['comment'])
-            self.assertEqual(lanes[i]['lane_number'], lanes_json[i]['lane_number'])
-            self.assertEqual(lanes[i]['flowcell'], lanes_json[i]['flowcell'])
-            self.assertEqual(lanes[i]['run_date'], lanes_json[i]['run_date'])
-
-    def test_lanes_for_no_lanes(self):
-        """
-        Do we get something meaningful back when the user isn't attached to anything?
-        """
-        user = 'supertest'
-        lanes = experiments.lanes_for(user)
-        self.assertEqual(len(lanes), 0)
-
-        response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
-        lanes_json = json.loads(response.content)
-
-    def test_lanes_for_no_user(self):
-        """
-        Do we get something meaningful back when its the wrong user
-        """
-        user = 'not a real user'
-        self.assertRaises(ObjectDoesNotExist, experiments.lanes_for, user)
-
-        response = self.client.get('/experiments/lanes_for/%s/json' % (user,), apidata)
-        self.assertEqual(response.status_code, 404)
-
-
-    def test_raw_data_dir(self):
-        """Raw data path generator check"""
-        flowcell_id = self.fc1_id
-        raw_dir = os.path.join(settings.RESULT_HOME_DIR, flowcell_id)
-
-        fc = models.FlowCell.objects.get(flowcell_id=flowcell_id)
-        self.assertEqual(fc.get_raw_data_directory(), raw_dir)
-
-        fc.flowcell_id = flowcell_id + " (failed)"
-        self.assertEqual(fc.get_raw_data_directory(), raw_dir)
-
-
-    def test_data_run_import(self):
-        srf_file_type = models.FileType.objects.get(name='SRF')
-        runxml_file_type = models.FileType.objects.get(name='run_xml')
-        flowcell_id = self.fc1_id
-        flowcell = models.FlowCell.objects.get(flowcell_id=flowcell_id)
-        flowcell.update_data_runs()
-        self.assertEqual(len(flowcell.datarun_set.all()), 1)
-
-        run = flowcell.datarun_set.all()[0]
-        result_files = run.datafile_set.all()
-        result_dict = dict(((rf.relative_pathname, rf) for rf in result_files))
-
-        srf4 = result_dict['FC12150/C1-37/woldlab_070829_SERIAL_FC12150_4.srf']
-        self.assertEqual(srf4.file_type, srf_file_type)
-        self.assertEqual(srf4.library_id, '11060')
-        self.assertEqual(srf4.data_run.flowcell.flowcell_id, 'FC12150')
-        self.assertEqual(
-            srf4.data_run.flowcell.lane_set.get(lane_number=4).library_id,
-            '11060')
-        self.assertEqual(
-            srf4.pathname,
-            os.path.join(settings.RESULT_HOME_DIR, srf4.relative_pathname))
-
-        lane_files = run.lane_files()
-        self.assertEqual(lane_files[4]['srf'], srf4)
-
-        runxml= result_dict['FC12150/C1-37/run_FC12150_2007-09-27.xml']
-        self.assertEqual(runxml.file_type, runxml_file_type)
-        self.assertEqual(runxml.library_id, None)
-
-        import1 = len(models.DataRun.objects.filter(result_dir='FC12150/C1-37'))
-        # what happens if we import twice?
-        flowcell.import_data_run('FC12150/C1-37',
-                                 'run_FC12150_2007-09-27.xml')
-        self.assertEqual(
-            len(models.DataRun.objects.filter(result_dir='FC12150/C1-37')),
-            import1)
-
-    def test_read_result_file(self):
-        """make sure we can return a result file
-        """
-        flowcell_id = self.fc1_id
-        flowcell = models.FlowCell.objects.get(flowcell_id=flowcell_id)
-        flowcell.update_data_runs()
-
-        #self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5')
-
-        result_files = flowcell.datarun_set.all()[0].datafile_set.all()
-        for f in result_files:
-            url = '/experiments/file/%s' % ( f.random_key,)
-            response = self.client.get(url)
-            self.assertEqual(response.status_code, 200)
-            mimetype = f.file_type.mimetype
-            if mimetype is None:
-                mimetype = 'application/octet-stream'
-
-            self.assertEqual(mimetype, response['content-type'])
-
-    def test_flowcell_rdf(self):
-        import RDF
-        from htsworkflow.util.rdfhelp import get_model, \
-             fromTypedNode, \
-             load_string_into_model, \
-             rdfNS, \
-             libraryOntology, \
-             dump_model
-
-        model = get_model()
-
-        expected = {'1': ['11034'],
-                    '2': ['11036'],
-                    '3': ['12044','11045'],
-                    '4': ['11047','13044'],
-                    '5': ['11055'],
-                    '6': ['11067'],
-                    '7': ['11069'],
-                    '8': ['11070']}
-        url = '/flowcell/42JU1AAXX/'
-        response = self.client.get(url)
-        self.assertEqual(response.status_code, 200)
-        status = validate_xhtml(response.content)
-        if status is not None: self.assertTrue(status)
-
-        ns = urljoin('http://localhost', url)
-        load_string_into_model(model, 'rdfa', response.content, ns=ns)
-        body = """prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
-        prefix libns: <http://jumpgate.caltech.edu/wiki/LibraryOntology#>
-
-        select ?flowcell ?flowcell_id ?lane_id ?library_id
-        where {
-          ?flowcell a libns:IlluminaFlowcell ;
-                    libns:flowcell_id ?flowcell_id ;
-                    libns:has_lane ?lane .
-          ?lane libns:lane_number ?lane_id ;
-                libns:library ?library .
-          ?library libns:library_id ?library_id .
-        }"""
-        query = RDF.SPARQLQuery(body)
-        count = 0
-        for r in query.execute(model):
-            count += 1
-            self.assertEqual(fromTypedNode(r['flowcell_id']), u'42JU1AAXX')
-            lane_id = fromTypedNode(r['lane_id'])
-            library_id = fromTypedNode(r['library_id'])
-            self.assertTrue(library_id in expected[lane_id])
-        self.assertEqual(count, 10)
-
-
-class TestFileType(TestCase):
-    fixtures = ['initial_data.json',
-                'test_flowcells.json',
-                ]
-
-    def test_file_type_unicode(self):
-        file_type_objects = models.FileType.objects
-        name = 'QSEQ tarfile'
-        file_type_object = file_type_objects.get(name=name)
-        self.assertEqual(u"QSEQ tarfile",
-                             unicode(file_type_object))
-
-    def test_find_file_type(self):
-        file_type_objects = models.FileType.objects
-        cases = [('woldlab_090921_HWUSI-EAS627_0009_42FC3AAXX_l7_r1.tar.bz2',
-                  'QSEQ tarfile', 7, 1),
-                 ('woldlab_091005_HWUSI-EAS627_0010_42JT2AAXX_1.srf',
-                  'SRF', 1, None),
-                 ('s_1_eland_extended.txt.bz2','ELAND Extended', 1, None),
-                 ('s_7_eland_multi.txt.bz2', 'ELAND Multi', 7, None),
-                 ('s_3_eland_result.txt.bz2','ELAND Result', 3, None),
-                 ('s_1_export.txt.bz2','ELAND Export', 1, None),
-                 ('s_1_percent_call.png', 'IVC Percent Call', 1, None),
-                 ('s_2_percent_base.png', 'IVC Percent Base', 2, None),
-                 ('s_3_percent_all.png', 'IVC Percent All', 3, None),
-                 ('s_4_call.png', 'IVC Call', 4, None),
-                 ('s_5_all.png', 'IVC All', 5, None),
-                 ('Summary.htm', 'Summary.htm', None, None),
-                 ('run_42JT2AAXX_2009-10-07.xml', 'run_xml', None, None),
-         ]
-        for filename, typename, lane, end in cases:
-            ft = models.find_file_type_metadata_from_filename(filename)
-            self.assertEqual(ft['file_type'],
-                                 file_type_objects.get(name=typename))
-            self.assertEqual(ft.get('lane', None), lane)
-            self.assertEqual(ft.get('end', None), end)
-
-    def test_assign_file_type_complex_path(self):
-        file_type_objects = models.FileType.objects
-        cases = [('/a/b/c/woldlab_090921_HWUSI-EAS627_0009_42FC3AAXX_l7_r1.tar.bz2',
-                  'QSEQ tarfile', 7, 1),
-                 ('foo/woldlab_091005_HWUSI-EAS627_0010_42JT2AAXX_1.srf',
-                  'SRF', 1, None),
-                 ('../s_1_eland_extended.txt.bz2','ELAND Extended', 1, None),
-                 ('/bleem/s_7_eland_multi.txt.bz2', 'ELAND Multi', 7, None),
-                 ('/qwer/s_3_eland_result.txt.bz2','ELAND Result', 3, None),
-                 ('/ty///1/s_1_export.txt.bz2','ELAND Export', 1, None),
-                 ('/help/s_1_percent_call.png', 'IVC Percent Call', 1, None),
-                 ('/bored/s_2_percent_base.png', 'IVC Percent Base', 2, None),
-                 ('/example1/s_3_percent_all.png', 'IVC Percent All', 3, None),
-                 ('amonkey/s_4_call.png', 'IVC Call', 4, None),
-                 ('fishie/s_5_all.png', 'IVC All', 5, None),
-                 ('/random/Summary.htm', 'Summary.htm', None, None),
-                 ('/notrandom/run_42JT2AAXX_2009-10-07.xml', 'run_xml', None, None),
-         ]
-        for filename, typename, lane, end in cases:
-            result = models.find_file_type_metadata_from_filename(filename)
-            self.assertEqual(result['file_type'],
-                                 file_type_objects.get(name=typename))
-            self.assertEqual(result.get('lane',None), lane)
-            self.assertEqual(result.get('end', None), end)
-
-class TestEmailNotify(TestCase):
-    fixtures = ['initial_data.json',
-                'test_flowcells.json']
-
-    def test_started_email_not_logged_in(self):
-        response = self.client.get('/experiments/started/153/')
-        self.assertEqual(response.status_code, 302)
-
-    def test_started_email_logged_in_user(self):
-        self.client.login(username='test', password='BJOKL5kAj6aFZ6A5')
-        response = self.client.get('/experiments/started/153/')
-        self.assertEqual(response.status_code, 302)
-
-    def test_started_email_logged_in_staff(self):
-        self.client.login(username='admintest', password='BJOKL5kAj6aFZ6A5')
-        response = self.client.get('/experiments/started/153/')
-        self.assertEqual(response.status_code, 200)
-
-    def test_started_email_send(self):
-        self.client.login(username='admintest', password='BJOKL5kAj6aFZ6A5')
-        response = self.client.get('/experiments/started/153/')
-        self.assertEqual(response.status_code, 200)
-
-        self.assertTrue('pk1@example.com' in response.content)
-        self.assertTrue('Lane #8 : (11064) Paired ends 104' in response.content)
-
-        response = self.client.get('/experiments/started/153/', {'send':'1','bcc':'on'})
-        self.assertEqual(response.status_code, 200)
-        self.assertEqual(len(mail.outbox), 4)
-        bcc = set(settings.NOTIFICATION_BCC).copy()
-        bcc.update(set(settings.MANAGERS))
-        for m in mail.outbox:
-            self.assertTrue(len(m.body) > 0)
-            self.assertEqual(set(m.bcc), bcc)
-
-    def test_email_navigation(self):
-        """
-        Can we navigate between the flowcell and email forms properly?
-        """
-        self.client.login(username='supertest', password='BJOKL5kAj6aFZ6A5')
-        response = self.client.get('/experiments/started/153/')
-        self.assertEqual(response.status_code, 200)
-        self.assertTrue(re.search('Flowcell FC12150', response.content))
-        # require that navigation back to the admin page exists
-        self.assertTrue(re.search('<a href="/admin/experiments/flowcell/153/">[^<]+</a>', response.content))
-
-def multi_lane_to_dict(lane):
-    """Convert a list of lane entries into a dictionary indexed by library ID
-    """
-    return dict( ((x['library_id'],x) for x in lane) )
-
-class TestSequencer(TestCase):
-    fixtures = ['initial_data.json',
-                'test_flowcells.json',
-                ]
-
-    def test_name_generation(self):
-        seq = models.Sequencer()
-        seq.name = "Seq1"
-        seq.instrument_name = "HWI-SEQ1"
-        seq.model = "Imaginary 5000"
-
-        self.assertEqual(unicode(seq), "Seq1 (HWI-SEQ1)")
-
-    def test_lookup(self):
-        fc = models.FlowCell.objects.get(pk=153)
-        self.assertEqual(fc.sequencer.model,
-                             "Illumina Genome Analyzer IIx")
-        self.assertEqual(fc.sequencer.instrument_name,
-                             "ILLUMINA-EC5D15")
-        # well actually we let the browser tack on the host name
-        url = fc.get_absolute_url()
-        self.assertEqual(url, '/flowcell/FC12150/')
-
-    def test_rdf(self):
-        response = self.client.get('/flowcell/FC12150/', apidata)
-        tree = fromstring(response.content)
-        seq_by = tree.xpath('//div[@rel="libns:sequenced_by"]',
-                            namespaces=NSMAP)
-        self.assertEqual(len(seq_by), 1)
-        self.assertEqual(seq_by[0].attrib['rel'], 'libns:sequenced_by')
-        seq = seq_by[0].getchildren()
-        self.assertEqual(len(seq), 1)
-        self.assertEqual(seq[0].attrib['about'], '/sequencer/2')
-        self.assertEqual(seq[0].attrib['typeof'], 'libns:Sequencer')
-
-        name = seq[0].xpath('./span[@property="libns:sequencer_name"]')
-        self.assertEqual(len(name), 1)
-        self.assertEqual(name[0].text, 'Tardigrade')
-        instrument = seq[0].xpath(
-            './span[@property="libns:sequencer_instrument"]')
-        self.assertEqual(len(instrument), 1)
-        self.assertEqual(instrument[0].text, 'ILLUMINA-EC5D15')
-        model = seq[0].xpath(
-            './span[@property="libns:sequencer_model"]')
-        self.assertEqual(len(model), 1)
-        self.assertEqual(model[0].text, 'Illumina Genome Analyzer IIx')
-
-    def test_flowcell_with_rdf_validation(self):
-        from htsworkflow.util.rdfhelp import add_default_schemas, \
-             dump_model, \
-             get_model, \
-             load_string_into_model
-        from htsworkflow.util.rdfinfer import Infer
-
-        model = get_model()
-        add_default_schemas(model)
-        inference = Infer(model)
-
-        url ='/flowcell/FC12150/'
-        response = self.client.get(url)
-        self.assertEqual(response.status_code, 200)
-        status = validate_xhtml(response.content)
-        if status is not None: self.assertTrue(status)
-
-        load_string_into_model(model, 'rdfa', response.content)
-
-        errmsgs = list(inference.run_validation())
-        self.assertEqual(len(errmsgs), 0)
-
-    def test_lane_with_rdf_validation(self):
-        from htsworkflow.util.rdfhelp import add_default_schemas, \
-             dump_model, \
-             get_model, \
-             load_string_into_model
-        from htsworkflow.util.rdfinfer import Infer
-
-        model = get_model()
-        add_default_schemas(model)
-        inference = Infer(model)
-
-        url = '/lane/1193'
-        response = self.client.get(url)
-        self.assertEqual(response.status_code, 200)
-        status = validate_xhtml(response.content)
-        if status is not None: self.assertTrue(status)
-
-        load_string_into_model(model, 'rdfa', response.content)
-
-        errmsgs = list(inference.run_validation())
-        self.assertEqual(len(errmsgs), 0)
-
-def suite():
-    from unittest import TestSuite, defaultTestLoader
-    suite = TestSuite()
-    for testcase in [ClusterStationTestCases,
-                     SequencerTestCases,
-                     ExerimentsTestCases,
-                     TestFileType,
-                     TestEmailNotify,
-                     TestSequencer]:
-        suite.addTests(defaultTestLoader.loadTestsFromTestCase(testcase))
-    return suite
-
-if __name__ == "__main__":
-    from unittest import main
-    main(defaultTest="suite")
diff --git a/htsworkflow/frontend/experiments/urls.py b/htsworkflow/frontend/experiments/urls.py
deleted file mode 100644 (file)
index 6a53cdb..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-from django.conf.urls import patterns
-
-urlpatterns = patterns('',
-    (r'^$', 'htsworkflow.frontend.experiments.views.index'),
-    #(r'^liblist$', 'htsworkflow.frontend.experiments.views.test_Libs'),
-    #(r'^(?P<run_folder>.+)/$', 'gaworkflow.frontend.experiments.views.detail'),
-    (r'^config/(?P<fc_id>.+)/json$', 'htsworkflow.frontend.experiments.experiments.flowcell_json'),
-    (r'^lanes_for/(?P<username>.+)/json$', 'htsworkflow.frontend.experiments.experiments.lanes_for_json'),
-    (r'^file/(?P<key>.+)/?$', 'htsworkflow.frontend.experiments.views.read_result_file'),
-    (r'^started/(?P<pk>.+)/$', 'htsworkflow.frontend.experiments.views.startedEmail'),
-    (r'^finished/(?P<pk>.+)/$', 'htsworkflow.frontend.experiments.views.finishedEmail'),
-                        
-)
diff --git a/htsworkflow/frontend/experiments/views.py b/htsworkflow/frontend/experiments/views.py
deleted file mode 100644 (file)
index 38b0e98..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-# Create your views here.
-from datetime import datetime
-import os
-
-#from django.template import Context, loader
-#shortcut to the above modules
-from django.contrib.auth.decorators import user_passes_test
-from django.conf import settings
-from django.core.exceptions import ObjectDoesNotExist
-from django.core.mail import EmailMessage, mail_managers
-from django.http import HttpResponse
-from django.shortcuts import render_to_response, get_object_or_404
-from django.template import RequestContext
-from django.template.loader import get_template
-
-from htsworkflow.frontend.experiments.models import \
-     DataRun, \
-     DataFile, \
-     FlowCell, \
-     Lane, \
-     Sequencer
-from htsworkflow.frontend.experiments.experiments import \
-     estimateFlowcellDuration, \
-     estimateFlowcellTimeRemaining, \
-     roundToDays, \
-     getUsersForFlowcell, \
-     makeEmailLaneMap
-
-def index(request):
-    all_runs = DataRun.objects.order_by('-run_start_time')
-    return render_to_response('experiments/index.html',{'data_run_list': all_runs})
-
-def detail(request, run_folder):
-    html_str = '<h2>Exp Track Details Page</h2>'
-    html_str += 'Run Folder: '+run_folder
-    r = get_object_or_404(DataRun,run_folder=run_folder)
-    return render_to_response('experiments/detail.html',{'run_f': r})
-
-def makeFCSheet(request,fcid):
-  # get Flowcell by input fcid
-  # ...
-  rec = None
-  try:
-    rec = FlowCell.objects.get(flowcell_id=fcid)
-  except ObjectDoesNotExist:
-    pass
-  lanes = ['1','2','3','4','5','6','7','8']
-  return render_to_response('experiments/flowcellSheet.html',{'fc': rec})
-
-
-@user_passes_test(lambda u: u.is_staff)
-def startedEmail(request, pk):
-    """
-    Create the we have started processing your samples email
-    """
-    fc = get_object_or_404(FlowCell, id=pk)
-
-    send = request.REQUEST.get('send',False)
-    if send in ('1', 'on', 'True', 'true', True):
-        send = True
-    else:
-        send = False
-
-    bcc_managers = request.REQUEST.get('bcc', False)
-    if bcc_managers in ('on', '1', 'True', 'true'):
-        bcc_managers = True
-    else:
-        bcc_managers = False
-
-    email_lane = makeEmailLaneMap(fc)
-    flowcell_users = getUsersForFlowcell(fc)
-    estimate = estimateFlowcellTimeRemaining(fc)
-    estimate_low, estimate_high = roundToDays(estimate)
-    email_verify = get_template('experiments/email_preview.html')
-    email_template = get_template('experiments/started_email.txt')
-    sender = settings.NOTIFICATION_SENDER
-
-    warnings = []
-    emails = []
-
-    emailless_users = []
-    for user in flowcell_users:
-        # provide warning
-        if user.email is None or len(user.email) == 0:
-            warnings.append((user.admin_url(), user.username))
-    user=None
-
-    for user_email in email_lane.keys():
-        sending = ""
-        # build body
-        context = RequestContext(request,
-                                 {u'flowcell': fc,
-                                  u'lanes': email_lane[user_email],
-                                  u'runfolder': 'blank',
-                                  u'finish_low': estimate_low,
-                                  u'finish_high': estimate_high,
-                                  u'now': datetime.now(),
-                                  })
-
-        # build view
-        subject = "Flowcell %s" % ( fc.flowcell_id )
-        body = email_template.render(context)
-
-        if send:
-            email = EmailMessage(subject, body, sender, to=[user_email])
-            notified = set()
-            if bcc_managers:
-                for manager in settings.MANAGERS:
-                    if len(manager) > 0:
-                        notified.add(manager)
-            for user in settings.NOTIFICATION_BCC:
-                if len(user) > 0:
-                    notified.add(user)
-            email.bcc = list(notified)
-            email.send()
-
-        emails.append((user_email, subject, body, sending))
-
-    verify_context = RequestContext(
-        request,
-        { 'emails': emails,
-          'flowcell': fc,
-          'from': sender,
-          'send': send,
-          'site_managers': settings.MANAGERS,
-          'title': fc.flowcell_id,
-          'warnings': warnings,
-        })
-    return HttpResponse(email_verify.render(verify_context))
-
-def finishedEmail(request, pk):
-    """
-    """
-    return HttpResponse("I've got nothing.")
-
-
-def flowcell_detail(request, flowcell_id, lane_number=None):
-    fc = get_object_or_404(FlowCell, flowcell_id__startswith=flowcell_id)
-    fc.update_data_runs()
-
-
-    if lane_number is not None:
-        lanes = fc.lane_set.filter(lane_number=lane_number)
-    else:
-        lanes = fc.lane_set.all()
-
-    context = RequestContext(request,
-                             {'flowcell': fc,
-                              'lanes': lanes})
-
-    return render_to_response('experiments/flowcell_detail.html',
-                              context)
-
-def flowcell_lane_detail(request, lane_pk):
-    lane = get_object_or_404(Lane, id=lane_pk)
-    lane.flowcell.update_data_runs()
-
-    dataruns = []
-    lane.flowcell.update_data_runs()
-    for run in lane.flowcell.datarun_set.all():
-        files = run.lane_files().get(lane.lane_number, None)
-        dataruns.append((run,
-                         lane.lane_number,
-                         files))
-
-    context = RequestContext(request,
-                             {'lib': lane.library,
-                              'lane': lane,
-                              'flowcell': lane.flowcell,
-                              'filtered_dataruns': dataruns})
-
-    return render_to_response('experiments/flowcell_lane_detail.html',
-                              context)
-
-def read_result_file(self, key):
-    """Return the contents of filename if everything is approved
-    """
-    data_file = get_object_or_404(DataFile, random_key = key)
-
-    content_type = 'application/octet-stream'
-    if data_file.file_type.mimetype is not None:
-        content_type = data_file.file_type.mimetype
-
-    if os.path.exists(data_file.pathname):
-        return HttpResponse(open(data_file.pathname,'r'),
-                            content_type=content_type)
-
-    raise Http404
-
-
-def sequencer(request, sequencer_id):
-    sequencer = get_object_or_404(Sequencer, id=sequencer_id)
-    context = RequestContext(request,
-                             {'sequencer': sequencer})
-    return render_to_response('experiments/sequencer.html', context)
diff --git a/htsworkflow/frontend/inventory/__init__.py b/htsworkflow/frontend/inventory/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/htsworkflow/frontend/inventory/admin.py b/htsworkflow/frontend/inventory/admin.py
deleted file mode 100644 (file)
index 04b87e8..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-from django.contrib import admin
-
-from htsworkflow.frontend.inventory.models import Item, ItemInfo, ItemType, Vendor, Location, LongTermStorage, ItemStatus, ReagentFlowcell, ReagentLibrary, PrinterTemplate
-
-class ItemAdmin(admin.ModelAdmin):
-    save_as = True
-    save_on_top = True
-    list_display = ('uuid', 'barcode_id','item_type', 'item_info', 'location', 'force_use_uuid', 'creation_date')
-    list_filter = (
-        'item_type', 'status'
-    )
-    search_fields = [
-        'barcode_id',
-        'uuid',
-        'status__name',
-        'item_type__name',
-        'location__name',
-        'notes'
-    ]
-
-class ItemInfoAdmin(admin.ModelAdmin):
-    save_as = True
-    save_on_top = True
-
-class ItemTypeAdmin(admin.ModelAdmin):
-    pass
-
-class VendorAdmin(admin.ModelAdmin):
-    pass
-
-class LocationAdmin(admin.ModelAdmin):
-    pass
-
-class LongTermStorageAdmin(admin.ModelAdmin):
-    pass
-
-class ItemStatusAdmin(admin.ModelAdmin):
-    pass
-
-class ReagentFlowcellAdmin(admin.ModelAdmin):
-    pass
-
-class ReagentLibraryAdmin(admin.ModelAdmin):
-    pass
-
-class PrinterTemplateAdmin(admin.ModelAdmin):
-    list_display = ('item_type', 'printer', 'default')
-
-admin.site.register(Item, ItemAdmin)
-admin.site.register(ItemInfo, ItemInfoAdmin)
-admin.site.register(ItemType, ItemTypeAdmin)
-admin.site.register(Vendor, VendorAdmin)
-admin.site.register(Location, LocationAdmin)
-admin.site.register(LongTermStorage, LongTermStorageAdmin)
-admin.site.register(ItemStatus, ItemStatusAdmin)
-#admin.site.register(ReagentFlowcell, ReagentFlowcellAdmin)
-#admin.site.register(ReagentLibrary, ReagentLibraryAdmin)
-admin.site.register(PrinterTemplate, PrinterTemplateAdmin)
-
diff --git a/htsworkflow/frontend/inventory/bcmagic.py b/htsworkflow/frontend/inventory/bcmagic.py
deleted file mode 100644 (file)
index 9d275c1..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-from htsworkflow.frontend.inventory.models import Item
-
-from django.core.exceptions import ObjectDoesNotExist
-
-def item_search(search):
-    """
-    Searches 
-    """
-    hits = []
-    try:
-        item = Item.objects.get(uuid=search)
-    except ObjectDoesNotExist:
-        item = None
-    
-    if item is not None:
-        hits.append((str(item), item.get_absolute_url()))
-    
-    try:
-        item = Item.objects.get(barcode_id=search)
-    except ObjectDoesNotExist:
-        item = None
-    
-    if item is not None:
-        hits.append((str(item), item.get_absolute_url()))
-
-    return hits
diff --git a/htsworkflow/frontend/inventory/fixtures/initial_data.json b/htsworkflow/frontend/inventory/fixtures/initial_data.json
deleted file mode 100644 (file)
index 028c026..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-[
-    {"pk": 1,
-     "model": "inventory.itemtype",
-     "fields": {"name": "Hard Drive"}
-    },
-    {"pk":   2,
-     "model": "inventory.itemtype",
-     "fields": {"name": "Illumina SR Cluster Generation Reagents"}
-    },
-    {"pk":   3,
-     "model": "inventory.itemtype",
-     "fields": {"name": "Illumina Library Creation Reagents"}
-    },
-    {"pk":   4,
-     "model": "inventory.itemtype",
-     "fields": {"name": "Illumina Sequencing Reagents"}
-    },
-    {"pk":   5,
-     "model": "inventory.itemtype",
-     "fields": {"name": "Illumina PE Cluster Generation Reagents"}
-    },
-    {"pk":   6,
-     "model": "inventory.itemtype",
-     "fields": {"name": "Library"}
-    }
-]
diff --git a/htsworkflow/frontend/inventory/fixtures/test_harddisks.json b/htsworkflow/frontend/inventory/fixtures/test_harddisks.json
deleted file mode 100644 (file)
index c990260..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-[
- {"pk": 1,
-  "model": "bcmagic.printer",
-  "fields": {"name": "ZM400 1.25x1",
-             "label_height": 1.0,
-             "notes": "Everyday use labels",
-             "label_width": 1.25,
-             "label_shape": "Square",
-             "model": "Zebra ZM400",
-             "ip_address": "131.215.34.116"}},
- {"pk": 2,
-  "model": "bcmagic.printer",
-  "fields": {"name": "ZM400 3x3",
-             "label_height": 3.0,
-             "notes": "Larger everyday use labels",
-             "label_width": 3.0,
-             "label_shape": "Square",
-             "model": "Zebra ZM400",
-             "ip_address": "131.215.34.117"}},
-  { "model": "experiments.Sequencer",
-    "pk": 7,
-    "fields": {
-      "name": "First sequencer",
-      "instrument_name": "USI-EAS99",
-      "serial_number": "",
-      "model": "Illumina Genome Analyzer I",
-      "active": false,
-      "isdefault": false,
-      "comment": "my first sequencer"
-    }
-  },
-  { "model": "experiments.ClusterStation",
-    "pk": 1,
-    "fields": {
-      "name": "Station",
-      "isdefault": true
-    }
-  },
-  {
-    "pk": 1,
-    "model": "inventory.vendor",
-    "fields": {
-      "url": "http://www.newegg.com/",
-      "name": "newegg.com"
-    }
-  },
-  {
-    "pk": 1,
-    "model": "inventory.location",
-    "fields": {
-      "uuid": "e344a4a2522211de99b00015172ce556",
-      "notes": "",
-      "location_description": "Office 1",
-      "name": "Dev Office"
-    }
-  },
-  {
-    "pk": 1,
-    "model": "inventory.iteminfo",
-    "fields": {
-      "model_id": "WD10EADS-00L5B1",
-      "vendor": 1,
-      "lot_number": "",
-      "url": "http://www.newegg.com/Product/Product.aspx?Item=N82E16822136317&Tpk=WD10EADS",
-      "warranty_months": 24,
-      "notes": "",
-      "part_number": "",
-      "purchase_date": "2009-05-19",
-      "qty_purchased": 17
-    }
-  },
-  {
-    "pk": 1,
-    "model": "inventory.itemtype",
-    "fields": {
-      "name": "Hard Drive",
-      "description": null
-    }
-  },
-  {
-    "pk": 1,
-    "model": "inventory.itemstatus",
-    "fields": {
-      "notes": "",
-      "name": "Used"
-    }
-  },
-  {
-    "pk": 2,
-    "model": "inventory.itemstatus",
-    "fields": {
-      "notes": "",
-      "name": "Unused"
-    }
-  },
-  {
-    "pk": 1,
-    "model": "inventory.item",
-    "fields": {
-      "status": null,
-      "modified_date": "2009-08-10T16:58:44-0800",
-      "uuid": "8a90b6ce522311de99b00015172ce556",
-      "barcode_id": "WCAU49183397",
-      "notes": "",
-      "item_info": 1,
-      "force_use_uuid": false,
-      "item_type": 1,
-      "location": 1,
-      "creation_date": "2009-06-05T15:52:26-0800"
-    }
-  },
-  {
-    "pk": 2,
-    "model": "inventory.item",
-    "fields": {
-      "status": null,
-      "modified_date": "2009-06-16T11:38:24-0800",
-      "uuid": "b0792d425aa411de99b00015172ce556",
-      "barcode_id": "WCAU49042470",
-      "notes": "",
-      "item_info": 1,
-      "force_use_uuid": false,
-      "item_type": 1,
-      "location": 1,
-      "creation_date": "2009-06-16T11:37:04-0800"
-    }
-  },
-  {
-    "pk": 1,
-    "model": "inventory.printertemplate",
-    "fields": {
-      "default": false,
-      "item_type": 1,
-      "printer": 2,
-      "template": "^FX=========================\r\n^FX 3\"x3\" Label\r\n^FX=========================\r\n^XA\r\n\r\n\r\n^FX======== Left Side ===========\r\n\r\n^FX------------\r\n^FX ^LH changes the 0,0 point of all subsequent location references\r\n^FX------------\r\n\r\n^LH0,50\r\n\r\n^FX ---Header---\r\n\r\n^FO25,0\r\n^CF0,50\r\n^FB250,2,,C\r\n^FD{{ item.barcode_id }}^FS\r\n\r\n^FX ---Column 1: Flowcells---\r\n\r\n^FX-----------------\r\n^FX FB command for automatic text formatting:\r\n^FX ^FB[dot width of area], [max # of lines], [change line spacing], [justification: L, C, R, J], [hanging indent]\r\n^FX-----------------\r\n\r\n^CF0,30,30\r\n^FO75,125\r\n^FB275,19,,L\r\n^FD{% for flowcell in flowcell_id_list %}{{ flowcell }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n^FX ---Date---\r\n\r\n^FO0,725\r\n^CF0,35\r\n^FB300,2,,C\r\n^FD{{ oldest_rundate|date:\"YMd\" }} - {{ latest_rundate|date:\"YMd\" }}^FS\r\n\r\n^FX ---Barcode---\r\n\r\n^FO135,795\r\n^BXN,3,200^FDinvb|{{ item.barcode_id }}^FS\r\n\r\n^FX======== Right Side ===========\r\n\r\n^LH300,60\r\n\r\n^FX ---Header---\r\n\r\n^FO0,0\r\n^CF0,50\r\n^FB600,2,,C\r\n^FD{{ barcode_id }}^FS\r\n\r\n^FX ---Dividing line---\r\n\r\n^FX---------------\r\n^FX GB command:\r\n^FX ^GB[box width], [box height], [border thickness], [color: B, W], [corner rounding: 0-8]^FS\r\n^FX---------------\r\n\r\n^FO0,100\r\n^GB0,600,10^FS\r\n\r\n^FX ---Column 2: Libraries 1-20---\r\n\r\n^CF0,30,30\r\n^FO75,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_1_to_20 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Column 3: Libraries 21-40---\r\n\r\n^CF0,30,30\r\n^FO200,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_21_to_40 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Column 4: Libraries 41-60---\r\n\r\n^CF0,30,30\r\n^FO325,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_41_to_60 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Column 5: Libraries 61-80---\r\n\r\n^CF0,30,30\r\n^FO450,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_61_to_80 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Date---\r\n\r\n^FO0,715\r\n^CF0,35\r\n^FB600,2,,C\r\n^FDRun Dates: {{ oldest_rundate|date:\"YMd\" }}-{{ latest_rundate|date:\"YMd\" }}^FS\r\n\r\n^FX ---Barcode---\r\n\r\n^FO255,785\r\n^BXN,3,200^FDinvb|{{ item.barcode_id }}^FS\r\n\r\n^LH0,0\r\n^FX ---End---\r\n^XZ\r\n"
-    }
-  },
-  {
-    "pk": 2,
-    "model": "inventory.printertemplate",
-    "fields": {
-      "default": true,
-      "item_type": 2,
-      "printer": 1,
-      "template": "^FX=========================\r\n^FX Harddrive Location Tracking Label\r\n^FX 300x375 dots\r\n^FX=========================\r\n\r\n^XA\r\n^LH 0,25\r\n\r\n^FO0,0\r\n^CF0,35\r\n^FB375,1,,C\r\n^FD{{ item.item_type.name }}:^FS\r\n\r\n^FX -------Text contains HD serial #-------------\r\n^FO15,75\r\n^CF0,42\r\n^FB325,3,,C\r\n^FD{% if use_uuid %}{{ item.uuid }}{% else %}{{ item.barcode_id }}{% endif %}^FS\r\n\r\n^FX -------Barcode contains HD serial #-----------\r\n^FO150,200\r\n^BXN,3,200\r\n^FD{% if use_uuid %}invu|{{ item.uuid }}{% else %}invb|{{ item.barcode_id }}{% endif %}^FS\r\n\r\n^XZ\r\n"
-    }
-  },
-  {
-    "pk": 3,
-    "model": "inventory.printertemplate",
-    "fields": {
-      "default": false,
-      "item_type": 6,
-      "printer": 1,
-      "template": "^XA\r\n\r\n^FX ---SIDE LABEL---\r\n^LH 190,40\r\n^CF 0,30\r\n\r\n^FX------Sideways ID------\r\n^FO 0,25\r\n^TB R,100,40\r\n^FD{{ library.id }}^FS\r\n^FX------Sideways Line------\r\n^FO 50,0\r\n^GB 5,200,5^FS\r\n\r\n^FX-------Name----------\r\n^FO 65,20\r\n^FB 325,4\r\n^FD{{ library.library_name }}^FS\r\n\r\n^FX ---TOP LABEL---\r\n^LH 12,28\r\n^CF 0,30\r\n\r\n^FX----ID #----\r\n^FO 5,25\r\n^FB 145,1,,C\r\n^FD{{ library.id }}^FS\r\n\r\n^FX----Name----\r\n^CF 0,16\r\n^FO 13,47\r\n^TB N,130,30\r\n^FD{{ library.library_name }}^FS\r\n\r\n^FX--------Barcode--------\r\n^FO 50,80\r\n^BXN ,3,200\r\n^FDl|0000000{{ library.id }}|woldlab^FS\r\n\r\n{% if not library.hidden %}\r\n^FX-----Border-------\r\n^FO 0,0\r\n^GC 150,10\r\n^FX ---End---\r\n{% endif %}\r\n^XZ\r\n"
-    }
-  },
-  {
-    "pk": 1,
-    "model": "inventory.longtermstorage",
-    "fields": {
-      "libraries": [
-        "10001",
-        "10002",
-        "10003"
-      ],
-      "modified_date": "2009-06-01T00:00:00-0800",
-      "storage_devices": [
-        1
-      ],
-      "flowcell": 1,
-      "creation_date": "2009-06-01T00:00:00-0800"
-    }
-  },
-  {
-    "pk": 2,
-    "model": "inventory.longtermstorage",
-    "fields": {
-      "libraries": [
-        "10001",
-        "10002",
-        "10003"
-      ],
-      "modified_date": "2009-06-01T00:00:00-0800",
-      "storage_devices": [
-        1
-      ],
-      "flowcell": 2,
-      "creation_date": "2009-06-01T00:00:00-0800"
-    }
-  },
- {"pk": 1, "model": "experiments.flowcell",
-  "fields": {
-      "paired_end": true,
-      "run_date": "2009-09-11T22:12:13-0800",
-      "read_length": 75,
-      "notes": "",
-      "advanced_run": false,
-      "control_lane": 2,
-      "flowcell_id": "11ONEAAXX"
-      }
-  },
-  {"pk": 2, "model": "experiments.flowcell",
-  "fields": {
-      "paired_end": false,
-      "run_date": "2010-09-11T22:12:13-0800",
-      "read_length": 75,
-      "notes": "",
-      "advanced_run": false,
-      "control_lane": 2,
-      "flowcell_id": "22TWOAAXX"
-      }
-  },
-  {"pk": 3, "model": "experiments.flowcell",
-  "fields": {
-      "paired_end": false,
-      "run_date": "2010-09-11T22:12:13-0800",
-      "read_length": 75,
-      "notes": "",
-      "advanced_run": false,
-      "control_lane": 2,
-      "flowcell_id": "33THRAAXX (failed)"
-      }
-  },
-  {"pk": "10001", "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 400,
-            "library_name": "10001",
-            "creation_date": "2009-07-21",
-            "cell_line": 1,
-            "library_species": 2,
-            "library_type": null,
-            "made_by": "Igor",
-            "affiliations": [
-                1
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "Done",
-            "tags": [],
-            "made_for": "Test",
-            "amplified_from_sample": null,
-            "notes": "",
-            "undiluted_concentration": "1",
-            "successful_pM": null,
-            "experiment_type": 10,
-            "antibody": null
-        }
-    },
-  {"pk": "10002", "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 400,
-            "library_name": "10002",
-            "creation_date": "2009-07-21",
-            "cell_line": 1,
-            "library_species": 2,
-            "library_type": null,
-            "made_by": "Igor",
-            "affiliations": [
-                1
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "Done",
-            "tags": [],
-            "made_for": "Test",
-            "amplified_from_sample": null,
-            "notes": "",
-            "undiluted_concentration": "1",
-            "successful_pM": null,
-            "experiment_type": 10,
-            "antibody": null
-        }
-    },
-  {"pk": "10003", "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 400,
-            "library_name": "10003",
-            "creation_date": "2009-07-21",
-            "cell_line": 1,
-            "library_species": 2,
-            "library_type": null,
-            "made_by": "Igor",
-            "affiliations": [
-                1
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "Done",
-            "tags": [],
-            "made_for": "Test",
-            "amplified_from_sample": null,
-            "notes": "",
-            "undiluted_concentration": "1",
-            "successful_pM": null,
-            "experiment_type": 10,
-            "antibody": null
-        }
-    },
-  {"pk": 1, "model": "experiments.lane",
-   "fields": {
-       "comment": "10001 lane 1",
-       "library": "10001",
-       "cluster_estimate": 100000,
-       "flowcell": 1,
-       "lane_number": 1,
-       "pM": "8"
-       }
-   },
-  {"pk": 2, "model": "experiments.lane",
-   "fields": {
-       "comment": "10002 lane 2",
-       "library": "10002",
-       "cluster_estimate": 100000,
-       "flowcell": 1,
-       "lane_number": 2,
-       "pM": "8"
-       }
-   },
-  {"pk": 3, "model": "experiments.lane",
-   "fields": {
-       "comment": "10003 lane 3",
-       "library": "10003",
-       "cluster_estimate": 100000,
-       "flowcell": 1,
-       "lane_number": 3,
-       "pM": "8"
-       }
-   },
-  {"pk": 4, "model": "experiments.lane",
-   "fields": {
-       "comment": "10004 lane 4",
-       "library": "10001",
-       "cluster_estimate": 100000,
-       "flowcell": 2,
-       "lane_number": 4,
-       "pM": "8"
-       }
-   },
-  {"pk": 5, "model": "experiments.lane",
-   "fields": {
-       "comment": "10001 lane 1",
-       "library": "10001",
-       "cluster_estimate": 100000,
-       "flowcell": 2,
-       "lane_number": 1,
-       "pM": "8"
-       }
-   },
-  {"pk": 6, "model": "experiments.lane",
-   "fields": {
-       "comment": "10001 lane 1",
-       "library": "10003",
-       "cluster_estimate": 100000,
-       "flowcell": 2,
-       "lane_number": 2,
-       "pM": "8"
-       }
-   },
-  {"pk": 7, "model": "experiments.lane",
-   "fields": {
-       "comment": "10003 lane 8",
-       "library": "10003",
-       "cluster_estimate": 100000,
-       "flowcell": 2,
-       "lane_number": 8,
-       "pM": "8"
-       }
-   },
-  {"pk": 8, "model": "experiments.lane",
-   "fields": {
-       "comment": "10002 lane 8",
-       "library": "10001",
-       "cluster_estimate": 100000,
-       "flowcell": 2,
-       "lane_number": 8,
-       "pM": "8"
-       }
-   },
-  {"pk": 9, "model": "experiments.lane",
-   "fields": {
-       "comment": "10004 lane 4",
-       "library": "10001",
-       "cluster_estimate": 100000,
-       "flowcell": 3,
-       "lane_number": 4,
-       "pM": "8"
-       }
-   },
-  {"pk": 10, "model": "experiments.lane",
-   "fields": {
-       "comment": "10001 lane 1",
-       "library": "10001",
-       "cluster_estimate": 100000,
-       "flowcell": 3,
-       "lane_number": 1,
-       "pM": "8"
-       }
-   },
-  {"pk": 11, "model": "experiments.lane",
-   "fields": {
-       "comment": "10001 lane 1",
-       "library": "10003",
-       "cluster_estimate": 100000,
-       "flowcell": 3,
-       "lane_number": 2,
-       "pM": "8"
-       }
-   },
-  {"pk": 12, "model": "experiments.lane",
-   "fields": {
-       "comment": "10003 lane 8",
-       "library": "10003",
-       "cluster_estimate": 100000,
-       "flowcell": 3,
-       "lane_number": 8,
-       "pM": "8"
-       }
-   },
-  {"pk": 13, "model": "experiments.lane",
-   "fields": {
-       "comment": "10002 lane 8",
-       "library": "10001",
-       "cluster_estimate": 100000,
-       "flowcell": 3,
-       "lane_number": 8,
-       "pM": "8"
-       }
-   }
-]
diff --git a/htsworkflow/frontend/inventory/fixtures/test_user.json b/htsworkflow/frontend/inventory/fixtures/test_user.json
deleted file mode 100644 (file)
index 2d1a61b..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-[
-    {"pk": 5, "model": "auth.user", 
-   "fields": {
-       "username": "test",
-       "first_name": "",
-       "last_name": "",
-       "is_active": true,
-       "is_superuser": false,
-       "is_staff": false,
-       "last_login": "2009-01-01T00:00:01-0800",
-       "groups": [],
-       "user_permissions": [],
-       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
-       "email": "",
-       "date_joined": "2009-01-01T00:01:01-0800"
-       }
-   },
-   {"pk": 5, "model": "samples.htsuser",
-    "fields" : {}
-   },
-   {"pk": 6, "model": "auth.user", 
-   "fields": {
-       "username": "admintest",
-       "first_name": "",
-       "last_name": "",
-       "is_active": true,
-       "is_superuser": false,
-       "is_staff": true,
-       "last_login": "2009-01-01T00:00:01-0800",
-       "groups": [],
-       "user_permissions": [],
-       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
-       "email": "",
-       "date_joined": "2009-01-01T00:01:01-0800"
-       }
-   },
-   {"pk": 6, "model": "samples.htsuser",
-    "fields" : {}
-   },
-   {"pk": 7, "model": "auth.user", 
-   "fields": {
-       "username": "supertest",
-       "first_name": "",
-       "last_name": "",
-       "is_active": true,
-       "is_superuser": true,
-       "is_staff": true,
-       "last_login": "2009-01-01T00:00:01-0800",
-       "groups": [],
-       "user_permissions": [],
-       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
-       "email": "",
-       "date_joined": "2009-01-01T00:01:01-0800"
-       }
-   },
-   {"pk": 7, "model": "samples.htsuser",
-    "fields" : {}
-   },
-   {"pk": 1, "model": "samples.affiliation",
-     "fields": {
-         "users": [5],
-         "contact": "group 1",
-         "name": "affiliation 1",
-         "email": "pk1@example.com"
-         }
-     },
-    {"pk": 2, "model": "samples.affiliation",
-     "fields": {
-         "users": [6],
-         "contact": "group 2",
-         "name": "affiliation 2",
-         "email": "pk2@example.com"
-         }
-     },
-    {"pk": 3, "model": "samples.affiliation",
-     "fields": {
-         "users": [],
-         "contact": "group 3",
-         "name": "affiliation 3",
-         "email": "pk3@example.com"
-         }
-     },
-    {"pk": 4, "model": "samples.affiliation",
-     "fields": {
-         "users": [],
-         "contact": "group 4",
-         "name": "affiliation 4",
-         "email": "pk1@example.com"
-         }
-     },
-    {"pk": 5, "model": "samples.affiliation",
-     "fields": {
-         "users": [],
-         "contact": "group 5",
-         "name": "affiliation 5",
-         "email": "pk5@example.com"
-         }
-     }
-]
diff --git a/htsworkflow/frontend/inventory/fixtures/woldlab.json b/htsworkflow/frontend/inventory/fixtures/woldlab.json
deleted file mode 100644 (file)
index 35568b5..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-[{"pk": 1,
-     "model": "inventory.printertemplate",
-     "fields": {"default": false,
-                "item_type": 1,
-                "printer": 2,
-             "template": "^FX=========================\r\n^FX 3\"x3\" Label\r\n^FX=========================\r\n^XA\r\n\r\n\r\n^FX======== Left Side ===========\r\n\r\n^FX------------\r\n^FX ^LH changes the 0,0 point of all subsequent location references\r\n^FX------------\r\n\r\n^LH0,50\r\n\r\n^FX ---Header---\r\n\r\n^FO25,0\r\n^CF0,50\r\n^FB250,2,,C\r\n^FD{{ item.barcode_id }}^FS\r\n\r\n^FX ---Column 1: Flowcells---\r\n\r\n^FX-----------------\r\n^FX FB command for automatic text formatting:\r\n^FX ^FB[dot width of area], [max # of lines], [change line spacing], [justification: L, C, R, J], [hanging indent]\r\n^FX-----------------\r\n\r\n^CF0,30,30\r\n^FO75,125\r\n^FB275,19,,L\r\n^FD{% for flowcell in flowcell_id_list %}{{ flowcell }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n^FX ---Date---\r\n\r\n^FO0,725\r\n^CF0,35\r\n^FB300,2,,C\r\n^FD{{ oldest_rundate|date:\"YMd\" }} - {{ latest_rundate|date:\"YMd\" }}^FS\r\n\r\n^FX ---Barcode---\r\n\r\n^FO135,795\r\n^BXN,3,200^FDinvb|{{ item.barcode_id }}^FS\r\n\r\n^FX======== Right Side ===========\r\n\r\n^LH300,60\r\n\r\n^FX ---Header---\r\n\r\n^FO0,0\r\n^CF0,50\r\n^FB600,2,,C\r\n^FD{{ barcode_id }}^FS\r\n\r\n^FX ---Dividing line---\r\n\r\n^FX---------------\r\n^FX GB command:\r\n^FX ^GB[box width], [box height], [border thickness], [color: B, W], [corner rounding: 0-8]^FS\r\n^FX---------------\r\n\r\n^FO0,100\r\n^GB0,600,10^FS\r\n\r\n^FX ---Column 2: Libraries 1-20---\r\n\r\n^CF0,30,30\r\n^FO75,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_1_to_20 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Column 3: Libraries 21-40---\r\n\r\n^CF0,30,30\r\n^FO200,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_21_to_40 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Column 4: Libraries 41-60---\r\n\r\n^CF0,30,30\r\n^FO325,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_41_to_60 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Column 5: Libraries 61-80---\r\n\r\n^CF0,30,30\r\n^FO450,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_61_to_80 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Date---\r\n\r\n^FO0,715\r\n^CF0,35\r\n^FB600,2,,C\r\n^FDRun Dates: {{ oldest_rundate|date:\"YMd\" }}-{{ latest_rundate|date:\"YMd\" }}^FS\r\n\r\n^FX ---Barcode---\r\n\r\n^FO255,785\r\n^BXN,3,200^FDinvb|{{ item.barcode_id }}^FS\r\n\r\n^LH0,0\r\n^FX ---End---\r\n^XZ\r\n"}},
- {"pk": 2,
-  "model": "inventory.printertemplate",
-  "fields": {"default": true,
-             "item_type": 2,
-             "printer": 1,
-             "template": "^FX=========================\r\n^FX Harddrive Location Tracking Label\r\n^FX 300x375 dots\r\n^FX=========================\r\n\r\n^XA\r\n^LH 0,25\r\n\r\n^FO0,0\r\n^CF0,35\r\n^FB375,1,,C\r\n^FD{{ item.item_type.name }}:^FS\r\n\r\n^FX -------Text contains HD serial #-------------\r\n^FO15,75\r\n^CF0,42\r\n^FB325,3,,C\r\n^FD{% if use_uuid %}{{ item.uuid }}{% else %}{{ item.barcode_id }}{% endif %}^FS\r\n\r\n^FX -------Barcode contains HD serial #-----------\r\n^FO150,200\r\n^BXN,3,200\r\n^FD{% if use_uuid %}invu|{{ item.uuid }}{% else %}invb|{{ item.barcode_id }}{% endif %}^FS\r\n\r\n^XZ\r\n"}}
-]
diff --git a/htsworkflow/frontend/inventory/models.py b/htsworkflow/frontend/inventory/models.py
deleted file mode 100644 (file)
index e729fe4..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-import logging
-
-from django.db import models
-from django.db.models.signals import pre_save
-
-from htsworkflow.frontend.samples.models import Library
-from htsworkflow.frontend.experiments.models import FlowCell
-from htsworkflow.frontend.bcmagic.models import Printer
-
-LOGGER = logging.getLogger(__name__)
-
-try:
-    import uuid
-except ImportError, e:
-    # Some systems are using python 2.4, which doesn't have uuid
-    # this is a stub
-    LOGGER.warning('Real uuid is not available, initializing fake uuid module')
-    class uuid:
-        def uuid1(self):
-            self.hex = None
-            return self
-
-def _assign_uuid(sender, instance, **kwargs):
-    """
-    Assigns a UUID to model on save
-    """
-    #print 'Entered _assign_uuid'
-    if instance.uuid is None or len(instance.uuid) != 32:
-        instance.uuid = uuid.uuid1().hex
-
-def _switch_default(sender, instance, **kwargs):
-    """
-    When new instance has default == True, uncheck all other defaults
-    """
-    if instance.default:
-        other_defaults = PrinterTemplate.objects.filter(default=True)
-
-        for other in other_defaults:
-            other.default = False
-            other.save()
-
-
-class Vendor(models.Model):
-    name = models.CharField(max_length=256)
-    url = models.URLField(blank=True, null=True)
-
-    def __unicode__(self):
-        return u"%s" % (self.name)
-
-
-class Location(models.Model):
-
-    name = models.CharField(max_length=256, unique=True)
-    location_description = models.TextField()
-
-    uuid = models.CharField(max_length=32, blank=True, help_text="Leave blank for automatic UUID generation", editable=False)
-
-    notes = models.TextField(blank=True, null=True)
-
-    def __unicode__(self):
-        if len(self.location_description) > 16:
-            return u"%s: %s" % (self.name, self.location_description[0:16]+u"...")
-        else:
-            return u"%s: %s" % (self.name, self.location_description)
-
-pre_save.connect(_assign_uuid, sender=Location)
-
-
-class ItemInfo(models.Model):
-    model_id = models.CharField(max_length=256, blank=True, null=True)
-    part_number = models.CharField(max_length=256, blank=True, null=True)
-    lot_number = models.CharField(max_length=256, blank=True, null=True)
-
-    url = models.URLField(blank=True, null=True)
-
-    qty_purchased = models.IntegerField(default=1)
-
-    vendor = models.ForeignKey(Vendor)
-    purchase_date = models.DateField(blank=True, null=True)
-    warranty_months = models.IntegerField(blank=True, null=True)
-
-    notes = models.TextField(blank=True, null=True)
-
-    def __unicode__(self):
-        name = u''
-        if self.model_id:
-            name += u"model:%s " % (self.model_id)
-        if self.part_number:
-            name += u"part:%s " % (self.part_number)
-        if self.lot_number:
-            name += u"lot:%s " % (self.lot_number)
-
-        return u"%s: %s" % (name, self.purchase_date)
-
-    class Meta:
-        verbose_name_plural = "Item Info"
-
-
-class ItemType(models.Model):
-
-    name = models.CharField(max_length=64, unique=True)
-    description = models.TextField(blank=True, null=True)
-
-    def __unicode__(self):
-        return u"%s" % (self.name)
-
-class ItemStatus(models.Model):
-    name = models.CharField(max_length=64, unique=True)
-    notes = models.TextField(blank=True, null=True)
-
-    def __unicode__(self):
-        return self.name
-
-    class Meta:
-        verbose_name_plural = "Item Status"
-
-
-class Item(models.Model):
-
-    item_type = models.ForeignKey(ItemType)
-
-    #Automatically assigned uuid; used for barcode if one is not provided in
-    # barcode_id
-    uuid = models.CharField(max_length=32, blank=True, help_text="Leave blank for automatic UUID generation", unique=True, editable=False)
-
-    # field for existing barcodes; used instead of uuid if provided
-    barcode_id = models.CharField(max_length=256, blank=True, null=True)
-    force_use_uuid = models.BooleanField(default=False)
-
-    item_info = models.ForeignKey(ItemInfo)
-
-    location = models.ForeignKey(Location)
-
-    status = models.ForeignKey(ItemStatus, blank=True, null=True)
-
-    creation_date = models.DateTimeField(auto_now_add=True)
-    modified_date = models.DateTimeField(auto_now=True)
-
-    notes = models.TextField(blank=True, null=True)
-
-    def __unicode__(self):
-        if self.barcode_id is None or len(self.barcode_id) == 0:
-            return u"invu|%s" % (self.uuid)
-        else:
-            return u"invb|%s" % (self.barcode_id)
-
-    def get_absolute_url(self):
-        return '/inventory/%s/' % (self.uuid)
-
-pre_save.connect(_assign_uuid, sender=Item)
-
-
-class PrinterTemplate(models.Model):
-    """
-    Maps templates to printer to use
-    """
-    item_type = models.ForeignKey(ItemType)
-    printer = models.ForeignKey(Printer)
-
-    default = models.BooleanField(default=False)
-
-    template = models.TextField()
-
-    def __unicode__(self):
-        if self.default:
-            return u'%s %s' % (self.item_type.name, self.printer.name)
-        else:
-            return u'%s %s (default)' % (self.item_type.name, self.printer.name)
-
-pre_save.connect(_switch_default, sender=PrinterTemplate)
-
-
-class LongTermStorage(models.Model):
-
-    flowcell = models.ForeignKey(FlowCell)
-    libraries = models.ManyToManyField(Library)
-
-    storage_devices = models.ManyToManyField(Item)
-
-    creation_date = models.DateTimeField(auto_now_add=True)
-    modified_date = models.DateTimeField(auto_now=True)
-
-    def __unicode__(self):
-        return u"%s: %s" % (str(self.flowcell), ', '.join([ str(s) for s in self.storage_devices.iterator() ]))
-
-    class Meta:
-        verbose_name_plural = "Long Term Storage"
-
-
-
-class ReagentBase(models.Model):
-
-    reagent = models.ManyToManyField(Item)
-
-    creation_date = models.DateTimeField(auto_now_add=True)
-    modified_date = models.DateTimeField(auto_now=True)
-
-    class Meta:
-        abstract = True
-
-
-class ReagentFlowcell(ReagentBase):
-    """
-    Links reagents and flowcells
-    """
-    flowcell = models.ForeignKey(FlowCell)
-
-    def __unicode__(self):
-        return u"%s: %s" % (str(self.flowcell), ', '.join([ str(s) for s in self.reagent.iterator() ]))
-
-
-class ReagentLibrary(ReagentBase):
-    """
-    Links libraries and flowcells
-    """
-    library = models.ForeignKey(Library)
-
-    def __unicode__(self):
-        return u"%s: %s" % (str(self.library), ', '.join([ str(s) for s in self.reagent.iterator() ]))
diff --git a/htsworkflow/frontend/inventory/test_inventory.py b/htsworkflow/frontend/inventory/test_inventory.py
deleted file mode 100644 (file)
index e3937e1..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-import RDF
-
-from django.test import TestCase
-from django.test.utils import setup_test_environment, \
-     teardown_test_environment
-from django.db import connection
-from django.conf import settings
-
-from django.contrib.auth.models import User
-from django.core import urlresolvers
-
-from htsworkflow.frontend.inventory.models import Item, Vendor
-from htsworkflow.util.rdfhelp import get_model, load_string_into_model, get_serializer, inventoryOntology, libraryOntology, fromTypedNode
-
-def localhostNode(url):
-    return RDF.Node(RDF.Uri('http://localhost%s' % (url,)))
-
-class InventoryTestCase(TestCase):
-    fixtures = ['initial_data', 'test_user', 'test_harddisks']
-
-    def test_fixture(self):
-        # make sure that some of our test data is was loaded
-        # since there was no error message when I typoed the test fixture
-        hd1 = Item.objects.get(pk=1)
-        self.failUnlessEqual(hd1.uuid, '8a90b6ce522311de99b00015172ce556')
-
-        user = User.objects.get(pk=5)
-        self.failUnlessEqual(user.username, 'test')
-
-    def test_item(self):
-        url = '/inventory/8a90b6ce522311de99b00015172ce556/'
-        self.client.login(username='test', password='BJOKL5kAj6aFZ6A5')
-        response = self.client.get(url)
-        self.failUnlessEqual(response.status_code, 200)
-
-        model = get_model()
-        load_string_into_model(model, 'rdfa', response.content, url)
-
-        itemNode = RDF.Node(RDF.Uri(url))
-        item_type = fromTypedNode(model.get_target(itemNode, inventoryOntology['item_type']))
-        self.failUnlessEqual(item_type, u'Hard Drive')
-
-    def test_itemindex(self):
-        url = '/inventory/it/Hard Drive/'
-        indexNode = localhostNode(url)
-        diskNode = localhostNode('/inventory/8a90b6ce522311de99b00015172ce556/')
-        self.client.login(username='test', password='BJOKL5kAj6aFZ6A5')
-
-        flowcells = self.get_flowcells_from_content(url, indexNode, diskNode)
-        self.failUnlessEqual(len(flowcells), 2)
-        self.failUnless('http://localhost/flowcell/11ONEAAXX/' in flowcells)
-        self.failUnless('http://localhost/flowcell/22TWOAAXX/' in flowcells)
-
-    def test_add_disk(self):
-        url = '/inventory/it/Hard Drive/'
-        #url_disk = '/inventory/8a90b6ce522311de99b00015172ce556/'
-        url_disk = '/inventory/b0792d425aa411de99b00015172ce556/'
-        indexNode = localhostNode(url)
-        diskNode = localhostNode(url_disk)
-        self.client.login(username='test', password='BJOKL5kAj6aFZ6A5')
-
-        flowcells = self.get_flowcells_from_content(url, indexNode, diskNode)
-        self.failUnlessEqual(len(flowcells), 0)
-
-        # step two link the flowcell
-        flowcell = '22TWOAAXX'
-        serial = 'WCAU49042470'
-        link_url = urlresolvers.reverse(
-                'htsworkflow.frontend.inventory.views.link_flowcell_and_device',
-                args=(flowcell, serial))
-        link_response = self.client.get(link_url)
-        self.failUnlessEqual(link_response.status_code, 200)
-
-        flowcells = self.get_flowcells_from_content(url, indexNode, diskNode)
-        self.failUnlessEqual(len(flowcells), 1)
-        self.failUnlessEqual('http://localhost/flowcell/%s/' % (flowcell),
-                             flowcells[0])
-
-    def test_add_disk_failed_flowcell(self):
-        url = '/inventory/it/Hard Drive/'
-        #url_disk = '/inventory/8a90b6ce522311de99b00015172ce556/'
-        url_disk = '/inventory/b0792d425aa411de99b00015172ce556/'
-        indexNode = localhostNode(url)
-        diskNode = localhostNode(url_disk)
-        self.client.login(username='test', password='BJOKL5kAj6aFZ6A5')
-
-        flowcells = self.get_flowcells_from_content(url, indexNode, diskNode)
-        self.failUnlessEqual(len(flowcells), 0)
-
-        # step two link the flowcell
-        flowcell = '33THRAAXX'
-        serial = 'WCAU49042470'
-        link_url = urlresolvers.reverse(
-                'htsworkflow.frontend.inventory.views.link_flowcell_and_device',
-                args=(flowcell, serial))
-        link_response = self.client.get(link_url)
-        self.failUnlessEqual(link_response.status_code, 200)
-
-        flowcells = self.get_flowcells_from_content(url, indexNode, diskNode)
-        self.failUnlessEqual(len(flowcells), 1)
-        self.failUnlessEqual('http://localhost/flowcell/%s/' % (flowcell),
-                             flowcells[0])
-
-
-    def get_flowcells_from_content(self, url, rootNode, diskNode):
-        model = get_model()
-
-        response = self.client.get(url)
-        self.failUnlessEqual(response.status_code, 200)
-
-        load_string_into_model(model, 'rdfa', response.content, rootNode.uri)
-        targets = model.get_targets(diskNode, libraryOntology['flowcell_id'])
-        flowcells = [ str(x.uri) for x in targets]
-        return flowcells
-
-def suite():
-    from unittest import TestSuite, defaultTestLoader
-    suite = TestSuite()
-    suite.addTests(defaultTestLoader.loadTestsFromTestCase(InventoryTestCase))
-    return suite
-
-if __name__ == "__main__":
-    from unittest import main
-    main(defaultTest="suite")
diff --git a/htsworkflow/frontend/inventory/urls.py b/htsworkflow/frontend/inventory/urls.py
deleted file mode 100644 (file)
index fc25768..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-from django.conf.urls import patterns
-
-urlpatterns = patterns('',
-    # DATA
-     (r'^data/items/$', 'htsworkflow.frontend.inventory.views.data_items'),
-    # REMOTE LINKING
-     (r'^lts/link/(?P<flowcell>.+)/(?P<serial>.+)/$', 'htsworkflow.frontend.inventory.views.link_flowcell_and_device'),
-
-    # INDEX
-    (r'^it/(?P<name>.+)/$', 'htsworkflow.frontend.inventory.views.itemtype_index'),
-    (r'^(?P<uuid>[a-fA-F0-9]{32})/$', 'htsworkflow.frontend.inventory.views.item_summary_by_uuid'),
-    (r'^(?P<uuid>[a-fA-F0-9]{32})/print/$', 'htsworkflow.frontend.inventory.views.item_print'),
-    (r'^(?P<barcode_id>.+)/$', 'htsworkflow.frontend.inventory.views.item_summary_by_barcode'),
-    (r'^all_index/$', 'htsworkflow.frontend.inventory.views.all_index'),
-    (r'^$', 'htsworkflow.frontend.inventory.views.index')
-    )
diff --git a/htsworkflow/frontend/inventory/views.py b/htsworkflow/frontend/inventory/views.py
deleted file mode 100644 (file)
index 265e1bc..0000000
+++ /dev/null
@@ -1,375 +0,0 @@
-from htsworkflow.frontend.samples.changelist import HTSChangeList
-from htsworkflow.frontend.inventory.models import Item, LongTermStorage, ItemType
-from htsworkflow.frontend.inventory.admin import ItemAdmin, ItemTypeAdmin
-from htsworkflow.frontend.inventory.bcmagic import item_search
-from htsworkflow.frontend.bcmagic.plugin import register_search_plugin
-from htsworkflow.frontend.experiments.models import FlowCell
-from htsworkflow.frontend.bcmagic.forms import BarcodeMagicForm
-from htsworkflow.frontend.bcmagic.utils import print_zpl_socket
-
-from django.conf import settings
-from django.contrib.auth.decorators import login_required
-from django.core.exceptions import ObjectDoesNotExist
-from django.http import HttpResponse, HttpResponseRedirect
-from django.shortcuts import render_to_response
-from django.template import RequestContext, Template
-from django.template.loader import get_template
-
-register_search_plugin('Inventory Item', item_search)
-
-try:
-    import json
-except ImportError, e:
-    import simplejson as json
-
-INVENTORY_CONTEXT_DEFAULTS = {
-    'app_name': 'Inventory Tracker',
-    'bcmagic': BarcodeMagicForm()
-}
-
-def __flowcell_rundate_sort(x, y):
-    """
-    Sort by rundate
-    """
-    if x.run_date > y.run_date:
-        return 1
-    elif x.run_date == y.run_date:
-        return 0
-    else:
-        return -1
-
-def __expand_longtermstorage_context(context, item):
-    """
-    Expand information for LongTermStorage
-    """
-    flowcell_list = []
-    flowcell_id_list = []
-    library_id_list = []
-
-    for lts in item.longtermstorage_set.all():
-        flowcell_list.append(lts.flowcell)
-        flowcell_id_list.append(lts.flowcell.flowcell_id)
-        library_id_list.extend([ lib.id for lib in lts.libraries.all() ])
-
-    flowcell_list.sort(__flowcell_rundate_sort)
-    context['oldest_rundate'] = flowcell_list[0].run_date
-    context['latest_rundate'] = flowcell_list[-1].run_date
-
-    context['flowcell_id_list'] = flowcell_id_list
-    context['library_id_list_1_to_20'] = library_id_list[0:20]
-    context['library_id_list_21_to_40'] = library_id_list[20:40]
-    context['library_id_list_41_to_60'] = library_id_list[40:60]
-    context['library_id_list_61_to_80'] = library_id_list[60:80]
-
-
-EXPAND_CONTEXT = {
-    'Hard Drive': __expand_longtermstorage_context
-}
-
-#INVENTORY_ITEM_PRINT_DEFAULTS = {
-#    'Hard Drive': 'inventory/hard_drive_shell.zpl',
-#    'default': 'inventory/default.zpl',
-#    'host': settings.BCPRINTER_PRINTER1_HOST
-#}
-
-def getPrinterTemplateByType(item_type):
-    """
-    returns template to use given item_type
-    """
-    assert item_type.printertemplate_set.count() < 2
-
-    # Get the template for item_type
-    if item_type.printertemplate_set.count() > 0:
-        printer_template = item_type.printertemplate_set.all()[0]
-        return printer_template
-    # Get default
-    else:
-        try:
-            printer_template = PrinterTemplate.objects.get(default=True)
-        except ObjectDoesNotExist:
-            msg = "No template for item type (%s) and no default template found" % (item_type.name)
-            raise ValueError, msg
-
-        return printer_template
-
-
-@login_required
-def data_items(request):
-    """
-    Returns items in json format
-    """
-    item_list = Item.objects.all()
-    d = { 'results': len(item_list) }
-    rows = []
-
-    for item in item_list:
-        item_d = {}
-        item_d['uuid'] = item.uuid
-        item_d['barcode_id'] = item.barcode_id
-        item_d['model_id'] = item.item_info.model_id
-        item_d['part_number'] = item.item_info.part_number
-        item_d['lot_number'] = item.item_info.lot_number
-        item_d['vendor'] = item.item_info.vendor.name
-        item_d['creation_date'] = item.creation_date.strftime('%Y-%m-%d %H:%M:%S')
-        item_d['modified_date'] = item.modified_date.strftime('%Y-%m-%d %H:%M:%S')
-        item_d['location'] = item.location.name
-
-        # Item status if exists
-        if item.status is None:
-            item_d['status'] = ''
-        else:
-            item_d['status'] = item.status.name
-
-        # Stored flowcells on device
-        if item.longtermstorage_set.count() > 0:
-            item_d['flowcells'] = ','.join([ lts.flowcell.flowcell_id for lts in item.longtermstorage_set.all() ])
-        else:
-            item_d['flowcells'] = ''
-
-        item_d['type'] = item.item_type.name
-        rows.append(item_d)
-
-    d['rows'] = rows
-
-    return HttpResponse(json.dumps(d), content_type="application/javascript")
-
-@login_required
-def all_index(request):
-    """
-    Inventory Index View
-    """
-    # build changelist
-    item_changelist = HTSChangeList(request, Item,
-        list_filter=[],
-        search_fields=[],
-        list_per_page=200,
-        model_admin=ItemAdmin(Item, None)
-    )
-
-    context_dict = {
-        'item_changelist': item_changelist,
-        'page_name': 'Inventory Index'
-    }
-    context_dict.update(INVENTORY_CONTEXT_DEFAULTS)
-
-    return render_to_response('inventory/inventory_all_index.html',
-                              context_dict,
-                              context_instance=RequestContext(request))
-
-@login_required
-def index(request):
-    """
-    Inventory Index View
-    """
-    # build changelist
-    item_changelist = HTSChangeList(request, ItemType,
-        list_filter=[],
-        search_fields=['name', 'description'],
-        list_per_page=50,
-        model_admin=ItemTypeAdmin(ItemType, None)
-    )
-
-    context_dict = {
-        'item_changelist': item_changelist,
-        'page_name': 'Inventory Index'
-    }
-    context_dict.update(INVENTORY_CONTEXT_DEFAULTS)
-    return render_to_response('inventory/inventory_index.html',
-                              context_dict,
-                              context_instance=RequestContext(request))
-
-@login_required
-def itemtype_index(request, name):
-    """
-    Inventory Index View
-    """
-
-    name = name.replace('%20', ' ')
-
-    itemtype = ItemType.objects.get(name=name)
-
-    # build changelist
-    item_changelist = HTSChangeList(request, Item,
-        list_filter=[],
-        search_fields=[],
-        list_per_page=200,
-        model_admin=ItemAdmin(Item, None)
-    )
-
-    context_dict = {
-        'item_changelist': item_changelist,
-        'page_name': 'Inventory Index'
-    }
-    context_dict.update(INVENTORY_CONTEXT_DEFAULTS)
-
-    return render_to_response('inventory/inventory_itemtype_index.html',
-                              context_dict,
-                              context_instance=RequestContext(request))
-
-
-@login_required
-def item_summary_by_barcode(request, barcode_id, msg=''):
-    """
-    Display a summary for an item by barcode
-    """
-    try:
-        item = Item.objects.get(barcode_id=barcode_id)
-    except ObjectDoesNotExist, e:
-        item = None
-
-    return item_summary_by_uuid(request, None, msg, item)
-
-
-@login_required
-def item_summary_by_uuid(request, uuid, msg='', item=None):
-    """
-    Display a summary for an item
-    """
-    # Use item instead of looking it up if it is passed.
-    if item is None:
-        try:
-            item = Item.objects.get(uuid=uuid)
-        except ObjectDoesNotExist, e:
-            item = None
-
-    context_dict = {
-        'page_name': 'Item Summary',
-        'item': item,
-        'uuid': uuid,
-        'msg': msg
-    }
-    context_dict.update(INVENTORY_CONTEXT_DEFAULTS)
-
-    return render_to_response('inventory/inventory_summary.html',
-                              context_dict,
-                              context_instance=RequestContext(request))
-
-
-
-
-
-
-def __expand_context(context, item):
-    """
-    If EXPAND_CONTEXT dictionary has item.item_type.name function registered, use it to expand context
-    """
-    if item.item_type.name in EXPAND_CONTEXT:
-        expand_func = EXPAND_CONTEXT[item.item_type.name]
-        expand_func(context, item)
-
-def _item_print(item, request):
-    """
-    Prints an item given a type of item label to print
-    """
-    #FIXME: Hard coding this for now... need to abstract later.
-    context = {'item': item}
-    __expand_context(context, item)
-
-    # Print using barcode_id
-    if not item.force_use_uuid and (item.barcode_id is None or len(item.barcode_id.strip())):
-        context['use_uuid'] = False
-        msg = 'Printing item with barcode id: %s' % (item.barcode_id)
-    # Print using uuid
-    else:
-        context['use_uuid'] = True
-        msg = 'Printing item with UUID: %s' % (item.uuid)
-
-    printer_template = getPrinterTemplateByType(item.item_type)
-
-    c = RequestContext(request, context)
-    t = Template(printer_template.template)
-    print_zpl_socket(t.render(c), host=printer_template.printer.ip_address)
-
-    return msg
-
-@login_required
-def item_print(request, uuid):
-    """
-    Print a label for a given item
-    """
-    try:
-        item = Item.objects.get(uuid=uuid)
-    except ObjectDoesNotExist, e:
-        item = None
-        msg = "Item with UUID %s does not exist" % (uuid)
-
-    if item is not None:
-        msg = _item_print(item, request)
-
-    return item_summary_by_uuid(request, uuid, msg)
-
-
-def link_flowcell_and_device(request, flowcell, serial):
-    """
-    Updates database records of a flowcell being archived on a device with a particular serial #
-    """
-    assert flowcell is not None
-    assert serial is not None
-
-    LTS_UPDATED = False
-    SD_UPDATED = False
-    LIBRARY_UPDATED = False
-
-    ###########################################
-    # Retrieve Storage Device
-    try:
-        sd = Item.objects.get(barcode_id=serial)
-    except ObjectDoesNotExist, e:
-        msg = "Item with barcode_id of %s not found." % (serial)
-        raise ObjectDoesNotExist(msg)
-
-    ###########################################
-    # Retrieve FlowCell
-    try:
-        fc = FlowCell.objects.get(flowcell_id__startswith=flowcell)
-    except ObjectDoesNotExist, e:
-        msg = "FlowCell with flowcell_id of %s not found." % (flowcell)
-        raise ObjectDoesNotExist(msg)
-
-    ###########################################
-    # Retrieve or create LongTermStorage Object
-    count = fc.longtermstorage_set.count()
-    lts = None
-    if count > 1:
-        msg = "There really should only be one longtermstorage object per flowcell"
-        raise ValueError, msg
-    elif count == 1:
-        # lts already attached to flowcell
-        lts = fc.longtermstorage_set.all()[0]
-    else:
-        lts = LongTermStorage()
-        # Attach flowcell
-        lts.flowcell = fc
-        # Need a primary keey before linking to storage devices
-        lts.save()
-        LTS_UPDATED = True
-
-
-    ############################################
-    # Link Storage to Flowcell
-
-    # Add a link to this storage device if it is not already linked.
-    if sd not in lts.storage_devices.all():
-        lts.storage_devices.add(sd)
-        SD_UPDATED = True
-
-    ###########################################
-    # Add Library Links to LTS
-
-    for lane in fc.lane_set.all():
-        if lane.library not in lts.libraries.all():
-            lts.libraries.add(lane.library)
-            LIBRARY_UPDATED = True
-
-    # Save Changes
-    lts.save()
-
-    msg = ['Success:']
-    if LTS_UPDATED or SD_UPDATED or LIBRARY_UPDATED:
-        msg.append('  LongTermStorage (LTS) Created: %s' % (LTS_UPDATED))
-        msg.append('   Storage Device Linked to LTS: %s' % (SD_UPDATED))
-        msg.append('       Libraries updated in LTS: %s' % (LIBRARY_UPDATED))
-    else:
-        msg.append('  No Updates Needed.')
-
-    return HttpResponse('\n'.join(msg))
diff --git a/htsworkflow/frontend/labels/__init__.py b/htsworkflow/frontend/labels/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/htsworkflow/frontend/labels/admin.py b/htsworkflow/frontend/labels/admin.py
deleted file mode 100644 (file)
index 24445e5..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-from htsworkflow.frontend.labels.models import LabelContent, LabelTemplate, LabelPrinter
-from htsworkflow.frontend.inventory.models import PrinterTemplate
-from htsworkflow.frontend.bcmagic.utils import print_zpl_socket
-from django.template import Context, Template
-from django.contrib import admin
-
-class LabelContentOptions(admin.ModelAdmin):
-    save_as = True
-    save_on_top = True
-    search_fields = (
-        'title',
-        'subtitle',
-        'text',
-        'barcode',
-        'creator',
-    )
-    list_display = ('title','subtitle','text','barcode','template','creator')
-    list_filter = ('template','creator',)
-    fieldsets = (
-      (None, {
-          'fields': (('title','subtitle','text','barcode'),
-                     ('template','creator'))
-
-      }),
-    )
-    actions = ['action_print_labels']
-    
-    def action_print_labels(self, request, queryset):
-        """
-        Django action which prints labels for the selected set of labels from the
-        Django Admin interface.
-        """
-       
-        zpl_list = []
-        #Iterate over selected labels to print
-        for label in queryset.all():
-
-          template_used = LabelTemplate.objects.get(name=label.template.name)
-          # ZPL Template
-          t = Template(template_used.ZPL_code)
-
-          # Django Template Context
-          c = Context({'label': label})
-            
-          # Send rendered template to the printer that the template
-          #  object has been attached to in the database.
-          zpl_list.append(t.render(c))
-        
-        print_zpl_socket(zpl_list, host=template_used.printer.ip_address)
-    
-        self.message_user(request, "%s labels printed." % (len(queryset)))
-                          
-    action_print_labels.short_description = "Print Selected Labels"
-
-class LabelTemplateOptions(admin.ModelAdmin):
-    save_as = True
-    save_on_top = True
-    list_display = ('name', 'printer', 'ZPL_code')
-
-class LabelPrinterOptions(admin.ModelAdmin):
-    list_display = ('name', 'ip_address', 'labels')
-
-admin.site.register(LabelContent, LabelContentOptions)
-admin.site.register(LabelTemplate, LabelTemplateOptions)
-admin.site.register(LabelPrinter, LabelPrinterOptions)
-
diff --git a/htsworkflow/frontend/labels/models.py b/htsworkflow/frontend/labels/models.py
deleted file mode 100644 (file)
index 8794492..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-from django.db import models
-
-class LabelPrinter(models.Model):
-    """
-    Barcode Printer Information
-    """
-    name = models.CharField(max_length=256)
-    model = models.CharField(max_length=64, default='ZM400')
-    ip_address = models.IPAddressField()
-    labels = models.CharField(max_length=200)
-    notes = models.TextField(null=True, blank=True)
-
-    def __unicode__(self):
-        return u'%s: %s' % (self.name, self.labels)
-
-class LabelTemplate(models.Model):
-    """
-    Maps templates to printer to use
-    """
-    name = models.CharField(max_length=200)
-    description = models.TextField(null=True, blank=True)
-    printer = models.ForeignKey(LabelPrinter)
-    
-    ZPL_code = models.TextField('template')
-    
-    def __unicode__(self):
-            return '%s %s' % (self.name, self.printer.name)
-
-class LabelContent(models.Model):
-    title = models.CharField(max_length=200, null=True, blank=True)
-    subtitle = models.CharField(max_length=200, null=True, blank=True)
-    text = models.CharField(max_length=200, null=True, blank=True)
-    barcode = models.CharField(max_length=200, null=True, blank=True)
-    template = models.ForeignKey(LabelTemplate)
-    creator = models.CharField(max_length=200)
diff --git a/htsworkflow/frontend/labels/test_labels.py b/htsworkflow/frontend/labels/test_labels.py
deleted file mode 100644 (file)
index ca3633b..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-"""
-This file demonstrates two different styles of tests (one doctest and one
-unittest). These will both pass when you run "manage.py test".
-
-Replace these with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-class SimpleTest(TestCase):
-    def test_basic_addition(self):
-        """
-        Tests that 1 + 1 always equals 2.
-        """
-        self.failUnlessEqual(1 + 1, 2)
-
-__test__ = {"doctest": """
-Another way to test that 1 + 1 is equal to 2.
-
->>> 1 + 1 == 2
-True
-"""}
-
-def suite():
-    from unittest import TestSuite, defaultTestLoader
-    suite = TestSuite()
-    suite.addTests(defaultTestLoader.loadTestsFromTestCase(SimpleTest))
-    return suite
-
-if __name__ == "__main__":
-    from unittest import main
-    main(defaultTest="suite")
diff --git a/htsworkflow/frontend/labels/views.py b/htsworkflow/frontend/labels/views.py
deleted file mode 100644 (file)
index 60f00ef..0000000
+++ /dev/null
@@ -1 +0,0 @@
-# Create your views here.
diff --git a/htsworkflow/frontend/samples/__init__.py b/htsworkflow/frontend/samples/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/htsworkflow/frontend/samples/admin.py b/htsworkflow/frontend/samples/admin.py
deleted file mode 100644 (file)
index 619b383..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-from django.contrib import admin
-from django.contrib.admin import widgets
-from django.contrib.auth.models import User
-from django.contrib.auth.admin import UserAdmin
-from django.contrib.auth.forms import UserCreationForm, UserChangeForm
-from django.template import Context, Template
-from django.db import models
-from django.utils.translation import ugettext_lazy as _
-from django.forms import TextInput, Textarea
-
-from htsworkflow.frontend.samples.models import \
-     Antibody, Cellline, Condition, ExperimentType, HTSUser, \
-     LibraryType, MultiplexIndex, Species, Affiliation, Library, Tag
-from htsworkflow.frontend.experiments.models import Lane
-from htsworkflow.frontend.inventory.models import PrinterTemplate
-from htsworkflow.frontend.bcmagic.utils import print_zpl_socket
-
-# Let's disable those pesky delete everything by accident features.
-admin.site.disable_action('delete_selected')
-
-class AffiliationOptions(admin.ModelAdmin):
-    list_display = ('name','contact','email')
-    fieldsets = (
-      (None, {
-          'fields': (('name','contact','email','users'))
-      }),
-    )
-
-    # some post 1.0.2 version of django has formfield_overrides
-    # which would replace this code with:
-    # formfield_overrids = {
-    #   models.ManyToMany: { 'widget': widgets.FilteredSelectMultiple }
-    # }
-    def formfield_for_dbfield(self, db_field, **kwargs):
-      if db_field.name == 'users':
-        kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))
-      rv = super(AffiliationOptions, self).formfield_for_dbfield(db_field, **kwargs)
-    #  print db_field.name, kwargs
-      return rv
-
-class AntibodyOptions(admin.ModelAdmin):
-    search_fields = ('antigene','nickname','catalog','antibodies','source','biology','notes')
-    list_display = ('antigene','nickname','antibodies','catalog','source','biology','notes')
-    list_filter = ('antibodies','source')
-    fieldsets = (
-      (None, {
-          'fields': (('antigene','nickname','antibodies'),('catalog','source'),('biology'),('notes'))
-      }),
-     )
-
-class CelllineOptions(admin.ModelAdmin):
-    list_display = ('cellline_name', 'notes')
-    search_fields = ('cellline_name', 'nickname', 'notes')
-    fieldsets = (
-      (None, {
-          'fields': (('cellline_name','nickname',),('notes'),)
-      }),
-     )
-
-class ConditionOptions(admin.ModelAdmin):
-    list_display = (('condition_name'), ('notes'),)
-    fieldsets = (
-      (None, {
-          'fields': (('condition_name'),('nickname'),('notes'),)
-      }),
-     )
-
-class ExperimentTypeOptions(admin.ModelAdmin):
-  model = ExperimentType
-  #list_display = ('name',)
-  #fieldsets = ( (None, { 'fields': ('name',) }), )
-
-class HTSUserCreationForm(UserCreationForm):
-    class Meta:
-        model = HTSUser
-        fields = ("username",'first_name','last_name')
-
-class HTSUserChangeForm(UserChangeForm):
-    class Meta:
-        model = HTSUser
-        fields = ("username",'first_name','last_name')
-
-class HTSUserOptions(UserAdmin):
-    form = HTSUserChangeForm
-    add_form = HTSUserCreationForm
-
-class LaneLibraryInline(admin.StackedInline):
-  model = Lane
-  extra = 0
-
-class Library_Inline(admin.TabularInline):
-  model = Library
-
-class LibraryTypeOptions(admin.ModelAdmin):
-    list_display = ['name', 'is_paired_end', 'can_multiplex']
-    model = LibraryType
-
-class MultiplexIndexOptions(admin.ModelAdmin):
-    model = MultiplexIndex
-    list_display = ['adapter_type', 'multiplex_id', 'sequence']
-
-class LibraryOptions(admin.ModelAdmin):
-    class Media:
-        css = {
-            "all": ("css/wide_account_number.css",)
-            }
-
-    date_hierarchy = "creation_date"
-    save_as = True
-    save_on_top = True
-    search_fields = (
-        'id',
-        'library_name',
-        'cell_line__cellline_name',
-        'library_species__scientific_name',
-        'library_species__common_name',
-    )
-    list_display = (
-        'id',
-        'library_name',
-        'index_sequence_text',
-        'affiliation',
-        'undiluted_concentration',
-        'gel_cut_size',
-        'creation_date',
-    )
-    list_filter = (
-        'hidden',
-        'experiment_type',
-        'library_type',
-        #'cell_line',
-        'stopping_point',
-        'made_by',
-        'library_species',
-        'affiliations',
-        )
-    list_display_links = ('id', 'library_name',)
-    fieldsets = (
-      (None, {
-        'fields': (
-          ('id','library_name','hidden'),
-          ('library_species', 'experiment_type'),
-          ('library_type', 'multiplex_id'),
-          )
-         }),
-         ('Experiment Detail:', {
-            'fields': (('cell_line', 'replicate',),
-                       ('condition',),
-                       ('antibody', ),
-                       ),
-            'classes': ('collapse',),
-            }),
-         ('Creation Information:', {
-             'fields' : (('made_by', 'creation_date', 'stopping_point'),
-                         ('amplified_from_sample'),
-                         ('gel_cut_size', 'insert_size',
-                          'undiluted_concentration'),
-                         ('bioanalyzer_concentration','bioanalyzer_image_url'),
-                         ('bioanalyzer_summary'),
-                         ('notes'))
-         }),
-         ('Library/Project Affiliation:', {
-             'fields' : (('account_number', 'affiliations'),)
-         }),
-         )
-    inlines = [
-      LaneLibraryInline,
-    ]
-    actions = ['action_print_library_labels']
-
-    def action_print_library_labels(self, request, queryset):
-        """
-        Django action which prints labels for the selected set of labels from the
-        Django Admin interface.
-        """
-
-        #Probably should ask if the user really meant to print all selected
-        # libraries if the count is above X. X=10 maybe?
-
-        # Grab the library template
-        #FIXME: Hardcoding library template name. Not a good idea... *sigh*.
-        EVIL_HARDCODED_LIBRARY_TEMPLATE_NAME = "Library"
-
-        try:
-            template = PrinterTemplate.objects.get(item_type__name=EVIL_HARDCODED_LIBRARY_TEMPLATE_NAME)
-        except PrinterTemplate.DoesNotExist:
-            self.message_user(request, "Could not find a library template with ItemType.name of '%s'" % \
-                              (EVIL_HARDCODED_LIBRARY_TEMPLATE_NAME))
-            return
-
-        # ZPL Template
-        t = Template(template.template)
-
-        zpl_list = []
-        #Iterate over selected labels to print
-        for library in queryset.all():
-
-            # Django Template Context
-            c = Context({'library': library})
-
-            # Send rendered template to the printer that the template
-            #  object has been attached to in the database.
-            zpl_list.append(t.render(c))
-
-        print_zpl_socket(zpl_list, host=template.printer.ip_address)
-
-        self.message_user(request, "%s labels printed." % (len(queryset)))
-
-    action_print_library_labels.short_description = "Print Labels"
-
-    def formfield_for_dbfield(self, db_field, **kwargs):
-        # Override Field type
-        if db_field.name in ('affiliations', 'tags'):
-            kwargs['widget'] = widgets.FilteredSelectMultiple(
-                db_field.verbose_name,
-                (db_field.name in self.filter_vertical)
-            )
-        field = super(LibraryOptions, self).formfield_for_dbfield(db_field,
-                                                                  **kwargs)
-        # Override field attributes
-        if db_field.name == "bioanalyzer_summary":
-            field.widget.attrs["rows"] = "3"
-        return field
-
-class SpeciesOptions(admin.ModelAdmin):
-    fieldsets = (
-      (None, {
-          'fields': (('scientific_name', 'common_name'),)
-      }),
-    )
-
-class TagOptions(admin.ModelAdmin):
-    list_display = ('tag_name', 'context')
-    fieldsets = (
-        (None, {
-          'fields': ('tag_name', 'context')
-          }),
-        )
-
-admin.site.register(Library, LibraryOptions)
-admin.site.register(Affiliation, AffiliationOptions)
-admin.site.register(Antibody, AntibodyOptions)
-admin.site.register(Cellline, CelllineOptions)
-admin.site.register(Condition, ConditionOptions)
-admin.site.register(ExperimentType, ExperimentTypeOptions)
-#admin.site.register(HTSUser, HTSUserOptions)
-admin.site.register(LibraryType, LibraryTypeOptions)
-admin.site.register(MultiplexIndex, MultiplexIndexOptions)
-admin.site.register(Species, SpeciesOptions)
-#admin.site.register(Tag, TagOptions)
diff --git a/htsworkflow/frontend/samples/auth_backend.py b/htsworkflow/frontend/samples/auth_backend.py
deleted file mode 100644 (file)
index e09d404..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-from django.conf import settings
-from django.contrib.auth.backends import ModelBackend
-from django.core.exceptions import ImproperlyConfigured
-from django.db.models import get_model
-
-import sys
-
-class HTSUserModelBackend(ModelBackend):
-    def authenticate(self, username=None, password=None):
-        try:
-            user = self.user_class.objects.get(username=username)
-            if user.check_password(password):
-                return user
-        #except self.user_class.DoesNotExist:
-        except Exception, e:
-            print >>sys.stderr, e
-            return None
-
-    def get_user(self, user_id):
-        try:
-            return self.user_class.objects.get(pk=user_id)
-        #except self.user_class.DoesNotExist:
-        except Exception, e:
-            print >>sys.stderr, e
-            return None
-
-    @property
-    def user_class(self):
-        if not hasattr(self, '_user_class'):
-            self._user_class = get_model(*settings.CUSTOM_USER_MODEL.split('.',2))
-            if not self._user_class:
-                raise ImproperlyConfigured('Could not get custom user model')
-            return self._user_class
-        
diff --git a/htsworkflow/frontend/samples/changelist.py b/htsworkflow/frontend/samples/changelist.py
deleted file mode 100644 (file)
index 960509e..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-import django
-from django.contrib.admin.views.main import ChangeList
-
-class HTSChangeList(ChangeList):
-    def __init__(self, request, model, list_filter, search_fields,
-                 list_per_page, model_admin, extra_filters=None):
-        """Simplification of the django model filter view
-
-        The new parameter "extra_filter" should be a mapping
-        of that will be passed as keyword arguments to
-        queryset.filter
-        """
-        self.extra_filters = extra_filters
-
-        args = {
-            'request': request, #request
-            'model': model, #model
-            'list_display': [], # list_display
-            'list_display_links': None, # list_display_links
-            'list_filter': list_filter, #list_filter
-            'date_hierarchy': None, # date_hierarchy
-            'search_fields': search_fields, #search_fields
-            'list_select_related': None, # list_select_related,
-            'list_per_page': list_per_page, #list_per_page
-            'list_editable': None, # list_editable
-            'model_admin': model_admin #model_admin
-        }
-        if django.VERSION[0] >= 1 and django.VERSION[1] >= 4:
-            args['list_max_show_all'] = 20000, #list_max_show_all
-        super(HTSChangeList, self).__init__(**args)
-
-        self.is_popup = False
-        # I removed to field in the first version
-
-        self.multi_page = True
-        self.can_show_all = False
-
-    def get_queryset(self, request=None):
-        args = {}
-        if django.VERSION[0] >= 1 and django.VERSION[1] >= 4:
-            args['request'] = request #list_max_show_all
-
-        qs = super(HTSChangeList, self).get_query_set(**args)
-        if self.extra_filters:
-            new_qs = qs.filter(**self.extra_filters)
-            if new_qs is not None:
-                qs = new_qs
-        return qs
diff --git a/htsworkflow/frontend/samples/fixtures/initial_data.json b/htsworkflow/frontend/samples/fixtures/initial_data.json
deleted file mode 100644 (file)
index ae22c1d..0000000
+++ /dev/null
@@ -1,929 +0,0 @@
-[
-  {
-     "model": "samples.Cellline",
-     "pk": 1,
-     "fields": {
-        "cellline_name": "Unknown",
-        "notes": "Unknown"
-     }
-  },
-  {
-     "model": "samples.Cellline",
-     "pk": 2,
-     "fields": {
-        "cellline_name": "C2C12",
-        "notes": ""
-     }
-  },
-  {
-     "model": "samples.Cellline",
-     "pk": 3,
-     "fields": {
-        "cellline_name": "C2C12 60 hrs",
-        "notes": "Unknown"
-     }
-  },
-  { "pk": 1, "model": "samples.Condition",
-    "fields": {
-        "condition_name": "Unknown",
-        "nickname": "",
-        "notes": "Unknown"
-    }
-  },
-  {
-     "model": "samples.LibraryType",
-     "pk": 1,
-     "fields": {
-        "name": "Single End (non-multiplexed)",
-        "can_multiplex": false,
-        "is_paired_end": false
-     }
-  },
-  {
-     "model": "samples.LibraryType",
-     "pk": 2,
-     "fields": {
-        "name": "Paired End (non-multiplexed)",
-        "can_multiplex": false,
-        "is_paired_end": true
-     }
-  },
-  {
-     "model": "samples.LibraryType",
-     "pk": 5,
-     "fields": {
-        "name": "Barcoded Illumina",
-        "can_multiplex": true,
-        "is_paired_end": true
-     }
-  },
-  {
-     "model": "samples.LibraryType",
-     "pk": 7,
-     "fields": {
-        "name": "Barcoded Small RNA",
-        "can_multiplex": true,
-        "is_paired_end": true
-     }
-  },
-  {
-     "model": "samples.LibraryType",
-     "pk": 8,
-     "fields": {
-        "name": "Nextera",
-        "can_multiplex": true,
-        "is_paired_end": true
-     }
-  },
-  {
-     "model": "samples.LibraryType",
-     "pk": 9,
-     "fields": {
-        "name": "Dual Index Illumina",
-        "can_multiplex": true,
-        "is_paired_end": true
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 1,
-     "fields": {
-        "name": "Unknown"
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 2,
-     "fields": {
-        "name": "ChIP-seq"
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 4,
-     "fields": {
-        "name": "RNA-seq"
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 7,
-     "fields": {
-        "name": "De Novo"
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 8,
-     "fields": {
-        "name": "Whole Genome"
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 9,
-     "fields": {
-        "name": "Small RNA"
-     }
-  },
-  {
-     "model": "samples.ExperimentType",
-     "pk": 10,
-     "fields": {
-        "name": "Multiplexed"
-     }
-  },
-  {
-     "model": "samples.Species",
-     "pk": 2,
-     "fields": {
-        "scientific_name": "Drosophila melanogaster",
-        "common_name": "fruit fly"
-     }
-  },
-  {
-     "model": "samples.Species",
-     "pk": 3,
-     "fields": {
-        "scientific_name": "Caenorhabditis elegans",
-        "common_name": ""
-     }
-  },
-  {
-     "model": "samples.Species",
-     "pk": 6,
-     "fields": {
-        "scientific_name": "Arabidopsis thaliana"
-     }
-  },
-  {
-     "model": "samples.Species",
-     "pk": 8,
-     "fields": {
-        "scientific_name": "Homo sapiens",
-        "common_name": "human"
-     }
-  },
-  {
-     "model": "samples.Species",
-     "pk": 9,
-     "fields": {
-        "scientific_name": "Mus musculus",
-        "common_name": "mouse"
-     }
-  },
-  {
-     "model": "samples.Species",
-     "pk": 10,
-     "fields": {
-        "scientific_name": "Strongylocentrotus purpuratus"
-     }
-  },
-  {
-    "pk": 1,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 1,
-      "adapter_type": 8,
-      "sequence": "ATCACG"
-    }
-  },
-  {
-    "pk": 2,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 2,
-      "adapter_type": 8,
-      "sequence": "CGATGT"
-    }
-  },
-  {
-    "pk": 3,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 3,
-      "adapter_type": 8,
-      "sequence": "TTAGGC"
-    }
-  },
-  {
-    "pk": 4,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 4,
-      "adapter_type": 8,
-      "sequence": "TGACCA"
-    }
-  },
-  {
-    "pk": 5,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 5,
-      "adapter_type": 8,
-      "sequence": "ACAGTG"
-    }
-  },
-  {
-    "pk": 6,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 6,
-      "adapter_type": 8,
-      "sequence": "GCCAAT"
-    }
-  },
-  {
-    "pk": 7,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 7,
-      "adapter_type": 8,
-      "sequence": "CAGATC"
-    }
-  },
-  {
-    "pk": 8,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 8,
-      "adapter_type": 8,
-      "sequence": "ACTTGA"
-    }
-  },
-  {
-    "pk": 9,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 9,
-      "adapter_type": 8,
-      "sequence": "GATCAG"
-    }
-  },
-  {
-    "pk": 10,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 10,
-      "adapter_type": 8,
-      "sequence": "TAGCTT"
-    }
-  },
-  {
-    "pk": 11,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 11,
-      "adapter_type": 8,
-      "sequence": "GGCTAC"
-    }
-  },
-  {
-    "pk": 12,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 12,
-      "adapter_type": 8,
-      "sequence": "CTTGTA"
-    }
-  },
-  {
-    "pk": 13,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 1,
-      "adapter_type": 7,
-      "sequence": "ATCACG"
-    }
-  },
-  {
-    "pk": 14,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 2,
-      "adapter_type": 7,
-      "sequence": "CGATGT"
-    }
-  },
-  {
-    "pk": 15,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 3,
-      "adapter_type": 7,
-      "sequence": "TTAGGC"
-    }
-  },
-  {
-    "pk": 16,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 4,
-      "adapter_type": 7,
-      "sequence": "TGACCA"
-    }
-  },
-  {
-    "pk": 17,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 5,
-      "adapter_type": 7,
-      "sequence": "ACAGTG"
-    }
-  },
-  {
-    "pk": 18,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 6,
-      "adapter_type": 7,
-      "sequence": "GCCAAT"
-    }
-  },
-  {
-    "pk": 19,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 7,
-      "adapter_type": 7,
-      "sequence": "CAGATC"
-    }
-  },
-  {
-    "pk": 20,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 8,
-      "adapter_type": 7,
-      "sequence": "ACTTGA"
-    }
-  },
-  {
-    "pk": 21,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 9,
-      "adapter_type": 7,
-      "sequence": "GATCAG"
-    }
-  },
-  {
-    "pk": 22,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 10,
-      "adapter_type": 7,
-      "sequence": "TAGCTT"
-    }
-  },
-  {
-    "pk": 23,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 11,
-      "adapter_type": 7,
-      "sequence": "GGCTAC"
-    }
-  },
-  {
-    "pk": 24,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 12,
-      "adapter_type": 7,
-      "sequence": "CTTGTA"
-    }
-  },
-  {
-    "pk": 25,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 13,
-      "adapter_type": 7,
-      "sequence": "AGTCAA"
-    }
-  },
-  {
-    "pk": 26,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 14,
-      "adapter_type": 7,
-      "sequence": "AGTTCC"
-    }
-  },
-  {
-    "pk": 27,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 15,
-      "adapter_type": 7,
-      "sequence": "ATGTCA"
-    }
-  },
-  {
-    "pk": 28,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 16,
-      "adapter_type": 7,
-      "sequence": "CCGTCC"
-    }
-  },
-  {
-    "pk": 29,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 17,
-      "adapter_type": 7,
-      "sequence": "GTAGAG"
-    }
-  },
-  {
-    "pk": 30,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 18,
-      "adapter_type": 7,
-      "sequence": "GTCCGC"
-    }
-  },
-  {
-    "pk": 31,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 19,
-      "adapter_type": 7,
-      "sequence": "GTGAAA"
-    }
-  },
-  {
-    "pk": 32,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 20,
-      "adapter_type": 7,
-      "sequence": "GTGGCC"
-    }
-  },
-  {
-    "pk": 33,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 21,
-      "adapter_type": 7,
-      "sequence": "GTTTCG"
-    }
-  },
-  {
-    "pk": 34,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 22,
-      "adapter_type": 7,
-      "sequence": "CGTACG"
-    }
-  },
-  {
-    "pk": 35,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 23,
-      "adapter_type": 7,
-      "sequence": "GAGTGG"
-    }
-  },
-  {
-    "pk": 36,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 24,
-      "adapter_type": 7,
-      "sequence": "GGTAGC"
-    }
-  },
-  {
-    "pk": 37,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 25,
-      "adapter_type": 7,
-      "sequence": "ACTGAT"
-    }
-  },
-  {
-    "pk": 38,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 26,
-      "adapter_type": 7,
-      "sequence": "ATGAGC"
-    }
-  },
-  {
-    "pk": 39,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 27,
-      "adapter_type": 7,
-      "sequence": "ATTCCT"
-    }
-  },
-  {
-    "pk": 40,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 28,
-      "adapter_type": 7,
-      "sequence": "CAAAAG"
-    }
-  },
-  {
-    "pk": 41,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 29,
-      "adapter_type": 7,
-      "sequence": "CAACTA"
-    }
-  },
-  {
-    "pk": 42,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 30,
-      "adapter_type": 7,
-      "sequence": "CACCGG"
-    }
-  },
-  {
-    "pk": 43,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 31,
-      "adapter_type": 7,
-      "sequence": "CACGAT"
-    }
-  },
-  {
-    "pk": 44,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 32,
-      "adapter_type": 7,
-      "sequence": "CACTCA"
-    }
-  },
-  {
-    "pk": 45,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 33,
-      "adapter_type": 7,
-      "sequence": "CAGGCG"
-    }
-  },
-  {
-    "pk": 46,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 34,
-      "adapter_type": 7,
-      "sequence": "CATGGC"
-    }
-  },
-  {
-    "pk": 47,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 35,
-      "adapter_type": 7,
-      "sequence": "CATTTT"
-    }
-  },
-  {
-    "pk": 48,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 36,
-      "adapter_type": 7,
-      "sequence": "CCAACA"
-    }
-  },
-  {
-    "pk": 49,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 37,
-      "adapter_type": 7,
-      "sequence": "CGGAAT"
-    }
-  },
-  {
-    "pk": 50,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 38,
-      "adapter_type": 7,
-      "sequence": "CTAGCT"
-    }
-  },
-  {
-    "pk": 51,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 39,
-      "adapter_type": 7,
-      "sequence": "CTATAC"
-    }
-  },
-  {
-    "pk": 52,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 40,
-      "adapter_type": 7,
-      "sequence": "CTCAGA"
-    }
-  },
-  {
-    "pk": 53,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 41,
-      "adapter_type": 7,
-      "sequence": "GACGAC"
-    }
-  },
-  {
-    "pk": 54,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 42,
-      "adapter_type": 7,
-      "sequence": "TAATCG"
-    }
-  },
-  {
-    "pk": 55,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 43,
-      "adapter_type": 7,
-      "sequence": "TACAGC"
-    }
-  },
-  {
-    "pk": 56,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 44,
-      "adapter_type": 7,
-      "sequence": "TATAAT"
-    }
-  },
-  {
-    "pk": 57,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 45,
-      "adapter_type": 7,
-      "sequence": "TCATTC"
-    }
-  },
-  {
-    "pk": 58,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 46,
-      "adapter_type": 7,
-      "sequence": "TCCCGA"
-    }
-  },
-  {
-    "pk": 59,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 47,
-      "adapter_type": 7,
-      "sequence": "TCGAAG"
-    }
-  },
-  {
-    "pk": 60,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 48,
-      "adapter_type": 7,
-      "sequence": "TCGGCA"
-    }
-  },
-  {
-    "pk": 61,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 1,
-      "adapter_type": 5,
-      "sequence": "ATCACG"
-    }
-  },
-  {
-    "pk": 62,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 2,
-      "adapter_type": 5,
-      "sequence": "CGATGT"
-    }
-  },
-  {
-    "pk": 63,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 3,
-      "adapter_type": 5,
-      "sequence": "TTAGGC"
-    }
-  },
-  {
-    "pk": 64,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 4,
-      "adapter_type": 5,
-      "sequence": "TGACCA"
-    }
-  },
-  {
-    "pk": 65,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 5,
-      "adapter_type": 5,
-      "sequence": "ACAGTG"
-    }
-  },
-  {
-    "pk": 66,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 6,
-      "adapter_type": 5,
-      "sequence": "GCCAAT"
-    }
-  },
-  {
-    "pk": 67,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 7,
-      "adapter_type": 5,
-      "sequence": "CAGATC"
-    }
-  },
-  {
-    "pk": 68,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 8,
-      "adapter_type": 5,
-      "sequence": "ACTTGA"
-    }
-  },
-  {
-    "pk": 69,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 9,
-      "adapter_type": 5,
-      "sequence": "GATCAG"
-    }
-  },
-  {
-    "pk": 70,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 10,
-      "adapter_type": 5,
-      "sequence": "TAGCTT"
-    }
-  },
-  {
-    "pk": 71,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 11,
-      "adapter_type": 5,
-      "sequence": "GGCTAC"
-    }
-  },
-  {
-    "pk": 72,
-    "model": "samples.MultiplexIndex",
-    "fields": {
-      "multiplex_id": 12,
-      "adapter_type": 5,
-      "sequence": "CTTGTA"
-    }
-  },
-  {"fields": {"adapter_type": 9,
-             "multiplex_id": "N501",
-             "sequence": "TAGATCGC"},
-  "model": "samples.multiplexindex",
-  "pk": 74
-  },
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N502",
-             "sequence": "CTCTCTAT"},
-  "model": "samples.multiplexindex",
-  "pk": 75},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N503",
-             "sequence": "TATCCTCT"},
-  "model": "samples.multiplexindex",
-  "pk": 76},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N504",
-             "sequence": "AGAGTAGA"},
-  "model": "samples.multiplexindex",
-  "pk": 77},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N505",
-             "sequence": "GTAAGGAG"},
-  "model": "samples.multiplexindex",
-  "pk": 78},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N506",
-             "sequence": "ACTGCATA"},
-  "model": "samples.multiplexindex",
-  "pk": 79},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N507",
-             "sequence": "AAGGAGTA"},
-  "model": "samples.multiplexindex",
-  "pk": 80},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N508",
-             "sequence": "CTAAGCCT"},
-  "model": "samples.multiplexindex",
-  "pk": 81},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N701",
-             "sequence": "TAAGGCGA"},
-  "model": "samples.multiplexindex",
-  "pk": 82},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N702",
-             "sequence": "CGTACTAG"},
-  "model": "samples.multiplexindex",
-  "pk": 83},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N703",
-             "sequence": "AGGCAGAA"},
-  "model": "samples.multiplexindex",
-  "pk": 84},
- {"fields": {"adapter_type": 9, "multiplex_id": "N704", "sequence": "TCCTGA"},
-  "model": "samples.multiplexindex",
-  "pk": 85},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N705",
-             "sequence": "GGACTCCT"},
-  "model": "samples.multiplexindex",
-  "pk": 86},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N706",
-             "sequence": "TAGGCATG"},
-  "model": "samples.multiplexindex",
-  "pk": 87},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N707",
-             "sequence": "CTCTCTAC"},
-  "model": "samples.multiplexindex",
-  "pk": 88},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N708",
-             "sequence": "CAGAGAGG"},
-  "model": "samples.multiplexindex",
-  "pk": 89},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N709",
-             "sequence": "GCTACGCT"},
-  "model": "samples.multiplexindex",
-  "pk": 90},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N710",
-             "sequence": "CGAGGCTG"},
-  "model": "samples.multiplexindex",
-  "pk": 91},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N711",
-             "sequence": "AAGAGGCA"},
-  "model": "samples.multiplexindex",
-  "pk": 92},
- {"fields": {"adapter_type": 9,
-             "multiplex_id": "N712",
-             "sequence": "GTAGAGGA"},
-  "model": "samples.multiplexindex",
-  "pk": 93}
-]
diff --git a/htsworkflow/frontend/samples/fixtures/test_samples.json b/htsworkflow/frontend/samples/fixtures/test_samples.json
deleted file mode 100644 (file)
index 41824e0..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-[
-  {"pk": 5, "model": "auth.user",
-   "fields": {
-       "username": "test",
-       "first_name": "",
-       "last_name": "",
-       "is_active": true,
-       "is_superuser": false,
-       "is_staff": false,
-       "last_login": "2009-01-01T00:00:01-0800",
-       "groups": [],
-       "user_permissions": [],
-       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
-       "email": "",
-       "date_joined": "2009-01-01T00:01:01-0800"
-       }
-   },
-   {"pk": 1, "model": "samples.affiliation",
-    "fields": {
-        "users": [5],
-        "name": "Alice",
-        "contact": "Lab Boss",
-        "email": "alice@some.where.else."
-        }
-    },
-    {"pk": 2, "model": "samples.affiliation",
-     "fields": { "name": "Bob",
-                 "contact": "Other Lab Boss",
-                 "email": "bob@some.where.else"
-               }
-    },
-    {"pk": 3, "model": "samples.affiliation",
-     "fields": {
-         "users": [],
-         "contact": "group 3",
-         "name": "affiliation 3",
-         "email": "pk3@example.com"
-         }
-     },
-    {"pk": 4, "model": "samples.affiliation",
-     "fields": {
-         "users": [],
-         "contact": "group 4",
-         "name": "affiliation 4",
-         "email": "pk1@example.com"
-         }
-     },
-    {"pk": 5, "model": "samples.affiliation",
-     "fields": {
-         "users": [],
-         "contact": "group 5",
-         "name": "affiliation 5",
-         "email": "pk5@example.com"
-         }
-     },
- {"pk": 153, "model": "experiments.flowcell",
-  "fields": {
-      "paired_end": true,
-      "run_date": "2009-09-11T22:12:13-0800",
-      "read_length": 75,
-      "notes": "",
-      "advanced_run": false,
-      "control_lane": 2,
-      "cluster_station": 3,
-      "sequencer": 2,
-      "flowcell_id": "303TUAAXX"
-      }
-  },
-  {"pk": 1193, "model": "experiments.lane",
-   "fields": {
-       "comment": "No change in cluster numbers, despite slight increase in pM",
-       "library": "10981",
-       "cluster_estimate": 129000,
-       "flowcell": 153,
-       "lane_number": 1,
-       "pM": "8"
-       }
-   },
-  {"pk": 1197, "model": "experiments.lane",
-   "fields": {
-       "comment": "stuff",
-       "library": "11016",
-       "cluster_estimate": 140000,
-       "flowcell": 153,
-       "lane_number": 5,
-       "pM": "7",
-       "status": 2
-       }
-   },
-  {"pk": "10981", "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 400,
-            "library_name": "Paired End Multiplexed Sp-BAC",
-            "creation_date": "2009-07-21",
-            "cell_line": 1,
-            "library_species": 2,
-            "library_type": null,
-            "made_by": "Igor",
-            "affiliations": [
-                2
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "Done",
-            "tags": [],
-            "made_for": "Andy Cameron",
-            "amplified_from_sample": null,
-            "notes": "Combined 10957-10968",
-            "undiluted_concentration": "5.1",
-            "successful_pM": null,
-            "experiment_type": 10,
-            "antibody": null
-        }
-    },
-    {
-        "pk": "11016",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 325,
-            "library_name": "Paired End Pfl #3 MP 7/24/9 a",
-            "creation_date": "2009-08-06",
-            "cell_line": 1,
-            "library_species": 9,
-            "library_type": 2,
-            "made_by": "Lorian",
-            "affiliations": [
-                3
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": "11003",
-            "notes": "7/31/2009 16:08:22\tColor: Blue",
-            "undiluted_concentration": "35.5",
-            "successful_pM": null,
-            "experiment_type": 8,
-            "antibody": null
-        }
-    },
-    {
-        "pk": "11039",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 300,
-            "library_name": "Paired ends 99 GM12892",
-            "creation_date": "2009-08-25",
-            "cell_line": 1,
-            "library_species": 8,
-            "library_type": 2,
-            "made_by": "Brian Williams",
-            "affiliations": [
-                1,
-                2,
-                4
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": false,
-            "stopping_point": "1Aa",
-            "tags": [],
-            "made_for": "Brian Williams",
-            "amplified_from_sample": null,
-            "notes": "fragment size = 300 bp, Amicon filtered\r\nnanodrop: 56.3",
-            "undiluted_concentration": "28.7",
-            "successful_pM": null,
-            "experiment_type": 4,
-            "antibody": null
-        }
-    },
-    {
-        "pk": "11003",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 325,
-            "library_name": "Paired End Pfl #3 MP 7/24/9",
-            "creation_date": "2009-08-05",
-            "cell_line": 1,
-            "library_species": 8,
-            "library_type": 2,
-            "made_by": "Lorian",
-            "affiliations": [
-                4
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": true,
-            "stopping_point": "1A",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "7/31/2009 16:08:22\tColor: Blue",
-            "undiluted_concentration": null,
-            "successful_pM": null,
-            "experiment_type": 8,
-            "antibody": null
-        }
-    },
-    {
-        "pk": "11005",
-        "model": "samples.library",
-        "fields": {
-            "ten_nM_dilution": false,
-            "gel_cut_size": 325,
-            "library_name": "null cell line",
-            "creation_date": "2009-08-05",
-            "cell_line": null,
-            "library_species": 8,
-            "library_type": 2,
-            "made_by": "Lorian",
-            "affiliations": [
-                4
-            ],
-            "replicate": 1,
-            "condition": 1,
-            "hidden": true,
-            "stopping_point": "1A",
-            "tags": [],
-            "made_for": "",
-            "amplified_from_sample": null,
-            "notes": "7/31/2009 16:08:22\tColor: Blue",
-            "undiluted_concentration": null,
-            "successful_pM": null,
-            "experiment_type": 8,
-            "antibody": null
-        }
-    }
-]
diff --git a/htsworkflow/frontend/samples/models.py b/htsworkflow/frontend/samples/models.py
deleted file mode 100644 (file)
index d7c70c2..0000000
+++ /dev/null
@@ -1,403 +0,0 @@
-import types
-import logging
-import urlparse
-from django.db import models
-from django.contrib.auth.models import User, UserManager
-from django.core import urlresolvers
-from django.db.models.signals import pre_save, post_save
-from django.db import connection
-from htsworkflow.frontend.reports.libinfopar import *
-
-logger = logging.getLogger(__name__)
-
-class Antibody(models.Model):
-    antigene = models.CharField(max_length=500, db_index=True)
-    # New field Aug/20/08
-    # SQL to add column:
-    # alter table fctracker_antibody add column "nickname" varchar(20) NULL;
-    nickname = models.CharField(
-        max_length=20,
-        blank=True,
-        null=True,
-        db_index=True
-    )
-    catalog = models.CharField(max_length=50, blank=True, null=True)
-    antibodies = models.CharField(max_length=500, db_index=True)
-    source = models.CharField(max_length=500, blank=True, null=True, db_index=True)
-    biology = models.TextField(blank=True, null=True)
-    notes = models.TextField(blank=True, null=True)
-    def __unicode__(self):
-        return u'%s - %s' % (self.antigene, self.antibodies)
-    class Meta:
-        verbose_name_plural = "antibodies"
-        ordering = ["antigene"]
-
-class Cellline(models.Model):
-    cellline_name = models.CharField(max_length=100, unique=True, db_index=True)
-    nickname = models.CharField(max_length=20,
-        blank=True,
-        null=True,
-        db_index=True)
-
-    notes = models.TextField(blank=True)
-    def __unicode__(self):
-        return unicode(self.cellline_name)
-
-    class Meta:
-        ordering = ["cellline_name"]
-
-class Condition(models.Model):
-    condition_name = models.CharField(
-        max_length=2000, unique=True, db_index=True)
-    nickname = models.CharField(max_length=20,
-        blank=True,
-        null=True,
-        db_index=True,
-        verbose_name = 'Short Name')
-    notes = models.TextField(blank=True)
-
-    def __unicode__(self):
-        return unicode(self.condition_name)
-
-    class Meta:
-        ordering = ["condition_name"]
-
-
-class ExperimentType(models.Model):
-  name = models.CharField(max_length=50, unique=True)
-
-  def __unicode__(self):
-    return unicode(self.name)
-
-class Tag(models.Model):
-  tag_name = models.CharField(max_length=100, db_index=True,blank=False,null=False)
-  TAG_CONTEXT = (
-      #('Antibody','Antibody'),
-      #('Cellline', 'Cellline'),
-      #('Condition', 'Condition'),
-      ('Library', 'Library'),
-      ('ANY','ANY'),
-  )
-  context = models.CharField(max_length=50,
-      choices=TAG_CONTEXT, default='Library')
-
-  def __unicode__(self):
-    return u'%s' % (self.tag_name)
-
-  class Meta:
-    ordering = ["context","tag_name"]
-
-class Species(models.Model):
-  scientific_name = models.CharField(max_length=256,
-      unique=False,
-      db_index=True
-  )
-  common_name = models.CharField(max_length=256, blank=True)
-  #use_genome_build = models.CharField(max_length=100, blank=False, null=False)
-
-  def __unicode__(self):
-    return u'%s (%s)' % (self.scientific_name, self.common_name)
-
-  class Meta:
-    verbose_name_plural = "species"
-    ordering = ["scientific_name"]
-
-  @models.permalink
-  def get_absolute_url(self):
-    return ('htsworkflow.frontend.samples.views.species', [str(self.id)])
-
-class Affiliation(models.Model):
-  name = models.CharField(max_length=256, db_index=True, verbose_name='Name')
-  contact = models.CharField(max_length=256, null=True, blank=True,verbose_name='Lab Name')
-  email = models.EmailField(null=True,blank=True)
-  users = models.ManyToManyField('HTSUser', null=True, blank=True)
-  users.admin_order_field = "username"
-
-  def __unicode__(self):
-    str = unicode(self.name)
-    if self.contact is not None and len(self.contact) > 0:
-      str += u' ('+self.contact+u')'
-    return str
-
-  def Users(self):
-      users = self.users.all().order_by('username')
-      return ", ".join([unicode(a) for a in users ])
-
-  class Meta:
-    ordering = ["name","contact"]
-    unique_together = (("name", "contact"),)
-
-class LibraryType(models.Model):
-  name = models.CharField(max_length=255, unique=True,
-                          verbose_name="Adapter Type")
-  is_paired_end = models.BooleanField(default=True,
-                    help_text="can you do a paired end run with this adapter")
-  can_multiplex = models.BooleanField(default=True,
-                    help_text="Does this adapter provide multiplexing?")
-
-  def __unicode__(self):
-      return unicode(self.name)
-
-  class Meta:
-      ordering = ["-id"]
-
-
-class MultiplexIndex(models.Model):
-    """Map adapter types to the multiplex sequence"""
-    adapter_type = models.ForeignKey(LibraryType)
-    multiplex_id = models.CharField(max_length=6, null=False)
-    sequence = models.CharField(max_length=12, blank=True, null=True)
-
-    class Meta:
-        verbose_name_plural = "multiplex indicies"
-        unique_together = ('adapter_type', 'multiplex_id')
-
-class Library(models.Model):
-  id = models.CharField(max_length=10, primary_key=True)
-  library_name = models.CharField(max_length=100, unique=True)
-  library_species = models.ForeignKey(Species)
-  hidden = models.BooleanField(default=False)
-  account_number = models.CharField(max_length=100, null=True, blank=True)
-  cell_line = models.ForeignKey(Cellline, blank=True, null=True,
-                                verbose_name="Background")
-  condition = models.ForeignKey(Condition, blank=True, null=True)
-  antibody = models.ForeignKey(Antibody,blank=True,null=True)
-  affiliations = models.ManyToManyField(
-      Affiliation,related_name='library_affiliations',null=True)
-  tags = models.ManyToManyField(Tag,related_name='library_tags',
-                                blank=True,null=True)
-  REPLICATE_NUM = [(x,x) for x in range(1,7)]
-  replicate =  models.PositiveSmallIntegerField(choices=REPLICATE_NUM,
-                                                blank=True,null=True)
-  experiment_type = models.ForeignKey(ExperimentType)
-  library_type = models.ForeignKey(LibraryType, blank=True, null=True,
-                                   verbose_name="Adapter Type")
-  multiplex_id = models.CharField(max_length=128,
-                                  blank=True, null=True,
-                                  verbose_name="Index ID")
-  creation_date = models.DateField(blank=True, null=True)
-  made_for = models.CharField(max_length=50, blank=True,
-                              verbose_name='ChIP/DNA/RNA Made By')
-  made_by = models.CharField(max_length=50, blank=True, default="Lorian")
-
-  PROTOCOL_END_POINTS = (
-      ('?', 'Unknown'),
-      ('Sample', 'Raw sample'),
-      ('Progress', 'In progress'),
-      ('1A', 'Ligation, then gel'),
-      ('PCR', 'Ligation, then PCR'),
-      ('1Ab', 'Ligation, PCR, then gel'),
-      ('1Ac', 'Ligation, gel, then 12x PCR'),
-      ('1Aa', 'Ligation, gel, then 18x PCR'),
-      ('2A', 'Ligation, PCR, gel, PCR'),
-      ('Done', 'Completed'),
-    )
-  PROTOCOL_END_POINTS_DICT = dict(PROTOCOL_END_POINTS)
-  stopping_point = models.CharField(max_length=25,
-                                    choices=PROTOCOL_END_POINTS,
-                                    default='Done')
-
-  amplified_from_sample = models.ForeignKey('self',
-                            related_name='amplified_into_sample',
-                            blank=True, null=True)
-
-  undiluted_concentration = models.DecimalField("Concentration",
-      max_digits=5, decimal_places=2, blank=True, null=True,
-      help_text=u"Undiluted concentration (ng/\u00b5l)")
-      # note \u00b5 is the micro symbol in unicode
-  successful_pM = models.DecimalField(max_digits=9,
-                                      decimal_places=1, blank=True, null=True)
-  ten_nM_dilution = models.BooleanField(default=False)
-  gel_cut_size = models.IntegerField(default=225, blank=True, null=True)
-  insert_size = models.IntegerField(blank=True, null=True)
-  notes = models.TextField(blank=True)
-
-  bioanalyzer_summary = models.TextField(blank=True,default="")
-  bioanalyzer_concentration = models.DecimalField(max_digits=5,
-                                decimal_places=2, blank=True, null=True,
-                                help_text=u"(ng/\u00b5l)")
-  bioanalyzer_image_url = models.URLField(blank=True,default="")
-
-  def __unicode__(self):
-    return u'#%s: %s' % (self.id, self.library_name)
-
-  class Meta:
-      verbose_name_plural = "libraries"
-      #ordering = ["-creation_date"]
-      ordering = ["-id"]
-
-  def antibody_name(self):
-    str ='<a target=_self href="/admin/samples/antibody/'+self.antibody.id.__str__()+'/" title="'+self.antibody.__str__()+'">'+self.antibody.label+'</a>'
-    return str
-  antibody_name.allow_tags = True
-
-  def organism(self):
-    return self.library_species.common_name
-
-  def index_sequences(self):
-      """Return a dictionary of multiplex index id to sequence
-      Return None if the library can't multiplex,
-
-      """
-      if self.library_type is None:
-          return None
-      if not self.library_type.can_multiplex:
-          return None
-      if self.multiplex_id is None or len(self.multiplex_id) == 0:
-          return 'Err: id empty'
-      sequences = {}
-      multiplex_expressions = self.multiplex_id.split(',')
-      for multiplex_term in multiplex_expressions:
-          pairs = multiplex_term.split('-')
-          if len(pairs) == 1:
-              key = pairs[0]
-              seq = self._lookup_index(pairs[0])
-          elif len(pairs) == 2:
-              key = pairs[0] + '-' + pairs[1]
-              seq0 = self._lookup_index(pairs[0])
-              seq1 = self._lookup_index(pairs[1])
-              if seq0 is None or seq1 is None:
-                  seq = None
-              else:
-                  seq = seq0 + '-' + seq1
-          else:
-              raise RuntimeError("Too many - seperated sequences")
-          if seq is None:
-              seq = 'Err: index not found'
-          sequences[key] = seq
-      return sequences
-
-  def _lookup_index(self, multiplex_id):
-      try:
-          multiplex = MultiplexIndex.objects.get(
-              adapter_type = self.library_type.id,
-              multiplex_id = multiplex_id)
-          return multiplex.sequence
-      except MultiplexIndex.DoesNotExist, e:
-          return None
-
-  def index_sequence_text(self, seperator=' '):
-      """Return formatted multiplex index sequences"""
-      sequences = self.index_sequences()
-      if sequences is None:
-          return ""
-      if type(sequences) in types.StringTypes:
-          return sequences
-      multiplex_ids = sequences.keys()
-      multiplex_ids.sort()
-      return seperator.join(( "%s:%s" %(i,sequences[i]) for i in multiplex_ids))
-  index_sequence_text.short_description = "Index"
-
-
-  def affiliation(self):
-    affs = self.affiliations.all().order_by('name')
-    tstr = ''
-    ar = []
-    for t in affs:
-        ar.append(t.__unicode__())
-    return '%s' % (", ".join(ar))
-
-  def is_archived(self):
-    """
-    returns True if archived else False
-    """
-    if self.longtermstorage_set.count() > 0:
-        return True
-    else:
-        return False
-
-  def stopping_point_name(self):
-      end_points = Library.PROTOCOL_END_POINTS_DICT
-      name = end_points.get(self.stopping_point, None)
-      if name is None:
-          name = "Lookup Error"
-          logger.error("protocol stopping point in database didn't match names in library model")
-      return name
-
-
-  def libtags(self):
-    affs = self.tags.all().order_by('tag_name')
-    ar = []
-    for t in affs:
-      ar.append(t.__unicode__())
-    return u'%s' % ( ", ".join(ar))
-
-  def DataRun(self):
-    str ='<a target=_self href="/admin/experiments/datarun/?q='+self.id+'" title="Check All Data Runs for This Specific Library ..." ">Data Run</a>'
-    return str
-  DataRun.allow_tags = True
-
-  def aligned_m_reads(self):
-    return getLibReads(self.id)
-
-  def aligned_reads(self):
-    res = getLibReads(self.id)
-
-    # Check data sanity
-    if res[2] != "OK":
-      return u'<div style="border:solid red 2px">'+res[2]+'</div>'
-
-    rc = "%1.2f" % (res[1]/1000000.0)
-    # Color Scheme: green is more than 10M, blue is more than 5M, orange is more than 3M and red is less. For RNAseq, all those thresholds should be doubled
-    if res[0] > 0:
-      bgcolor = '#ff3300'  # Red
-      rc_thr = [10000000,5000000,3000000]
-      if self.experiment_type == 'RNA-seq':
-        rc_thr = [20000000,10000000,6000000]
-
-      if res[1] > rc_thr[0]:
-        bgcolor = '#66ff66'  # Green
-      else:
-        if res[1] > rc_thr[1]:
-          bgcolor ='#00ccff'  # Blue
-        else:
-           if res[1] > rc_thr[2]:
-             bgcolor ='#ffcc33'  # Orange
-      tstr = '<div style="background-color:'+bgcolor+';color:black">'
-      tstr += res[0].__unicode__()+' Lanes, '+rc+' M Reads'
-      tstr += '</div>'
-    else: tstr = 'not processed yet'
-    return tstr
-  aligned_reads.allow_tags = True
-
-  def public(self):
-    SITE_ROOT = '/'
-    summary_url = self.get_absolute_url()
-    return '<a href="%s">S</a>' % (summary_url,)
-  public.allow_tags = True
-
-  @models.permalink
-  def get_absolute_url(self):
-    return ('htsworkflow.frontend.samples.views.library_to_flowcells', [str(self.id)])
-
-  def get_admin_url(self):
-      return urlresolvers.reverse('admin:samples_library_change',
-                                  args=(self.id,))
-
-class HTSUser(User):
-    """
-    Provide some site-specific customization for the django user class
-    """
-    #objects = UserManager()
-
-    class Meta:
-        ordering = ['first_name', 'last_name', 'username']
-
-    def admin_url(self):
-        return '/admin/%s/%s/%d' % (self._meta.app_label, self._meta.module_name, self.id)
-
-    def __unicode__(self):
-        #return unicode(self.username) + u" (" + unicode(self.get_full_name()) + u")"
-        return unicode(self.get_full_name()) + u' (' + unicode(self.username) + ')'
-
-def HTSUserInsertID(sender, instance, **kwargs):
-    """
-    Force addition of HTSUsers when someone just modifies the auth_user object
-    """
-    u = HTSUser.objects.filter(pk=instance.id)
-    if len(u) == 0:
-        cursor = connection.cursor()
-        cursor.execute('INSERT INTO samples_htsuser (user_ptr_id) VALUES (%s);' % (instance.id,))
-        cursor.close()
-
-post_save.connect(HTSUserInsertID, sender=User)
diff --git a/htsworkflow/frontend/samples/results.py b/htsworkflow/frontend/samples/results.py
deleted file mode 100644 (file)
index 2724a37..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-from django.conf import settings
-
-import glob
-import os
-import re
-
-s_paren = re.compile("^\w+")
-
-def get_flowcell_result_dict(flowcell_id):
-    """
-    returns a dictionary following the following pattern for
-    a given flowcell_id:
-    
-     
-    d['C1-33']['summary']           # Summary.htm file path
-    d['C1-33']['eland_results'][5]  # C1-33 lane 5 file eland results file path
-    d['C1-33']['run_xml']           # run_*.xml file path
-    d['C1-33']['scores']            # scores.tar.gz file path
-    """
-    flowcell_id = flowcell_id.strip()
-    
-    d = {}
-    
-    ################################
-    # Flowcell Directory
-    fc_dir = glob.glob(os.path.join(settings.RESULT_HOME_DIR, flowcell_id))
-    
-    # Not found
-    if len(fc_dir) == 0:
-        return None
-    
-    # No duplicates!
-    assert len(fc_dir) <= 1
-    
-    # Found fc dir
-    fc_dir = fc_dir[0]
-    
-    ################################
-    # C#-## dirs
-    c_dir_list = glob.glob(os.path.join(fc_dir, 'C*'))
-    
-    # Not found
-    if len(c_dir_list) == 0:
-        return d
-    
-    for c_dir_path in c_dir_list:
-        summary_file = glob.glob(os.path.join(c_dir_path, 'Summary.htm'))
-        pathdir, c_dir = os.path.split(c_dir_path)
-        
-        # Create sub-dictionary
-        d[c_dir] = {}
-        
-        
-        ###############################
-        # Summary.htm file
-        
-        # Not found
-        if len(summary_file) == 0:
-            d[c_dir]['summary'] = None
-            
-        # Found
-        else:
-            # No duplicates!
-            assert len(summary_file) == 1
-            
-            summary_file = summary_file[0]
-            d[c_dir]['summary'] = summary_file
-            
-        ###############################
-        # Result files
-        
-        d[c_dir]['eland_results'] = {}
-        
-        result_filepaths = glob.glob(os.path.join(c_dir_path, 's_*_eland_*'))
-        
-        for filepath in result_filepaths:
-            
-            junk, result_name = os.path.split(filepath)
-            
-            #lanes 1-8, single digit, therefore s_#; # == index 2
-            lane = int(result_name[2])
-            d[c_dir]['eland_results'][lane] = filepath
-            
-        ###############################
-        # run*.xml file
-        run_xml_filepath = glob.glob(os.path.join(c_dir_path, 'run_*.xml'))
-        
-        if len(run_xml_filepath) == 0:
-            d[c_dir]['run_xml'] = None
-        else:
-            # No duplicates
-            assert len(run_xml_filepath) == 1
-            
-            d[c_dir]['run_xml'] = run_xml_filepath[0]
-            
-        ###############################
-        # scores.tar.gz
-        # restrict to only compressed files, so in case there are *.md5 files
-        # we don't get confused.
-        scores_filepath = []
-        for pattern in ['scores*.tar.bz2', 'scores*.tar.gz', 'scores*.tgz']:
-            scores_filepath += glob.glob(os.path.join(c_dir_path, pattern))
-        
-        if len(scores_filepath) == 0:
-            d[c_dir]['scores'] = None
-        else:
-            # No duplicates
-            assert len(scores_filepath) == 1
-            
-            d[c_dir]['scores'] = scores_filepath[0]
-        
-    return d
-
-    
-def cn_mTobp(cn_m):
-    """
-    Converts CN-M (i.e. C1-33, C1-26, C4-28) cycle information into
-    number of base pairs.
-    """
-    pass
-
-
diff --git a/htsworkflow/frontend/samples/test_samples.py b/htsworkflow/frontend/samples/test_samples.py
deleted file mode 100644 (file)
index 38e0dc2..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-import datetime
-
-try:
-    import json
-except ImportError, e:
-    import simplejson as json
-
-from django.test import TestCase
-from django.test.utils import setup_test_environment, \
-     teardown_test_environment
-from django.db import connection
-from django.conf import settings
-
-from htsworkflow.frontend.samples.models import \
-        Affiliation, \
-        ExperimentType, \
-        Species, \
-        Library
-
-from htsworkflow.frontend.samples.views import \
-     library_dict, \
-     library_json
-
-from htsworkflow.frontend.auth import apidata
-from htsworkflow.util.conversion import unicode_or_none
-from htsworkflow.util.ethelp import validate_xhtml
-
-class LibraryTestCase(TestCase):
-    fixtures = ['initial_data.json',
-                'woldlab.json',
-                'test_samples.json']
-
-    def setUp(self):
-        create_db(self)
-
-    def testOrganism(self):
-        self.assertEquals(self.library_10001.organism(), 'human')
-
-    def testAffiliations(self):
-        self.library_10001.affiliations.add(self.affiliation_alice)
-        self.library_10002.affiliations.add(
-                self.affiliation_alice,
-                self.affiliation_bob
-        )
-        self.failUnless(len(self.library_10001.affiliations.all()), 1)
-        self.failUnless(self.library_10001.affiliation(), 'Alice')
-
-        self.failUnless(len(self.library_10002.affiliations.all()), 2)
-        self.failUnless(self.library_10001.affiliation(), 'Alice, Bob')
-
-
-class SampleWebTestCase(TestCase):
-    """
-    Test returning data from our database in rest like ways.
-    (like returning json objects)
-    """
-    fixtures = ['initial_data.json',
-                'woldlab.json',
-                'test_samples.json']
-
-    def test_library_info(self):
-        for lib in Library.objects.all():
-            lib_dict = library_dict(lib.id)
-            url = '/samples/library/%s/json' % (lib.id,)
-            lib_response = self.client.get(url, apidata)
-            self.failUnlessEqual(lib_response.status_code, 200)
-            lib_json = json.loads(lib_response.content)
-
-            for d in [lib_dict, lib_json]:
-                # amplified_from_sample is a link to the library table,
-                # I want to use the "id" for the data lookups not
-                # the embedded primary key.
-                # It gets slightly confusing on how to implement sending the right id
-                # since amplified_from_sample can be null
-                #self.failUnlessEqual(d['amplified_from_sample'], lib.amplified_from_sample)
-                self.failUnlessEqual(d['antibody_id'], lib.antibody_id)
-                self.failUnlessEqual(d['cell_line_id'], lib.cell_line_id)
-                self.failUnlessEqual(d['cell_line'], unicode_or_none(lib.cell_line))
-                self.failUnlessEqual(d['experiment_type'], lib.experiment_type.name)
-                self.failUnlessEqual(d['experiment_type_id'], lib.experiment_type_id)
-                self.failUnlessEqual(d['gel_cut_size'], lib.gel_cut_size)
-                self.failUnlessEqual(d['hidden'], lib.hidden)
-                self.failUnlessEqual(d['id'], lib.id)
-                self.failUnlessEqual(d['insert_size'], lib.insert_size)
-                self.failUnlessEqual(d['library_name'], lib.library_name)
-                self.failUnlessEqual(d['library_species'], lib.library_species.scientific_name)
-                self.failUnlessEqual(d['library_species_id'], lib.library_species_id)
-                self.failUnlessEqual(d['library_type_id'], lib.library_type_id)
-                if lib.library_type_id is not None:
-                    self.failUnlessEqual(d['library_type'], lib.library_type.name)
-                else:
-                    self.failUnlessEqual(d['library_type'], None)
-                    self.failUnlessEqual(d['made_for'], lib.made_for)
-                    self.failUnlessEqual(d['made_by'], lib.made_by)
-                    self.failUnlessEqual(d['notes'], lib.notes)
-                    self.failUnlessEqual(d['replicate'], lib.replicate)
-                    self.failUnlessEqual(d['stopping_point'], lib.stopping_point)
-                    self.failUnlessEqual(d['successful_pM'], lib.successful_pM)
-                    self.failUnlessEqual(d['undiluted_concentration'],
-                                         unicode(lib.undiluted_concentration))
-                # some specific tests
-                if lib.id == '10981':
-                    # test a case where there is no known status
-                    lane_set = {u'status': u'Unknown',
-                                u'paired_end': True,
-                                u'read_length': 75,
-                                u'lane_number': 1,
-                                u'lane_id': 1193,
-                                u'flowcell': u'303TUAAXX',
-                                u'status_code': None}
-                    self.failUnlessEqual(len(d['lane_set']), 1)
-                    self.failUnlessEqual(d['lane_set'][0], lane_set)
-                elif lib.id == '11016':
-                    # test a case where there is a status
-                    lane_set = {u'status': 'Good',
-                                u'paired_end': True,
-                                u'read_length': 75,
-                                u'lane_number': 5,
-                                u'lane_id': 1197,
-                                u'flowcell': u'303TUAAXX',
-                                u'status_code': 2}
-                    self.failUnlessEqual(len(d['lane_set']), 1)
-                    self.failUnlessEqual(d['lane_set'][0], lane_set)
-
-
-    def test_invalid_library_json(self):
-        """
-        Make sure we get a 404 if we request an invalid library id
-        """
-        response = self.client.get('/samples/library/nottheone/json', apidata)
-        self.failUnlessEqual(response.status_code, 404)
-
-
-    def test_invalid_library(self):
-        response = self.client.get('/library/nottheone/')
-        self.failUnlessEqual(response.status_code, 404)
-
-
-    def test_library_no_key(self):
-        """
-        Make sure we get a 302 if we're not logged in
-        """
-        response = self.client.get('/samples/library/10981/json')
-        self.failUnlessEqual(response.status_code, 403)
-        response = self.client.get('/samples/library/10981/json', apidata)
-        self.failUnlessEqual(response.status_code, 200)
-
-    def test_library_rdf(self):
-        import RDF
-        from htsworkflow.util.rdfhelp import get_model, \
-             dump_model, \
-             fromTypedNode, \
-             load_string_into_model, \
-             rdfNS, \
-             libraryOntology
-        model = get_model()
-
-        response = self.client.get('/library/10981/')
-        self.assertEqual(response.status_code, 200)
-        content = response.content
-        load_string_into_model(model, 'rdfa', content)
-
-        body = """prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
-        prefix libns: <http://jumpgate.caltech.edu/wiki/LibraryOntology#>
-
-        select ?library ?name ?library_id ?gel_cut ?made_by
-        where {
-           ?library a libns:library ;
-                    libns:name ?name ;
-                    libns:library_id ?library_id ;
-                    libns:gel_cut ?gel_cut ;
-                    libns:made_by ?made_by
-        }"""
-        query = RDF.SPARQLQuery(body)
-        for r in query.execute(model):
-            self.assertEqual(fromTypedNode(r['library_id']), u'10981')
-            self.assertEqual(fromTypedNode(r['name']),
-                             u'Paired End Multiplexed Sp-BAC')
-            self.assertEqual(fromTypedNode(r['gel_cut']), 400)
-            self.assertEqual(fromTypedNode(r['made_by']), u'Igor')
-
-        state = validate_xhtml(content)
-        if state is not None:
-            self.assertTrue(state)
-
-        # validate a library page.
-        from htsworkflow.util.rdfhelp import add_default_schemas
-        from htsworkflow.util.rdfinfer import Infer
-        add_default_schemas(model)
-        inference = Infer(model)
-        errmsgs = list(inference.run_validation())
-        self.assertEqual(len(errmsgs), 0)
-
-    def test_library_index_rdfa(self):
-        from htsworkflow.util.rdfhelp import \
-             add_default_schemas, get_model, load_string_into_model, \
-             dump_model
-        from htsworkflow.util.rdfinfer import Infer
-
-        model = get_model()
-        add_default_schemas(model)
-        inference = Infer(model)
-
-        response = self.client.get('/library/')
-        self.assertEqual(response.status_code, 200)
-        load_string_into_model(model, 'rdfa', response.content)
-
-        errmsgs = list(inference.run_validation())
-        self.assertEqual(len(errmsgs), 0)
-
-        body =  """prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
-        prefix libns: <http://jumpgate.caltech.edu/wiki/LibraryOntology#>
-
-        select ?library ?library_id ?name ?species ?species_name
-        where {
-           ?library a libns:Library .
-           OPTIONAL { ?library libns:library_id ?library_id . }
-           OPTIONAL { ?library libns:species ?species .
-                      ?species libns:species_name ?species_name . }
-           OPTIONAL { ?library libns:name ?name . }
-        }"""
-        bindings = set(['library', 'library_id', 'name', 'species', 'species_name'])
-        query = RDF.SPARQLQuery(body)
-        count = 0
-        for r in query.execute(model):
-            count += 1
-            for name, value in r.items():
-                self.assertTrue(name in bindings)
-                self.assertTrue(value is not None)
-
-        self.assertEqual(count, len(Library.objects.filter(hidden=False)))
-
-        state = validate_xhtml(response.content)
-        if state is not None: self.assertTrue(state)
-
-
-# The django test runner flushes the database between test suites not cases,
-# so to be more compatible with running via nose we flush the database tables
-# of interest before creating our sample data.
-def create_db(obj):
-    obj.species_human = Species.objects.get(pk=8)
-    obj.experiment_rna_seq = ExperimentType.objects.get(pk=4)
-    obj.affiliation_alice = Affiliation.objects.get(pk=1)
-    obj.affiliation_bob = Affiliation.objects.get(pk=2)
-
-    Library.objects.all().delete()
-    obj.library_10001 = Library(
-        id = "10001",
-        library_name = 'C2C12 named poorly',
-        library_species = obj.species_human,
-        experiment_type = obj.experiment_rna_seq,
-        creation_date = datetime.datetime.now(),
-        made_for = 'scientist unit 2007',
-        made_by = 'microfludics system 7321',
-        stopping_point = '2A',
-        undiluted_concentration = '5.01',
-        hidden = False,
-    )
-    obj.library_10001.save()
-    obj.library_10002 = Library(
-        id = "10002",
-        library_name = 'Worm named poorly',
-        library_species = obj.species_human,
-        experiment_type = obj.experiment_rna_seq,
-        creation_date = datetime.datetime.now(),
-        made_for = 'scientist unit 2007',
-        made_by = 'microfludics system 7321',
-        stopping_point = '2A',
-        undiluted_concentration = '5.01',
-        hidden = False,
-    )
-    obj.library_10002.save()
-
-try:
-    import RDF
-    HAVE_RDF = True
-
-    rdfNS = RDF.NS("http://www.w3.org/1999/02/22-rdf-syntax-ns#")
-    xsdNS = RDF.NS("http://www.w3.org/2001/XMLSchema#")
-    libNS = RDF.NS("http://jumpgate.caltech.edu/wiki/LibraryOntology#")
-except ImportError,e:
-    HAVE_RDF = False
-
-
-class TestRDFaLibrary(TestCase):
-    fixtures = ['initial_data.json',
-                'woldlab.json',
-                'test_samples.json']
-
-    def test_parse_rdfa(self):
-        model = get_rdf_memory_model()
-        parser = RDF.Parser(name='rdfa')
-        url = '/library/10981/'
-        lib_response = self.client.get(url)
-        self.failIfEqual(len(lib_response.content), 0)
-
-        parser.parse_string_into_model(model,
-                                       lib_response.content,
-                                       'http://localhost'+url)
-        # http://jumpgate.caltech.edu/wiki/LibraryOntology#affiliation>
-        self.check_literal_object(model, ['Bob'], p=libNS['affiliation'])
-        self.check_literal_object(model, ['Multiplexed'], p=libNS['experiment_type'])
-        self.check_literal_object(model, ['400'], p=libNS['gel_cut'])
-        self.check_literal_object(model, ['Igor'], p=libNS['made_by'])
-        self.check_literal_object(model, ['Paired End Multiplexed Sp-BAC'], p=libNS['name'])
-        self.check_literal_object(model, ['Drosophila melanogaster'], p=libNS['species_name'])
-
-        self.check_uri_object(model,
-                              [u'http://localhost/lane/1193'],
-                              p=libNS['has_lane'])
-
-        fc_uri = RDF.Uri('http://localhost/flowcell/303TUAAXX/')
-        self.check_literal_object(model,
-                                  [u"303TUAAXX"],
-                                  s=fc_uri, p=libNS['flowcell_id'])
-
-    def check_literal_object(self, model, values, s=None, p=None, o=None):
-        statements = list(model.find_statements(
-            RDF.Statement(s,p,o)))
-        self.failUnlessEqual(len(statements), len(values),
-                        "Couln't find %s %s %s" % (s,p,o))
-        for s in statements:
-            self.failUnless(s.object.literal_value['string'] in values)
-
-
-    def check_uri_object(self, model, values, s=None, p=None, o=None):
-        statements = list(model.find_statements(
-            RDF.Statement(s,p,o)))
-        self.failUnlessEqual(len(statements), len(values),
-                        "Couln't find %s %s %s" % (s,p,o))
-        for s in statements:
-            self.failUnless(unicode(s.object.uri) in values)
-
-
-
-def get_rdf_memory_model():
-    storage = RDF.MemoryStorage()
-    model = RDF.Model(storage)
-    return model
-
-def suite():
-    from unittest import TestSuite, defaultTestLoader
-    suite = TestSuite()
-    suite.addTests(defaultTestLoader.loadTestsFromTestCase(LibraryTestCase))
-    suite.addTests(defaultTestLoader.loadTestsFromTestCase(SampleWebTestCase))
-    suite.addTests(defaultTestLoader.loadTestsFromTestCase(TestRDFaLibrary))
-    return suite
-
-if __name__ == "__main__":
-    from unittest import main
-    main(defaultTest="suite")
diff --git a/htsworkflow/frontend/samples/urls.py b/htsworkflow/frontend/samples/urls.py
deleted file mode 100644 (file)
index 570b1db..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-from django.conf.urls import patterns, url
-
-urlpatterns = patterns('',
-    url(r"^library/(?P<library_id>\w+)/json", 'htsworkflow.frontend.samples.views.library_json'),
-    url(r"^species/(?P<species_id>\w+)/json", 'htsworkflow.frontend.samples.views.species_json'),
-    url(r"^species/(?P<species_id>\w+)", 'htsworkflow.frontend.samples.views.species'),
-    url(r"^antibody/$", 'htsworkflow.frontend.samples.views.antibodies'),
-)
diff --git a/htsworkflow/frontend/samples/views.py b/htsworkflow/frontend/samples/views.py
deleted file mode 100644 (file)
index fcd5314..0000000
+++ /dev/null
@@ -1,564 +0,0 @@
-# Create your views here.
-import StringIO
-import logging
-import os
-import sys
-
-try:
-    import json
-except ImportError, e:
-    import simplejson as json
-
-from django.views.decorators.csrf import csrf_exempt
-from django.core.exceptions import ObjectDoesNotExist
-from django.http import HttpResponse, HttpResponseRedirect, Http404
-from django.shortcuts import render_to_response, get_object_or_404
-from django.template import RequestContext
-from django.template.loader import get_template
-from django.contrib.auth.decorators import login_required
-from django.conf import settings
-
-from htsworkflow.frontend.auth import require_api_key
-from htsworkflow.frontend.experiments.models import FlowCell, Lane, LANE_STATUS_MAP
-from htsworkflow.frontend.experiments.admin import LaneOptions
-from htsworkflow.frontend.samples.changelist import HTSChangeList
-from htsworkflow.frontend.samples.models import Antibody, Library, Species, HTSUser
-from htsworkflow.frontend.samples.admin import LibraryOptions
-from htsworkflow.frontend.samples.results import get_flowcell_result_dict
-from htsworkflow.frontend.bcmagic.forms import BarcodeMagicForm
-from htsworkflow.pipelines import runfolder
-from htsworkflow.pipelines.eland import ResultLane
-from htsworkflow.pipelines.samplekey import SampleKey
-from htsworkflow.util.conversion import unicode_or_none, parse_flowcell_id
-from htsworkflow.util import makebed
-from htsworkflow.util import opener
-
-
-
-LANE_LIST = [1,2,3,4,5,6,7,8]
-SAMPLES_CONTEXT_DEFAULTS = {
-    'app_name': 'Flowcell/Library Tracker',
-    'bcmagic': BarcodeMagicForm()
-}
-
-LOGGER = logging.getLogger(__name__)
-
-def count_lanes(lane_set):
-    single = 0
-    paired = 1
-    short_read = 0
-    medium_read = 1
-    long_read = 2
-    counts = [[0,0,0,],[0,0,0]]
-
-    for lane in lane_set.all():
-        if lane.flowcell.paired_end:
-            lane_type = paired
-        else:
-            lane_type = single
-        if lane.flowcell.read_length < 40:
-            read_type = short_read
-        elif lane.flowcell.read_length < 100:
-            read_type = medium_read
-        else:
-            read_type = long_read
-        counts[lane_type][read_type] += 1
-
-    return counts
-
-def create_library_context(cl):
-    """
-     Create a list of libraries that includes how many lanes were run
-    """
-    records = []
-    #for lib in library_items.object_list:
-    for lib in cl.result_list:
-       summary = {}
-       summary['library'] = lib
-       summary['library_id'] = lib.id
-       summary['library_name'] = lib.library_name
-       summary['species_name' ] = lib.library_species.scientific_name
-       if lib.amplified_from_sample is not None:
-           summary['amplified_from'] = lib.amplified_from_sample.id
-       else:
-           summary['amplified_from'] = ''
-       lanes_run = count_lanes(lib.lane_set)
-       # suppress zeros
-       for row in xrange(len(lanes_run)):
-           for col in xrange(len(lanes_run[row])):
-               if lanes_run[row][col] == 0:
-                   lanes_run[row][col] = ''
-       summary['lanes_run'] = lanes_run
-       summary['is_archived'] = lib.is_archived()
-       records.append(summary)
-    cl.result_count = unicode(cl.paginator._count)
-    return {'library_list': records }
-
-
-def library(request, todo_only=False):
-    queryset = Library.objects.filter(hidden__exact=0)
-    filters = {'hidden__exact': 0}
-    if todo_only:
-        filters['lane'] = None
-    # build changelist
-    fcl = HTSChangeList(request, Library,
-        list_filter=['affiliations', 'library_species'],
-        search_fields=['id', 'library_name', 'amplified_from_sample__id'],
-        list_per_page=200,
-        model_admin=LibraryOptions(Library, None),
-        extra_filters=filters
-    )
-
-    context = { 'cl': fcl, 'title': 'Library Index', 'todo_only': todo_only}
-    context.update(create_library_context(fcl))
-    t = get_template('samples/library_index.html')
-    c = RequestContext(request, context)
-    return HttpResponse( t.render(c) )
-
-
-def library_not_run(request):
-    return library(request, todo_only=True)
-
-
-def library_to_flowcells(request, lib_id):
-    """
-    Display information about all the flowcells a library has been run on.
-    """
-    try:
-        lib = Library.objects.get(id=lib_id)
-    except:
-        raise Http404('Library %s does not exist' % (lib_id,))
-
-    flowcell_list = []
-    flowcell_run_results = {} # aka flowcells we're looking at
-    for lane in lib.lane_set.all():
-        fc = lane.flowcell
-        flowcell_id, id = parse_flowcell_id(fc.flowcell_id)
-        if flowcell_id not in flowcell_run_results:
-            flowcell_run_results[flowcell_id] = get_flowcell_result_dict(flowcell_id)
-        flowcell_list.append((fc.flowcell_id, lane.lane_number))
-
-    flowcell_list.sort()
-    lane_summary_list = []
-    eland_results = []
-    for fc, lane_number in flowcell_list:
-        lane_summary, err_list = _summary_stats(fc, lane_number, lib_id)
-        lane_summary_list.extend(lane_summary)
-
-        eland_results.extend(_make_eland_results(fc, lane_number, flowcell_run_results))
-
-    context = {
-        'page_name': 'Library Details',
-        'lib': lib,
-        'eland_results': eland_results,
-        'lane_summary_list': lane_summary_list,
-    }
-    context.update(SAMPLES_CONTEXT_DEFAULTS)
-
-    return render_to_response(
-        'samples/library_detail.html',
-        context,
-        context_instance = RequestContext(request))
-
-def lanes_for(request, username=None):
-    """
-    Generate a report of recent activity for a user
-    """
-    query = {}
-    if username is not None:
-        user = HTSUser.objects.get(username=username)
-        query.update({'library__affiliations__users__id':user.id})
-    fcl = HTSChangeList(request, Lane,
-        list_filter=[],
-        search_fields=['flowcell__flowcell_id', 'library__id', 'library__library_name'],
-        list_per_page=200,
-        model_admin=LaneOptions,
-        queryset=Lane.objects.filter(**query)
-    )
-
-    context = { 'lanes': fcl, 'title': 'Lane Index'}
-
-    return render_to_response(
-        'samples/lanes_for.html',
-        context,
-        context_instance = RequestContext(request)
-    )
-
-
-def summaryhtm_fc_cnm(request, flowcell_id, cnm):
-    """
-    returns a Summary.htm file if it exists.
-    """
-    fc_id, status = parse_flowcell_id(flowcell_id)
-    d = get_flowcell_result_dict(fc_id)
-
-    if d is None:
-        return HttpResponse('<b>Results for Flowcell %s not found.</b>' % (fc_id))
-
-    if cnm not in d:
-        return HttpResponse('<b>Results for Flowcell %s; %s not found.</b>' % (fc_id, cnm))
-
-    summary_filepath = d[cnm]['summary']
-
-    if summary_filepath is None:
-        return HttpResponse('<b>Summary.htm for Flowcell %s; %s not found.</b>' % (fc_id, cnm))
-
-    f = open(summary_filepath, 'r')
-
-    return HttpResponse(f)
-
-
-def result_fc_cnm_eland_lane(request, flowcell_id, cnm, lane):
-    """
-    returns an eland_file upon calling.
-    """
-    fc_id, status = parse_flowcell_id(flowcell_id)
-    d = get_flowcell_result_dict(fc_id)
-
-    if d is None:
-        return HttpResponse('<b>Results for Flowcell %s not found.</b>' % (fc_id))
-
-    if cnm not in d:
-        return HttpResponse('<b>Results for Flowcell %s; %s not found.</b>' % (fc_id, cnm))
-
-    erd = d[cnm]['eland_results']
-    lane = int(lane)
-
-    if lane not in erd:
-        return HttpResponse('<b>Results for Flowcell %s; %s; lane %s not found.</b>' % (fc_id, cnm, lane))
-
-    filepath = erd[lane]
-
-    #f = opener.autoopen(filepath, 'r')
-    # return HttpResponse(f, content_type="application/x-elandresult")
-
-    f = open(filepath, 'r')
-    return HttpResponse(f, content_type='application/x-bzip2')
-
-
-
-def bedfile_fc_cnm_eland_lane_ucsc(request, fc_id, cnm, lane):
-    """
-    returns a bed file for a given flowcell, CN-M (i.e. C1-33), and lane (ucsc compatible)
-    """
-    return bedfile_fc_cnm_eland_lane(request, fc_id, cnm, lane, ucsc_compatible=True)
-
-
-def bedfile_fc_cnm_eland_lane(request, flowcell_id, cnm, lane, ucsc_compatible=False):
-    """
-    returns a bed file for a given flowcell, CN-M (i.e. C1-33), and lane
-    """
-    fc_id, status = parse_flowcell_id(flowcell_id)
-    d = get_flowcell_result_dict(fc_id)
-
-    if d is None:
-        return HttpResponse('<b>Results for Flowcell %s not found.</b>' % (fc_id))
-
-    if cnm not in d:
-        return HttpResponse('<b>Results for Flowcell %s; %s not found.</b>' % (fc_id, cnm))
-
-    erd = d[cnm]['eland_results']
-    lane = int(lane)
-
-    if lane not in erd:
-        return HttpResponse('<b>Results for Flowcell %s; %s; lane %s not found.</b>' % (fc_id, cnm, lane))
-
-    filepath = erd[lane]
-
-    # Eland result file
-    fi = opener.autoopen(filepath, 'r')
-    # output memory file
-
-    name, description = makebed.make_description( fc_id, lane )
-
-    bedgen = makebed.make_bed_from_eland_generator(fi, name, description)
-
-    if ucsc_compatible:
-        return HttpResponse(bedgen)
-    else:
-        return HttpResponse(bedgen, content_type="application/x-bedfile")
-
-
-def _summary_stats(flowcell_id, lane_id, library_id):
-    """
-    Return the summary statistics for a given flowcell, lane, and end.
-    """
-    fc_id, status = parse_flowcell_id(flowcell_id)
-    fc_result_dict = get_flowcell_result_dict(fc_id)
-
-    summary_list = []
-    err_list = []
-
-    if fc_result_dict is None:
-        err_list.append('Results for Flowcell %s not found.' % (fc_id))
-        return (summary_list, err_list)
-
-    for cycle_width in fc_result_dict:
-        xmlpath = fc_result_dict[cycle_width]['run_xml']
-
-        if xmlpath is None:
-            err_list.append('Run xml for Flowcell %s(%s) not found.' % (fc_id, cycle_width))
-            continue
-
-        run = runfolder.load_pipeline_run_xml(xmlpath)
-        # skip if we don't have available metadata.
-        if run.gerald is None or run.gerald.summary is None:
-            continue
-        
-        gerald_summary = run.gerald.summary.lane_results
-        key = SampleKey(lane=lane_id, sample='s')
-        eland_results = list(run.gerald.eland_results.find_keys(key))
-        key = SampleKey(lane=lane_id, sample=library_id)
-        eland_results.extend(run.gerald.eland_results.find_keys(key))
-        for key in eland_results:
-            eland_summary = run.gerald.eland_results.results[key]
-            # add information to lane_summary
-            eland_summary.flowcell_id = flowcell_id
-
-            read = key.read-1 if key.read is not None else 0
-            try:
-                eland_summary.clusters = gerald_summary[read][key.lane].cluster
-            except (IndexError, KeyError) as e:
-                eland_summary.clustes = None
-            eland_summary.cycle_width = cycle_width
-            if hasattr(eland_summary, 'genome_map'):
-                eland_summary.summarized_reads = runfolder.summarize_mapped_reads(
-                                                   eland_summary.genome_map,
-                                                   eland_summary.mapped_reads)
-
-            # grab some more information out of the flowcell db
-            flowcell = FlowCell.objects.get(flowcell_id=flowcell_id)
-            #pm_field = 'lane_%d_pM' % (lane_id)
-            lanes = flowcell.lane_set.filter(lane_number=lane_id)
-            eland_summary.flowcell = flowcell
-            eland_summary.lanes = lanes
-
-            summary_list.append(eland_summary)
-
-        #except Exception, e:
-        #    summary_list.append("Summary report needs to be updated.")
-        #    LOGGER.error("Exception: " + str(e))
-
-    return (summary_list, err_list)
-
-
-def get_eland_result_type(pathname):
-    """
-    Guess the eland result file type from the filename
-    """
-    path, filename = os.path.split(pathname)
-    if 'extended' in filename:
-        return 'extended'
-    elif 'multi' in filename:
-        return 'multi'
-    elif 'result' in filename:
-        return 'result'
-    else:
-        return 'unknown'
-
-def _make_eland_results(flowcell_id, lane_number, interesting_flowcells):
-    fc_id, status = parse_flowcell_id(flowcell_id)
-    cur_fc = interesting_flowcells.get(fc_id, None)
-    if cur_fc is None:
-      return []
-
-    flowcell = FlowCell.objects.get(flowcell_id=flowcell_id)
-    lanes = flowcell.lane_set.filter(lane_number=lane_number)
-    # Loop throw storage devices if a result has been archived
-    storage_id_list = []
-    if cur_fc is not None:
-        for lts in flowcell.longtermstorage_set.all():
-            for sd in lts.storage_devices.all():
-                # Use barcode_id if it exists
-                if sd.barcode_id is not None and sd.barcode_id != '':
-                    storage_id_list.append(sd.barcode_id)
-                # Otherwise use UUID
-                else:
-                    storage_id_list.append(sd.uuid)
-
-    # Formatting for template use
-    if len(storage_id_list) == 0:
-        storage_ids = None
-    else:
-        storage_ids = ', '.join([ '<a href="/inventory/%s/">%s</a>' % (s,s) for s in storage_id_list ])
-
-    results = []
-    for cycle in cur_fc.keys():
-        result_path = cur_fc[cycle]['eland_results'].get(lanes[0], None)
-        result_link = make_result_link(fc_id, cycle, lanes[0], result_path)
-        results.append({'flowcell_id': fc_id,
-                        'flowcell': flowcell,
-                        'run_date': flowcell.run_date,
-                        'cycle': cycle,
-                        'lane': lanes[0],
-                        'summary_url': make_summary_url(flowcell_id, cycle),
-                        'result_url': result_link[0],
-                        'result_label': result_link[1],
-                        'bed_url': result_link[2],
-                        'storage_ids': storage_ids
-        })
-    return results
-
-def make_summary_url(flowcell_id, cycle_name):
-    url = '/results/%s/%s/summary/' % (flowcell_id, cycle_name)
-    return url
-
-def make_result_link(flowcell_id, cycle_name, lane, eland_result_path):
-    if eland_result_path is None:
-        return ("", "", "")
-
-    result_type = get_eland_result_type(eland_result_path)
-    result_url = '/results/%s/%s/eland_result/%s' % (flowcell_id, cycle_name, lane)
-    result_label = 'eland %s' % (result_type,)
-    bed_url = None
-    if result_type == 'result':
-       bed_url_pattern = '/results/%s/%s/bedfile/%s'
-       bed_url = bed_url_pattern % (flowcell_id, cycle_name, lane)
-
-    return (result_url, result_label, bed_url)
-
-def _files(flowcell_id, lane):
-    """
-    Sets up available files for download
-    """
-    lane = int(lane)
-
-    flowcell_id, id = parse_flowcell_id(flowcell_id)
-    d = get_flowcell_result_dict(flowcell_id)
-
-    if d is None:
-        return ''
-
-    output = []
-
-    # c_name == 'CN-M' (i.e. C1-33)
-    for c_name in d:
-
-        if d[c_name]['summary'] is not None:
-            output.append('<a href="/results/%s/%s/summary/">summary(%s)</a>' \
-                          % (flowcell_id, c_name, c_name))
-
-        erd = d[c_name]['eland_results']
-        if lane in erd:
-            result_type = get_eland_result_type(erd[lane])
-            result_url_pattern = '<a href="/results/%s/%s/eland_result/%s">eland %s(%s)</a>'
-            output.append(result_url_pattern % (flowcell_id, c_name, lane, result_type, c_name))
-            if result_type == 'result':
-                bed_url_pattern = '<a href="/results/%s/%s/bedfile/%s">bedfile(%s)</a>'
-                output.append(bed_url_pattern % (flowcell_id, c_name, lane, c_name))
-
-    if len(output) == 0:
-        return ''
-
-    return '(' + '|'.join(output) + ')'
-
-def library_id_to_admin_url(request, lib_id):
-    lib = Library.objects.get(id=lib_id)
-    return HttpResponseRedirect('/admin/samples/library/%s' % (lib.id,))
-
-def library_dict(library_id):
-    """
-    Given a library id construct a dictionary containing important information
-    return None if nothing was found
-    """
-    try:
-        lib = Library.objects.get(id = library_id)
-    except Library.DoesNotExist, e:
-        return None
-
-    #lane_info = lane_information(lib.lane_set)
-    lane_info = []
-    for lane in lib.lane_set.all():
-        lane_info.append( {'flowcell':lane.flowcell.flowcell_id,
-                           'lane_number': lane.lane_number,
-                           'lane_id': lane.id,
-                           'paired_end': lane.flowcell.paired_end,
-                           'read_length': lane.flowcell.read_length,
-                           'status_code': lane.status,
-                           'status': LANE_STATUS_MAP[lane.status]} )
-
-    info = {
-        # 'affiliations'?
-        # 'aligned_reads': lib.aligned_reads,
-        #'amplified_into_sample': lib.amplified_into_sample, # into is a colleciton...
-        #'amplified_from_sample_id': lib.amplified_from_sample,
-        #'antibody_name': lib.antibody_name(), # we have no antibodies.
-        'antibody_id': lib.antibody_id,
-        'cell_line_id': lib.cell_line_id,
-        'cell_line': unicode_or_none(lib.cell_line),
-        'experiment_type': lib.experiment_type.name,
-        'experiment_type_id': lib.experiment_type_id,
-        'gel_cut_size': lib.gel_cut_size,
-        'hidden': lib.hidden,
-        'id': lib.id,
-        'insert_size': lib.insert_size,
-        'lane_set': lane_info,
-        'library_id': lib.id,
-        'library_name': lib.library_name,
-        'library_species': lib.library_species.scientific_name,
-        'library_species_id': lib.library_species_id,
-        #'library_type': lib.library_type.name,
-        'library_type_id': lib.library_type_id,
-        'made_for': lib.made_for,
-        'made_by': lib.made_by,
-        'notes': lib.notes,
-        'replicate': lib.replicate,
-        'stopping_point': lib.stopping_point,
-        'successful_pM': unicode_or_none(lib.successful_pM),
-        'undiluted_concentration': unicode_or_none(lib.undiluted_concentration)
-        }
-    if lib.library_type_id is None:
-        info['library_type'] = None
-    else:
-        info['library_type'] = lib.library_type.name
-    return info
-
-@csrf_exempt
-def library_json(request, library_id):
-    """
-    Return a json formatted library dictionary
-    """
-    require_api_key(request)
-    # what validation should we do on library_id?
-
-    lib = library_dict(library_id)
-    if lib is None:
-        raise Http404
-
-    lib_json = json.dumps(lib)
-    return HttpResponse(lib_json, content_type='application/json')
-
-@csrf_exempt
-def species_json(request, species_id):
-    """
-    Return information about a species.
-    """
-    raise Http404
-
-def species(request, species_id):
-    species = get_object_or_404(Species, id=species_id)
-
-    context = RequestContext(request,
-                             { 'species': species })
-
-    return render_to_response("samples/species_detail.html", context)
-
-def antibodies(request):
-    context = RequestContext(request,
-                             {'antibodies': Antibody.objects.order_by('antigene')})
-    return render_to_response("samples/antibody_index.html", context)
-
-@login_required
-def user_profile(request):
-    """
-    Information about the user
-    """
-    context = {
-                'page_name': 'User Profile',
-                'media': '',
-                #'bcmagic': BarcodeMagicForm(),
-                #'select': 'settings',
-            }
-    context.update(SAMPLES_CONTEXT_DEFAULTS)
-    return render_to_response('registration/profile.html', context,
-                              context_instance=RequestContext(request))
diff --git a/htsworkflow/frontend/static/css/admin_flowcell.css b/htsworkflow/frontend/static/css/admin_flowcell.css
deleted file mode 100644 (file)
index 19e7589..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-.strikeout { text-decoration: line-through; }
-
diff --git a/htsworkflow/frontend/static/css/app.css b/htsworkflow/frontend/static/css/app.css
deleted file mode 100644 (file)
index 1725e15..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-#header {
-    background: #7F99BE url(/static/img/layout-browser-hd-bg.gif) repeat-x center;
-}
-#header h1 {
-    font-size: 16px;
-    color: #fff;
-    font-weight: normal;
-    padding: 5px 10px;
-}
-
-#left_bar {
-    position: absolute;
-    top: 5px;
-    left: 5px;
-    width: 172px;
-    height: auto;
-    min-height: 600px;
-}
-
-#main {
-    position: relative;
-    /* background: #BBBBFF; */
-    width:auto;
-    min-width:120px;
-    padding: 10px;
-    margin:0px 0px 0px 175px;
-    min-height:600px;
-}
-
-.icon_button {
-   border-style: solid;
-   border-width: 1px;
-   padding: 1px;
-   margin: 0px 0px -2px 2px;
-}
-
-div.msg {
-    color: white;
-    background: #880000;
-}
-
-div.htswdetail {
-    clear: both;
-    margin: 0;
-    padding: 0;
-}
-div.htswdetail table, div.htswdetail td {
-    border-style: solid;
-}
-div.htswdetail table {
-    border-width: 0 0 1px 1px;
-    border-spacing: 0;
-    border-collapse: collapse;
-}
-div.htswdetail td {
-    margin: 0;
-    padding: 3px;
-    border-width: 1px 1px 0 0;
-}
-div.htswdetail thead {
-    text-align: center;
-}
-div.htswdetail tbody {
-    text-align: left;
-  }
-div.htswdetail h1,
-div.htswdetail h2
-{
-    font-size: 150%;
-}
-
-div.htswdetail h3 {
-     font-size: 125%;
-     margin: 0;
-}
-
-div.htswdetail h4,
-div.htswdetail h5,
-div.htswdetail ul,
-div.htswdetail ol,
-div.htswdetail li
-{
-  list-style: none;
-  margin: 0;
-}
-
-div.htswdetail ul,
-div.htswdetail ol
-{
-  margin-bottom: .5em;
-}
-
-/* style library detail headers */
-div#librarydetail {
-  margin: 0;
-  padding: 0;
-}
-div#librarydetail table, div#librarydetail td {
-  border-style: solid;
-}
-div#librarydetail table {
-  border-width: 0 0 1px 1px;
-  border-spacing: 0;
-  border-collapse: collapse;
-}
-div#librarydetail td {
-  margin: 0;
-  padding: 3px;
-  border-width: 1px 1px 0 0;
-}
-div#librarydetail thead {
-  text-align: center;
-  }
-div#librarydetail tbody {
-  text-align: right;
-}
-div#librarydetail h1,
-div#librarydetail h2
-{
-  font-size: 150%;
-}
-
-div#librarydetail h3 {
-   font-size: 125%;
-   margin: 0;
-}
-
-div#librarydetail h4,
-div#librarydetail h5,
-div#librarydetail ul,
-div#librarydetail ol,
-div#librarydetail li
-{
-  list-style: none;
-  margin: 0;
-}
-
-div#librarydetail ul,
-div#librarydetail ol
-{
-  margin-bottom: .5em;
-}
-
-div.library_identity {
-  clear: left; float: left; margin: 5px; }
-div.library_sample_detail { float: left; margin: 5px; }
-div.library_library_detail { float: left; margin: 5px; }
-div.library_statistics { clear: both; border: 1px; }
-
-div.flowcell_identity { clear: left; float: left; margin: 5px;}
-div.flowcell_lane_detail { float: left; margin: 5px; }
\ No newline at end of file
diff --git a/htsworkflow/frontend/static/css/base.css b/htsworkflow/frontend/static/css/base.css
deleted file mode 100644 (file)
index 9760d67..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
-    DJANGO Admin
-    by Wilson Miner wilson@lawrence.com
-*/
-
-/* Block IE 5 */
-@import "null.css?\"\{";
-
-/* Import other styles */
-@import url('global.css');
-@import url('layout.css');
-
-/* Import patch for IE 6 Windows */
-/*\*/ @import "patch-iewin.css"; /**/
diff --git a/htsworkflow/frontend/static/css/changelists.css b/htsworkflow/frontend/static/css/changelists.css
deleted file mode 100644 (file)
index bde1636..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-@import url('base.css');
-
-/* CHANGELISTS */
-#changelist {  margin-bottom: 0pm; }
-#changelist table { display: block; }
-#changelist table.filtered { overflow-y: scroll; }
-.change-list .filtered table { border-right:1px solid #ddd;  }
-.change-list .filtered { min-height:400px; }
-.change-list .filtered { background:white url(../img/changelist-bg.gif) top right repeat-y !important; }
-.change-list .filtered table, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { width:auto !important; }
-.change-list .filtered table tbody th { padding-right:1em; }
-#changelist .toplinks { border-bottom:1px solid #ccc !important; }
-#changelist .paginator { color:#666; border-top:1px solid #eee; border-bottom:1px solid #eee; background:white url(../img/nav-bg.gif) 0 180% repeat-x; overflow:hidden; }
-.change-list .filtered .paginator { border-right:1px solid #ddd; }
-
-/*  CHANGELIST TABLES  */
-#changelist table thead th { white-space:nowrap; }
-#changelist table tbody td { border-left: 1px solid #ddd;  }
-#changelist table tfoot { color: #666; }
-#changelist tbody { }
-
-/*  TOOLBAR  */
-#changelist #toolbar { padding:3px; border-bottom:1px solid #ddd; background:#e1e1e1 url(../img/nav-bg.gif) top left repeat-x; color:#666; }
-#changelist #toolbar form input { font-size:11px; padding:1px 2px; }
-#changelist #toolbar form #searchbar { padding:2px; }
-#changelist #changelist-search img { vertical-align:middle; }
-
-/*  FILTER COLUMN  */
-/*position:absolute; top:0; right:0; z-index:1000; */
-#changelist-filter { float: right;
-                     width: 20em;
-                     border-left:1px solid #ddd; margin:0; 
-                     background:#efefef; 
-                     overflow-y: scroll; }
-#changelist-filter h2 { font-size:11px; padding:2px 5px; border-bottom:1px solid #ddd; }
-#changelist-filter h3 { font-size:12px; margin-bottom:0; }
-#changelist-filter ul { padding-left:0;margin-left:10px; }
-#changelist-filter li { list-style-type:none; margin-left:0; padding-left:0; }
-#changelist-filter a { color:#999; }
-#changelist-filter a:hover { color:#036; }
-#changelist-filter li.selected { border-left:5px solid #ccc; padding-left:5px;margin-left:-10px; }
-#changelist-filter li.selected a { color:#5b80b2 !important; }
-
-/*  DATE DRILLDOWN  */
-.change-list ul.toplinks { display:block; background:white url(../img/nav-bg-reverse.gif) 0 -10px repeat-x; border-top:1px solid white; float:left;  padding:0 !important;  margin:0 !important; width:100%; }
-.change-list ul.toplinks li { float: left; width: 9em; padding:3px 6px; font-weight: bold; list-style-type:none; }
-.change-list ul.toplinks .date-back a { color:#999; }
-.change-list ul.toplinks .date-back a:hover { color:#036; }
-
-/* PAGINATOR */
-.paginator { font-size:11px; padding-top:10px; padding-bottom:10px; line-height:22px; margin:0; border-top:1px solid #ddd; }
-.paginator a:link, .paginator a:visited { padding:2px 6px; border:solid 1px #ccc; background:white; text-decoration:none; }
-.paginator a.showall { padding:0 !important; border:none !important; }
-.paginator a.showall:hover { color:#036 !important; background:transparent !important; }
-.paginator .end { border-width:2px !important; margin-right:6px; }
-.paginator .this-page { padding:2px 6px; font-weight:bold; font-size:13px; vertical-align:top; }
-.paginator a:hover { color:white; background:#5b80b2; border-color:#036; }
diff --git a/htsworkflow/frontend/static/css/click-table.css b/htsworkflow/frontend/static/css/click-table.css
deleted file mode 100644 (file)
index 27b793c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-table, td {
-  border-style: solid;
-}
-table {
-  border-width: 0 0 1px 1px;
-  border-spacing: 0;
-  border-collapse: collapse;
-}
-thead {
-  text-align: center;
-}
-td {
-  margin: 0;
-  padding: 4px;
-  border-width: 1px 1px 0 0;
-}
-td.cell_list a {
-  display: block;
-}
-
diff --git a/htsworkflow/frontend/static/css/dashboard.css b/htsworkflow/frontend/static/css/dashboard.css
deleted file mode 100644 (file)
index 05808bc..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* DASHBOARD */
-
-.dashboard .module table th {
-    width: 100%;
-}
-
-.dashboard .module table td {
-    white-space: nowrap;
-}
-
-.dashboard .module table td a {
-    display: block;
-    padding-right: .6em;
-}
-
-/* RECENT ACTIONS MODULE */
-
-.module ul.actionlist {
-    margin-left: 0;
-}
-
-ul.actionlist li {
-    list-style-type: none;
-}
-
-ul.actionlist li {
-    overflow: hidden;
-    text-overflow: ellipsis;
-    -o-text-overflow: ellipsis;
-}
diff --git a/htsworkflow/frontend/static/css/data-browse-index.css b/htsworkflow/frontend/static/css/data-browse-index.css
deleted file mode 100644 (file)
index 59119bf..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-@import url('changelists.css');
-@import url('click-table.css');
diff --git a/htsworkflow/frontend/static/css/forms.css b/htsworkflow/frontend/static/css/forms.css
deleted file mode 100644 (file)
index a4b145f..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-@import url('base.css');
-@import url('widgets.css');
-
-/* FORM ROWS */
-.form-row { overflow:hidden; padding:8px 12px; font-size:11px; border-bottom:1px solid #eee; }
-.form-row img, .form-row input { vertical-align:middle; }
-form .form-row p { padding-left:0; font-size:11px; }
-
-/* FORM LABELS */
-form h4 { margin:0 !important; padding:0 !important; border:none !important; }
-label { font-weight:normal !important; color:#666; font-size:12px; }
-.required label, label.required { font-weight:bold !important; color:#333 !important; }
-
-/* RADIO BUTTONS */
-form ul.radiolist li { list-style-type:none; }
-form ul.radiolist label { float:none; display:inline; }
-form ul.inline { margin-left:0; padding:0; }
-form ul.inline li { float:left; padding-right:7px; }
-
-/* ALIGNED FIELDSETS */
-.aligned label { display:block; padding:3px 10px 0 0; float:left; width:8em; }
-.colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField { width:350px; }
-form .aligned p, form .aligned ul { margin-left:7em; padding-left:30px; }
-form .aligned table p { margin-left:0; padding-left:0; }
-form .aligned p.help { padding-left:38px; }
-.aligned .vCheckboxLabel { float:none !important; display:inline; padding-left:4px; }
-.colM .aligned .vLargeTextField, .colM .aligned .vXMLLargeTextField { width:610px; }
-.checkbox-row p.help { margin-left:0; padding-left:0 !important; }
-fieldset .field-box { float:left; margin-right: 20px; }
-
-/* WIDE FIELDSETS */
-.wide label { width:15em !important; }
-form .wide p { margin-left:15em; }
-form .wide p.help { padding-left:38px; }
-.colM fieldset.wide .vLargeTextField, .colM fieldset.wide .vXMLLargeTextField { width:450px; }
-
-/* COLLAPSED FIELDSETS */
-fieldset.collapsed * { display:none; }
-fieldset.collapsed h2, fieldset.collapsed { display:block !important; }
-fieldset.collapsed h2 { background-image:url(../img/nav-bg.gif); background-position:bottom left; color:#999; }
-fieldset.collapsed .collapse-toggle { padding:3px 5px !important; background:transparent; display:inline !important;}
-
-/* MONOSPACE TEXTAREAS */
-fieldset.monospace textarea { font-family:"Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace; }
-
-/* SUBMIT ROW */
-.submit-row { padding:5px 7px; text-align:right; background:white url(../img/nav-bg.gif) 0 100% repeat-x; border:1px solid #ccc; margin:5px 0; overflow:hidden; }
-.submit-row input { margin:0 0 0 5px; }
-.submit-row p { margin:0.3em; }
-.submit-row p.deletelink-box { float: left; }
-.submit-row .deletelink { background:url(../img/icon_deletelink.gif) 0 50% no-repeat; padding-left:14px; }
-
-/* CUSTOM FORM FIELDS */
-.vSelectMultipleField { vertical-align:top !important; }
-.vCheckboxField { border:none; }
-.vDateField, .vTimeField { margin-right:2px; }
-.vURLField { width:30em; }
-.vLargeTextField, .vXMLLargeTextField { width:48em; }
-.flatpages-flatpage #id_content { height:40.2em; }
-.module table .vPositiveSmallIntegerField { width:2.2em; }
-.vTextField { width:20em; }
-.vIntegerField { width:5em; }
-.vForeignKeyRawIdAdminField { width: 5em; }
-
-/* INLINES */
-.inline-group {padding:0; border:1px solid #ccc; margin:10px 0;}
-.inline-group .aligned label { width: 8em; }
-
-.inline-related {position:relative;}
-.inline-related h3 {margin: 0; color:#666; padding:3px 5px; font-size:11px; background:#e1e1e1 url(../img/nav-bg.gif) top left repeat-x; border-bottom:1px solid #ddd;}
-.inline-related h3 span.delete {padding-left:20px; position:absolute; top:2px; right:10px;}
-.inline-related h3 span.delete label {margin-left:2px; font-size: 11px;}
-.inline-related fieldset {margin: 0; background:#fff; border: none; }
-.inline-related fieldset.module h3 { margin:0; padding:2px 5px 3px 5px; font-size:11px; text-align:left; font-weight:bold; background:#bcd; color:#fff; }
-.inline-related.tabular fieldset.module table {width:100%;}
-.last-related fieldset {border: none;}
-
-.inline-group .tabular tr.has_original td {padding-top:2em;}
-.inline-group .tabular tr td.original { padding:2px 0 0 0; width:0; _position:relative; }
-.inline-group .tabular th.original {width:0px; padding:0;}
-.inline-group .tabular td.original p {position:absolute; left:0; height:1.1em; padding:2px 7px; overflow:hidden; font-size:9px; font-weight:bold; color:#666; _width:700px;     }
-.inline-group ul.tools {padding:0; margin: 0; list-style:none;}
-.inline-group ul.tools li {display:inline; padding:0 5px;}
-.inline-group ul.tools a.add {background:url(../img/icon_addlink.gif) 0 50% no-repeat; padding-left:14px;}
diff --git a/htsworkflow/frontend/static/css/global.css b/htsworkflow/frontend/static/css/global.css
deleted file mode 100644 (file)
index adc2539..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-body { margin:0; padding:0; font-size:14px; font-family:"Lucida Grande","DejaVu Sans","Bitstream Vera Sans",Verdana,Arial,sans-serif; color:#333; background:#fff; }
-
-/* LINKS */
-a:link, a:visited { color: #5b80b2; text-decoration:none; }
-a:hover { color: #036; }
-a img { border:none; }
-a.section:link, a.section:visited { color: white; text-decoration:none; }
-
-/* GLOBAL DEFAULTS */
-p, ol, ul, dl { margin:.2em 0 .8em 0; }
-p { padding:0; line-height:140%; }
-
-h1,h2,h3,h4,h5 { font-weight:bold; }
-h1 { font-size:18px; color:#666; padding:0 6px 0 0; margin:0 0 .2em 0; }
-h2 { font-size:16px; margin:1em 0 .5em 0; }
-h2.subhead { font-weight:normal;margin-top:0; }
-h3 { font-size:14px; margin:.8em 0 .3em 0; color:#666; font-weight:bold; }
-h4 { font-size:12px; margin:1em 0 .8em 0; padding-bottom:3px; }
-h5 { font-size:10px; margin:1.5em 0 .5em 0; color:#666; text-transform:uppercase; letter-spacing:1px; }
-
-ul li { list-style-type:square; padding:1px 0; }
-ul.plainlist { margin-left:0 !important; }
-ul.plainlist li { list-style-type:none; }
-li ul { margin-bottom:0; }
-li, dt, dd { font-size:11px; line-height:14px; }
-dt { font-weight:bold; margin-top:4px; }
-dd { margin-left:0; }
-
-form { margin:0; padding:0; }
-fieldset { margin:0; padding:0; }
-
-blockquote { font-size:11px; color:#777; margin-left:2px; padding-left:10px; border-left:5px solid #ddd; }
-code, pre { font-family:"Bitstream Vera Sans Mono", Monaco, "Courier New", Courier, monospace; background:inherit; color:#666; font-size:11px; }
-pre.literal-block { margin:10px; background:#eee; padding:6px 8px; }
-code strong { color:#930; }
-hr { clear:both; color:#eee; background-color:#eee; height:1px; border:none; margin:0; padding:0; font-size:1px; line-height:1px; }
-
-/* TEXT STYLES & MODIFIERS */
-.small { font-size:11px; }
-.tiny { font-size:10px; }
-p.tiny { margin-top:-2px; }
-.mini { font-size:9px; }
-p.mini { margin-top:-3px; }
-.help, p.help { font-size:10px !important; color:#999; }
-p img, h1 img, h2 img, h3 img, h4 img, td img { vertical-align:middle; }
-.quiet, a.quiet:link, a.quiet:visited { color:#999 !important;font-weight:normal !important; }
-.quiet strong { font-weight:bold !important; }
-.float-right { float:right; }
-.float-left { float:left; }
-.clear { clear:both; }
-.align-left { text-align:left; }
-.align-right { text-align:right; }
-.example { margin:10px 0; padding:5px 10px; background:#efefef; }
-.nowrap { white-space:nowrap; }
-
-/* TABLES */
-table { border-collapse:collapse; border-color:#ccc; }
-td, th { font-size:11px; line-height:13px; border-bottom:1px solid #eee; vertical-align:top; padding:5px; font-family:"Lucida Grande", Verdana, Arial, sans-serif; }
-th { text-align:left; font-size:12px; font-weight:bold; }
-thead th, 
-tfoot td { color:#666; padding:2px 5px; font-size:11px; background:#e1e1e1 url(../img/nav-bg.gif) top left repeat-x; border-left:1px solid #ddd; border-bottom:1px solid #ddd; }
-tfoot td { border-bottom:none; border-top:1px solid #ddd; }
-thead th:first-child, 
-tfoot td:first-child { border-left:none !important; }
-thead th.optional { font-weight:normal !important; }
-fieldset table { border-right:1px solid #eee; }
-tr.row-label td { font-size:9px; padding-top:2px; padding-bottom:0; border-bottom:none; color:#666; margin-top:-1px; }
-tr.alt { background:#f6f6f6; }
-.row1 { background:#EDF3FE; }
-.row2 { background:white; }
-
-/* SORTABLE TABLES */
-thead th a:link, thead th a:visited { color:#666; display:block; }
-table thead th.sorted { background-position:bottom left !important; }
-table thead th.sorted a { padding-right:13px; }
-table thead th.ascending a { background:url(../img/arrow-down.gif) right .4em no-repeat; }
-table thead th.descending a { background:url(../img/arrow-up.gif) right .4em no-repeat; }
-
-/* ORDERABLE TABLES */
-table.orderable tbody tr td:hover { cursor:move; }
-table.orderable tbody tr td:first-child { padding-left:14px; background-image:url(../img/nav-bg-grabber.gif); background-repeat:repeat-y; }
-table.orderable-initalized .order-cell, body>tr>td.order-cell { display:none; }
-
-/* FORM DEFAULTS */
-input, textarea, select { margin:2px 0; padding:2px 3px; vertical-align:middle; font-family:"Lucida Grande", Verdana, Arial, sans-serif; font-weight:normal; font-size:11px; }
-textarea { vertical-align:top !important; }
-input[type=text], input[type=password], textarea, select, .vTextField { border:1px solid #ccc; }
-
-/*  FORM BUTTONS  */
-.button, input[type=submit], input[type=button], .submit-row input { background:white url(../img/nav-bg.gif) bottom repeat-x; padding:3px; color:black; border:1px solid #bbb; border-color:#ddd #aaa #aaa #ddd; }
-.button:active, input[type=submit]:active, input[type=button]:active { background-image:url(../img/nav-bg-reverse.gif); background-position:top; }
-.button.default, input[type=submit].default, .submit-row input.default { border:2px solid #5b80b2; background:#7CA0C7 url(../img/default-bg.gif) bottom repeat-x; font-weight:bold; color:white; float:right; }
-.button.default:active, input[type=submit].default:active { background-image:url(../img/default-bg-reverse.gif); background-position:top; }
-
-/* MODULES */
-.module { border:1px solid #ccc; margin-bottom:5px; background:white; }
-.module p, .module ul, .module h3, .module h4, .module dl, .module pre { padding-left:10px; padding-right:10px; }
-.module blockquote { margin-left:12px; }
-.module ul, .module ol { margin-left:1.5em; }
-.module h3 { margin-top:.6em; }
-.module h2, .module caption, .inline-group h2 { margin:0; padding:2px 5px 3px 5px; font-size:11px; text-align:left; font-weight:bold; background:#7CA0C7 url(../img/default-bg.gif) top left repeat-x; color:white; }
-.module table { border-collapse: collapse; }
-
-/* MESSAGES & ERRORS */
-ul.messagelist { padding:0 0 5px 0; margin:0; }
-ul.messagelist li { font-size:12px; display:block; padding:4px 5px 4px 25px; margin:0 0 3px 0; border-bottom:1px solid #ddd; color:#666; background:#ffc url(../img/icon_success.gif) 5px .3em no-repeat; }
-.errornote { font-size:12px !important; display:block; padding:4px 5px 4px 25px; margin:0 0 3px 0; border:1px solid red; color:red;background:#ffc url(../img/icon_error.gif) 5px .3em no-repeat; }
-ul.errorlist { margin:0 !important; padding:0 !important; }
-.errorlist li { font-size:12px !important; display:block; padding:4px 5px 4px 25px; margin:0 0 3px 0; border:1px solid red; color:white; background:red url(../img/icon_alert.gif) 5px .3em no-repeat; }
-td ul.errorlist { margin:0 !important; padding:0 !important; }
-td ul.errorlist li { margin:0 !important; }
-.errors { background:#ffc; }
-.errors input, .errors select { border:1px solid red; }
-div.system-message { background: #ffc; margin: 10px; padding: 6px 8px; font-size: .8em; }
-div.system-message p.system-message-title { padding:4px 5px 4px 25px; margin:0; color:red; background:#ffc url(../img/icon_error.gif) 5px .3em no-repeat; }
-.description { font-size:12px; padding:5px 0 0 12px; }
-
-/* BREADCRUMBS */
-div.breadcrumbs { background:white url(../img/nav-bg-reverse.gif) 0 -10px repeat-x; padding:2px 8px 3px 8px; font-size:11px;  color:#999;  border-top:1px solid white; border-bottom:1px solid #ccc; text-align:left; }
-
-/* ACTION ICONS */
-.addlink { padding-left:12px; background:url(../img/icon_addlink.gif) 0 .2em no-repeat; }
-.changelink { padding-left:12px; background:url(../img/icon_changelink.gif) 0 .2em no-repeat; }
-.deletelink { padding-left:12px; background:url(../img/icon_deletelink.gif) 0 .25em no-repeat; }
-a.deletelink:link, a.deletelink:visited { color:#CC3434; }
-a.deletelink:hover { color:#993333; }
-
-/* OBJECT TOOLS */
-.object-tools { font-size:10px; font-weight:bold; font-family:Arial,Helvetica,sans-serif; padding-left:0; float:right; position:relative; margin-top:-2.4em; margin-bottom:-2em; }
-.form-row .object-tools { margin-top:5px; margin-bottom:5px; float:none; height:2em; padding-left:3.5em; }
-.object-tools li { display:block; float:left; background:url(../img/tool-left.gif) 0 0 no-repeat; padding:0 0 0 8px; margin-left:2px; height:16px; }
-.object-tools li:hover { background:url(../img/tool-left_over.gif) 0 0 no-repeat; }
-.object-tools a:link, .object-tools a:visited { display:block; float:left; color:white; padding:.1em 14px .1em 8px; height:14px; background:#999 url(../img/tool-right.gif) 100% 0 no-repeat; }
-.object-tools a:hover, .object-tools li:hover a { background:#5b80b2 url(../img/tool-right_over.gif) 100% 0 no-repeat; }
-.object-tools a.viewsitelink, .object-tools a.golink { background:#999 url(../img/tooltag-arrowright.gif) top right no-repeat; padding-right:28px; }
-.object-tools a.viewsitelink:hover, .object-tools a.golink:hover { background:#5b80b2 url(../img/tooltag-arrowright_over.gif) top right no-repeat; }
-.object-tools a.addlink { background:#999 url(../img/tooltag-add.gif) top right no-repeat; padding-right:28px; }
-.object-tools a.addlink:hover { background:#5b80b2 url(../img/tooltag-add_over.gif) top right no-repeat; }
-
-/* OBJECT HISTORY */
-table#change-history { width:100%; }
-table#change-history tbody th { width:16em; }
diff --git a/htsworkflow/frontend/static/css/htsw.css b/htsworkflow/frontend/static/css/htsw.css
deleted file mode 100644 (file)
index 49e3965..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#header {
-    background: #7F99BE url(/static/img/layout-browser-hd-bg.gif) repeat-x center;
-}
-#header h1 {
-    font-size: 16px;
-    color: #fff;
-    font-weight: normal;
-    padding: 5px 10px;
-}
-
-#left_bar {
-    position: absolute;
-    top: 5px;
-    left: 5px;
-    width: 172px;
-    height: auto;
-    min-height: 600px;
-    
-    
-}
-
-#main {
-    position: relative;
-    /* background: #BBBBFF; */
-    width:auto;
-    min-width:120px;
-    padding: 10px;
-    margin:0px 0px 0px 175px;
-    min-height:600px;
-}
-
-div.msg {
-    color: white;
-    background: #880000;
-}
\ No newline at end of file
diff --git a/htsworkflow/frontend/static/css/layout.css b/htsworkflow/frontend/static/css/layout.css
deleted file mode 100644 (file)
index bab2121..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* PAGE STRUCTURE */
-#container { position:relative; width:100%; min-width:760px; padding:0; }
-#content { margin:10px 15px; }
-#header { width:100%; }
-#content-main { float:left; width:100%; }
-#content-related { float:right; width:18em; position:relative; margin-right:-19em; }
-#footer { clear:both; padding:10px; }
-
-/*  COLUMN TYPES  */
-.colMS { margin-right:20em !important; }
-.colSM { margin-left:20em !important; }
-.colSM #content-related { float:left; margin-right:0; margin-left:-19em; }
-.colSM #content-main { float:right; }
-.popup .colM { width:95%; }
-.subcol { float:left; width:46%; margin-right:15px; }
-.dashboard #content { width:500px; }
-
-/*  HEADER  */
-#header { background:#417690; color:#ffc; overflow:hidden; }
-#header a:link, #header a:visited { color:white; }
-#header a:hover { text-decoration:underline; }
-#branding h1 { padding:0 10px; font-size:18px; margin:8px 0; font-weight:normal; color:#f4f379; }
-#branding h2 { padding:0 10px; font-size:14px; margin:-8px 0 8px 0; font-weight:normal; color:#ffc; }
-#user-tools { position:absolute; top:0; right:0; padding:1.2em 10px; font-size:11px; text-align:right; }
-
-/* SIDEBAR */
-#content-related h3 { font-size:12px; color:#666; margin-bottom:3px; }
-#content-related h4 { font-size:11px; }
-#content-related .module h2 { background:#eee url(../img/nav-bg.gif) bottom left repeat-x; color:#666; }
diff --git a/htsworkflow/frontend/static/css/null.css b/htsworkflow/frontend/static/css/null.css
deleted file mode 100644 (file)
index 1a93f22..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/* Nothing to see here. Dummy file to feed to the high pass filter which hides CSS from IE5/win. Details: http://tantek.com/CSS/Examples/highpass.html */
\ No newline at end of file
diff --git a/htsworkflow/frontend/static/css/patch-iewin.css b/htsworkflow/frontend/static/css/patch-iewin.css
deleted file mode 100644 (file)
index 2de1305..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-* html #container { position:static; } /* keep header from flowing off the page */
-* html .colMS #content-related { margin-right:0; margin-left:10px; position:static; } /* put the right sidebars back on the page */
-* html .colSM #content-related { margin-right:10px; margin-left:-115px; position:static; } /* put the left sidebars back on the page */
-* html .form-row { height:1%; }
-* html .dashboard #content { width:768px; } /* proper fixed width for dashboard in IE6 */
-* html .dashboard #content-main { width:535px; } /* proper fixed width for dashboard in IE6 */
-* html #changelist-filter ul { margin-right:-10px; } /* fix right margin for changelist filters in IE6 */
-* html .change-list .filtered { height:400px; } /* IE ignores min-height, but treats height as if it were min-height */
\ No newline at end of file
diff --git a/htsworkflow/frontend/static/css/wide_account_number.css b/htsworkflow/frontend/static/css/wide_account_number.css
deleted file mode 100644 (file)
index 6eee12b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#id_account_number { width: 50em; }
\ No newline at end of file
diff --git a/htsworkflow/frontend/static/img/changelist-bg.gif b/htsworkflow/frontend/static/img/changelist-bg.gif
deleted file mode 100644 (file)
index 7f46994..0000000
Binary files a/htsworkflow/frontend/static/img/changelist-bg.gif and /dev/null differ
diff --git a/htsworkflow/frontend/static/img/default-bg.gif b/htsworkflow/frontend/static/img/default-bg.gif
deleted file mode 100644 (file)
index 003aeca..0000000
Binary files a/htsworkflow/frontend/static/img/default-bg.gif and /dev/null differ
diff --git a/htsworkflow/frontend/static/img/dna80.png b/htsworkflow/frontend/static/img/dna80.png
deleted file mode 100644 (file)
index 845c255..0000000
Binary files a/htsworkflow/frontend/static/img/dna80.png and /dev/null differ
diff --git a/htsworkflow/frontend/static/img/hdd_unmount.png b/htsworkflow/frontend/static/img/hdd_unmount.png
deleted file mode 100755 (executable)
index 4972e55..0000000
Binary files a/htsworkflow/frontend/static/img/hdd_unmount.png and /dev/null differ
diff --git a/htsworkflow/frontend/static/img/icon_searchbox.png b/htsworkflow/frontend/static/img/icon_searchbox.png
deleted file mode 100644 (file)
index 8ab579e..0000000
Binary files a/htsworkflow/frontend/static/img/icon_searchbox.png and /dev/null differ
diff --git a/htsworkflow/frontend/static/img/layout-browser-hd-bg.gif b/htsworkflow/frontend/static/img/layout-browser-hd-bg.gif
deleted file mode 100644 (file)
index 29bf23f..0000000
Binary files a/htsworkflow/frontend/static/img/layout-browser-hd-bg.gif and /dev/null differ
diff --git a/htsworkflow/frontend/static/img/nav-bg-reverse.gif b/htsworkflow/frontend/static/img/nav-bg-reverse.gif
deleted file mode 100644 (file)
index f11029f..0000000
Binary files a/htsworkflow/frontend/static/img/nav-bg-reverse.gif and /dev/null differ
diff --git a/htsworkflow/frontend/static/img/nav-bg.gif b/htsworkflow/frontend/static/img/nav-bg.gif
deleted file mode 100644 (file)
index f8402b8..0000000
Binary files a/htsworkflow/frontend/static/img/nav-bg.gif and /dev/null differ
diff --git a/htsworkflow/frontend/static/img/readme.txt b/htsworkflow/frontend/static/img/readme.txt
deleted file mode 100644 (file)
index 81c803e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-This copyright and license notice covers the following images:
- * hdd_unmount.png
-************************************************************************
-
-TITLE: Crystal Project Icons
-AUTHOR:        Everaldo Coelho
-SITE:  http://www.everaldo.com
-CONTACT: everaldo@everaldo.com
-
-Copyright (c)  2006-2007  Everaldo Coelho.
diff --git a/htsworkflow/frontend/static/img/s.gif b/htsworkflow/frontend/static/img/s.gif
deleted file mode 100644 (file)
index 1d11fa9..0000000
Binary files a/htsworkflow/frontend/static/img/s.gif and /dev/null differ
diff --git a/htsworkflow/frontend/static/js/bcmagic-ext.js b/htsworkflow/frontend/static/js/bcmagic-ext.js
deleted file mode 100644 (file)
index a3d9c6c..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-//-----------------------------------------------
-// Barcode Magic JavaScript
-// Authors: Brandon W. King
-// Feb. 2009
-//-----------------------------------------------
-
-//---------------------------------------
-// BCMagic Core Processing AJAX Callback
-//---------------------------------------
-//var bcmagic_process_callback = function(data, textStatus) {
-var bcmagic_process_callback = function(response, opt) {
-    //FIXME: temp bypass hack
-    var textStatus = 'success';
-    if (textStatus != 'success')
-    {
-        bcmagic_message('AJAX Status: '+textStatus);
-        return;
-    }
-    
-    var data = Ext.decode(response.responseText);
-    
-    for (key in data)
-    {
-        if (key == 'mode')
-        {
-            if (data['mode'] == 'clear')
-            {
-                bcmagic_status('','');
-            }
-            else if (data['mode'] == 'redirect')
-            {
-                if ('url' in data)
-                {
-                    bcmagic_redirect(data['url']);
-                }
-                else
-                {
-                    bcmagic_status('Error', 'No redirect URL provided by server');
-                }
-            }
-            else if (data['mode'] == 'autofill')
-            {
-                bcmagic_autofill(data['field'], data['value'])
-            }
-            else {
-                bcmagic_message('Message recieved!');
-                bcmagic_status(data['mode'], data['status']);    
-            }
-            
-        }
-        if (key == 'msg')
-        {
-            bcmagic_message(data['msg']);
-        }
-    }
-}
-
-var bcmagic_callback = function(data, textStatus)
-{
-    if (textStatus != 'success')
-        bcmagic_message('Failed!');
-    else
-        bcmagic_message('Success!');
-}
-
-var bcmagic_process = function(){
-    var magic = Ext.get("bcmagic_input_field");
-    var text = magic.getValue();
-    magic.dom.value = '';
-    magic.focus();
-    
-    //var bcm_mode = $("#id_bcm_mode");
-    //var mode = bcm_mode.attr('value');
-    var mode = 'default';
-    
-    // Show what we have captured
-    bcmagic_message('Sent command to server');
-    //$.post('/bcmagic/magic/', {'text': text, 'bcm_mode': mode}, bcmagic_process_callback, 'json');
-    Ext.Ajax.request({
-        url: '/bcmagic/magic/',
-        success: bcmagic_process_callback,
-        failure: function (r, o) { quick_msg('Some AJAX Fail!'); },
-        params: {'text': text, 'bcm_mode': mode}
-    });
-}
-
-var bcmagic_keyhandler = function(e) {
-    //Process upon enter key as input.
-    if (e.which == 13)
-      bcmagic_process();
-}
-
-//---------------------------------------
-// Utility Functions
-//---------------------------------------
-var bcmagic_message = function(text)
-{
-    // Show message
-    //$("#bcm_msg").html(text);
-    quick_msg(text);
-    
-    // clear message after 3000ms
-    /*
-    setTimeout(function() {
-        $("#bcm_msg").html('');
-        }, 3000);
-    */
-}
-
-var bcmagic_status = function(state, text)
-{
-    //var msg = $('#bcm_status');
-    if (state.length > 0 || text.length > 0)
-        quick_msg(state+': '+text);
-    //else
-    //    msg.html('');
-}
-
-
-var bcmagic_redirect = function(url)
-{
-    bcmagic_message('Redirecting to:' + url);
-    window.location = url;
-}
-
-var bcmagic_autofill = function(field, val)
-{
-    var txtbox = $('#'+field);
-    txtbox.attr('value', val);
-    
-    var input_fields = $('form input').not(':hidden').not('[type=submit]');
-    
-    // Count the number of text fields which have been filled in.
-    var count = 0;
-    input_fields.each( function(){
-                   if(this.value.length > 0){
-                        count = count + 1;
-                   }
-                });
-    
-    // If the number of text fields filled in is equal to the number of input_fields in the form, submit the form!
-    if (count == input_fields.length)
-    {
-        bcmagic_status('Form Full', 'Form is now full and ready to process');
-        form = $('form');
-        form.submit();
-        form.reset();
-    
-    }
-    else
-    {
-        bcmagic_status('Form Fill Count', 'Count(' + count +') - Total(' + input_fields.length + ')');
-    }
-}
-
-//---------------------------------------
-// Main Ready Function
-//---------------------------------------
-/*$(document).ready(function() {
-        
-        // Grab initial focus on magic text input
-        $("#id_magic").focus();
-        
-        // Set some initial text
-        //$("#id_magic").attr('value','Moo cow!');
-        
-        // Trigger when enterkey is pressed
-        $("#id_magic").keypress(bcmagic_keyhandler)
-});*/
\ No newline at end of file
diff --git a/htsworkflow/frontend/static/js/htsw-inventory.js b/htsworkflow/frontend/static/js/htsw-inventory.js
deleted file mode 100644 (file)
index 3cbca3f..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-
-var inventory_item_dblclick_handler = function(grid, row_index, e){
-    //quick_msg('Choose Row: ' + row_index);
-    var rec = grid.getStore().getAt(row_index);
-    //quick_msg('UUID: ' + rec.get('uuid'));
-    goto_url('/inventory/'+rec.get('uuid')+'/');
-}
-
-var getInventoryDataGrid = function(){
-    
-    var Item = Ext.data.Record.create([
-       { name: 'uuid' },
-       { name: 'barcode_id'},
-       { name: 'model_id'},
-       { name: 'part_number'},
-       { name: 'lot_number'},
-       { name: 'vendor'},
-       { name: 'creation_date'/*, type: 'date', dateFormat: 'n/j h:ia'*/},
-       { name: 'modified_date'/*, type: 'date', dateFormat: 'n/j h:ia'*/},
-       { name: 'location'},
-       { name: 'status'},
-       { name: 'flowcells'},
-       { name: 'type'}
-    ]);
-    
-    var inventoryReader = new Ext.data.JsonReader(
-        {
-            totalProperty: "results",
-            root: "rows",
-            idProperty: "uuid"
-        },
-        Item
-    );
-    
-    /*
-    var inventoryStore = new Ext.data.JsonStore({
-       autoDestory: true,
-       url: '/inventory/data/items/',
-       storeId: 'item_store',
-       
-    });
-    */
-    
-    var grid = new Ext.grid.GridPanel({
-        store: new Ext.data.GroupingStore({
-            reader: inventoryReader,
-            url: '/inventory/data/items/',
-            storeId: 'item_group_store',
-            groupField: 'type',
-            sortInfo: { field: 'creation_date', direction: "DESC"},
-            autoLoad: true
-        }),
-    
-        columns: [
-            {id: 'uuid', header:"UUID", width: 32, sortable: true, dataIndex: 'uuid'},
-            {header: 'Barcode ID', width: 20, sortable: true, dataIndex: 'barcode_id'},
-            {header: 'Location', width: 20, sortable: true, dataIndex: 'location'},
-            {header: 'Model', width: 20, sortable: true, dataIndex: 'model_id'},
-            {header: 'Part #', width: 20, sortable: true, dataIndex: 'part_number', hidden: true},
-            {header: 'Lot #', width: 20, sortable: true, dataIndex: 'lot_number', hidden: true},
-            {header: 'Vendor', width: 20, sortable: true, dataIndex: 'vendor'},
-            {header: 'Creation Date', width: 20, sortable: true, dataIndex: 'creation_date'/*, renderer: Ext.util.Format.dateRenderer('Y/m/d')*/},
-            {header: 'Modified Date', width: 20, sortable: true, dataIndex: 'modified_date', hidden: true/*, renderer: Ext.util.Format.dateRenderer('Y/m/d')*/},
-            {header: 'Status', width: 20, sortable: true, dataIndex: 'status', hidden: true},
-            {header: 'Stored Flowcells', width: 20, sortable: true, dataIndex: 'flowcells'},
-            {header: 'Type', width: 20, sortable: true, dataIndex: 'type', hidden: true}
-        ],
-        
-        view: new Ext.grid.GroupingView({
-           forceFit: true,
-           groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})'
-        }),
-        
-        frame: true,
-        width: 'auto',
-        //height: 500,
-        //autoHeight: true,
-        collapsible: false,
-        title: "Inventory Index",
-        iconCls: 'icon-grid',
-        id: 'inventory_item_panel',
-        stateId: 'inventory_item_panel_state',
-        stateful: true
-        //renderTo: 'grid_target'
-    });
-    
-    grid.on('rowdblclick', inventory_item_dblclick_handler);
-    
-    return grid;
-}
\ No newline at end of file
diff --git a/htsworkflow/frontend/static/js/htsw.js b/htsworkflow/frontend/static/js/htsw.js
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/htsworkflow/frontend/static/js/jquery.timers-1.0.0.js b/htsworkflow/frontend/static/js/jquery.timers-1.0.0.js
deleted file mode 100644 (file)
index db866cf..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/**\r
- * jQuery.timers - Timer abstractions for jQuery\r
- * Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)\r
- * Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).\r
- * Date: 2008/08/26\r
- *\r
- * @author Blair Mitchelmore\r
- * @version 1.0.0\r
- *\r
- **/\r
-\r
-jQuery.fn.extend({\r
-       everyTime: function(interval, label, fn, times, belay) {\r
-               return this.each(function() {\r
-                       jQuery.timer.add(this, interval, label, fn, times, belay);\r
-               });\r
-       },\r
-       oneTime: function(interval, label, fn) {\r
-               return this.each(function() {\r
-                       jQuery.timer.add(this, interval, label, fn, 1);\r
-               });\r
-       },\r
-       stopTime: function(label, fn) {\r
-               return this.each(function() {\r
-                       jQuery.timer.remove(this, label, fn);\r
-               });\r
-       }\r
-});\r
-\r
-jQuery.extend({\r
-       timer: {\r
-               guid: 1,\r
-               global: {},\r
-               regex: /^([0-9]+)\s*(.*s)?$/,\r
-               powers: {\r
-                       // Yeah this is major overkill...\r
-                       'ms': 1,\r
-                       'cs': 10,\r
-                       'ds': 100,\r
-                       's': 1000,\r
-                       'das': 10000,\r
-                       'hs': 100000,\r
-                       'ks': 1000000\r
-               },\r
-               timeParse: function(value) {\r
-                       if (value == undefined || value == null)\r
-                               return null;\r
-                       var result = this.regex.exec(jQuery.trim(value.toString()));\r
-                       if (result[2]) {\r
-                               var num = parseInt(result[1], 10);\r
-                               var mult = this.powers[result[2]] || 1;\r
-                               return num * mult;\r
-                       } else {\r
-                               return value;\r
-                       }\r
-               },\r
-               add: function(element, interval, label, fn, times, belay) {\r
-                       var counter = 0;\r
-                       \r
-                       if (jQuery.isFunction(label)) {\r
-                               if (!times) \r
-                                       times = fn;\r
-                               fn = label;\r
-                               label = interval;\r
-                       }\r
-                       \r
-                       interval = jQuery.timer.timeParse(interval);\r
-\r
-                       if (typeof interval != 'number' || isNaN(interval) || interval <= 0)\r
-                               return;\r
-\r
-                       if (times && times.constructor != Number) {\r
-                               belay = !!times;\r
-                               times = 0;\r
-                       }\r
-                       \r
-                       times = times || 0;\r
-                       belay = belay || false;\r
-                       \r
-                       if (!element.$timers) \r
-                               element.$timers = {};\r
-                       \r
-                       if (!element.$timers[label])\r
-                               element.$timers[label] = {};\r
-                       \r
-                       fn.$timerID = fn.$timerID || this.guid++;\r
-                       \r
-                       var handler = function() {\r
-                               if (belay && this.inProgress) \r
-                                       return;\r
-                               this.inProgress = true;\r
-                               if ((++counter > times && times !== 0) || fn.call(element, counter) === false)\r
-                                       jQuery.timer.remove(element, label, fn);\r
-                               this.inProgress = false;\r
-                       };\r
-                       \r
-                       handler.$timerID = fn.$timerID;\r
-                       \r
-                       if (!element.$timers[label][fn.$timerID]) \r
-                               element.$timers[label][fn.$timerID] = window.setInterval(handler,interval);\r
-                       \r
-                       if ( !this.global[label] )\r
-                               this.global[label] = [];\r
-                       this.global[label].push( element );\r
-                       \r
-               },\r
-               remove: function(element, label, fn) {\r
-                       var timers = element.$timers, ret;\r
-                       \r
-                       if ( timers ) {\r
-                               \r
-                               if (!label) {\r
-                                       for ( label in timers )\r
-                                               this.remove(element, label, fn);\r
-                               } else if ( timers[label] ) {\r
-                                       if ( fn ) {\r
-                                               if ( fn.$timerID ) {\r
-                                                       window.clearInterval(timers[label][fn.$timerID]);\r
-                                                       delete timers[label][fn.$timerID];\r
-                                               }\r
-                                       } else {\r
-                                               for ( var fn in timers[label] ) {\r
-                                                       window.clearInterval(timers[label][fn]);\r
-                                                       delete timers[label][fn];\r
-                                               }\r
-                                       }\r
-                                       \r
-                                       for ( ret in timers[label] ) break;\r
-                                       if ( !ret ) {\r
-                                               ret = null;\r
-                                               delete timers[label];\r
-                                       }\r
-                               }\r
-                               \r
-                               for ( ret in timers ) break;\r
-                               if ( !ret ) \r
-                                       element.$timers = null;\r
-                       }\r
-               }\r
-       }\r
-});\r
-\r
-if (jQuery.browser.msie)\r
-       jQuery(window).one("unload", function() {\r
-               var global = jQuery.timer.global;\r
-               for ( var label in global ) {\r
-                       var els = global[label], i = els.length;\r
-                       while ( --i )\r
-                               jQuery.timer.remove(els[i], label);\r
-               }\r
-       });\r
diff --git a/htsworkflow/frontend/static/js/magicbc.js b/htsworkflow/frontend/static/js/magicbc.js
deleted file mode 100644 (file)
index b294abd..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-//-----------------------------------------------
-// Barcode Magic JavaScript
-// Authors: Brandon W. King
-// Feb. 2009
-//-----------------------------------------------
-
-//---------------------------------------
-// BCMagic Core Processing AJAX Callback
-//---------------------------------------
-var bcmagic_process_callback = function(data, textStatus) {
-    if (textStatus != 'success')
-    {
-        bcmagic_message('AJAX Status: '+textStatus);
-        return;
-    }
-    
-    for (key in data)
-    {
-        if (key == 'mode')
-        {
-            if (data['mode'] == 'clear')
-            {
-                bcmagic_status('','');
-            }
-            else if (data['mode'] == 'redirect')
-            {
-                if ('url' in data)
-                {
-                    bcmagic_redirect(data['url']);
-                }
-                else
-                {
-                    bcmagic_status('Error', 'No redirect URL provided by server');
-                }
-            }
-            else if (data['mode'] == 'autofill')
-            {
-                bcmagic_autofill(data['field'], data['value'])
-            }
-            else {
-                bcmagic_message('Message recieved!');
-                bcmagic_status(data['mode'], data['status']);    
-            }
-            
-        }
-        if (key == 'msg')
-        {
-            bcmagic_message(data['msg']);
-        }
-    }
-}
-
-var bcmagic_callback = function(data, textStatus)
-{
-    if (textStatus != 'success')
-        bcmagic_message('Failed!');
-    else
-        bcmagic_message('Success!');
-}
-
-var bcmagic_process = function(){
-    var magic = $("#id_magic");
-    var text = magic.attr('value');
-    magic.attr('value', '');
-    
-    var bcm_mode = $("#id_bcm_mode");
-    var mode = bcm_mode.attr('value');
-    
-    // Show what we have captured
-    bcmagic_message('Sent command to server');
-    $.post('/bcmagic/magic/', {'text': text, 'bcm_mode': mode}, bcmagic_process_callback, 'json');
-}
-
-var bcmagic_keyhandler = function(e) {
-    //Process upon enter key as input.
-    if (e.which == 13)
-      bcmagic_process();
-}
-
-//---------------------------------------
-// Utility Functions
-//---------------------------------------
-var bcmagic_message = function(text)
-{
-    // Show message
-    $("#bcm_msg").html(text);
-    
-    // clear message after 3000ms
-    setTimeout(function() {
-        $("#bcm_msg").html('');
-        }, 3000);
-}
-
-var bcmagic_status = function(state, text)
-{
-    var msg = $('#bcm_status');
-    if (state.length > 0 || text.length > 0)
-        msg.html('<b>'+state+':</b> '+text);
-    else
-        msg.html('');
-}
-
-
-var bcmagic_redirect = function(url)
-{
-    bcmagic_message('Redirecting to:' + url);
-    window.location = url;
-}
-
-var bcmagic_autofill = function(field, val)
-{
-    var txtbox = $('#'+field);
-    txtbox.attr('value', val);
-    
-    var input_fields = $('form input').not(':hidden').not('[type=submit]');
-    
-    // Count the number of text fields which have been filled in.
-    var count = 0;
-    input_fields.each( function(){
-                   if(this.value.length > 0){
-                        count = count + 1;
-                   }
-                });
-    
-    // If the number of text fields filled in is equal to the number of input_fields in the form, submit the form!
-    if (count == input_fields.length)
-    {
-        bcmagic_status('Form Full', 'Form is now full and ready to process');
-        form = $('form');
-        form.submit();
-        form.reset();
-    
-    }
-    else
-    {
-        bcmagic_status('Form Fill Count', 'Count(' + count +') - Total(' + input_fields.length + ')');
-    }
-}
-
-//---------------------------------------
-// Main Ready Function
-//---------------------------------------
-/*$(document).ready(function() {
-        
-        // Grab initial focus on magic text input
-        $("#id_magic").focus();
-        
-        // Set some initial text
-        //$("#id_magic").attr('value','Moo cow!');
-        
-        // Trigger when enterkey is pressed
-        $("#id_magic").keypress(bcmagic_keyhandler)
-});*/
\ No newline at end of file
diff --git a/htsworkflow/frontend/templates/404.html b/htsworkflow/frontend/templates/404.html
deleted file mode 100644 (file)
index 687b49a..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-<html>
-    <head>
-        <title>404 - Not Found</title>
-    </head>
-    <body>
-        <h1>404 - Not Found</h1>
-        <p>The URL you tried to reach does not appear to exist, 
-           if you have reason to believe this in error, please try again later.</p>
-    </body>
-</html>
-    
diff --git a/htsworkflow/frontend/templates/admin/auth/user/add_form.html b/htsworkflow/frontend/templates/admin/auth/user/add_form.html
deleted file mode 100644 (file)
index d3eaf3f..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-{% extends "admin/change_form.html" %}
-{% load i18n %}
-
-{% block after_field_sets %}
-
-<p>{% trans "First, enter a username and password. Then, you'll be able to edit more user options." %}</p>
-
-<fieldset class="module aligned">
-
-<div class="form-row">
-  {{ form.username.errors }}
-  {# TODO: get required class on label_tag #}
-  <label for="id_username" class="required">{% trans 'Username' %}:</label> {{ form.username }}
-  <p class="help">{{ form.username.help_text }}</p>
-</div>
-
-<div class="form-row">
-  {{ form.first_name.errors }}
-  {{ form.last_name.errors }}
- {# TODO: get required class on label_tag #}
-  <div class="field-box">
-  <label for="first_name" >{% trans 'First Name' %}:</label> {{ form.first_name }}
-  <p class="help">{{ form.first_name.help_text }}</p>
-  </div>  
-  <div class="field-box">
-  <label for="last_name" >{% trans 'Last Name' %}:</label> {{ form.last_name }}
-  <p class="help">{{ form.last_name.help_text }}</p>
-  </div>
-</div>
-
-<div class="form-row">
-  {{ form.password1.errors }}
-  {# TODO: get required class on label_tag #}
-  <label for="id_password1" class="required">{% trans 'Password' %}:</label> {{ form.password1 }}
-</div>
-
-<div class="form-row">
-  {{ form.password2.errors }}
-  {# TODO: get required class on label_tag #}
-  <label for="id_password2" class="required">{% trans 'Password (again)' %}:</label> {{ form.password2 }}
-  <p class="help">{% trans 'Enter the same password as above, for verification.' %}</p>
-</div>
-
-<script type="text/javascript">document.getElementById("id_username").focus();</script>
-
-</fieldset>
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/admin/base_site.html b/htsworkflow/frontend/templates/admin/base_site.html
deleted file mode 100644 (file)
index c212302..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-{% extends "admin/base.html" %}
-{% load i18n %}
-
-{% block title %}
-{{ title }}|{%trans "dev site admin" %}
-{% endblock %}
-
-{% block branding %}
-<h1 id="site-name" style="background-color:#cccccc;color:black">
-  {%block sitename %}
-    {% trans 'HTS Workflow Dev Server' %}
-  {%endblock%}
-</h1>
-{% endblock %}
-
-{% block nav-global %}{% endblock %}
diff --git a/htsworkflow/frontend/templates/admin/experiments/flowcell/change_form.html b/htsworkflow/frontend/templates/admin/experiments/flowcell/change_form.html
deleted file mode 100644 (file)
index 068fbfe..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{% extends "admin/change_form.html" %}
-{% load i18n %}
-{% block object-tools %}
-{% if change %}{% if not is_popup %}
-  <ul class="object-tools">
-    <li><a href="../../../../{{ app_label }}/started/{{ object_id }}/">{% trans "Started Email" %}</a></li>
-    <li><a href="history/" class="historylink">{% trans "History" %}</a></li>
-  {% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
-  </ul>
-{% endif %}{% endif %}
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/admin/index.html b/htsworkflow/frontend/templates/admin/index.html
deleted file mode 100644 (file)
index 66b6942..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-{% extends "admin/base_site.html" %}
-{% load i18n %}
-
-{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% load staticfiles %}{% static "css/dashboard.css" %}"/>{% endblock %}
-
-{% block coltype %}colMS{% endblock %}
-
-{% block bodyclass %}dashboard{% endblock %}
-
-{% block breadcrumbs %}{% endblock %}
-
-{% block content %}
-<div id="content-main">
-
-<div class='module'>
-<table>
-<caption>Frequently Used</caption>
-<tr>
-<th scope="row"><a href="/admin/samples/library/">Libraries</a></th>
-<td><a href="/admin/samples/library/add/" class="addlink">{% trans 'Add' %}</a></td>
-</tr>
-<tr>
-<th scope="row"><a href="/admin/experiments/flowcell/">Flowcells</a></th>
-<td><a href="/admin/experiments/flowcell/add/" class="addlink">{% trans 'Add' %}</a></td>
-</tr>
-</table></div>
-
-<div class='module'>
-<table>
-<caption>Label Printing</caption>
-<tr>
-<th scope="row"><a href="/admin/labels/labelcontent/">Label Contents</a></th>
-<td><a href="/admin/labels/labelcontent/add/" class="addlink">{% trans 'Add' %}</a></td>
-</tr>
-<tr>
-<th scope="row"><a href="/admin/labels/labeltemplate/">Label Templates</a></th>
-<td><a href="/admin/labels/labeltemplate/add/" class="addlink">{% trans 'Add' %}</a></td>
-</tr>
-</table></div><BR>
-
-{% if app_list %}
-    {% for app in app_list %}
-        <div class="module">
-        <table summary="{% blocktrans with app.name as name %}Models available in the {{ name }} application.{% endblocktrans %}">
-        <caption><a href="{{ app.app_url }}" class="section">{% blocktrans with app.name as name %}{{ name }}{% endblocktrans %}</a></caption>
-        {% for model in app.models %}
-            <tr>
-            {% if model.perms.change %}
-                <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
-            {% else %}
-                <th scope="row">{{ model.name }}</th>
-            {% endif %}
-
-            {% if model.perms.add %}
-                <td><a href="{{ model.admin_url }}add/" class="addlink">{% trans 'Add' %}</a></td>
-            {% else %}
-                <td>&nbsp;</td>
-            {% endif %}
-            </tr>
-        {% endfor %}
-        </table>
-        </div>
-    {% endfor %}
-{% else %}
-    <p>{% trans "You don't have permission to edit anything." %}</p>
-{% endif %}
-</div>
-{% endblock %}
-
-{% block sidebar %}
-<div id="content-related">
-    <div class="module" id="recent-actions-module">
-        <h2>{% trans 'Recent Actions' %}</h2>
-        <h3>{% trans 'My Actions' %}</h3>
-            {% load log %}
-            {% get_admin_log 10 as admin_log for_user user %}
-            {% if not admin_log %}
-            <p>{% trans 'None available' %}</p>
-            {% else %}
-            <ul class="actionlist">
-            {% for entry in admin_log %}
-            <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">
-                {% if entry.is_deletion %}
-                    {{ entry.object_repr }}
-                {% else %}
-                    <a href="{{ entry.get_admin_url }}">{{ entry.object_repr }}</a>
-                {% endif %}
-                <br/>
-                {% if entry.content_type %}
-                    <span class="mini quiet">{% filter capfirst %}{% trans entry.content_type.name %}{% endfilter %}</span>
-                {% else %}
-                    <span class="mini quiet">{% trans 'Unknown content' %}</span>
-                {% endif %}
-            </li>
-            {% endfor %}
-            </ul>
-            {% endif %}
-    </div>
-</div>
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/admin/pagination.html b/htsworkflow/frontend/templates/admin/pagination.html
deleted file mode 100644 (file)
index f7de053..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-<!--overrride pagination-->
-{% load admin_list %}
-{% load i18n %}
-<p class="paginator">
-{% if pagination_required %}
-{% for i in page_range %}
-    {% paginator_number cl i %}
-{% endfor %}
-{% endif %}
-{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %}
-{% if show_all_url %}&#160;&#160;<a href="{{ show_all_url }}" class="showall">{% trans 'Show all' %}</a>{% endif %}
-{% if cl.formset and cl.result_count %}<input type="submit" name="_save" class="default" value="{% trans 'Save' %}"/>{% endif %}
-</p>
diff --git a/htsworkflow/frontend/templates/base.html b/htsworkflow/frontend/templates/base.html
deleted file mode 100644 (file)
index 0325a84..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-{% load i18n %}<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN"
-    "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml"
-      version="XHTML+RDFa 1.0"
-      xmlns:xml="http://www.w3.org/XML/1998/namespace"
-      xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-      xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
-      xmlns:dc="http://purl.org/dc/elements/1.1/"
-      xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
-      xmlns:libns="http://jumpgate.caltech.edu/wiki/LibraryOntology#"
-      xmlns:invns="http://jumpgate.caltech.edu/wiki/InventoryOntology#"
-      xml:lang="en"
->
-<!--base.html-->
-<head>
-    <title>{% block title %}{{ app_name }} - {{ page_name }}{% endblock %}</title>
-
-{% block additional_css %}
-    {% load staticfiles %}
-    {% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "css/rtl.css" %}{% endblock %}" />{% endif %}
-    {% block extrastyle %}{% endblock %}
-    {% block extrahead %}{% endblock %}
-    {% block blockbots %}<meta name="robots" content="NONE,NOARCHIVE" />{% endblock %}
-    <link rel="stylesheet" type="text/css" href="{% static "css/data-browse-index.css" %}" />
-{% endblock %}
-
-</head>
-<body>
-<!-- Container -->
-    {% if not is_popup %}
-
-    <div id="header">
-        <div id="branding">
-        {% block branding %}{% endblock %}
-        </div>
-        <div id="user-tools">
-        {% if user.is_authenticated %}
-        {% trans 'Welcome,' %}
-        <strong>{% firstof user.first_name user.username %}</strong>.
-        {% block userlinks %}
-            {% url "django.admindocs.docroot" as docsroot %}
-            {% if docsroot %}
-                <a href="{{ docsroot }}">{% trans 'Documentation' %}</a> /
-            {% endif %}
-            <a href="{{root_path}}/accounts/password_change/">{% trans 'Change password' %}</a> /
-            <a href="{{root_path}}/accounts/logout/">{% trans 'Log out' %}</a>
-        {% endblock %}
-        {% else %}
-            <a href="{{root_path}}/accounts/login/?next={{thispage}}">{% trans 'Log in' %}</a>
-        {% endif %}
-        </div>
-        {% block nav-global %}{% endblock %}
-    </div>
-    {% endif %}
-    {% block breadcrumbs %}{% endblock %}
-    {% if messages %}
-        <ul class="messagelist">{% for message in messages %}<li>{{ message }}</li>{% endfor %}</ul>
-    {% endif %}
-
-    <!-- Content -->
-    <div id="content" class="{% block coltype %}colM{% endblock %}">
-        {% block pretitle %}{% endblock %}
-        {% block content_title %}{% if title %}<h1>{{ title }}</h1>{% endif %}{% endblock %}
-        {% block content %}
-        {% block object-tools %}{% endblock %}
-        {{ content }}
-        {% endblock %}
-        {% block sidebar %}{% endblock %}
-    </div>
-    <!-- END Content -->
-
-    {% block footer %}<div id="footer"></div>{% endblock %}
-<!-- END Container -->
-</body>
-</html>
diff --git a/htsworkflow/frontend/templates/base_site.html b/htsworkflow/frontend/templates/base_site.html
deleted file mode 100644 (file)
index 1c02752..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{% extends "base.html" %}
-{% load staticfiles %}
-{% load i18n %}
-
-<link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}" />
-
-{% block title %}{{ sitename }}{% endblock %}
-
-{% block branding %}
-<h1 id="site-name">HTSWorkflow</h1>
-{% endblock %}
-
-{% block nav-global %}{% endblock %}
diff --git a/htsworkflow/frontend/templates/bcmagic/magic.html b/htsworkflow/frontend/templates/bcmagic/magic.html
deleted file mode 100644 (file)
index e1d1061..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<div id="bcm_msg"></div>
-{{ bcmagic }}<br />
-<div id="bcm_status"></div>
diff --git a/htsworkflow/frontend/templates/experiments/detail.html b/htsworkflow/frontend/templates/experiments/detail.html
deleted file mode 100644 (file)
index 65d3c00..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-{% if run_f %}
-    <ul>
-        RUN FOLDER:  <li>{{ run_f.run_folder }}</li>
-    </ul>
-{% else %}
-    <p>Run folder not found.</p>
-{% endif %}
diff --git a/htsworkflow/frontend/templates/experiments/email_preview.html b/htsworkflow/frontend/templates/experiments/email_preview.html
deleted file mode 100644 (file)
index 9c35c6d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-{% extends "base.html" %}
-{% load i18n %}
-
-{% block breadcrumbs %}
-<div class="breadcrumbs">
-  <a href="/admin">{% trans 'Home' %}</a> &rsaquo;
-  <a href="/admin/experiments">Experiments</a> &rsaquo;
-  <a href="/admin/experiments/flowcell">flowcell</a> &rsaquo;
-  <a href="{{ flowcell.get_admin_url }}">{{ flowcell.flowcell_id }}</a>
-</div>  
-{% endblock %}
-
-{% block content %}
-{% if warnings %}
-<hr/>
-<p>
-{% for user_admin_url, username in warnings %}
-Warning: User <a href="{{ user_admin_url}}">{{ username }}</a> has no
-email address <br/>
-{% endfor %}
-{% endif %}
-</p>
-{% for to, subject, body, sending in emails %}
-<hr/>
-{% if sending %}<b>Message:</b> {{ sending }}<br/>{% endif %}
-<b>From:</b> {{ from }}<br/>
-<b>To:</b> {{ to }}<br/>
-<b>Subject:</b> {{ subject }}<br/>
-<pre>
-{{ body }}
-</pre>
-{% endfor %}<hr/>
-<form method="get">
-<label for="bcc">BCC {% for m in site_managers %}{{ m }} {% endfor %}</label>
-<input type="checkbox" id="bcc" name="bcc" checked="on"/><br/>
-<input type="hidden" name="send" value="1"/>
-<input type="submit" value="Send Email"/>
-{% endblock %}
\ No newline at end of file
diff --git a/htsworkflow/frontend/templates/experiments/flowcellSheet.html b/htsworkflow/frontend/templates/experiments/flowcellSheet.html
deleted file mode 100644 (file)
index 103b045..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-<html><head><title>{{ fc.flowcell_id }} - GA SEQUENCING (SOLEXA) LOG</title>
-<style type="text/css">
-<!--
-TD
-  {
-  color:black;
-  font-size:9pt;
-  font-face:Arial;
-  }
--->
-</style>
-</head><body>
-{% if fc %}
-<table border="1" cellspacing="1">
-<tr><td colspan=2 nowrap><b>GA SEQUENCING (SOLEXA) LOG</b></td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
-<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
-<tr><td>Date Run Started</td><td colspan=2>{{ fc.run_date }}</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
-<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
-<tr><td>Cluster station used</td><td colspan=2 nowrap>{{ fc.cluster_station.name }}</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
-<tr><td>GA used</td><td colspan=2 nowrap>{{ fc.sequencer.name }}</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
-
-<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
-<tr><td>Flowcell number</td><td colspan=2 nowrap>{{ fc.flowcell_id }}</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
-<tr><td>Number of Tiles per Lane</td><td>100</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
-<tr><td>Number of Cycles</td><td>{{ fc.read_length  }}</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
-<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
-<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
-<tr><td><font point-size="9" face="Arial"><b>SAMPLE INFORMATION</b><font></td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
-<tr><td>&nbsp;</td><td>FC#</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td colspan=2 nowrap>FC bar code</td></tr>
-
-<tr><td valign=middle nowrap>Lane</td>
-{% for lane in fc.lane_set.all %}
-<td>{{ lane.lane_number }}</td>
-{% endfor %}
-</tr>
-<tr><td valign=middle nowrap>Solexa Library Number</td>
-{% for lane in fc.lane_set.all %}
-<td bgcolor=#CCFFCC>{{ lane.library.id }}</td>
-{% endfor %}
-</tr>
-
-<tr><td valign=middle nowrap>Sample Name</td>
-{% for lane in fc.lane_set.all %}
-<td bgcolor=#CCFFCC>{{ lane.library.library_name }}</td>
-{% endfor %}
-</tr>
-
-<tr><td valign=middle nowrap>Organism</td>
-{% for lane in fc.lane_set.all %}
-<td bgcolor=#CCFFCC>{{ lane.library.library_species.scientific_name }}</td>
-{% endfor %}
-</tr>
-
-<tr><td valign=middle nowrap>Submitter</td>
-{% for lane in fc.lane_set.all %}
-<td bgcolor=#CCFFCC>{{ lane.library.made_for }}</td>
-{% endfor %}
-</tr>
-
-
-<tr><td valign=middle nowrap>First time run?</td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td></tr>
-
-<tr><td valign=middle nowrap>Gel Cut Size (bp)</td>
-{% for lane in fc.lane_set.all %}
-<td bgcolor=#CCFFCC>{{ lane.library.gel_cut_size }}</td>
-{% endfor %}
-</tr>  
-
-<tr><td valign=middle nowrap>Template Concentration (ng/ul)</td>
-{% for lane in fc.lane_set.all %}
-<td bgcolor=#CCFFCC>{{ lane.library.undiluted_concentration }}</td>
-{% endfor %}
-</tr>
-
-<tr><td valign=middle nowrap>Run Concentration (pM)</td>
-{% for lane in fc.lane_set.all %}
-<td bgcolor=#CCFFCC>{{ lane.pM }}</td>
-{% endfor %}
-</tr>
-
-</table>
-
-{% else %}
-    <p>Flowcell object missing. Can't create sheet.</p>
-{% endif %}
-
-</body></html
diff --git a/htsworkflow/frontend/templates/experiments/flowcell_detail.html b/htsworkflow/frontend/templates/experiments/flowcell_detail.html
deleted file mode 100644 (file)
index 64da7e2..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-{% extends "base_site.html" %}
-{% load staticfiles %}
-{% load humanize i18n %}
-{% block extrahead %}
-    <!-- App Stuff -->
-    <link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}" />
-    <script type="text/javascript" src="{% static "js/jquery.min.js" %}"></script>
-
-    {% block additional_javascript %}
-    {% endblock %}
-{% endblock %}
-
-{% block content %}
-<div>
-  {% include "experiments/flowcell_header.html" %}
-  <div class="htswdetail" typeof="libns:IlluminaFlowcell" resource="{{flowcell.get_absolute_url}}">
-    <h2>Lanes</h2>
-    <table>
-      <thead>
-       <tr>
-         <td>Lane</td>
-         <td>Library ID</td>
-         <td>Library Name</td>
-         <td>Species</td>
-         <td>Comment</td>
-       </tr>
-      </thead>
-      <tbody>
-      {% for lane in lanes %}
-        <tr>
-          <td rel="libns:has_lane">
-            <a href="{{lane.get_absolute_url}}" typeof="libns:IlluminaLane">
-              <span property="libns:lane_number">{{lane.lane_number}}</span>
-            </a>
-          </td>
-          <td rel="libns:library"
-              about="{{lane.get_absolute_url}}"
-              resource="{{lane.library.get_absolute_url}}">
-            <a typeof="libns:Library" href="{{lane.library.get_absolute_url}}">
-              <span property="libns:library_id"
-                    >{{lane.library.id}}</span></a>
-              {% if user.is_staff %}
-              <a href="{{lane.library.get_admin_url}}">
-                  <img class="icon_button"
-                       src="{% static "admin/img/icon_changelink.gif" %}"/>
-              </a>{% endif %}
-          </td>
-          <td>
-            <a href="{{lane.library.get_absolute_url}}">
-              <span property="libns:name"
-                    about="{{lane.library.get_absolute_url}}"
-                    >{{lane.library.library_name}}</span>
-            </a>
-          </td>
-          <td about="{{lane.library.get_absolute_url}}" rel="libns:species">
-            <a href="{{lane.library.library_species.get_absolute_url}}"
-               typeof="libns:Species">
-              <span property="libns:species_name">{{ lane.library.library_species.scientific_name }}</span></a>
-          </td>
-          <td about="{{lane.get_absolute_url}}">
-            <span property="libns:comment">{{lane.comment}}</span>
-          </td>
-        </tr>
-      {% endfor %}
-      </tbody>
-    </table>
-    <div class="htsw_flowcell_ivc">
-    {% for run in flowcell.datarun_set.all %}
-       <h2>Run {{ run.runfolder_name }}</h2>
-       {% if run.lane_files %}
-       <table>
-         <thead>
-           <tr>
-             <td>Lane</td>
-             <td>IVC All</td>
-             <td>IVC Call</td>
-             <td>IVC Percent Base</td>
-             <td>IVC Percent Base All</td>
-             <td>IVC Percent Base Called</td>
-           </tr>
-         </thead>
-         <tbody>
-            {% for lane_id, lane_file_set in run.lane_files.items %}
-            {% if lane_file_set.ivc_all %}
-            <tr>
-              <td>{{ lane_id }}</td>
-              <td>
-                <a href="{{ lane_file_set.ivc_all.get_absolute_url }}">
-                <img height="84" width="126" alt="Lane {{lane_id }} IVC All"
-                     src="{{ lane_file_set.ivc_all.get_absolute_url }}"/></a>
-              </td>
-              <td>
-                <a href="{{ lane_file_set.ivc_call.get_absolute_url }}">
-                <img height="84" width="126" alt="Lane {{lane_id }} IVC Call"
-                     src="{{ lane_file_set.ivc_call.get_absolute_url }}"/>
-                </a>
-              </td>
-              <td>
-                <a href="{{ lane_file_set.ivc_percent_base.get_absolute_url }}">
-                <img height="84" width="126" alt="Lane {{lane_id }} IVC % Base"
-                     src="{{ lane_file_set.ivc_percent_base.get_absolute_url }}"/>
-                </a>
-              </td>
-              <td>
-                <a href="{{ lane_file_set.ivc_percent_all.get_absolute_url }}">
-                <img height="84" width="126" alt="Lane {{lane_id }} IVC % Base All"
-                     src="{{ lane_file_set.ivc_percent_all.get_absolute_url }}"/>
-                </a>
-              </td>
-              <td>
-                <a href="{{ lane_file_set.ivc_percent_call.get_absolute_url }}">
-                <img height="84" width="126"
-                     alt="Lane {{lane_id }} IVC % Base Called"
-                     src="{{ lane_file_set.ivc_percent_call.get_absolute_url }}"/>
-                </a>
-              </td>
-            </tr>
-            {% endif %}
-            {% endfor %}
-         </tbody>
-       </table>
-       {% endif %}
-    {% endfor %}
-    </div>
-  </div>
-</div>
-<!-- end flowcell_detail -->
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/experiments/flowcell_header.html b/htsworkflow/frontend/templates/experiments/flowcell_header.html
deleted file mode 100644 (file)
index f0cb470..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-{% load staticfiles %}
-<div class="flowcell_identity" typeof="libns:IlluminaFlowcell" resource="{{flowcell.get_absolute_url}}">
-  <h2>About this Flowcell</h2>
-  <b>Flowcell</b>:
-    <a href="{{flowcell.get_absolute_url}}"><span property="libns:flowcell_id">{{flowcell.flowcell_id}}</span></a>{% if user.is_staff %}<a href="{{flowcell.get_admin_url}}"><img class="icon_button" src="{% static "admin/img/icon_changelink.gif" %}" alt="Edit"/></a>{% endif%}
-  <br/>
-  <div rel="libns:sequenced_by">
-  <div typeof="libns:Sequencer"
-       about="{{flowcell.sequencer.get_absolute_url}}">
-  <b>Instrument</b>:
-    <span property="libns:sequencer_name">{{ flowcell.sequencer.name }}</span>
-    {% if flowcell.sequencer.instrument_name %}
-    (<span property="libns:sequencer_instrument">{{ flowcell.sequencer.instrument_name}}</span>)
-    {% endif %}
-    <br/>
-  <b>Instrument Model</b>:
-    <span property="libns:sequencer_model">{{flowcell.sequencer.model}}</span>
-    <br/>
-  </div>
-  </div>
-  {% for datarun in flowcell.datarun_set.all %}
-  <b>Image Analysis</b>:
-    <span property="libns:image_software">{{datarun.image_software}}</span>
-    <span property="libns:image_version">{{datarun.image_version}}</span><br/>
-  <b>Base Caller</b>:
-    <span property="libns:basecall_software">{{datarun.basecall_software}}</span>
-    <span property="libns:basecall_version">{{datarun.basecall_version}}</span><br/>
-  <b>Alignment</b>:
-    <span property="libns:alignment_software">{{datarun.alignment_software}}</span>
-    <span property="libns:alignment_version">{{datarun.alignment_version}}</span><br/>
-  {% endfor %}
-  <b>Run Date</b>:
-    <span property="libns:date" content="{{flowcell.run_date|date:'Y-m-d\TH:i:s'}}" datatype="xsd:dateTime">{{ flowcell.run_date }}</span><br/>
-  <b>Type</b>:
-    <span property="libns:flowcell_type">{{flowcell.flowcell_type}}</span><br/>
-  <b>Read Length</b>:
-    <span property="libns:read_length" datatype="xsd:integer">{{flowcell.read_length}}</span><br/>
-  <b>Control Lane</b>:
-    <span property="libns:control_lane">{{flowcell.control_lane}}</span><br/>
-
-  <b>Notes</b>:
-    <pre property="libns:flowcell_notes">{{flowcell.notes}}</pre>
- </div>
diff --git a/htsworkflow/frontend/templates/experiments/flowcell_lane_detail.html b/htsworkflow/frontend/templates/experiments/flowcell_lane_detail.html
deleted file mode 100644 (file)
index ebe2c59..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-{% extends "base_site.html" %}
-{% load humanize i18n %}
-{% load staticfiles %}
-{% block extrahead %}
-    <!-- App Stuff -->
-    <link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}"/>
-    <script type="text/javascript" src="{% static "js/jquery.min.js" %}"></script>
-
-    {% block additional_javascript %}
-    {% endblock %}
-{% endblock %}
-
-{% block content %}
-<div id="lane_detail" class="htswdetail" typeof="libns:IlluminaLane" resource="{{lane.get_absolute_url}}">
-  <div rel="libns:flowcell" resource="{{flowcell.get_absolute_url}}">
-  {% include "experiments/flowcell_header.html" %}
-  </div>
-  <div class="flowcell_lane_detail">
-  <h2>About this lane</h2>
-  <b>Lane</b>:
-    <span property="libns:lane_number">{{lane.lane_number}}</span><br/>
-  <b>pM</b>:
-    <span property="libns:pM" datatype="xsd:decimal">{{ lane.pM }}</span><br/>
-  {% if lane.cluster_estimate %}
-  <b>Cluster Estimate</b>:
-    <span property="libns:cluster_estimate" datatype="xsd:decimal"
-          content="{{lane.cluster_estimate}}">{{ lane.cluster_estimate|intcomma }}</span><br/>{% endif %}
-  {% if lane.status %}
-  <b>Lane Status</b>:
-    <span property="libns:status">{{ lane.status }}</span><br/>{% endif %}
-  {% if lane.comment %}
-  <b>Comments</b>:
-    <span property="libns:comment">{{ lane.comment }}</span><br/>{% endif %}
-  </div>
-  <hr/>
-  {% include "sample_header.html" %}
-  <hr/>
-  <div class="htsw_flowcell_ivc">
-  {% for run in flowcell.datarun_set.all %}
-     <h2>Run {{ run.runfolder_name }}</h2>
-     <table>
-       <thead>
-         <tr>
-           <td>Lane</td>
-           <td>IVC All</td>
-           <td>IVC Call</td>
-           <td>IVC Percent Base</td>
-           <td>IVC Percent Base All</td>
-           <td>IVC Percent Base Called</td>
-         </tr>
-       </thead>
-       <tbody>
-          {% for run, lane_number, lane_file_set in filtered_dataruns %}
-          {% if lane_file_set.ivc_all %}
-          <tr>
-            <td>{{lane_number}}</td>
-            <td>
-              <a href="{{ lane_file_set.ivc_all.get_absolute_url }}">
-              <img height="84" width="126" alt="Lane {{lane_id }} IVC All"
-                   src="{{ lane_file_set.ivc_all.get_absolute_url }}"/></a>
-            </td>
-            <td>
-              <a href="{{ lane_file_set.ivc_call.get_absolute_url }}">
-              <img height="84" width="126" alt="Lane {{lane_id }} IVC Call"
-                   src="{{ lane_file_set.ivc_call.get_absolute_url }}"/>
-              </a>
-            </td>
-            <td>
-              <a href="{{ lane_file_set.ivc_percent_base.get_absolute_url }}">
-              <img height="84" width="126" alt="Lane {{lane_id }} IVC % Base"
-                   src="{{ lane_file_set.ivc_percent_base.get_absolute_url }}"/>
-              </a>
-            </td>
-            <td>
-              <a href="{{ lane_file_set.ivc_percent_all.get_absolute_url }}">
-              <img height="84" width="126" alt="Lane {{lane_id }} IVC % Base All"
-                   src="{{ lane_file_set.ivc_percent_all.get_absolute_url }}"/>
-              </a>
-            </td>
-            <td>
-              <a href="{{ lane_file_set.ivc_percent_call.get_absolute_url }}">
-              <img height="84" width="126"
-                   alt="Lane {{lane_id }} IVC % Base Called"
-                   src="{{ lane_file_set.ivc_percent_call.get_absolute_url }}"/>
-              </a>
-            </td>
-          </tr>
-          {% else %}
-            <tr><td colspan="6">No data</td></tr>
-          {% endif %}
-          {% endfor %}
-       </tbody>
-     </table>
-  {% endfor %}
-  </div>
-</div>
-
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/experiments/index.html b/htsworkflow/frontend/templates/experiments/index.html
deleted file mode 100644 (file)
index 28c24bf..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{% if data_run_list %}
-    <table>
-      {% for run in data_run_list %}
-        <tr>
-          <td>{{run.run_folder}}</td>
-          <td><a href="fcsheet/{{run.fcid}}">sheet</td>
-          <td><a href="started/{{run.fcid}}">started email</td>
-          <td><a href="finished/{{run.fcid}}">finished email</td>
-       </tr>
-      {% endfor %}
-   </table>
-{% else %}
-    <p>No data runs are available.</p>
-{% endif %}
diff --git a/htsworkflow/frontend/templates/experiments/sequencer.html b/htsworkflow/frontend/templates/experiments/sequencer.html
deleted file mode 100644 (file)
index 411288c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-{% extends "base_site.html" %}
-{% load humanize i18n %}
-{% load staticfiles %}
-{% block extrahead %}
-    <!-- App Stuff -->
-    <link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}" />
-    <script type="text/javascript" src="{% static "js/jquery.min.js" %}"></script>
-
-    {% block additional_javascript %}
-    {% endblock %}
-{% endblock %}
-
-{% block content %}
-    <h1>Sequencer</h1>
-    <dl about="{{sequencer.get_absolute_url}}" typeof="libns:sequencer">
-      <dt>Name</dt>
-      <dl property="libns:sequencer_name">{{sequencer.name}}</dl>
-      <dt>Instrument Name</dt>
-      <dl property="libns:insrument_name">{{sequencer.instrument_name}}</dl>
-      <dt>Model</dt>
-      <dl property="libns:model">{{sequencer.model}}</dl>
-      <dt>Comment</dt>
-      <dl></dl>
-    </dl>
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/experiments/started_email.html b/htsworkflow/frontend/templates/experiments/started_email.html
deleted file mode 100644 (file)
index 180cde6..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<p>
-The following libraries are on the flowcell {{ flowcell.flowcell_id }}
-which is a {{ flowcell.read_length }} base pair {% if flowcell.paired_end %}paired end{% else %}single ended{% endif %} flowcell.
-</p>
-<p>{% for lane in lanes %}
-Lane #{{ lane.lane_number }} : 
-<a href="https://jumpgate.caltech.edu/library/{{lane.library.id}}">
-{{ lane.library.id }}</a>
-{{ lane.library.library_name }}<br/>
-{% endfor %}</p>
-<p>
-The data should be available at the following link when
-the pipeline finishes, probably in about {{ finish_low.days }} to {{ finish_high.days }} 
-days from {{ now|date:"D, M d Y" }}
-</p>
-<p>
-<a href="https://jumpgate.caltech.edu/runfolders/{{ flowcell.sequencer}}/">
-https://jumpgate.caltech.edu/runfolders/{{ flowcell.sequencer }}
-</a></p>
diff --git a/htsworkflow/frontend/templates/experiments/started_email.txt b/htsworkflow/frontend/templates/experiments/started_email.txt
deleted file mode 100644 (file)
index 7337ef8..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-The following libraries are on the flowcell {{ flowcell.flowcell_id }}
-which is a {{ flowcell.read_length }} base pair {% if flowcell.paired_end %}paired end{% else %}single ended{% endif %} flowcell.
-
-Lane : (Library Id) Library Name (Cluster Estimate)
-{% for lane in lanes %}
-Lane #{{ lane.lane_number }} : ({{ lane.library.id }}) {{ lane.library.library_name }} ({{ lane.cluster_estimate }})
-     https://jumpgate.caltech.edu/library/{{ lane.library.id }}
-{% endfor %}
-
-The raw data should be available at the following link when the
-pipeline finishes, probably in about {{ finish_low.days }} to {{ finish_high.days }} 
-days from {{ now|date:"D, M d Y" }}
-
-https://jumpgate.caltech.edu/runfolders/{{ flowcell.sequencer}}
-
-Username: gec
-Password: gecilluminadata
-
-- Jumpgate
diff --git a/htsworkflow/frontend/templates/inventory/default.zpl b/htsworkflow/frontend/templates/inventory/default.zpl
deleted file mode 100644 (file)
index 802ac69..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-^FX=========================
-^FX Harddrive Location Tracking Label
-^FX 300x375 dots
-^FX=========================
-
-^XA
-^LH 0,25
-
-^FO0,0
-^CF0,35
-^FB375,1,,C
-^FD{{ item.item_type.name }}:^FS
-
-^FX -------Text contains HD serial #-------------
-^FO15,75
-^CF0,42
-^FB325,3,,C
-^FD{% if use_uuid %}{{ item.uuid }}{% else %}{{ item.barcode_id }}{% endif %}^FS
-
-^FX -------Barcode contains HD serial #-----------
-^FO150,200
-^BXN,3,200
-^FD{% if use_uuid %}invu|{{ item.uuid }}{% else %}invb|{{ item.barcode_id }}{% endif %}^FS
-
-^XZ
diff --git a/htsworkflow/frontend/templates/inventory/hard_drive_shell.zpl b/htsworkflow/frontend/templates/inventory/hard_drive_shell.zpl
deleted file mode 100644 (file)
index 610df2e..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-^FX=========================
-^FX 3"x3" Label
-^FX=========================
-^XA
-
-
-^FX======== Left Side ===========
-
-^FX------------
-^FX ^LH changes the 0,0 point of all subsequent location references
-^FX------------
-
-^LH0,50
-
-^FX ---Header---
-
-^FO25,0
-^CF0,50
-^FB250,2,,C
-^FD{{ item.barcode_id }}^FS
-
-^FX ---Column 1: Flowcells---
-
-^FX-----------------
-^FX FB command for automatic text formatting:
-^FX ^FB[dot width of area], [max # of lines], [change line spacing], [justification: L, C, R, J], [hanging indent]
-^FX-----------------
-
-^CF0,30,30
-^FO75,125
-^FB275,19,,L
-^FD{% for flowcell in flowcell_id_list %}{{ flowcell }}{% if not forloop.last %}\&{% endif %}{% endfor %}^FS
-^FX ---Date---
-
-^FO0,725
-^CF0,35
-^FB300,2,,C
-^FD{{ oldest_rundate|date:"YMd" }} - {{ latest_rundate|date:"YMd" }}^FS
-
-^FX ---Barcode---
-
-^FO135,795
-^BXN,3,200^FDinvb|{{ item.barcode_id }}^FS
-
-^FX======== Right Side ===========
-
-^LH300,60
-
-^FX ---Header---
-
-^FO0,0
-^CF0,50
-^FB600,2,,C
-^FD{{ barcode_id }}^FS
-
-^FX ---Dividing line---
-
-^FX---------------
-^FX GB command:
-^FX ^GB[box width], [box height], [border thickness], [color: B, W], [corner rounding: 0-8]^FS
-^FX---------------
-
-^FO0,100
-^GB0,600,10^FS
-
-^FX ---Column 2: Libraries 1-20---
-
-^CF0,30,30
-^FO75,100
-^FB100,20,,L
-^FD{% for lib_id in library_id_list_1_to_20 %}{{ lib_id }}{% if not forloop.last %}\&{% endif %}{% endfor %}^FS
-
-^FX ---Column 3: Libraries 21-40---
-
-^CF0,30,30
-^FO200,100
-^FB100,20,,L
-^FD{% for lib_id in library_id_list_21_to_40 %}{{ lib_id }}{% if not forloop.last %}\&{% endif %}{% endfor %}^FS
-
-^FX ---Column 4: Libraries 41-60---
-
-^CF0,30,30
-^FO325,100
-^FB100,20,,L
-^FD{% for lib_id in library_id_list_41_to_60 %}{{ lib_id }}{% if not forloop.last %}\&{% endif %}{% endfor %}^FS
-
-^FX ---Column 5: Libraries 61-80---
-
-^CF0,30,30
-^FO450,100
-^FB100,20,,L
-^FD{% for lib_id in library_id_list_61_to_80 %}{{ lib_id }}{% if not forloop.last %}\&{% endif %}{% endfor %}^FS
-
-^FX ---Date---
-
-^FO0,715
-^CF0,35
-^FB600,2,,C
-^FDRun Dates: {{ oldest_rundate|date:"YMd" }}-{{ latest_rundate|date:"YMd" }}^FS
-
-^FX ---Barcode---
-
-^FO255,785
-^BXN,3,200^FDinvb|{{ item.barcode_id }}^FS
-
-^LH0,0
-^FX ---End---
-^XZ
\ No newline at end of file
diff --git a/htsworkflow/frontend/templates/inventory/inventory_all_index.html b/htsworkflow/frontend/templates/inventory/inventory_all_index.html
deleted file mode 100644 (file)
index c95a78b..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-{% extends "base_site.html" %}
-{% load admin_list i18n %}
-{% block extrahead %}
-    <script type="text/javascript">
-      $(document).ready(function() {
-        $(window).resize(function() {
-           var window_height = $(window).height();
-           var position = $("#changelist table").position();
-           height = window_height - position.top;
-           $("#changelist table.filtered").height(height);
-           $("#changelist-filter").height(height);
-        });
-        $(window).resize();
-      });
-    </script>
-{% endblock %}
-{% block bodyclass %}change-list{% endblock %}
-{% block coltype %}flex{% endblock %}
-{% block content %}
-<div id="inventory-index-div" >
-  <div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
-    {% block search %}{% search_form item_changelist %}{% endblock %}
-    {% block pagination %}{% pagination item_changelist %}{% endblock %}
-
-    {% block filters %}
-    {% if item_changelist.has_filters %}
-    <div id="changelist-filter">
-      <h2 >{% trans 'Filter' %}</h2>
-      {% for spec in item_changelist.filter_specs %}
-         {% admin_list_filter cl spec %}
-         {% endfor %}
-       </div>
-    {% endif %}
-    {% endblock %}
-  {% block summary_stats %}
-  <table class="{% if cl.has_filters %} filtered{% endif %}">
-    <thead >
-      <tr >
-        <td >UUID</td>
-        <td >Barcode ID</td>
-        <td >Location</td>
-        <td >Model</td>
-        <td >Vendor</td>
-        <td >Created</td>
-        <td >Contains</td>
-      </tr>
-    </thead>
-    <tbody >
-      {% for item in item_changelist.get_query_set %}
-      <tr >
-        <td >{{ item.uuid }}</td>
-        <td >{{ item.barcode_id}}</td>
-        <td >{{ item.location }}</td>
-        <td >{{ item.item_type }}</td>
-        <td ></td>      
-        <td >{{ item.creation_date }}</td>      
-        <td >
-          {% for content in item.longtermstorage_set.all %}
-          {{ content.flowcell }}
-          {% endfor %}
-        </td>
-      </tr>
-      {% endfor %}
-    </tbody>
-  </table>
-  {% endblock %}
-</div>
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/inventory/inventory_index.html b/htsworkflow/frontend/templates/inventory/inventory_index.html
deleted file mode 100644 (file)
index 7c7eb50..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-{% extends "base_site.html" %}
-{% load admin_list i18n %}
-{% block extrahead %}
-    <script type="text/javascript">
-      $(document).ready(function() {
-        $(window).resize(function() {
-           var window_height = $(window).height();
-           var position = $("#changelist table").position();
-           height = window_height - position.top;
-           $("#changelist table.filtered").height(height);
-           $("#changelist-filter").height(height);
-        });
-        $(window).resize();
-      });
-    </script>
-{% endblock %}
-{% block bodyclass %}change-list{% endblock %}
-{% block coltype %}flex{% endblock %}
-{% block content %}
-<div id="inventory-index-div" >
-  <div class="module{% if item_changelist.has_filters %} filtered{% endif %}" id="changelist">
-    {% block search %}{% search_form item_changelist %}{% endblock %}
-    {% block pagination %}{% pagination item_changelist %}{% endblock %}
-
-    {% block filters %}
-    {% if item_changelist.has_filters %}
-    <div id="changelist-filter">
-      <h2 >{% trans 'Filter' %}</h2>
-      {% for spec in item_changelist.filter_specs %}
-         {% admin_list_filter item_changelist spec %}
-         {% endfor %}
-       </div>
-    {% endif %}
-    {% endblock %}
-  {% block summary_stats %}
-  <table class="{% if item_changelist.has_filters %} filtered{% endif %}">
-    <thead >
-      <tr >
-        <td >Name</td>
-        <td >Description</td>
-      </tr>
-    </thead>
-    <tbody >
-      {% for itemtype in item_changelist.result_list %}
-      <tr >
-        <td ><a href="/inventory/it/{{ itemtype.name }}/">{{ itemtype.name }}</a></td>
-        <td >{{ itemtype.description }}</td>
-      </tr>
-      {% endfor %}
-    </tbody>
-  </table>
-  {% endblock %}
-</div>
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/inventory/inventory_itemtype_index.html b/htsworkflow/frontend/templates/inventory/inventory_itemtype_index.html
deleted file mode 100644 (file)
index eb559b1..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-{% extends "base_site.html" %}
-{% load admin_list i18n %}
-{% block extrahead %}
-    <script type="text/javascript">
-      $(document).ready(function() {
-        $(window).resize(function() {
-           var window_height = $(window).height();
-           var position = $("#changelist table").position();
-           height = window_height - position.top;
-           $("#changelist table.filtered").height(height);
-           $("#changelist-filter").height(height);
-        });
-        $(window).resize();
-      });
-    </script>
-{% endblock %}
-{% block bodyclass %}change-list{% endblock %}
-{% block coltype %}flex{% endblock %}
-{% block content %}
-<div id="inventory-index-div" >
-  <div class="module{% if item_changelist.has_filters %} filtered{% endif %}" id="changelist">
-    {% block search %}{% search_form item_changelist %}{% endblock %}
-
-    {% block pagination %}{% pagination item_changelist %}{% endblock %}
-
-    {% block filters %}
-    {% if item_changelist.has_filters %}
-    <div id="changelist-filter">
-      <h2 >{% trans 'Filter' %}</h2>
-      {% for spec in item_changelist.filter_specs %}
-         {% admin_list_filter item_changelist spec %}
-         {% endfor %}
-    </div>
-    {% endif %}
-    {% endblock %}
-  {% block summary_stats %}
-  <table class="{% if item_changelist.has_filters %} filtered{% endif %}">
-    <thead >
-      <tr >
-        <td >UUID</td>
-        <td >Barcode ID</td>
-        <td >Location</td>
-        <td >Model</td>
-        <td >Vendor</td>
-        <td >Created</td>
-        <td >Contains</td>
-      </tr>
-    </thead>
-    <tbody >
-      {% for item in item_changelist.result_list %}
-      <tr about="{{ item.get_absolute_url }}">
-        <td ><a href="{{ item.get_absolute_url}}" rel="invns:uuid">{{ item.uuid }}</a></td>
-        <td ><a href="/inventory/{{ item.barcode_id }}/" rel="invns:barcode">{{ item.barcode_id }}</a></td>
-        <td property="invns:location">{{ item.location }}</td>
-        <td property="invns:item_type">{{ item.item_type }}</td>
-        <td ></td>
-        <td property="invnfs:creation_date" content="{{item.creation_date|date:'Y-m-d\TH:i:s'}}" datatype="xsd:dateTime">{{ item.creation_date }}</td>
-        <td class="cell_list" >
-          {% for content in item.longtermstorage_set.all %}
-          <a href="{{content.flowcell.get_absolute_url}}" rel="libns:flowcell_id">{{ content.flowcell }}</a>
-          {% endfor %}
-        </td>
-      </tr>
-      {% endfor %}
-    </tbody>
-  </table>
-  {% endblock %}
-  </div>
-</div>
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/inventory/inventory_summary.html b/htsworkflow/frontend/templates/inventory/inventory_summary.html
deleted file mode 100644 (file)
index 1a4797c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-{% extends "base_site.html" %}
-
-{% block content %}
-{% if item %}
-        <h2>Item Summary:</h2>
-        <a href="{% url "htsworkflow.frontend.inventory.views.index" %}{{item.uuid}}/print/">Print</a><br />
-        <br />
-        <b>UUID:</b> <span property="invns:uuid">{{item.uuid}}</span><br />
-        <b>Barcode ID:</b> <span property="invns:barcode">{{ item.barcode_id }}</span><br />
-        <b>Type:</b> <span property="invns:item_type">{{ item.item_type.name }}</span><br />
-        <br />
-        <b>Location:</b> <span property="invns:location">{{ item.location.name }}</span><br />
-        <b>Status: </b> {% if item.status %}<span property="invns:status">{{ item.status.name }}</span>{% else %}N/A{% endif %}<br />
-        <br />
-        {% if item.item_info.model_id %}
-        <b>Model ID:</b> <span property="invns:model">{{ item.item_info.model_id }}</span><br />
-        {% endif %}
-        {% if item.item_info.part_number %}
-        <b>Part Number:</b> <span property="invns:part_number">{{ item.item_info.part_number }}</span><br />
-        {% endif %}
-        {% if item.item_info.lot_number %}
-        <b>Lot Number:</b> <span property="invns:lot_number">{{ item.item_info.lot_number }}</span><br />
-        {% endif %}
-        <br />
-        {% if item.item_info.url %}
-        <b>Item Website:</b> <a href="{{ item.item_info.url }}" rel="invns:vendor_link">Link</a><br />
-        {% endif %}
-        <b>Vendor:</b> {% if item.item_info.vendor.url %}<a href="{{ item.item_info.vendor.url }}">{% endif %}{{ item.item_info.vendor.name }}{% if item.item_info.vendor.url %}</a>{% endif %}<br />
-        <b>Purchase Date:</b>{% if item.item_info.purchase_date %}{{ item.item_info.purchase_date }}{% else %}N/A{% endif %}<br />
-        <b>Warenty (Months):</b>{% if item.item_info.warenty_months %}{{item.item_info.warenty_months}}{% else %}N/A{% endif %}<br />
-        <br />
-        <b>Item Info Notes:</b>
-        <p>
-                {% if item.item_info.notes %}{{ item.item_info.notes }}{% else %}No notes found{% endif %}
-        </p>
-        <br />
-        <b>Item Specific Notes:</b>
-        <p>
-                {% if item.notes %}{{ item.notes }}{% else %}No notes found{% endif %}
-        </p>
-        <br />
-        <center><div id="lts-grid"></div></center>
-        
-{% else %}
-        <h3>Item with UUID of {{ uuid }} not found.</h3>
-{% endif %}
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/registration/login.html b/htsworkflow/frontend/templates/registration/login.html
deleted file mode 100644 (file)
index d3d108b..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-{% extends "base_site.html" %}
-{% load i18n %}
-
-{% block additional_css %}{% load staticfiles %}{{ block.super }}
-<link rel="stylesheet" type="text/css" href="{% static "css/base.css" %}"/>
-<link rel="stylesheet" type="text/css" href="{% static "css/login.css" %}"/>
-{% endblock %}
-
-{% block title %}Login{% endblock %}
-{% block bodyclass %}login{% endblock %}
-
-{% block content %}
-{% if error_message %}
-<p class="errornote">{{ error_message }}</p>
-{% endif %}
-<div id="container">
-    <h1>Login</h1>
-<form action="{{ app_path }}" method="post" id="login-form">
-  {% csrf_token %}
-  <div class="form-row">
-    <label for="id_username">{% trans 'Username:' %}</label> <input type="text" name="username" id="id_username" />
-  </div>
-  <div class="form-row">
-    <label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" />
-    <input type="hidden" name="this_is_the_login_form" value="1" />
-  </div>
-  <div class="submit-row">
-    <label>&nbsp;</label><input type="submit" value="{% trans 'Log in' %}" />
-  </div>
-</form>
-
-<script type="text/javascript">
-document.getElementById('id_username').focus()
-</script>
-</div>
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/registration/profile.html b/htsworkflow/frontend/templates/registration/profile.html
deleted file mode 100644 (file)
index fec48b0..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-{% extends "base_site.html" %}
-
-{% block content %}
-<table>
-    <tr><td>User Name:</td><td>{{ user.username }}</td></tr>
-    <tr><td>Full Name:</td><td>{{ user.get_full_name }}</td></tr>
-    <tr><td>E-mail:</td><td>{{ user.email }}</td></tr>
-</table>
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/reports/report.html b/htsworkflow/frontend/templates/reports/report.html
deleted file mode 100644 (file)
index c134377..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-{% extends "admin/base_site.html" %}
-
-{% if main %}
-{% block content %}
- {{ main|safe }}
-
-{% endblock %}
-{% else %}
-    <p>No content. Can't create report.</p>
-{% endif %}
diff --git a/htsworkflow/frontend/templates/sample_header.html b/htsworkflow/frontend/templates/sample_header.html
deleted file mode 100644 (file)
index a198cef..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-{% load staticfiles %}
-<div id="librarydetail"
-     about="{{lib.get_absolute_url}}"
-     typeof="libns:Library">
-  <div class="library_identity">
-    <h2>Library Name</h2>
-    <b>Library ID</b>:
-       <a href="{{lib.get_absolute_url}}"><span property="libns:library_id">{{ lib.id }}</span></a>
-       {% if user.is_staff %}<a href="{{lib.get_admin_url}}"><img class="icon_button" src="{% static "admin/img/icon_changelink.gif" %}" alt="Edit"/></a>{% endif %}
-       <br />
-    <b>Name</b>:
-      <span property="libns:name">{{ lib.library_name }}</span>
-    <br/>
-    <b>Affiliations</b>:
-    <ul>
-      {% for individual in lib.affiliations.all %}
-        <li property="libns:affiliation" content="{{individual.name}}">
-          {{ individual.name }} ( {{ individual.contact }} )
-        </li>
-      {% endfor %}
-    </ul>
-  </div>
-  <div class="library_sample_detail">
-    <h2>Sample Details</h2>
-    <b>Species</b>:
-      <span property="libns:species_name" content="{{lib.library_species.scientific_name}}"><a href="{{lib.library_species.get_absolute_url}}">{{ lib.library_species.scientific_name }}</a></span>
-    <br/>
-    <b>Experiment Type</b>:
-       <span property="libns:experiment_type">{{ lib.experiment_type }}</span>
-    <br/>
-    {% if lib.antibody %}
-    <b>Antibody</b>:
-       <span property="libns:antibody">{{ lib.antibody.antibodies }}</span>
-       {% if lib.antibody.antibodies.nickname %}
-       (<span property="libns:antibody_term">{{ lib.antibody.nickname }}</span>)
-       {% endif %}
-    <br/>
-    {% endif %}
-    {% if lib.cell_line %}
-    <b>Background or Cell Line</b>:
-       <span property="libns:cell_line">{{ lib.cell_line }}</span>
-    <br/>
-    {% endif %}
-    {% if lib.condition %}
-    <b>Condition</b>:
-       <span property="libns:condition">{{ lib.condition.condition_name }}</span>
-       {% if lib.condition.nickname %}
-       (<span property="libns:condition_term">{{ lib.condition.nickname }}</span>)
-       {% endif %}
-    <br/>
-    {% endif %}
-    {% if lib.replicate %}
-    <b>Replicate</b>:
-       <span property="libns:replicate">{{ lib.replicate }}</span>
-    <br/>
-    {% endif %}
-  </div>
-  <div class="library_library_detail">
-    <h2>Library Details</h2>
-    <b>Library Type</b>:
-       <span property="libns:library_type">{{ lib.library_type }}</span>
-    <br/>
-    <b>Multiplex Index</b>:
-       <span property="libns:multiplex_index">{{ lib.index_sequence_text }}</span>
-    <br/>
-    <b>Creation Date</b>
-      <span property="libns:date" content="{{lib.creation_date|date:'Y-m-d'}}T00:00:00" datatype="xsd:dateTime">{{ lib.creation_date }}</span>
-    <br/>
-    <b>Made By</b>:
-      <span property="libns:made_by">{{ lib.made_by }}</span>
-    <br/>
-    {% if lib.gel_cut_size %}
-    <b>Gel Cut Size</b>:
-      <span property="libns:gel_cut" datatype="xsd:integer">{{ lib.gel_cut_size }}</span>
-    <br/>
-    {% endif %}
-    {% if lib.insert_size %}
-    <b>Insert Size</b>:
-      <span property="libns:insert_size" datatype="xsd:integer">{{ lib.insert_size }}</span>
-    <br/>
-    {% endif %}
-    {% if lib.undiluted_concentration %}
-    <b>Concentration</b>:
-      <span property="libns:concentration">{{ lib.undiluted_concentration }} ng/µl</span>
-    <br/>
-    {% endif %}
-    {% if lib.stopping_point_name %}
-    <b>Protocol Stopping Point</b>
-      <span property="libns:stopping_point">{{ lib.stopping_point_name }}</span>
-    <br/>
-    {% endif %}
-  </div>
-</div>
diff --git a/htsworkflow/frontend/templates/samples/antibody_index.html b/htsworkflow/frontend/templates/samples/antibody_index.html
deleted file mode 100644 (file)
index 7ef6c54..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-{% extends "base_site.html" %}
-{% load admin_list i18n %}
-
-{% block bodyclass %}change-list{% endblock %}
-{% block coltype %}flex{% endblock %}
-
-{% block content %}
-<div id="antibody-index-div">
-{% block body %}
-<table >
-  <thead >
-    <tr >
-      <td >Antigene</td>
-      <td >Nickname</td>
-      <td >Antibodies</td>
-      <td >Catalog</td>
-      <td >Source</td>
-  </tr>
-  </thead>
-  <tbody >
-    {% for antibody in antibodies %}
-    <tr >
-      <td >
-        {{ antibody.antigene }}
-      </td>
-      <td >
-        {{ antibody.nickname }}
-      </td>
-      <td >
-        {{ antibody.antibodies }}
-      </td>
-      <td >
-        {{ antibody.catalog }}
-      </td>
-      <td >
-        {{ antibody.source }}
-      </td>
-   </tr>
-    {% endfor %}
-  </tbody>
-</table>
-</div>
-{% endblock %}
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/samples/lanes_for.html b/htsworkflow/frontend/templates/samples/lanes_for.html
deleted file mode 100644 (file)
index b71d0be..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-{% extends "base_site.html" %}
-{% load admin_list i18n %}
-
-{% block bodyclass %}change-list{% endblock %}
-{% block coltype %}flex{% endblock %}
-
-{% block content %}
-<div id="lanes-index-div">
-  <div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
-    {% block search %}{% search_form lanes %}{% endblock %}
-
-    {% block filters %}
-    {% if lanes.has_filters %}
-    <div id="changelist-filter">
-      <h2 >{% trans 'Filter' %}</h2>
-      {% for spec in lanes.filter_specs %}
-         {% admin_list_filter lanes spec %}
-         {% endfor %}
-       </div>
-       {% endif %}
-       {% endblock %}
-
-  
- {% block pagination %}{% pagination lanes %}{% endblock %}
-
-{% block body %}
-<table >
-  <thead >
-    <tr >
-      <td >Run Date</td>
-      <td >Flowcell Type</td>
-      <td >Cycles</td>
-      <td >Flowcell ID</td>
-      <td >Lane</td>
-      <td >Library ID</td>
-      <td >Library Name</td>
-  </tr>
-  </thead>
-  <tbody >
-    {% for lane in lanes.query_set %}
-    <tr >
-      <td >
-        {{ lane.flowcell.run_date|date:"Y-M-d" }}
-      </td>
-      <td >
-        {{ lane.flowcell.flowcell_type }}
-      </td>
-      <td >
-        {{ lane.flowcell.read_length }}
-      </td>
-      <td >
-        {{ lane.flowcell.flowcell_id }}
-      </td>
-      <td >
-        {{ lane.lane_number }}
-      </td>
-      <td >
-        <a href="/library/{{ lane.library_id }}">{{ lane.library_id }}</a>
-      </td>
-      <td >
-        <a href="/library/{{ lane.library_id }}">{{ lane.library.library_name }}</a>
-      </td>
-   </tr>
-    {% endfor %}
-  </tbody>
-</table>
-</div>
-{% endblock %}
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/samples/library_detail.html b/htsworkflow/frontend/templates/samples/library_detail.html
deleted file mode 100644 (file)
index 65747dc..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-{% extends "base_site.html" %}
-{% load staticfiles %}
-{% load humanize i18n %}
-{% block extrahead %}
-    <!-- App Stuff -->
-    <link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}"/>
-    <script type="text/javascript" src="{% static "js/jquery.min.js" %}"></script>
-
-    {% block additional_javascript %}
-    {% endblock %}
-{% endblock %}
-
-{% block content %}
-  {% include "sample_header.html" %}
-  <hr/>
-  <div class="library_statistics">
-  <h2>Raw Result Files</h2>
-  <table>
-  <thead>
-    <tr>
-      <td>Run Start Date</td>
-      <td>Cycle</td>
-      <td>Flowcell</td>
-      <td>Lane</td>
-      <td>Summary</td>
-      <td>Eland</td>
-      <td>Bed</td>
-      <td>Archived</td>
-    </tr>
-  </thead>
-  <tbody>
-  {% if eland_results %}
-    {% for result in eland_results %}
-    <tr about="{{result.flowcell.get_absolute_url}}">
-      <td property="libns:date" content="{{result.run_date|date:'Y-m-d\TH:i:s'}}" datatype="xsd:dateTime">{{ result.run_date|date}}</td>
-      <td>{{ result.cycle }}</td>
-      <td><a href="{{result.flowcell.get_absolute_url}}"><span property="libns:flowcell_id">{{ result.flowcell_id }}</span></a>{% if user.is_staff %}<a href="{{result.flowcell.get_admin_url}}"><img class="icon_button" src="{% static "admin/img/icon_changelink.gif" %}" alt="Edit"/></a>{% endif%}</td>
-      <td>{{ result.lane.lane_number }}</td>
-      <td><a href="{{ result.summary_url }}">Summary</a></td>
-      <td><a href="{{ result.result_url }}">{{ result.result_label }}</a></td>
-      <td>
-      {% if result.bed_url %}
-        <a href="{{ result.bed_url }}">Bed</a>
-      {% endif %}
-      </td>
-      <td>
-        {% if result.storage_ids %}
-          {{ result.storage_ids|safe }}
-        {% endif %}
-      </td>
-    </tr>
-    {% endfor %}
-  {% else %}
-    <tr><td colspan="8">No data</td></tr>
-  {% endif %}
-  </tbody>
-  </table>
-
-  <h2>Lane Summary Statistics</h2>
-  {% block summary_stats %}
-  <table>
-    <thead>
-      <tr>
-        <td colspan="7"></td>
-        <td colspan="2">No Match</td>
-        <td colspan="2">QC Failed</td>
-        <td colspan="4">Unique</td>
-        <td colspan="4">Repeat</td>
-      </tr>
-      <tr>
-      <td>Cycles</td>
-      <td>Flowcell</td>
-      <td>Lane</td>
-      <td>End</td>
-      <td>Cluster / Tile</td>
-      <td>pM</td>
-      <td>Raw Reads</td>
-      <td>total</td>
-      <td>%</td>
-      <td>total</td>
-      <td>%</td>
-      <td>0 mismatch</td>
-      <td>1 mismatch</td>
-      <td>2 mismatch</td>
-      <td>Total</td>
-      <td>0 mismatch</td>
-      <td>1 mismatch</td>
-      <td>2 mismatch</td>
-      <td>Total</td>
-      </tr>
-    </thead>
-    <tbody>
-    {% if lane_summary_list %}
-      {# ls short for lane summary #}
-      {% for ls in lane_summary_list %}
-      <tr about="{{ls.lane.get_absolute_url}}">
-        <td>{{ ls.cycle_width }}</td>
-        <td><a href="{{ls.flowcell.get_absolute_url}}">{{ ls.flowcell_id }}</a>
-        </td>
-        <td><a href="{{ls.lane.get_absolute_url}}">{{ ls.lane_id }}</a></td>
-        <td>{% if ls.end %}{{ ls.end }}{% endif %}</td>
-        <td>{{ ls.clusters.0|intcomma }}</td>
-        <td>{{ ls.successful_pm }}</td>
-        <td>{{ ls.reads|intcomma }}</td>
-        <td>{{ ls.no_match|intcomma }}</td>
-        <td>{{ ls.no_match_percent|stringformat:".2f" }}</td>
-        <td>{{ ls.qc_failed|intcomma }}</td>
-        <td>{{ ls.qc_failed_percent|stringformat:".2f" }}</td>
-        <td>{{ ls.match_codes.U0|intcomma }}</td>
-        <td>{{ ls.match_codes.U1|intcomma }}</td>
-        <td>{{ ls.match_codes.U2|intcomma }}</td>
-        <td {% if ls.unique_reads %}property="libns:total_unique_locations" content="{{ls.unique_reads}}" datatype="xsd:decimal"{% endif %}>{{ ls.unique_reads|intcomma }}</td>
-        <td>{{ ls.match_codes.R0|intcomma }}</td>
-        <td>{{ ls.match_codes.R1|intcomma }}</td>
-        <td>{{ ls.match_codes.R2|intcomma }}</td>
-        <td>{{ ls.repeat_reads|intcomma }}</td>
-      </tr>
-      {% endfor %}
-      {% else %}
-       <tr><td colspan="20">No data</td></tr>
-    {% endif %}
-  </tbody>
-    </table>
-
-  <h2>Flowcell Notes</h2>
-  <table>
-    <thead>
-      <tr>
-       <td>Flowcell ID</td>
-       <td>Lane</td>
-       <td>Comment</td>
-      </tr>
-    </thead>
-    {% if lib.lane_set.all %}
-    <tbody>
-      {% for lane in lib.lane_set.all %}
-      <tr rel="libns:has_lane" 
-          about="{{lib.get_absolute_url}}"
-          resource="{{lane.get_absolute_url}}">
-        <td>
-          <a typeof="libns:IlluminaFlowcell" href="{{lane.flowcell.get_absolute_url}}">
-            <span property="libns:flowcell_id"
-                  >{{lane.flowcell.flowcell_id}}</span></a>
-          {% if user.is_staff %}
-            <a href="{{lane.flowcell.get_admin_url}}">
-               <img class="icon_button"
-                    src="{% static "admin/img/icon_changelink.gif" %}" alt="Edit"/>
-            </a>
-          {% endif%}
-        </td>
-        <td typeof="libns:IlluminaLane" about="{{lane.get_absolute_url}}">
-          <span rel="libns:flowcell" resource="{{lane.flowcell.get_absolute_url}}"></span>
-          <a href="{{lane.get_absolute_url}}">
-            <span property="libns:lane_number"
-               >{{ lane.lane_number }}</span>
-            </a></td>
-        <td>{{ lane.comment }}</td>
-      </tr>
-         {% endfor %}
-    </tbody>
-    {% endif %}
-  </table>
-  <br/>
-  <hr/>
-  <h2>Count of multi-reads</h2>
-  {% for eland_lane in lane_summary_list %}
-    {% if eland_lane.summarized_reads %}
-    <h3>{{eland_lane.cycle_width}} {{ eland_lane.flowcell_id }} lane {{ eland_lane.lane_id }}
-      {% if eland_lane.end %} end {{ eland_lane.end }}{% endif %}
-    </h3>
-    <ul about="{{eland_lane.lane.get_absolute_url}}">
-      {% for name, counts in eland_lane.summarized_reads.items %}
-      <li rel="libns:has_mappings">
-         <b property="libns:mapped_to">{{ name }}</b>:
-         <span property="libns:reads" content="{{counts}}" datatype="xsd:integer">{{ counts|intcomma }}</span></li>
-      {% endfor %}
-    </ul>
-    {% endif %}
-  {% endfor %}
-  {% endblock %}
-  </div>
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/samples/library_index.html b/htsworkflow/frontend/templates/samples/library_index.html
deleted file mode 100644 (file)
index 6ee9750..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-{% extends "base_site.html" %}
-{% load admin_list i18n %}
-{% load staticfiles %}
-{% block extrahead %}
-    <!-- App Stuff -->
-    <link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}"/>
-
-    {% block additional_javascript %}
-    <script type="text/javascript" src="{% static "js/jquery.min.js" %}"></script>
-    <script type="text/javascript" src="{% static "js/htsw.js" %}"></script>
-    <script type="text/javascript">
-      $(document).ready(function() {
-        $(window).resize(function() {
-           var window_height = $(window).height();
-           var position = $("#changelist table").position();
-           height = window_height - position.top;
-           $("#changelist table.filtered").height(height);
-           $("#changelist-filter").height(height);
-        });
-        $(window).resize();
-      });
-    </script>
-    {% endblock %}
-{% endblock %}
-{% block bodyclass %}change-list{% endblock %}
-{% block coltype %}flex{% endblock %}
-
-{% block content %}
-<div id="library_header_link">
-{% if todo_only %}<a href="..">All</a>{% else %}<a href="not_run/">Not run</a>
-{% endif %}
-</div>
-<div id="library-index-div" >
-  <div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
-    {% block search %}{% search_form cl %}{% endblock %}
-
-    {% block pagination %}{% pagination cl %}{% endblock %}
-
-    {% block filters %}
-    {% if cl.has_filters %}
-    <div id="changelist-filter">
-      <h2 >{% trans 'Filter' %}</h2>
-      {% for spec in cl.filter_specs %}
-         {% admin_list_filter cl spec %}
-         {% endfor %}
-    </div>
-    {% endif %}
-    {% endblock %}
-  {% block summary_stats %}
-  <table class="{% if cl.has_filters %} filtered{% endif %}">
-    <thead >
-      <tr >
-        <td >Parent</td>
-        <td >Library ID</td>
-        <td >Species</td>
-        <td >Library Name</td>
-        <td colspan="3" >Single</td>
-        <td colspan="3" >Paired</td>
-        <td >HD</td>
-      </tr>
-      <tr >
-        <td colspan="4"></td>
-        <td>&lt;40</td>
-        <td>&lt;100</td>
-        <td>100+</td>
-        <td>&lt;40</td>
-        <td>&lt;100</td>
-        <td>100+</td>
-        <td></td>
-      </tr>
-    </thead>
-    <tbody >
-      {% for lib in library_list %}
-      <tr typeof="libns:Library" about="{{lib.library.get_absolute_url}}">
-        <td ><a href="{{lib.library.get_absolute_url}}">{{ lib.amplified_from }}</a></td>
-        <td ><a href="{{lib.library.get_absolute_url}}"><span property="libns:library_id">{{ lib.library_id }}</span></a></td>
-        <td rel="libns:species">
-          <a typeof="libns:Species"
-             href="{{lib.library.library_species.get_absolute_url}}">
-            <span property="libns:species_name">{{ lib.species_name }}</span>
-          </a>
-        </td>
-        <td >
-          <a href="{{ lib.library.get_absolute_url }}">
-            <span property="libns:name">{{ lib.library_name }}</span>
-          </a>
-        </td>
-        <td  bgcolor="#00BFFF">{{ lib.lanes_run.0.0 }}</td>
-        <td  bgcolor="#00BFFF">{{ lib.lanes_run.0.1 }}</td>
-        <td  bgcolor="#00BFFF">{{ lib.lanes_run.0.2 }}</td>
-        <td  bgcolor="#66CDAA">{{ lib.lanes_run.1.0 }}</td>
-        <td  bgcolor="#66CDAA">{{ lib.lanes_run.1.1 }}</td>
-        <td  bgcolor="#66CDAA">{{ lib.lanes_run.1.2 }}</td>
-        {% if lib.is_archived %}
-          <td ><img src="{% static "img/hdd_unmount.png" %}" alt="Archived" /></td>
-        {% else %}
-          <td ></td>
-        {% endif %}
-      </tr>
-      {% endfor %}
-    </tbody>
-  </table>
-  </div>
-  {% endblock %}
-</div>
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/samples/species_detail.html b/htsworkflow/frontend/templates/samples/species_detail.html
deleted file mode 100644 (file)
index 36561c7..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-{% extends "base_site.html" %}
-{% load staticfiles %}
-{% load humanize i18n %}
-{% block extrahead %}
-    <!-- App Stuff -->
-    <link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}" />
-    <script type="text/javascript" src="{% static "js/jquery.min.js" %}"></script>
-    
-    {% block additional_javascript %}
-    {% endblock %}
-{% endblock %}
-
-{% block content %}
-<div id="genome_detail">
-  <h2>About this Genome</h2>
-  <b>Common Name</b>: 
-     <span property="libns:species_name">{{ species.common_name}}</span><br/>
-  <b>Scientific Name</b>: 
-     <span property="libns:species_name">{{ species.scientific_name}}</span><br/>
-</div>  
-{% endblock %}
diff --git a/htsworkflow/frontend/templates/search_form.html b/htsworkflow/frontend/templates/search_form.html
deleted file mode 100644 (file)
index 3c66304..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{% load staticfiles %}
-{% load i18n %}
-{% if cl.search_fields %}
-<div id="toolbar"><form id="changelist-search" action="" method="get">
-<div><!-- DIV needed for valid HTML -->
-<label for="searchbar"><img src="{% static "img/admin/icon_searchbox.png" %}" alt="Search" /></label>
-<input type="text" size="40" name="{{ search_var }}" value="{{ cl.query }}" id="searchbar" />
-<input type="submit" value="{% trans 'Go' %}" />
-{% if show_result_count %}
-    <span class="small quiet">{% blocktrans count cl.result_count as counter %}1 result{% plural %}{{ counter }} results{% endblocktrans %} (<a href="?{% if cl.is_popup %}pop=1{% endif %}">{% blocktrans with cl.full_result_count as full_result_count %}{{ full_result_count }} total{% endblocktrans %}</a>)</span>
-{% endif %}
-{% for pair in cl.params.items %}
-    {% ifnotequal pair.0 search_var %}<input type="hidden" name="{{ pair.0 }}" value="{{ pair.1 }}"/>{% endifnotequal %}
-{% endfor %}
-</div>
-</form></div>
-<script type="text/javascript">document.getElementById("searchbar").focus();</script>
-{% endif %}
diff --git a/htsworkflow/frontend/urls.py b/htsworkflow/frontend/urls.py
deleted file mode 100644 (file)
index 681edaa..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-from django.conf.urls import include, patterns, url
-from django.contrib import admin
-import django
-admin.autodiscover()
-
-from django.conf import settings
-
-urlpatterns = patterns('',
-    url('^accounts/login/$', 'django.contrib.auth.views.login'),
-    url('^accounts/logout/$', 'django.contrib.auth.views.logout'),
-    url('^accounts/logout_then_login/$', 'django.contrib.auth.views.logout_then_login'),
-    url('^accounts/password_change/$', 'django.contrib.auth.views.password_change'),
-    url('^accounts/password_change_done/$', 'django.contrib.auth.views.password_change_done'),
-    #url('^accounts/profile/$', 'htsworkflow.frontend.samples.views.user_profile'),
-    # Base:
-    url(r'^eland_config/', include('htsworkflow.frontend.eland_config.urls')),
-    ### MOVED Admin from here ###
-    # Experiments:
-    url(r'^experiments/', include('htsworkflow.frontend.experiments.urls')),
-    ### Flowcell:
-    url(r'^lane/(?P<lane_pk>\w+)',
-        'htsworkflow.frontend.experiments.views.flowcell_lane_detail'),
-    url(r'^flowcell/(?P<flowcell_id>\w+)/((?P<lane_number>\w+)/)?$',
-        'htsworkflow.frontend.experiments.views.flowcell_detail'),
-    ## AnalysTrack:
-    ##(r'^analysis/', include('htsworkflow.frontend.analysis.urls')),
-    ## Inventory urls
-    url(r'^inventory/', include('htsworkflow.frontend.inventory.urls')),
-    ## Report Views:
-    ##url(r'^reports/', include('htsworkflow.frontend.reports.urls')),
-    ## Library browser
-    url(r'^library/$', 'htsworkflow.frontend.samples.views.library'),
-    url(r'^library/not_run/$',
-        'htsworkflow.frontend.samples.views.library_not_run'),
-    url(r'^library/(?P<lib_id>\w+)/$',
-        'htsworkflow.frontend.samples.views.library_to_flowcells'),
-    url(r'^lanes_for/$', 'htsworkflow.frontend.samples.views.lanes_for'),
-    url(r'^lanes_for/(?P<username>\w+)', 'htsworkflow.frontend.samples.views.lanes_for'),
-    ### library id to admin url
-    url(r'^library_id_to_admin_url/(?P<lib_id>\w+)/$',
-        'htsworkflow.frontend.samples.views.library_id_to_admin_url'),
-    ### sample / library information
-    url(r'^samples/', include('htsworkflow.frontend.samples.urls')),
-    url(r'^sequencer/(?P<sequencer_id>\w+)',
-        'htsworkflow.frontend.experiments.views.sequencer'),
-    ## Raw result files
-    #url(r'^results/(?P<flowcell_id>\w+)/(?P<cnm>C[0-9]+-[0-9]+)/summary/',
-      #'htsworkflow.frontend.samples.views.summaryhtm_fc_cnm'),
-    #url(r'^results/(?P<flowcell_id>\w+)/(?P<cnm>C[0-9]+-[0-9]+)/eland_result/(?P<lane>[1-8])',
-      #'htsworkflow.frontend.samples.views.result_fc_cnm_eland_lane'),
-    #url(r'^results/(?P<fc_id>\w+)/(?P<cnm>C[1-9]-[0-9]+)/bedfile/(?P<lane>[1-8])/ucsc',
-      #'htsworkflow.frontend.samples.views.bedfile_fc_cnm_eland_lane_ucsc'),
-    #url(r'^results/(?P<fc_id>\w+)/(?P<cnm>C[1-9]-[0-9]+)/bedfile/(?P<lane>[1-8])',
-      #'htsworkflow.frontend.samples.views.bedfile_fc_cnm_eland_lane'),
-    url(r'^bcmagic/', include('htsworkflow.frontend.bcmagic.urls')),
-
-    url(r'^admin/', include(admin.site.urls)),
-)
index fe2b9428cd01c38775c6a743dc2588b140425833..7951752318aebe7d2443c010e64ac24149023167 100644 (file)
@@ -15,7 +15,7 @@ try:
 except ImportError, e:
     import simplejson as json
 
-from htsworkflow.frontend.auth import apidata
+from htsworkflow.auth import apidata
 from htsworkflow.util import api
 from htsworkflow.util import alphanum
 from htsworkflow.util.url import normalize_url
index cf30dd734e77b5e3d0ea98fd4ad9c00b77f6af5d..fd1c11287ce9934d12060f148728938155b7ffb8 100644 (file)
@@ -10,7 +10,7 @@ except ImportError, e:
 
 from django.test import TestCase
 
-from htsworkflow.frontend.auth import apidata
+from htsworkflow.auth import apidata
 from htsworkflow.pipelines.retrieve_config import \
      format_gerald_config, \
      getCombinedOptions, \
index dce3d90c53608f876cf6b786604288513e96b972..f030a957444f947452d6d02aea7d70e963ffd50b 100644 (file)
@@ -10,8 +10,10 @@ https://docs.djangoproject.com/en/1.6/ref/settings/
 
 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
 import os
-BASE_DIR = os.path.dirname(os.path.dirname(__file__))
+import sys
 
+DJANGO_ROOT = os.path.dirname(__file__)
+PROJECT_ROOT = os.path.dirname(DJANGO_ROOT)
 
 # Quick-start development settings - unsuitable for production
 # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
@@ -31,7 +33,7 @@ ALLOWED_HOSTS = ['jumpgate.caltech.edu']
 
 # Application definition
 AUTHENTICATION_BACKENDS = (
-  'htsworkflow.frontend.samples.auth_backend.HTSUserModelBackend', )
+  'samples.auth_backend.HTSUserModelBackend', )
 CUSTOM_USER_MODEL = 'samples.HTSUser'
 
 INSTALLED_APPS = (
@@ -43,12 +45,12 @@ INSTALLED_APPS = (
     'django.contrib.staticfiles',
     'django.contrib.humanize',
 
-    'htsworkflow.frontend.eland_config',
-    'htsworkflow.frontend.samples',
-    'htsworkflow.frontend.experiments',
-    'htsworkflow.frontend.bcmagic',
-    'htsworkflow.frontend.inventory',
-    'htsworkflow.frontend.labels',
+    'eland_config',
+    'samples',
+    'experiments',
+    'bcmagic',
+    'inventory',
+    'labels',
 )
 
 MIDDLEWARE_CLASSES = (
@@ -61,11 +63,10 @@ MIDDLEWARE_CLASSES = (
 )
 
 TEMPLATE_DIRS = (
-    os.path.join(BASE_DIR, 'htsworkflow', 'frontend', 'templates'),
-    os.path.join(BASE_DIR, 'htsworkflow', 'templates'),
+    os.path.join(DJANGO_ROOT, 'templates'),
 )
 
-ROOT_URLCONF = 'htsworkflow.frontend.urls'
+ROOT_URLCONF = 'htsworkflow.urls'
 
 WSGI_APPLICATION = 'wsgi.application'
 
@@ -75,7 +76,7 @@ WSGI_APPLICATION = 'wsgi.application'
 DATABASES = {
     'default': {
         'ENGINE': 'django.db.backends.sqlite3',
-        'NAME': os.path.join(BASE_DIR, 'fctracker.db'),
+        'NAME': os.path.join(PROJECT_ROOT, 'fctracker.db'),
     }
 }
 
@@ -99,7 +100,7 @@ TIME_ZONE='America/Los_Angeles'
 # Static files (CSS, JavaScript, Images)
 # https://docs.djangoproject.com/en/1.6/howto/static-files/
 STATICFILES_DIRS = (
-    os.path.join(BASE_DIR, 'htsworkflow', 'frontend', 'static'),
+    os.path.join(DJANGO_ROOT, 'static'),
 )
 STATIC_URL = '/static/'
 
@@ -111,7 +112,7 @@ DEFAULT_PM = 5
 # How often to recheck the result archive
 RESCAN_DELAY=1
 # Update this in settings_local to point to your flowcell result directory
-RESULT_HOME_DIR = os.path.join(BASE_DIR, 'test', 'result', 'flowcells')
+RESULT_HOME_DIR = os.path.join(PROJECT_ROOT, 'test', 'result', 'flowcells')
 
 # configure who is sending email and who should get BCCs of announcments
 NOTIFICATION_SENDER = "noreply@example.com"
diff --git a/htsworkflow/static/css/admin_flowcell.css b/htsworkflow/static/css/admin_flowcell.css
new file mode 100644 (file)
index 0000000..19e7589
--- /dev/null
@@ -0,0 +1,2 @@
+.strikeout { text-decoration: line-through; }
+
diff --git a/htsworkflow/static/css/app.css b/htsworkflow/static/css/app.css
new file mode 100644 (file)
index 0000000..1725e15
--- /dev/null
@@ -0,0 +1,151 @@
+#header {
+    background: #7F99BE url(/static/img/layout-browser-hd-bg.gif) repeat-x center;
+}
+#header h1 {
+    font-size: 16px;
+    color: #fff;
+    font-weight: normal;
+    padding: 5px 10px;
+}
+
+#left_bar {
+    position: absolute;
+    top: 5px;
+    left: 5px;
+    width: 172px;
+    height: auto;
+    min-height: 600px;
+}
+
+#main {
+    position: relative;
+    /* background: #BBBBFF; */
+    width:auto;
+    min-width:120px;
+    padding: 10px;
+    margin:0px 0px 0px 175px;
+    min-height:600px;
+}
+
+.icon_button {
+   border-style: solid;
+   border-width: 1px;
+   padding: 1px;
+   margin: 0px 0px -2px 2px;
+}
+
+div.msg {
+    color: white;
+    background: #880000;
+}
+
+div.htswdetail {
+    clear: both;
+    margin: 0;
+    padding: 0;
+}
+div.htswdetail table, div.htswdetail td {
+    border-style: solid;
+}
+div.htswdetail table {
+    border-width: 0 0 1px 1px;
+    border-spacing: 0;
+    border-collapse: collapse;
+}
+div.htswdetail td {
+    margin: 0;
+    padding: 3px;
+    border-width: 1px 1px 0 0;
+}
+div.htswdetail thead {
+    text-align: center;
+}
+div.htswdetail tbody {
+    text-align: left;
+  }
+div.htswdetail h1,
+div.htswdetail h2
+{
+    font-size: 150%;
+}
+
+div.htswdetail h3 {
+     font-size: 125%;
+     margin: 0;
+}
+
+div.htswdetail h4,
+div.htswdetail h5,
+div.htswdetail ul,
+div.htswdetail ol,
+div.htswdetail li
+{
+  list-style: none;
+  margin: 0;
+}
+
+div.htswdetail ul,
+div.htswdetail ol
+{
+  margin-bottom: .5em;
+}
+
+/* style library detail headers */
+div#librarydetail {
+  margin: 0;
+  padding: 0;
+}
+div#librarydetail table, div#librarydetail td {
+  border-style: solid;
+}
+div#librarydetail table {
+  border-width: 0 0 1px 1px;
+  border-spacing: 0;
+  border-collapse: collapse;
+}
+div#librarydetail td {
+  margin: 0;
+  padding: 3px;
+  border-width: 1px 1px 0 0;
+}
+div#librarydetail thead {
+  text-align: center;
+  }
+div#librarydetail tbody {
+  text-align: right;
+}
+div#librarydetail h1,
+div#librarydetail h2
+{
+  font-size: 150%;
+}
+
+div#librarydetail h3 {
+   font-size: 125%;
+   margin: 0;
+}
+
+div#librarydetail h4,
+div#librarydetail h5,
+div#librarydetail ul,
+div#librarydetail ol,
+div#librarydetail li
+{
+  list-style: none;
+  margin: 0;
+}
+
+div#librarydetail ul,
+div#librarydetail ol
+{
+  margin-bottom: .5em;
+}
+
+div.library_identity {
+  clear: left; float: left; margin: 5px; }
+div.library_sample_detail { float: left; margin: 5px; }
+div.library_library_detail { float: left; margin: 5px; }
+div.library_statistics { clear: both; border: 1px; }
+
+div.flowcell_identity { clear: left; float: left; margin: 5px;}
+div.flowcell_lane_detail { float: left; margin: 5px; }
\ No newline at end of file
diff --git a/htsworkflow/static/css/base.css b/htsworkflow/static/css/base.css
new file mode 100644 (file)
index 0000000..9760d67
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+    DJANGO Admin
+    by Wilson Miner wilson@lawrence.com
+*/
+
+/* Block IE 5 */
+@import "null.css?\"\{";
+
+/* Import other styles */
+@import url('global.css');
+@import url('layout.css');
+
+/* Import patch for IE 6 Windows */
+/*\*/ @import "patch-iewin.css"; /**/
diff --git a/htsworkflow/static/css/changelists.css b/htsworkflow/static/css/changelists.css
new file mode 100644 (file)
index 0000000..bde1636
--- /dev/null
@@ -0,0 +1,57 @@
+@import url('base.css');
+
+/* CHANGELISTS */
+#changelist {  margin-bottom: 0pm; }
+#changelist table { display: block; }
+#changelist table.filtered { overflow-y: scroll; }
+.change-list .filtered table { border-right:1px solid #ddd;  }
+.change-list .filtered { min-height:400px; }
+.change-list .filtered { background:white url(../img/changelist-bg.gif) top right repeat-y !important; }
+.change-list .filtered table, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { width:auto !important; }
+.change-list .filtered table tbody th { padding-right:1em; }
+#changelist .toplinks { border-bottom:1px solid #ccc !important; }
+#changelist .paginator { color:#666; border-top:1px solid #eee; border-bottom:1px solid #eee; background:white url(../img/nav-bg.gif) 0 180% repeat-x; overflow:hidden; }
+.change-list .filtered .paginator { border-right:1px solid #ddd; }
+
+/*  CHANGELIST TABLES  */
+#changelist table thead th { white-space:nowrap; }
+#changelist table tbody td { border-left: 1px solid #ddd;  }
+#changelist table tfoot { color: #666; }
+#changelist tbody { }
+
+/*  TOOLBAR  */
+#changelist #toolbar { padding:3px; border-bottom:1px solid #ddd; background:#e1e1e1 url(../img/nav-bg.gif) top left repeat-x; color:#666; }
+#changelist #toolbar form input { font-size:11px; padding:1px 2px; }
+#changelist #toolbar form #searchbar { padding:2px; }
+#changelist #changelist-search img { vertical-align:middle; }
+
+/*  FILTER COLUMN  */
+/*position:absolute; top:0; right:0; z-index:1000; */
+#changelist-filter { float: right;
+                     width: 20em;
+                     border-left:1px solid #ddd; margin:0; 
+                     background:#efefef; 
+                     overflow-y: scroll; }
+#changelist-filter h2 { font-size:11px; padding:2px 5px; border-bottom:1px solid #ddd; }
+#changelist-filter h3 { font-size:12px; margin-bottom:0; }
+#changelist-filter ul { padding-left:0;margin-left:10px; }
+#changelist-filter li { list-style-type:none; margin-left:0; padding-left:0; }
+#changelist-filter a { color:#999; }
+#changelist-filter a:hover { color:#036; }
+#changelist-filter li.selected { border-left:5px solid #ccc; padding-left:5px;margin-left:-10px; }
+#changelist-filter li.selected a { color:#5b80b2 !important; }
+
+/*  DATE DRILLDOWN  */
+.change-list ul.toplinks { display:block; background:white url(../img/nav-bg-reverse.gif) 0 -10px repeat-x; border-top:1px solid white; float:left;  padding:0 !important;  margin:0 !important; width:100%; }
+.change-list ul.toplinks li { float: left; width: 9em; padding:3px 6px; font-weight: bold; list-style-type:none; }
+.change-list ul.toplinks .date-back a { color:#999; }
+.change-list ul.toplinks .date-back a:hover { color:#036; }
+
+/* PAGINATOR */
+.paginator { font-size:11px; padding-top:10px; padding-bottom:10px; line-height:22px; margin:0; border-top:1px solid #ddd; }
+.paginator a:link, .paginator a:visited { padding:2px 6px; border:solid 1px #ccc; background:white; text-decoration:none; }
+.paginator a.showall { padding:0 !important; border:none !important; }
+.paginator a.showall:hover { color:#036 !important; background:transparent !important; }
+.paginator .end { border-width:2px !important; margin-right:6px; }
+.paginator .this-page { padding:2px 6px; font-weight:bold; font-size:13px; vertical-align:top; }
+.paginator a:hover { color:white; background:#5b80b2; border-color:#036; }
diff --git a/htsworkflow/static/css/click-table.css b/htsworkflow/static/css/click-table.css
new file mode 100644 (file)
index 0000000..27b793c
--- /dev/null
@@ -0,0 +1,20 @@
+table, td {
+  border-style: solid;
+}
+table {
+  border-width: 0 0 1px 1px;
+  border-spacing: 0;
+  border-collapse: collapse;
+}
+thead {
+  text-align: center;
+}
+td {
+  margin: 0;
+  padding: 4px;
+  border-width: 1px 1px 0 0;
+}
+td.cell_list a {
+  display: block;
+}
+
diff --git a/htsworkflow/static/css/dashboard.css b/htsworkflow/static/css/dashboard.css
new file mode 100644 (file)
index 0000000..05808bc
--- /dev/null
@@ -0,0 +1,30 @@
+/* DASHBOARD */
+
+.dashboard .module table th {
+    width: 100%;
+}
+
+.dashboard .module table td {
+    white-space: nowrap;
+}
+
+.dashboard .module table td a {
+    display: block;
+    padding-right: .6em;
+}
+
+/* RECENT ACTIONS MODULE */
+
+.module ul.actionlist {
+    margin-left: 0;
+}
+
+ul.actionlist li {
+    list-style-type: none;
+}
+
+ul.actionlist li {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    -o-text-overflow: ellipsis;
+}
diff --git a/htsworkflow/static/css/data-browse-index.css b/htsworkflow/static/css/data-browse-index.css
new file mode 100644 (file)
index 0000000..59119bf
--- /dev/null
@@ -0,0 +1,2 @@
+@import url('changelists.css');
+@import url('click-table.css');
diff --git a/htsworkflow/static/css/forms.css b/htsworkflow/static/css/forms.css
new file mode 100644 (file)
index 0000000..a4b145f
--- /dev/null
@@ -0,0 +1,84 @@
+@import url('base.css');
+@import url('widgets.css');
+
+/* FORM ROWS */
+.form-row { overflow:hidden; padding:8px 12px; font-size:11px; border-bottom:1px solid #eee; }
+.form-row img, .form-row input { vertical-align:middle; }
+form .form-row p { padding-left:0; font-size:11px; }
+
+/* FORM LABELS */
+form h4 { margin:0 !important; padding:0 !important; border:none !important; }
+label { font-weight:normal !important; color:#666; font-size:12px; }
+.required label, label.required { font-weight:bold !important; color:#333 !important; }
+
+/* RADIO BUTTONS */
+form ul.radiolist li { list-style-type:none; }
+form ul.radiolist label { float:none; display:inline; }
+form ul.inline { margin-left:0; padding:0; }
+form ul.inline li { float:left; padding-right:7px; }
+
+/* ALIGNED FIELDSETS */
+.aligned label { display:block; padding:3px 10px 0 0; float:left; width:8em; }
+.colMS .aligned .vLargeTextField, .colMS .aligned .vXMLLargeTextField { width:350px; }
+form .aligned p, form .aligned ul { margin-left:7em; padding-left:30px; }
+form .aligned table p { margin-left:0; padding-left:0; }
+form .aligned p.help { padding-left:38px; }
+.aligned .vCheckboxLabel { float:none !important; display:inline; padding-left:4px; }
+.colM .aligned .vLargeTextField, .colM .aligned .vXMLLargeTextField { width:610px; }
+.checkbox-row p.help { margin-left:0; padding-left:0 !important; }
+fieldset .field-box { float:left; margin-right: 20px; }
+
+/* WIDE FIELDSETS */
+.wide label { width:15em !important; }
+form .wide p { margin-left:15em; }
+form .wide p.help { padding-left:38px; }
+.colM fieldset.wide .vLargeTextField, .colM fieldset.wide .vXMLLargeTextField { width:450px; }
+
+/* COLLAPSED FIELDSETS */
+fieldset.collapsed * { display:none; }
+fieldset.collapsed h2, fieldset.collapsed { display:block !important; }
+fieldset.collapsed h2 { background-image:url(../img/nav-bg.gif); background-position:bottom left; color:#999; }
+fieldset.collapsed .collapse-toggle { padding:3px 5px !important; background:transparent; display:inline !important;}
+
+/* MONOSPACE TEXTAREAS */
+fieldset.monospace textarea { font-family:"Bitstream Vera Sans Mono",Monaco,"Courier New",Courier,monospace; }
+
+/* SUBMIT ROW */
+.submit-row { padding:5px 7px; text-align:right; background:white url(../img/nav-bg.gif) 0 100% repeat-x; border:1px solid #ccc; margin:5px 0; overflow:hidden; }
+.submit-row input { margin:0 0 0 5px; }
+.submit-row p { margin:0.3em; }
+.submit-row p.deletelink-box { float: left; }
+.submit-row .deletelink { background:url(../img/icon_deletelink.gif) 0 50% no-repeat; padding-left:14px; }
+
+/* CUSTOM FORM FIELDS */
+.vSelectMultipleField { vertical-align:top !important; }
+.vCheckboxField { border:none; }
+.vDateField, .vTimeField { margin-right:2px; }
+.vURLField { width:30em; }
+.vLargeTextField, .vXMLLargeTextField { width:48em; }
+.flatpages-flatpage #id_content { height:40.2em; }
+.module table .vPositiveSmallIntegerField { width:2.2em; }
+.vTextField { width:20em; }
+.vIntegerField { width:5em; }
+.vForeignKeyRawIdAdminField { width: 5em; }
+
+/* INLINES */
+.inline-group {padding:0; border:1px solid #ccc; margin:10px 0;}
+.inline-group .aligned label { width: 8em; }
+
+.inline-related {position:relative;}
+.inline-related h3 {margin: 0; color:#666; padding:3px 5px; font-size:11px; background:#e1e1e1 url(../img/nav-bg.gif) top left repeat-x; border-bottom:1px solid #ddd;}
+.inline-related h3 span.delete {padding-left:20px; position:absolute; top:2px; right:10px;}
+.inline-related h3 span.delete label {margin-left:2px; font-size: 11px;}
+.inline-related fieldset {margin: 0; background:#fff; border: none; }
+.inline-related fieldset.module h3 { margin:0; padding:2px 5px 3px 5px; font-size:11px; text-align:left; font-weight:bold; background:#bcd; color:#fff; }
+.inline-related.tabular fieldset.module table {width:100%;}
+.last-related fieldset {border: none;}
+
+.inline-group .tabular tr.has_original td {padding-top:2em;}
+.inline-group .tabular tr td.original { padding:2px 0 0 0; width:0; _position:relative; }
+.inline-group .tabular th.original {width:0px; padding:0;}
+.inline-group .tabular td.original p {position:absolute; left:0; height:1.1em; padding:2px 7px; overflow:hidden; font-size:9px; font-weight:bold; color:#666; _width:700px;     }
+.inline-group ul.tools {padding:0; margin: 0; list-style:none;}
+.inline-group ul.tools li {display:inline; padding:0 5px;}
+.inline-group ul.tools a.add {background:url(../img/icon_addlink.gif) 0 50% no-repeat; padding-left:14px;}
diff --git a/htsworkflow/static/css/global.css b/htsworkflow/static/css/global.css
new file mode 100644 (file)
index 0000000..adc2539
--- /dev/null
@@ -0,0 +1,142 @@
+body { margin:0; padding:0; font-size:14px; font-family:"Lucida Grande","DejaVu Sans","Bitstream Vera Sans",Verdana,Arial,sans-serif; color:#333; background:#fff; }
+
+/* LINKS */
+a:link, a:visited { color: #5b80b2; text-decoration:none; }
+a:hover { color: #036; }
+a img { border:none; }
+a.section:link, a.section:visited { color: white; text-decoration:none; }
+
+/* GLOBAL DEFAULTS */
+p, ol, ul, dl { margin:.2em 0 .8em 0; }
+p { padding:0; line-height:140%; }
+
+h1,h2,h3,h4,h5 { font-weight:bold; }
+h1 { font-size:18px; color:#666; padding:0 6px 0 0; margin:0 0 .2em 0; }
+h2 { font-size:16px; margin:1em 0 .5em 0; }
+h2.subhead { font-weight:normal;margin-top:0; }
+h3 { font-size:14px; margin:.8em 0 .3em 0; color:#666; font-weight:bold; }
+h4 { font-size:12px; margin:1em 0 .8em 0; padding-bottom:3px; }
+h5 { font-size:10px; margin:1.5em 0 .5em 0; color:#666; text-transform:uppercase; letter-spacing:1px; }
+
+ul li { list-style-type:square; padding:1px 0; }
+ul.plainlist { margin-left:0 !important; }
+ul.plainlist li { list-style-type:none; }
+li ul { margin-bottom:0; }
+li, dt, dd { font-size:11px; line-height:14px; }
+dt { font-weight:bold; margin-top:4px; }
+dd { margin-left:0; }
+
+form { margin:0; padding:0; }
+fieldset { margin:0; padding:0; }
+
+blockquote { font-size:11px; color:#777; margin-left:2px; padding-left:10px; border-left:5px solid #ddd; }
+code, pre { font-family:"Bitstream Vera Sans Mono", Monaco, "Courier New", Courier, monospace; background:inherit; color:#666; font-size:11px; }
+pre.literal-block { margin:10px; background:#eee; padding:6px 8px; }
+code strong { color:#930; }
+hr { clear:both; color:#eee; background-color:#eee; height:1px; border:none; margin:0; padding:0; font-size:1px; line-height:1px; }
+
+/* TEXT STYLES & MODIFIERS */
+.small { font-size:11px; }
+.tiny { font-size:10px; }
+p.tiny { margin-top:-2px; }
+.mini { font-size:9px; }
+p.mini { margin-top:-3px; }
+.help, p.help { font-size:10px !important; color:#999; }
+p img, h1 img, h2 img, h3 img, h4 img, td img { vertical-align:middle; }
+.quiet, a.quiet:link, a.quiet:visited { color:#999 !important;font-weight:normal !important; }
+.quiet strong { font-weight:bold !important; }
+.float-right { float:right; }
+.float-left { float:left; }
+.clear { clear:both; }
+.align-left { text-align:left; }
+.align-right { text-align:right; }
+.example { margin:10px 0; padding:5px 10px; background:#efefef; }
+.nowrap { white-space:nowrap; }
+
+/* TABLES */
+table { border-collapse:collapse; border-color:#ccc; }
+td, th { font-size:11px; line-height:13px; border-bottom:1px solid #eee; vertical-align:top; padding:5px; font-family:"Lucida Grande", Verdana, Arial, sans-serif; }
+th { text-align:left; font-size:12px; font-weight:bold; }
+thead th, 
+tfoot td { color:#666; padding:2px 5px; font-size:11px; background:#e1e1e1 url(../img/nav-bg.gif) top left repeat-x; border-left:1px solid #ddd; border-bottom:1px solid #ddd; }
+tfoot td { border-bottom:none; border-top:1px solid #ddd; }
+thead th:first-child, 
+tfoot td:first-child { border-left:none !important; }
+thead th.optional { font-weight:normal !important; }
+fieldset table { border-right:1px solid #eee; }
+tr.row-label td { font-size:9px; padding-top:2px; padding-bottom:0; border-bottom:none; color:#666; margin-top:-1px; }
+tr.alt { background:#f6f6f6; }
+.row1 { background:#EDF3FE; }
+.row2 { background:white; }
+
+/* SORTABLE TABLES */
+thead th a:link, thead th a:visited { color:#666; display:block; }
+table thead th.sorted { background-position:bottom left !important; }
+table thead th.sorted a { padding-right:13px; }
+table thead th.ascending a { background:url(../img/arrow-down.gif) right .4em no-repeat; }
+table thead th.descending a { background:url(../img/arrow-up.gif) right .4em no-repeat; }
+
+/* ORDERABLE TABLES */
+table.orderable tbody tr td:hover { cursor:move; }
+table.orderable tbody tr td:first-child { padding-left:14px; background-image:url(../img/nav-bg-grabber.gif); background-repeat:repeat-y; }
+table.orderable-initalized .order-cell, body>tr>td.order-cell { display:none; }
+
+/* FORM DEFAULTS */
+input, textarea, select { margin:2px 0; padding:2px 3px; vertical-align:middle; font-family:"Lucida Grande", Verdana, Arial, sans-serif; font-weight:normal; font-size:11px; }
+textarea { vertical-align:top !important; }
+input[type=text], input[type=password], textarea, select, .vTextField { border:1px solid #ccc; }
+
+/*  FORM BUTTONS  */
+.button, input[type=submit], input[type=button], .submit-row input { background:white url(../img/nav-bg.gif) bottom repeat-x; padding:3px; color:black; border:1px solid #bbb; border-color:#ddd #aaa #aaa #ddd; }
+.button:active, input[type=submit]:active, input[type=button]:active { background-image:url(../img/nav-bg-reverse.gif); background-position:top; }
+.button.default, input[type=submit].default, .submit-row input.default { border:2px solid #5b80b2; background:#7CA0C7 url(../img/default-bg.gif) bottom repeat-x; font-weight:bold; color:white; float:right; }
+.button.default:active, input[type=submit].default:active { background-image:url(../img/default-bg-reverse.gif); background-position:top; }
+
+/* MODULES */
+.module { border:1px solid #ccc; margin-bottom:5px; background:white; }
+.module p, .module ul, .module h3, .module h4, .module dl, .module pre { padding-left:10px; padding-right:10px; }
+.module blockquote { margin-left:12px; }
+.module ul, .module ol { margin-left:1.5em; }
+.module h3 { margin-top:.6em; }
+.module h2, .module caption, .inline-group h2 { margin:0; padding:2px 5px 3px 5px; font-size:11px; text-align:left; font-weight:bold; background:#7CA0C7 url(../img/default-bg.gif) top left repeat-x; color:white; }
+.module table { border-collapse: collapse; }
+
+/* MESSAGES & ERRORS */
+ul.messagelist { padding:0 0 5px 0; margin:0; }
+ul.messagelist li { font-size:12px; display:block; padding:4px 5px 4px 25px; margin:0 0 3px 0; border-bottom:1px solid #ddd; color:#666; background:#ffc url(../img/icon_success.gif) 5px .3em no-repeat; }
+.errornote { font-size:12px !important; display:block; padding:4px 5px 4px 25px; margin:0 0 3px 0; border:1px solid red; color:red;background:#ffc url(../img/icon_error.gif) 5px .3em no-repeat; }
+ul.errorlist { margin:0 !important; padding:0 !important; }
+.errorlist li { font-size:12px !important; display:block; padding:4px 5px 4px 25px; margin:0 0 3px 0; border:1px solid red; color:white; background:red url(../img/icon_alert.gif) 5px .3em no-repeat; }
+td ul.errorlist { margin:0 !important; padding:0 !important; }
+td ul.errorlist li { margin:0 !important; }
+.errors { background:#ffc; }
+.errors input, .errors select { border:1px solid red; }
+div.system-message { background: #ffc; margin: 10px; padding: 6px 8px; font-size: .8em; }
+div.system-message p.system-message-title { padding:4px 5px 4px 25px; margin:0; color:red; background:#ffc url(../img/icon_error.gif) 5px .3em no-repeat; }
+.description { font-size:12px; padding:5px 0 0 12px; }
+
+/* BREADCRUMBS */
+div.breadcrumbs { background:white url(../img/nav-bg-reverse.gif) 0 -10px repeat-x; padding:2px 8px 3px 8px; font-size:11px;  color:#999;  border-top:1px solid white; border-bottom:1px solid #ccc; text-align:left; }
+
+/* ACTION ICONS */
+.addlink { padding-left:12px; background:url(../img/icon_addlink.gif) 0 .2em no-repeat; }
+.changelink { padding-left:12px; background:url(../img/icon_changelink.gif) 0 .2em no-repeat; }
+.deletelink { padding-left:12px; background:url(../img/icon_deletelink.gif) 0 .25em no-repeat; }
+a.deletelink:link, a.deletelink:visited { color:#CC3434; }
+a.deletelink:hover { color:#993333; }
+
+/* OBJECT TOOLS */
+.object-tools { font-size:10px; font-weight:bold; font-family:Arial,Helvetica,sans-serif; padding-left:0; float:right; position:relative; margin-top:-2.4em; margin-bottom:-2em; }
+.form-row .object-tools { margin-top:5px; margin-bottom:5px; float:none; height:2em; padding-left:3.5em; }
+.object-tools li { display:block; float:left; background:url(../img/tool-left.gif) 0 0 no-repeat; padding:0 0 0 8px; margin-left:2px; height:16px; }
+.object-tools li:hover { background:url(../img/tool-left_over.gif) 0 0 no-repeat; }
+.object-tools a:link, .object-tools a:visited { display:block; float:left; color:white; padding:.1em 14px .1em 8px; height:14px; background:#999 url(../img/tool-right.gif) 100% 0 no-repeat; }
+.object-tools a:hover, .object-tools li:hover a { background:#5b80b2 url(../img/tool-right_over.gif) 100% 0 no-repeat; }
+.object-tools a.viewsitelink, .object-tools a.golink { background:#999 url(../img/tooltag-arrowright.gif) top right no-repeat; padding-right:28px; }
+.object-tools a.viewsitelink:hover, .object-tools a.golink:hover { background:#5b80b2 url(../img/tooltag-arrowright_over.gif) top right no-repeat; }
+.object-tools a.addlink { background:#999 url(../img/tooltag-add.gif) top right no-repeat; padding-right:28px; }
+.object-tools a.addlink:hover { background:#5b80b2 url(../img/tooltag-add_over.gif) top right no-repeat; }
+
+/* OBJECT HISTORY */
+table#change-history { width:100%; }
+table#change-history tbody th { width:16em; }
diff --git a/htsworkflow/static/css/htsw.css b/htsworkflow/static/css/htsw.css
new file mode 100644 (file)
index 0000000..49e3965
--- /dev/null
@@ -0,0 +1,35 @@
+#header {
+    background: #7F99BE url(/static/img/layout-browser-hd-bg.gif) repeat-x center;
+}
+#header h1 {
+    font-size: 16px;
+    color: #fff;
+    font-weight: normal;
+    padding: 5px 10px;
+}
+
+#left_bar {
+    position: absolute;
+    top: 5px;
+    left: 5px;
+    width: 172px;
+    height: auto;
+    min-height: 600px;
+    
+    
+}
+
+#main {
+    position: relative;
+    /* background: #BBBBFF; */
+    width:auto;
+    min-width:120px;
+    padding: 10px;
+    margin:0px 0px 0px 175px;
+    min-height:600px;
+}
+
+div.msg {
+    color: white;
+    background: #880000;
+}
\ No newline at end of file
diff --git a/htsworkflow/static/css/layout.css b/htsworkflow/static/css/layout.css
new file mode 100644 (file)
index 0000000..bab2121
--- /dev/null
@@ -0,0 +1,29 @@
+/* PAGE STRUCTURE */
+#container { position:relative; width:100%; min-width:760px; padding:0; }
+#content { margin:10px 15px; }
+#header { width:100%; }
+#content-main { float:left; width:100%; }
+#content-related { float:right; width:18em; position:relative; margin-right:-19em; }
+#footer { clear:both; padding:10px; }
+
+/*  COLUMN TYPES  */
+.colMS { margin-right:20em !important; }
+.colSM { margin-left:20em !important; }
+.colSM #content-related { float:left; margin-right:0; margin-left:-19em; }
+.colSM #content-main { float:right; }
+.popup .colM { width:95%; }
+.subcol { float:left; width:46%; margin-right:15px; }
+.dashboard #content { width:500px; }
+
+/*  HEADER  */
+#header { background:#417690; color:#ffc; overflow:hidden; }
+#header a:link, #header a:visited { color:white; }
+#header a:hover { text-decoration:underline; }
+#branding h1 { padding:0 10px; font-size:18px; margin:8px 0; font-weight:normal; color:#f4f379; }
+#branding h2 { padding:0 10px; font-size:14px; margin:-8px 0 8px 0; font-weight:normal; color:#ffc; }
+#user-tools { position:absolute; top:0; right:0; padding:1.2em 10px; font-size:11px; text-align:right; }
+
+/* SIDEBAR */
+#content-related h3 { font-size:12px; color:#666; margin-bottom:3px; }
+#content-related h4 { font-size:11px; }
+#content-related .module h2 { background:#eee url(../img/nav-bg.gif) bottom left repeat-x; color:#666; }
diff --git a/htsworkflow/static/css/null.css b/htsworkflow/static/css/null.css
new file mode 100644 (file)
index 0000000..1a93f22
--- /dev/null
@@ -0,0 +1 @@
+/* Nothing to see here. Dummy file to feed to the high pass filter which hides CSS from IE5/win. Details: http://tantek.com/CSS/Examples/highpass.html */
\ No newline at end of file
diff --git a/htsworkflow/static/css/patch-iewin.css b/htsworkflow/static/css/patch-iewin.css
new file mode 100644 (file)
index 0000000..2de1305
--- /dev/null
@@ -0,0 +1,8 @@
+* html #container { position:static; } /* keep header from flowing off the page */
+* html .colMS #content-related { margin-right:0; margin-left:10px; position:static; } /* put the right sidebars back on the page */
+* html .colSM #content-related { margin-right:10px; margin-left:-115px; position:static; } /* put the left sidebars back on the page */
+* html .form-row { height:1%; }
+* html .dashboard #content { width:768px; } /* proper fixed width for dashboard in IE6 */
+* html .dashboard #content-main { width:535px; } /* proper fixed width for dashboard in IE6 */
+* html #changelist-filter ul { margin-right:-10px; } /* fix right margin for changelist filters in IE6 */
+* html .change-list .filtered { height:400px; } /* IE ignores min-height, but treats height as if it were min-height */
\ No newline at end of file
diff --git a/htsworkflow/static/css/wide_account_number.css b/htsworkflow/static/css/wide_account_number.css
new file mode 100644 (file)
index 0000000..6eee12b
--- /dev/null
@@ -0,0 +1 @@
+#id_account_number { width: 50em; }
\ No newline at end of file
diff --git a/htsworkflow/static/img/changelist-bg.gif b/htsworkflow/static/img/changelist-bg.gif
new file mode 100644 (file)
index 0000000..7f46994
Binary files /dev/null and b/htsworkflow/static/img/changelist-bg.gif differ
diff --git a/htsworkflow/static/img/default-bg.gif b/htsworkflow/static/img/default-bg.gif
new file mode 100644 (file)
index 0000000..003aeca
Binary files /dev/null and b/htsworkflow/static/img/default-bg.gif differ
diff --git a/htsworkflow/static/img/dna80.png b/htsworkflow/static/img/dna80.png
new file mode 100644 (file)
index 0000000..845c255
Binary files /dev/null and b/htsworkflow/static/img/dna80.png differ
diff --git a/htsworkflow/static/img/hdd_unmount.png b/htsworkflow/static/img/hdd_unmount.png
new file mode 100755 (executable)
index 0000000..4972e55
Binary files /dev/null and b/htsworkflow/static/img/hdd_unmount.png differ
diff --git a/htsworkflow/static/img/icon_searchbox.png b/htsworkflow/static/img/icon_searchbox.png
new file mode 100644 (file)
index 0000000..8ab579e
Binary files /dev/null and b/htsworkflow/static/img/icon_searchbox.png differ
diff --git a/htsworkflow/static/img/layout-browser-hd-bg.gif b/htsworkflow/static/img/layout-browser-hd-bg.gif
new file mode 100644 (file)
index 0000000..29bf23f
Binary files /dev/null and b/htsworkflow/static/img/layout-browser-hd-bg.gif differ
diff --git a/htsworkflow/static/img/nav-bg-reverse.gif b/htsworkflow/static/img/nav-bg-reverse.gif
new file mode 100644 (file)
index 0000000..f11029f
Binary files /dev/null and b/htsworkflow/static/img/nav-bg-reverse.gif differ
diff --git a/htsworkflow/static/img/nav-bg.gif b/htsworkflow/static/img/nav-bg.gif
new file mode 100644 (file)
index 0000000..f8402b8
Binary files /dev/null and b/htsworkflow/static/img/nav-bg.gif differ
diff --git a/htsworkflow/static/img/readme.txt b/htsworkflow/static/img/readme.txt
new file mode 100644 (file)
index 0000000..81c803e
--- /dev/null
@@ -0,0 +1,11 @@
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+This copyright and license notice covers the following images:
+ * hdd_unmount.png
+************************************************************************
+
+TITLE: Crystal Project Icons
+AUTHOR:        Everaldo Coelho
+SITE:  http://www.everaldo.com
+CONTACT: everaldo@everaldo.com
+
+Copyright (c)  2006-2007  Everaldo Coelho.
diff --git a/htsworkflow/static/img/s.gif b/htsworkflow/static/img/s.gif
new file mode 100644 (file)
index 0000000..1d11fa9
Binary files /dev/null and b/htsworkflow/static/img/s.gif differ
diff --git a/htsworkflow/static/js/bcmagic-ext.js b/htsworkflow/static/js/bcmagic-ext.js
new file mode 100644 (file)
index 0000000..a3d9c6c
--- /dev/null
@@ -0,0 +1,169 @@
+//-----------------------------------------------
+// Barcode Magic JavaScript
+// Authors: Brandon W. King
+// Feb. 2009
+//-----------------------------------------------
+
+//---------------------------------------
+// BCMagic Core Processing AJAX Callback
+//---------------------------------------
+//var bcmagic_process_callback = function(data, textStatus) {
+var bcmagic_process_callback = function(response, opt) {
+    //FIXME: temp bypass hack
+    var textStatus = 'success';
+    if (textStatus != 'success')
+    {
+        bcmagic_message('AJAX Status: '+textStatus);
+        return;
+    }
+    
+    var data = Ext.decode(response.responseText);
+    
+    for (key in data)
+    {
+        if (key == 'mode')
+        {
+            if (data['mode'] == 'clear')
+            {
+                bcmagic_status('','');
+            }
+            else if (data['mode'] == 'redirect')
+            {
+                if ('url' in data)
+                {
+                    bcmagic_redirect(data['url']);
+                }
+                else
+                {
+                    bcmagic_status('Error', 'No redirect URL provided by server');
+                }
+            }
+            else if (data['mode'] == 'autofill')
+            {
+                bcmagic_autofill(data['field'], data['value'])
+            }
+            else {
+                bcmagic_message('Message recieved!');
+                bcmagic_status(data['mode'], data['status']);    
+            }
+            
+        }
+        if (key == 'msg')
+        {
+            bcmagic_message(data['msg']);
+        }
+    }
+}
+
+var bcmagic_callback = function(data, textStatus)
+{
+    if (textStatus != 'success')
+        bcmagic_message('Failed!');
+    else
+        bcmagic_message('Success!');
+}
+
+var bcmagic_process = function(){
+    var magic = Ext.get("bcmagic_input_field");
+    var text = magic.getValue();
+    magic.dom.value = '';
+    magic.focus();
+    
+    //var bcm_mode = $("#id_bcm_mode");
+    //var mode = bcm_mode.attr('value');
+    var mode = 'default';
+    
+    // Show what we have captured
+    bcmagic_message('Sent command to server');
+    //$.post('/bcmagic/magic/', {'text': text, 'bcm_mode': mode}, bcmagic_process_callback, 'json');
+    Ext.Ajax.request({
+        url: '/bcmagic/magic/',
+        success: bcmagic_process_callback,
+        failure: function (r, o) { quick_msg('Some AJAX Fail!'); },
+        params: {'text': text, 'bcm_mode': mode}
+    });
+}
+
+var bcmagic_keyhandler = function(e) {
+    //Process upon enter key as input.
+    if (e.which == 13)
+      bcmagic_process();
+}
+
+//---------------------------------------
+// Utility Functions
+//---------------------------------------
+var bcmagic_message = function(text)
+{
+    // Show message
+    //$("#bcm_msg").html(text);
+    quick_msg(text);
+    
+    // clear message after 3000ms
+    /*
+    setTimeout(function() {
+        $("#bcm_msg").html('');
+        }, 3000);
+    */
+}
+
+var bcmagic_status = function(state, text)
+{
+    //var msg = $('#bcm_status');
+    if (state.length > 0 || text.length > 0)
+        quick_msg(state+': '+text);
+    //else
+    //    msg.html('');
+}
+
+
+var bcmagic_redirect = function(url)
+{
+    bcmagic_message('Redirecting to:' + url);
+    window.location = url;
+}
+
+var bcmagic_autofill = function(field, val)
+{
+    var txtbox = $('#'+field);
+    txtbox.attr('value', val);
+    
+    var input_fields = $('form input').not(':hidden').not('[type=submit]');
+    
+    // Count the number of text fields which have been filled in.
+    var count = 0;
+    input_fields.each( function(){
+                   if(this.value.length > 0){
+                        count = count + 1;
+                   }
+                });
+    
+    // If the number of text fields filled in is equal to the number of input_fields in the form, submit the form!
+    if (count == input_fields.length)
+    {
+        bcmagic_status('Form Full', 'Form is now full and ready to process');
+        form = $('form');
+        form.submit();
+        form.reset();
+    
+    }
+    else
+    {
+        bcmagic_status('Form Fill Count', 'Count(' + count +') - Total(' + input_fields.length + ')');
+    }
+}
+
+//---------------------------------------
+// Main Ready Function
+//---------------------------------------
+/*$(document).ready(function() {
+        
+        // Grab initial focus on magic text input
+        $("#id_magic").focus();
+        
+        // Set some initial text
+        //$("#id_magic").attr('value','Moo cow!');
+        
+        // Trigger when enterkey is pressed
+        $("#id_magic").keypress(bcmagic_keyhandler)
+});*/
\ No newline at end of file
diff --git a/htsworkflow/static/js/htsw-inventory.js b/htsworkflow/static/js/htsw-inventory.js
new file mode 100644 (file)
index 0000000..3cbca3f
--- /dev/null
@@ -0,0 +1,90 @@
+
+var inventory_item_dblclick_handler = function(grid, row_index, e){
+    //quick_msg('Choose Row: ' + row_index);
+    var rec = grid.getStore().getAt(row_index);
+    //quick_msg('UUID: ' + rec.get('uuid'));
+    goto_url('/inventory/'+rec.get('uuid')+'/');
+}
+
+var getInventoryDataGrid = function(){
+    
+    var Item = Ext.data.Record.create([
+       { name: 'uuid' },
+       { name: 'barcode_id'},
+       { name: 'model_id'},
+       { name: 'part_number'},
+       { name: 'lot_number'},
+       { name: 'vendor'},
+       { name: 'creation_date'/*, type: 'date', dateFormat: 'n/j h:ia'*/},
+       { name: 'modified_date'/*, type: 'date', dateFormat: 'n/j h:ia'*/},
+       { name: 'location'},
+       { name: 'status'},
+       { name: 'flowcells'},
+       { name: 'type'}
+    ]);
+    
+    var inventoryReader = new Ext.data.JsonReader(
+        {
+            totalProperty: "results",
+            root: "rows",
+            idProperty: "uuid"
+        },
+        Item
+    );
+    
+    /*
+    var inventoryStore = new Ext.data.JsonStore({
+       autoDestory: true,
+       url: '/inventory/data/items/',
+       storeId: 'item_store',
+       
+    });
+    */
+    
+    var grid = new Ext.grid.GridPanel({
+        store: new Ext.data.GroupingStore({
+            reader: inventoryReader,
+            url: '/inventory/data/items/',
+            storeId: 'item_group_store',
+            groupField: 'type',
+            sortInfo: { field: 'creation_date', direction: "DESC"},
+            autoLoad: true
+        }),
+    
+        columns: [
+            {id: 'uuid', header:"UUID", width: 32, sortable: true, dataIndex: 'uuid'},
+            {header: 'Barcode ID', width: 20, sortable: true, dataIndex: 'barcode_id'},
+            {header: 'Location', width: 20, sortable: true, dataIndex: 'location'},
+            {header: 'Model', width: 20, sortable: true, dataIndex: 'model_id'},
+            {header: 'Part #', width: 20, sortable: true, dataIndex: 'part_number', hidden: true},
+            {header: 'Lot #', width: 20, sortable: true, dataIndex: 'lot_number', hidden: true},
+            {header: 'Vendor', width: 20, sortable: true, dataIndex: 'vendor'},
+            {header: 'Creation Date', width: 20, sortable: true, dataIndex: 'creation_date'/*, renderer: Ext.util.Format.dateRenderer('Y/m/d')*/},
+            {header: 'Modified Date', width: 20, sortable: true, dataIndex: 'modified_date', hidden: true/*, renderer: Ext.util.Format.dateRenderer('Y/m/d')*/},
+            {header: 'Status', width: 20, sortable: true, dataIndex: 'status', hidden: true},
+            {header: 'Stored Flowcells', width: 20, sortable: true, dataIndex: 'flowcells'},
+            {header: 'Type', width: 20, sortable: true, dataIndex: 'type', hidden: true}
+        ],
+        
+        view: new Ext.grid.GroupingView({
+           forceFit: true,
+           groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items" : "Item"]})'
+        }),
+        
+        frame: true,
+        width: 'auto',
+        //height: 500,
+        //autoHeight: true,
+        collapsible: false,
+        title: "Inventory Index",
+        iconCls: 'icon-grid',
+        id: 'inventory_item_panel',
+        stateId: 'inventory_item_panel_state',
+        stateful: true
+        //renderTo: 'grid_target'
+    });
+    
+    grid.on('rowdblclick', inventory_item_dblclick_handler);
+    
+    return grid;
+}
\ No newline at end of file
diff --git a/htsworkflow/static/js/htsw.js b/htsworkflow/static/js/htsw.js
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/htsworkflow/static/js/jquery.timers-1.0.0.js b/htsworkflow/static/js/jquery.timers-1.0.0.js
new file mode 100644 (file)
index 0000000..db866cf
--- /dev/null
@@ -0,0 +1,151 @@
+/**\r
+ * jQuery.timers - Timer abstractions for jQuery\r
+ * Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)\r
+ * Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).\r
+ * Date: 2008/08/26\r
+ *\r
+ * @author Blair Mitchelmore\r
+ * @version 1.0.0\r
+ *\r
+ **/\r
+\r
+jQuery.fn.extend({\r
+       everyTime: function(interval, label, fn, times, belay) {\r
+               return this.each(function() {\r
+                       jQuery.timer.add(this, interval, label, fn, times, belay);\r
+               });\r
+       },\r
+       oneTime: function(interval, label, fn) {\r
+               return this.each(function() {\r
+                       jQuery.timer.add(this, interval, label, fn, 1);\r
+               });\r
+       },\r
+       stopTime: function(label, fn) {\r
+               return this.each(function() {\r
+                       jQuery.timer.remove(this, label, fn);\r
+               });\r
+       }\r
+});\r
+\r
+jQuery.extend({\r
+       timer: {\r
+               guid: 1,\r
+               global: {},\r
+               regex: /^([0-9]+)\s*(.*s)?$/,\r
+               powers: {\r
+                       // Yeah this is major overkill...\r
+                       'ms': 1,\r
+                       'cs': 10,\r
+                       'ds': 100,\r
+                       's': 1000,\r
+                       'das': 10000,\r
+                       'hs': 100000,\r
+                       'ks': 1000000\r
+               },\r
+               timeParse: function(value) {\r
+                       if (value == undefined || value == null)\r
+                               return null;\r
+                       var result = this.regex.exec(jQuery.trim(value.toString()));\r
+                       if (result[2]) {\r
+                               var num = parseInt(result[1], 10);\r
+                               var mult = this.powers[result[2]] || 1;\r
+                               return num * mult;\r
+                       } else {\r
+                               return value;\r
+                       }\r
+               },\r
+               add: function(element, interval, label, fn, times, belay) {\r
+                       var counter = 0;\r
+                       \r
+                       if (jQuery.isFunction(label)) {\r
+                               if (!times) \r
+                                       times = fn;\r
+                               fn = label;\r
+                               label = interval;\r
+                       }\r
+                       \r
+                       interval = jQuery.timer.timeParse(interval);\r
+\r
+                       if (typeof interval != 'number' || isNaN(interval) || interval <= 0)\r
+                               return;\r
+\r
+                       if (times && times.constructor != Number) {\r
+                               belay = !!times;\r
+                               times = 0;\r
+                       }\r
+                       \r
+                       times = times || 0;\r
+                       belay = belay || false;\r
+                       \r
+                       if (!element.$timers) \r
+                               element.$timers = {};\r
+                       \r
+                       if (!element.$timers[label])\r
+                               element.$timers[label] = {};\r
+                       \r
+                       fn.$timerID = fn.$timerID || this.guid++;\r
+                       \r
+                       var handler = function() {\r
+                               if (belay && this.inProgress) \r
+                                       return;\r
+                               this.inProgress = true;\r
+                               if ((++counter > times && times !== 0) || fn.call(element, counter) === false)\r
+                                       jQuery.timer.remove(element, label, fn);\r
+                               this.inProgress = false;\r
+                       };\r
+                       \r
+                       handler.$timerID = fn.$timerID;\r
+                       \r
+                       if (!element.$timers[label][fn.$timerID]) \r
+                               element.$timers[label][fn.$timerID] = window.setInterval(handler,interval);\r
+                       \r
+                       if ( !this.global[label] )\r
+                               this.global[label] = [];\r
+                       this.global[label].push( element );\r
+                       \r
+               },\r
+               remove: function(element, label, fn) {\r
+                       var timers = element.$timers, ret;\r
+                       \r
+                       if ( timers ) {\r
+                               \r
+                               if (!label) {\r
+                                       for ( label in timers )\r
+                                               this.remove(element, label, fn);\r
+                               } else if ( timers[label] ) {\r
+                                       if ( fn ) {\r
+                                               if ( fn.$timerID ) {\r
+                                                       window.clearInterval(timers[label][fn.$timerID]);\r
+                                                       delete timers[label][fn.$timerID];\r
+                                               }\r
+                                       } else {\r
+                                               for ( var fn in timers[label] ) {\r
+                                                       window.clearInterval(timers[label][fn]);\r
+                                                       delete timers[label][fn];\r
+                                               }\r
+                                       }\r
+                                       \r
+                                       for ( ret in timers[label] ) break;\r
+                                       if ( !ret ) {\r
+                                               ret = null;\r
+                                               delete timers[label];\r
+                                       }\r
+                               }\r
+                               \r
+                               for ( ret in timers ) break;\r
+                               if ( !ret ) \r
+                                       element.$timers = null;\r
+                       }\r
+               }\r
+       }\r
+});\r
+\r
+if (jQuery.browser.msie)\r
+       jQuery(window).one("unload", function() {\r
+               var global = jQuery.timer.global;\r
+               for ( var label in global ) {\r
+                       var els = global[label], i = els.length;\r
+                       while ( --i )\r
+                               jQuery.timer.remove(els[i], label);\r
+               }\r
+       });\r
diff --git a/htsworkflow/static/js/magicbc.js b/htsworkflow/static/js/magicbc.js
new file mode 100644 (file)
index 0000000..b294abd
--- /dev/null
@@ -0,0 +1,153 @@
+//-----------------------------------------------
+// Barcode Magic JavaScript
+// Authors: Brandon W. King
+// Feb. 2009
+//-----------------------------------------------
+
+//---------------------------------------
+// BCMagic Core Processing AJAX Callback
+//---------------------------------------
+var bcmagic_process_callback = function(data, textStatus) {
+    if (textStatus != 'success')
+    {
+        bcmagic_message('AJAX Status: '+textStatus);
+        return;
+    }
+    
+    for (key in data)
+    {
+        if (key == 'mode')
+        {
+            if (data['mode'] == 'clear')
+            {
+                bcmagic_status('','');
+            }
+            else if (data['mode'] == 'redirect')
+            {
+                if ('url' in data)
+                {
+                    bcmagic_redirect(data['url']);
+                }
+                else
+                {
+                    bcmagic_status('Error', 'No redirect URL provided by server');
+                }
+            }
+            else if (data['mode'] == 'autofill')
+            {
+                bcmagic_autofill(data['field'], data['value'])
+            }
+            else {
+                bcmagic_message('Message recieved!');
+                bcmagic_status(data['mode'], data['status']);    
+            }
+            
+        }
+        if (key == 'msg')
+        {
+            bcmagic_message(data['msg']);
+        }
+    }
+}
+
+var bcmagic_callback = function(data, textStatus)
+{
+    if (textStatus != 'success')
+        bcmagic_message('Failed!');
+    else
+        bcmagic_message('Success!');
+}
+
+var bcmagic_process = function(){
+    var magic = $("#id_magic");
+    var text = magic.attr('value');
+    magic.attr('value', '');
+    
+    var bcm_mode = $("#id_bcm_mode");
+    var mode = bcm_mode.attr('value');
+    
+    // Show what we have captured
+    bcmagic_message('Sent command to server');
+    $.post('/bcmagic/magic/', {'text': text, 'bcm_mode': mode}, bcmagic_process_callback, 'json');
+}
+
+var bcmagic_keyhandler = function(e) {
+    //Process upon enter key as input.
+    if (e.which == 13)
+      bcmagic_process();
+}
+
+//---------------------------------------
+// Utility Functions
+//---------------------------------------
+var bcmagic_message = function(text)
+{
+    // Show message
+    $("#bcm_msg").html(text);
+    
+    // clear message after 3000ms
+    setTimeout(function() {
+        $("#bcm_msg").html('');
+        }, 3000);
+}
+
+var bcmagic_status = function(state, text)
+{
+    var msg = $('#bcm_status');
+    if (state.length > 0 || text.length > 0)
+        msg.html('<b>'+state+':</b> '+text);
+    else
+        msg.html('');
+}
+
+
+var bcmagic_redirect = function(url)
+{
+    bcmagic_message('Redirecting to:' + url);
+    window.location = url;
+}
+
+var bcmagic_autofill = function(field, val)
+{
+    var txtbox = $('#'+field);
+    txtbox.attr('value', val);
+    
+    var input_fields = $('form input').not(':hidden').not('[type=submit]');
+    
+    // Count the number of text fields which have been filled in.
+    var count = 0;
+    input_fields.each( function(){
+                   if(this.value.length > 0){
+                        count = count + 1;
+                   }
+                });
+    
+    // If the number of text fields filled in is equal to the number of input_fields in the form, submit the form!
+    if (count == input_fields.length)
+    {
+        bcmagic_status('Form Full', 'Form is now full and ready to process');
+        form = $('form');
+        form.submit();
+        form.reset();
+    
+    }
+    else
+    {
+        bcmagic_status('Form Fill Count', 'Count(' + count +') - Total(' + input_fields.length + ')');
+    }
+}
+
+//---------------------------------------
+// Main Ready Function
+//---------------------------------------
+/*$(document).ready(function() {
+        
+        // Grab initial focus on magic text input
+        $("#id_magic").focus();
+        
+        // Set some initial text
+        //$("#id_magic").attr('value','Moo cow!');
+        
+        // Trigger when enterkey is pressed
+        $("#id_magic").keypress(bcmagic_keyhandler)
+});*/
\ No newline at end of file
diff --git a/htsworkflow/templates/404.html b/htsworkflow/templates/404.html
new file mode 100644 (file)
index 0000000..687b49a
--- /dev/null
@@ -0,0 +1,11 @@
+<html>
+    <head>
+        <title>404 - Not Found</title>
+    </head>
+    <body>
+        <h1>404 - Not Found</h1>
+        <p>The URL you tried to reach does not appear to exist, 
+           if you have reason to believe this in error, please try again later.</p>
+    </body>
+</html>
+    
diff --git a/htsworkflow/templates/admin/auth/user/add_form.html b/htsworkflow/templates/admin/auth/user/add_form.html
new file mode 100644 (file)
index 0000000..d3eaf3f
--- /dev/null
@@ -0,0 +1,47 @@
+{% extends "admin/change_form.html" %}
+{% load i18n %}
+
+{% block after_field_sets %}
+
+<p>{% trans "First, enter a username and password. Then, you'll be able to edit more user options." %}</p>
+
+<fieldset class="module aligned">
+
+<div class="form-row">
+  {{ form.username.errors }}
+  {# TODO: get required class on label_tag #}
+  <label for="id_username" class="required">{% trans 'Username' %}:</label> {{ form.username }}
+  <p class="help">{{ form.username.help_text }}</p>
+</div>
+
+<div class="form-row">
+  {{ form.first_name.errors }}
+  {{ form.last_name.errors }}
+ {# TODO: get required class on label_tag #}
+  <div class="field-box">
+  <label for="first_name" >{% trans 'First Name' %}:</label> {{ form.first_name }}
+  <p class="help">{{ form.first_name.help_text }}</p>
+  </div>  
+  <div class="field-box">
+  <label for="last_name" >{% trans 'Last Name' %}:</label> {{ form.last_name }}
+  <p class="help">{{ form.last_name.help_text }}</p>
+  </div>
+</div>
+
+<div class="form-row">
+  {{ form.password1.errors }}
+  {# TODO: get required class on label_tag #}
+  <label for="id_password1" class="required">{% trans 'Password' %}:</label> {{ form.password1 }}
+</div>
+
+<div class="form-row">
+  {{ form.password2.errors }}
+  {# TODO: get required class on label_tag #}
+  <label for="id_password2" class="required">{% trans 'Password (again)' %}:</label> {{ form.password2 }}
+  <p class="help">{% trans 'Enter the same password as above, for verification.' %}</p>
+</div>
+
+<script type="text/javascript">document.getElementById("id_username").focus();</script>
+
+</fieldset>
+{% endblock %}
diff --git a/htsworkflow/templates/admin/base_site.html b/htsworkflow/templates/admin/base_site.html
new file mode 100644 (file)
index 0000000..c212302
--- /dev/null
@@ -0,0 +1,16 @@
+{% extends "admin/base.html" %}
+{% load i18n %}
+
+{% block title %}
+{{ title }}|{%trans "dev site admin" %}
+{% endblock %}
+
+{% block branding %}
+<h1 id="site-name" style="background-color:#cccccc;color:black">
+  {%block sitename %}
+    {% trans 'HTS Workflow Dev Server' %}
+  {%endblock%}
+</h1>
+{% endblock %}
+
+{% block nav-global %}{% endblock %}
diff --git a/htsworkflow/templates/admin/experiments/flowcell/change_form.html b/htsworkflow/templates/admin/experiments/flowcell/change_form.html
new file mode 100644 (file)
index 0000000..068fbfe
--- /dev/null
@@ -0,0 +1,11 @@
+{% extends "admin/change_form.html" %}
+{% load i18n %}
+{% block object-tools %}
+{% if change %}{% if not is_popup %}
+  <ul class="object-tools">
+    <li><a href="../../../../{{ app_label }}/started/{{ object_id }}/">{% trans "Started Email" %}</a></li>
+    <li><a href="history/" class="historylink">{% trans "History" %}</a></li>
+  {% if has_absolute_url %}<li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
+  </ul>
+{% endif %}{% endif %}
+{% endblock %}
diff --git a/htsworkflow/templates/admin/index.html b/htsworkflow/templates/admin/index.html
new file mode 100644 (file)
index 0000000..66b6942
--- /dev/null
@@ -0,0 +1,100 @@
+{% extends "admin/base_site.html" %}
+{% load i18n %}
+
+{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% load staticfiles %}{% static "css/dashboard.css" %}"/>{% endblock %}
+
+{% block coltype %}colMS{% endblock %}
+
+{% block bodyclass %}dashboard{% endblock %}
+
+{% block breadcrumbs %}{% endblock %}
+
+{% block content %}
+<div id="content-main">
+
+<div class='module'>
+<table>
+<caption>Frequently Used</caption>
+<tr>
+<th scope="row"><a href="/admin/samples/library/">Libraries</a></th>
+<td><a href="/admin/samples/library/add/" class="addlink">{% trans 'Add' %}</a></td>
+</tr>
+<tr>
+<th scope="row"><a href="/admin/experiments/flowcell/">Flowcells</a></th>
+<td><a href="/admin/experiments/flowcell/add/" class="addlink">{% trans 'Add' %}</a></td>
+</tr>
+</table></div>
+
+<div class='module'>
+<table>
+<caption>Label Printing</caption>
+<tr>
+<th scope="row"><a href="/admin/labels/labelcontent/">Label Contents</a></th>
+<td><a href="/admin/labels/labelcontent/add/" class="addlink">{% trans 'Add' %}</a></td>
+</tr>
+<tr>
+<th scope="row"><a href="/admin/labels/labeltemplate/">Label Templates</a></th>
+<td><a href="/admin/labels/labeltemplate/add/" class="addlink">{% trans 'Add' %}</a></td>
+</tr>
+</table></div><BR>
+
+{% if app_list %}
+    {% for app in app_list %}
+        <div class="module">
+        <table summary="{% blocktrans with app.name as name %}Models available in the {{ name }} application.{% endblocktrans %}">
+        <caption><a href="{{ app.app_url }}" class="section">{% blocktrans with app.name as name %}{{ name }}{% endblocktrans %}</a></caption>
+        {% for model in app.models %}
+            <tr>
+            {% if model.perms.change %}
+                <th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
+            {% else %}
+                <th scope="row">{{ model.name }}</th>
+            {% endif %}
+
+            {% if model.perms.add %}
+                <td><a href="{{ model.admin_url }}add/" class="addlink">{% trans 'Add' %}</a></td>
+            {% else %}
+                <td>&nbsp;</td>
+            {% endif %}
+            </tr>
+        {% endfor %}
+        </table>
+        </div>
+    {% endfor %}
+{% else %}
+    <p>{% trans "You don't have permission to edit anything." %}</p>
+{% endif %}
+</div>
+{% endblock %}
+
+{% block sidebar %}
+<div id="content-related">
+    <div class="module" id="recent-actions-module">
+        <h2>{% trans 'Recent Actions' %}</h2>
+        <h3>{% trans 'My Actions' %}</h3>
+            {% load log %}
+            {% get_admin_log 10 as admin_log for_user user %}
+            {% if not admin_log %}
+            <p>{% trans 'None available' %}</p>
+            {% else %}
+            <ul class="actionlist">
+            {% for entry in admin_log %}
+            <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">
+                {% if entry.is_deletion %}
+                    {{ entry.object_repr }}
+                {% else %}
+                    <a href="{{ entry.get_admin_url }}">{{ entry.object_repr }}</a>
+                {% endif %}
+                <br/>
+                {% if entry.content_type %}
+                    <span class="mini quiet">{% filter capfirst %}{% trans entry.content_type.name %}{% endfilter %}</span>
+                {% else %}
+                    <span class="mini quiet">{% trans 'Unknown content' %}</span>
+                {% endif %}
+            </li>
+            {% endfor %}
+            </ul>
+            {% endif %}
+    </div>
+</div>
+{% endblock %}
diff --git a/htsworkflow/templates/admin/pagination.html b/htsworkflow/templates/admin/pagination.html
new file mode 100644 (file)
index 0000000..f7de053
--- /dev/null
@@ -0,0 +1,13 @@
+<!--overrride pagination-->
+{% load admin_list %}
+{% load i18n %}
+<p class="paginator">
+{% if pagination_required %}
+{% for i in page_range %}
+    {% paginator_number cl i %}
+{% endfor %}
+{% endif %}
+{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %}
+{% if show_all_url %}&#160;&#160;<a href="{{ show_all_url }}" class="showall">{% trans 'Show all' %}</a>{% endif %}
+{% if cl.formset and cl.result_count %}<input type="submit" name="_save" class="default" value="{% trans 'Save' %}"/>{% endif %}
+</p>
diff --git a/htsworkflow/templates/base.html b/htsworkflow/templates/base.html
new file mode 100644 (file)
index 0000000..0325a84
--- /dev/null
@@ -0,0 +1,76 @@
+{% load i18n %}<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN"
+    "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+      version="XHTML+RDFa 1.0"
+      xmlns:xml="http://www.w3.org/XML/1998/namespace"
+      xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+      xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+      xmlns:dc="http://purl.org/dc/elements/1.1/"
+      xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
+      xmlns:libns="http://jumpgate.caltech.edu/wiki/LibraryOntology#"
+      xmlns:invns="http://jumpgate.caltech.edu/wiki/InventoryOntology#"
+      xml:lang="en"
+>
+<!--base.html-->
+<head>
+    <title>{% block title %}{{ app_name }} - {{ page_name }}{% endblock %}</title>
+
+{% block additional_css %}
+    {% load staticfiles %}
+    {% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "css/rtl.css" %}{% endblock %}" />{% endif %}
+    {% block extrastyle %}{% endblock %}
+    {% block extrahead %}{% endblock %}
+    {% block blockbots %}<meta name="robots" content="NONE,NOARCHIVE" />{% endblock %}
+    <link rel="stylesheet" type="text/css" href="{% static "css/data-browse-index.css" %}" />
+{% endblock %}
+
+</head>
+<body>
+<!-- Container -->
+    {% if not is_popup %}
+
+    <div id="header">
+        <div id="branding">
+        {% block branding %}{% endblock %}
+        </div>
+        <div id="user-tools">
+        {% if user.is_authenticated %}
+        {% trans 'Welcome,' %}
+        <strong>{% firstof user.first_name user.username %}</strong>.
+        {% block userlinks %}
+            {% url "django.admindocs.docroot" as docsroot %}
+            {% if docsroot %}
+                <a href="{{ docsroot }}">{% trans 'Documentation' %}</a> /
+            {% endif %}
+            <a href="{{root_path}}/accounts/password_change/">{% trans 'Change password' %}</a> /
+            <a href="{{root_path}}/accounts/logout/">{% trans 'Log out' %}</a>
+        {% endblock %}
+        {% else %}
+            <a href="{{root_path}}/accounts/login/?next={{thispage}}">{% trans 'Log in' %}</a>
+        {% endif %}
+        </div>
+        {% block nav-global %}{% endblock %}
+    </div>
+    {% endif %}
+    {% block breadcrumbs %}{% endblock %}
+    {% if messages %}
+        <ul class="messagelist">{% for message in messages %}<li>{{ message }}</li>{% endfor %}</ul>
+    {% endif %}
+
+    <!-- Content -->
+    <div id="content" class="{% block coltype %}colM{% endblock %}">
+        {% block pretitle %}{% endblock %}
+        {% block content_title %}{% if title %}<h1>{{ title }}</h1>{% endif %}{% endblock %}
+        {% block content %}
+        {% block object-tools %}{% endblock %}
+        {{ content }}
+        {% endblock %}
+        {% block sidebar %}{% endblock %}
+    </div>
+    <!-- END Content -->
+
+    {% block footer %}<div id="footer"></div>{% endblock %}
+<!-- END Container -->
+</body>
+</html>
diff --git a/htsworkflow/templates/base_site.html b/htsworkflow/templates/base_site.html
new file mode 100644 (file)
index 0000000..1c02752
--- /dev/null
@@ -0,0 +1,13 @@
+{% extends "base.html" %}
+{% load staticfiles %}
+{% load i18n %}
+
+<link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}" />
+
+{% block title %}{{ sitename }}{% endblock %}
+
+{% block branding %}
+<h1 id="site-name">HTSWorkflow</h1>
+{% endblock %}
+
+{% block nav-global %}{% endblock %}
diff --git a/htsworkflow/templates/bcmagic/magic.html b/htsworkflow/templates/bcmagic/magic.html
new file mode 100644 (file)
index 0000000..e1d1061
--- /dev/null
@@ -0,0 +1,3 @@
+<div id="bcm_msg"></div>
+{{ bcmagic }}<br />
+<div id="bcm_status"></div>
diff --git a/htsworkflow/templates/experiments/detail.html b/htsworkflow/templates/experiments/detail.html
new file mode 100644 (file)
index 0000000..65d3c00
--- /dev/null
@@ -0,0 +1,7 @@
+{% if run_f %}
+    <ul>
+        RUN FOLDER:  <li>{{ run_f.run_folder }}</li>
+    </ul>
+{% else %}
+    <p>Run folder not found.</p>
+{% endif %}
diff --git a/htsworkflow/templates/experiments/email_preview.html b/htsworkflow/templates/experiments/email_preview.html
new file mode 100644 (file)
index 0000000..9c35c6d
--- /dev/null
@@ -0,0 +1,38 @@
+{% extends "base.html" %}
+{% load i18n %}
+
+{% block breadcrumbs %}
+<div class="breadcrumbs">
+  <a href="/admin">{% trans 'Home' %}</a> &rsaquo;
+  <a href="/admin/experiments">Experiments</a> &rsaquo;
+  <a href="/admin/experiments/flowcell">flowcell</a> &rsaquo;
+  <a href="{{ flowcell.get_admin_url }}">{{ flowcell.flowcell_id }}</a>
+</div>  
+{% endblock %}
+
+{% block content %}
+{% if warnings %}
+<hr/>
+<p>
+{% for user_admin_url, username in warnings %}
+Warning: User <a href="{{ user_admin_url}}">{{ username }}</a> has no
+email address <br/>
+{% endfor %}
+{% endif %}
+</p>
+{% for to, subject, body, sending in emails %}
+<hr/>
+{% if sending %}<b>Message:</b> {{ sending }}<br/>{% endif %}
+<b>From:</b> {{ from }}<br/>
+<b>To:</b> {{ to }}<br/>
+<b>Subject:</b> {{ subject }}<br/>
+<pre>
+{{ body }}
+</pre>
+{% endfor %}<hr/>
+<form method="get">
+<label for="bcc">BCC {% for m in site_managers %}{{ m }} {% endfor %}</label>
+<input type="checkbox" id="bcc" name="bcc" checked="on"/><br/>
+<input type="hidden" name="send" value="1"/>
+<input type="submit" value="Send Email"/>
+{% endblock %}
\ No newline at end of file
diff --git a/htsworkflow/templates/experiments/flowcellSheet.html b/htsworkflow/templates/experiments/flowcellSheet.html
new file mode 100644 (file)
index 0000000..103b045
--- /dev/null
@@ -0,0 +1,87 @@
+<html><head><title>{{ fc.flowcell_id }} - GA SEQUENCING (SOLEXA) LOG</title>
+<style type="text/css">
+<!--
+TD
+  {
+  color:black;
+  font-size:9pt;
+  font-face:Arial;
+  }
+-->
+</style>
+</head><body>
+{% if fc %}
+<table border="1" cellspacing="1">
+<tr><td colspan=2 nowrap><b>GA SEQUENCING (SOLEXA) LOG</b></td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
+<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
+<tr><td>Date Run Started</td><td colspan=2>{{ fc.run_date }}</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
+<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
+<tr><td>Cluster station used</td><td colspan=2 nowrap>{{ fc.cluster_station.name }}</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
+<tr><td>GA used</td><td colspan=2 nowrap>{{ fc.sequencer.name }}</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
+
+<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
+<tr><td>Flowcell number</td><td colspan=2 nowrap>{{ fc.flowcell_id }}</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
+<tr><td>Number of Tiles per Lane</td><td>100</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
+<tr><td>Number of Cycles</td><td>{{ fc.read_length  }}</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
+<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
+<tr><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
+<tr><td><font point-size="9" face="Arial"><b>SAMPLE INFORMATION</b><font></td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>
+<tr><td>&nbsp;</td><td>FC#</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td colspan=2 nowrap>FC bar code</td></tr>
+
+<tr><td valign=middle nowrap>Lane</td>
+{% for lane in fc.lane_set.all %}
+<td>{{ lane.lane_number }}</td>
+{% endfor %}
+</tr>
+<tr><td valign=middle nowrap>Solexa Library Number</td>
+{% for lane in fc.lane_set.all %}
+<td bgcolor=#CCFFCC>{{ lane.library.id }}</td>
+{% endfor %}
+</tr>
+
+<tr><td valign=middle nowrap>Sample Name</td>
+{% for lane in fc.lane_set.all %}
+<td bgcolor=#CCFFCC>{{ lane.library.library_name }}</td>
+{% endfor %}
+</tr>
+
+<tr><td valign=middle nowrap>Organism</td>
+{% for lane in fc.lane_set.all %}
+<td bgcolor=#CCFFCC>{{ lane.library.library_species.scientific_name }}</td>
+{% endfor %}
+</tr>
+
+<tr><td valign=middle nowrap>Submitter</td>
+{% for lane in fc.lane_set.all %}
+<td bgcolor=#CCFFCC>{{ lane.library.made_for }}</td>
+{% endfor %}
+</tr>
+
+
+<tr><td valign=middle nowrap>First time run?</td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td><td bgcolor=#CCFFCC></td></tr>
+
+<tr><td valign=middle nowrap>Gel Cut Size (bp)</td>
+{% for lane in fc.lane_set.all %}
+<td bgcolor=#CCFFCC>{{ lane.library.gel_cut_size }}</td>
+{% endfor %}
+</tr>  
+
+<tr><td valign=middle nowrap>Template Concentration (ng/ul)</td>
+{% for lane in fc.lane_set.all %}
+<td bgcolor=#CCFFCC>{{ lane.library.undiluted_concentration }}</td>
+{% endfor %}
+</tr>
+
+<tr><td valign=middle nowrap>Run Concentration (pM)</td>
+{% for lane in fc.lane_set.all %}
+<td bgcolor=#CCFFCC>{{ lane.pM }}</td>
+{% endfor %}
+</tr>
+
+</table>
+
+{% else %}
+    <p>Flowcell object missing. Can't create sheet.</p>
+{% endif %}
+
+</body></html
diff --git a/htsworkflow/templates/experiments/flowcell_detail.html b/htsworkflow/templates/experiments/flowcell_detail.html
new file mode 100644 (file)
index 0000000..64da7e2
--- /dev/null
@@ -0,0 +1,128 @@
+{% extends "base_site.html" %}
+{% load staticfiles %}
+{% load humanize i18n %}
+{% block extrahead %}
+    <!-- App Stuff -->
+    <link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}" />
+    <script type="text/javascript" src="{% static "js/jquery.min.js" %}"></script>
+
+    {% block additional_javascript %}
+    {% endblock %}
+{% endblock %}
+
+{% block content %}
+<div>
+  {% include "experiments/flowcell_header.html" %}
+  <div class="htswdetail" typeof="libns:IlluminaFlowcell" resource="{{flowcell.get_absolute_url}}">
+    <h2>Lanes</h2>
+    <table>
+      <thead>
+       <tr>
+         <td>Lane</td>
+         <td>Library ID</td>
+         <td>Library Name</td>
+         <td>Species</td>
+         <td>Comment</td>
+       </tr>
+      </thead>
+      <tbody>
+      {% for lane in lanes %}
+        <tr>
+          <td rel="libns:has_lane">
+            <a href="{{lane.get_absolute_url}}" typeof="libns:IlluminaLane">
+              <span property="libns:lane_number">{{lane.lane_number}}</span>
+            </a>
+          </td>
+          <td rel="libns:library"
+              about="{{lane.get_absolute_url}}"
+              resource="{{lane.library.get_absolute_url}}">
+            <a typeof="libns:Library" href="{{lane.library.get_absolute_url}}">
+              <span property="libns:library_id"
+                    >{{lane.library.id}}</span></a>
+              {% if user.is_staff %}
+              <a href="{{lane.library.get_admin_url}}">
+                  <img class="icon_button"
+                       src="{% static "admin/img/icon_changelink.gif" %}"/>
+              </a>{% endif %}
+          </td>
+          <td>
+            <a href="{{lane.library.get_absolute_url}}">
+              <span property="libns:name"
+                    about="{{lane.library.get_absolute_url}}"
+                    >{{lane.library.library_name}}</span>
+            </a>
+          </td>
+          <td about="{{lane.library.get_absolute_url}}" rel="libns:species">
+            <a href="{{lane.library.library_species.get_absolute_url}}"
+               typeof="libns:Species">
+              <span property="libns:species_name">{{ lane.library.library_species.scientific_name }}</span></a>
+          </td>
+          <td about="{{lane.get_absolute_url}}">
+            <span property="libns:comment">{{lane.comment}}</span>
+          </td>
+        </tr>
+      {% endfor %}
+      </tbody>
+    </table>
+    <div class="htsw_flowcell_ivc">
+    {% for run in flowcell.datarun_set.all %}
+       <h2>Run {{ run.runfolder_name }}</h2>
+       {% if run.lane_files %}
+       <table>
+         <thead>
+           <tr>
+             <td>Lane</td>
+             <td>IVC All</td>
+             <td>IVC Call</td>
+             <td>IVC Percent Base</td>
+             <td>IVC Percent Base All</td>
+             <td>IVC Percent Base Called</td>
+           </tr>
+         </thead>
+         <tbody>
+            {% for lane_id, lane_file_set in run.lane_files.items %}
+            {% if lane_file_set.ivc_all %}
+            <tr>
+              <td>{{ lane_id }}</td>
+              <td>
+                <a href="{{ lane_file_set.ivc_all.get_absolute_url }}">
+                <img height="84" width="126" alt="Lane {{lane_id }} IVC All"
+                     src="{{ lane_file_set.ivc_all.get_absolute_url }}"/></a>
+              </td>
+              <td>
+                <a href="{{ lane_file_set.ivc_call.get_absolute_url }}">
+                <img height="84" width="126" alt="Lane {{lane_id }} IVC Call"
+                     src="{{ lane_file_set.ivc_call.get_absolute_url }}"/>
+                </a>
+              </td>
+              <td>
+                <a href="{{ lane_file_set.ivc_percent_base.get_absolute_url }}">
+                <img height="84" width="126" alt="Lane {{lane_id }} IVC % Base"
+                     src="{{ lane_file_set.ivc_percent_base.get_absolute_url }}"/>
+                </a>
+              </td>
+              <td>
+                <a href="{{ lane_file_set.ivc_percent_all.get_absolute_url }}">
+                <img height="84" width="126" alt="Lane {{lane_id }} IVC % Base All"
+                     src="{{ lane_file_set.ivc_percent_all.get_absolute_url }}"/>
+                </a>
+              </td>
+              <td>
+                <a href="{{ lane_file_set.ivc_percent_call.get_absolute_url }}">
+                <img height="84" width="126"
+                     alt="Lane {{lane_id }} IVC % Base Called"
+                     src="{{ lane_file_set.ivc_percent_call.get_absolute_url }}"/>
+                </a>
+              </td>
+            </tr>
+            {% endif %}
+            {% endfor %}
+         </tbody>
+       </table>
+       {% endif %}
+    {% endfor %}
+    </div>
+  </div>
+</div>
+<!-- end flowcell_detail -->
+{% endblock %}
diff --git a/htsworkflow/templates/experiments/flowcell_header.html b/htsworkflow/templates/experiments/flowcell_header.html
new file mode 100644 (file)
index 0000000..f0cb470
--- /dev/null
@@ -0,0 +1,43 @@
+{% load staticfiles %}
+<div class="flowcell_identity" typeof="libns:IlluminaFlowcell" resource="{{flowcell.get_absolute_url}}">
+  <h2>About this Flowcell</h2>
+  <b>Flowcell</b>:
+    <a href="{{flowcell.get_absolute_url}}"><span property="libns:flowcell_id">{{flowcell.flowcell_id}}</span></a>{% if user.is_staff %}<a href="{{flowcell.get_admin_url}}"><img class="icon_button" src="{% static "admin/img/icon_changelink.gif" %}" alt="Edit"/></a>{% endif%}
+  <br/>
+  <div rel="libns:sequenced_by">
+  <div typeof="libns:Sequencer"
+       about="{{flowcell.sequencer.get_absolute_url}}">
+  <b>Instrument</b>:
+    <span property="libns:sequencer_name">{{ flowcell.sequencer.name }}</span>
+    {% if flowcell.sequencer.instrument_name %}
+    (<span property="libns:sequencer_instrument">{{ flowcell.sequencer.instrument_name}}</span>)
+    {% endif %}
+    <br/>
+  <b>Instrument Model</b>:
+    <span property="libns:sequencer_model">{{flowcell.sequencer.model}}</span>
+    <br/>
+  </div>
+  </div>
+  {% for datarun in flowcell.datarun_set.all %}
+  <b>Image Analysis</b>:
+    <span property="libns:image_software">{{datarun.image_software}}</span>
+    <span property="libns:image_version">{{datarun.image_version}}</span><br/>
+  <b>Base Caller</b>:
+    <span property="libns:basecall_software">{{datarun.basecall_software}}</span>
+    <span property="libns:basecall_version">{{datarun.basecall_version}}</span><br/>
+  <b>Alignment</b>:
+    <span property="libns:alignment_software">{{datarun.alignment_software}}</span>
+    <span property="libns:alignment_version">{{datarun.alignment_version}}</span><br/>
+  {% endfor %}
+  <b>Run Date</b>:
+    <span property="libns:date" content="{{flowcell.run_date|date:'Y-m-d\TH:i:s'}}" datatype="xsd:dateTime">{{ flowcell.run_date }}</span><br/>
+  <b>Type</b>:
+    <span property="libns:flowcell_type">{{flowcell.flowcell_type}}</span><br/>
+  <b>Read Length</b>:
+    <span property="libns:read_length" datatype="xsd:integer">{{flowcell.read_length}}</span><br/>
+  <b>Control Lane</b>:
+    <span property="libns:control_lane">{{flowcell.control_lane}}</span><br/>
+
+  <b>Notes</b>:
+    <pre property="libns:flowcell_notes">{{flowcell.notes}}</pre>
+ </div>
diff --git a/htsworkflow/templates/experiments/flowcell_lane_detail.html b/htsworkflow/templates/experiments/flowcell_lane_detail.html
new file mode 100644 (file)
index 0000000..ebe2c59
--- /dev/null
@@ -0,0 +1,98 @@
+{% extends "base_site.html" %}
+{% load humanize i18n %}
+{% load staticfiles %}
+{% block extrahead %}
+    <!-- App Stuff -->
+    <link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}"/>
+    <script type="text/javascript" src="{% static "js/jquery.min.js" %}"></script>
+
+    {% block additional_javascript %}
+    {% endblock %}
+{% endblock %}
+
+{% block content %}
+<div id="lane_detail" class="htswdetail" typeof="libns:IlluminaLane" resource="{{lane.get_absolute_url}}">
+  <div rel="libns:flowcell" resource="{{flowcell.get_absolute_url}}">
+  {% include "experiments/flowcell_header.html" %}
+  </div>
+  <div class="flowcell_lane_detail">
+  <h2>About this lane</h2>
+  <b>Lane</b>:
+    <span property="libns:lane_number">{{lane.lane_number}}</span><br/>
+  <b>pM</b>:
+    <span property="libns:pM" datatype="xsd:decimal">{{ lane.pM }}</span><br/>
+  {% if lane.cluster_estimate %}
+  <b>Cluster Estimate</b>:
+    <span property="libns:cluster_estimate" datatype="xsd:decimal"
+          content="{{lane.cluster_estimate}}">{{ lane.cluster_estimate|intcomma }}</span><br/>{% endif %}
+  {% if lane.status %}
+  <b>Lane Status</b>:
+    <span property="libns:status">{{ lane.status }}</span><br/>{% endif %}
+  {% if lane.comment %}
+  <b>Comments</b>:
+    <span property="libns:comment">{{ lane.comment }}</span><br/>{% endif %}
+  </div>
+  <hr/>
+  {% include "sample_header.html" %}
+  <hr/>
+  <div class="htsw_flowcell_ivc">
+  {% for run in flowcell.datarun_set.all %}
+     <h2>Run {{ run.runfolder_name }}</h2>
+     <table>
+       <thead>
+         <tr>
+           <td>Lane</td>
+           <td>IVC All</td>
+           <td>IVC Call</td>
+           <td>IVC Percent Base</td>
+           <td>IVC Percent Base All</td>
+           <td>IVC Percent Base Called</td>
+         </tr>
+       </thead>
+       <tbody>
+          {% for run, lane_number, lane_file_set in filtered_dataruns %}
+          {% if lane_file_set.ivc_all %}
+          <tr>
+            <td>{{lane_number}}</td>
+            <td>
+              <a href="{{ lane_file_set.ivc_all.get_absolute_url }}">
+              <img height="84" width="126" alt="Lane {{lane_id }} IVC All"
+                   src="{{ lane_file_set.ivc_all.get_absolute_url }}"/></a>
+            </td>
+            <td>
+              <a href="{{ lane_file_set.ivc_call.get_absolute_url }}">
+              <img height="84" width="126" alt="Lane {{lane_id }} IVC Call"
+                   src="{{ lane_file_set.ivc_call.get_absolute_url }}"/>
+              </a>
+            </td>
+            <td>
+              <a href="{{ lane_file_set.ivc_percent_base.get_absolute_url }}">
+              <img height="84" width="126" alt="Lane {{lane_id }} IVC % Base"
+                   src="{{ lane_file_set.ivc_percent_base.get_absolute_url }}"/>
+              </a>
+            </td>
+            <td>
+              <a href="{{ lane_file_set.ivc_percent_all.get_absolute_url }}">
+              <img height="84" width="126" alt="Lane {{lane_id }} IVC % Base All"
+                   src="{{ lane_file_set.ivc_percent_all.get_absolute_url }}"/>
+              </a>
+            </td>
+            <td>
+              <a href="{{ lane_file_set.ivc_percent_call.get_absolute_url }}">
+              <img height="84" width="126"
+                   alt="Lane {{lane_id }} IVC % Base Called"
+                   src="{{ lane_file_set.ivc_percent_call.get_absolute_url }}"/>
+              </a>
+            </td>
+          </tr>
+          {% else %}
+            <tr><td colspan="6">No data</td></tr>
+          {% endif %}
+          {% endfor %}
+       </tbody>
+     </table>
+  {% endfor %}
+  </div>
+</div>
+
+{% endblock %}
diff --git a/htsworkflow/templates/experiments/index.html b/htsworkflow/templates/experiments/index.html
new file mode 100644 (file)
index 0000000..28c24bf
--- /dev/null
@@ -0,0 +1,14 @@
+{% if data_run_list %}
+    <table>
+      {% for run in data_run_list %}
+        <tr>
+          <td>{{run.run_folder}}</td>
+          <td><a href="fcsheet/{{run.fcid}}">sheet</td>
+          <td><a href="started/{{run.fcid}}">started email</td>
+          <td><a href="finished/{{run.fcid}}">finished email</td>
+       </tr>
+      {% endfor %}
+   </table>
+{% else %}
+    <p>No data runs are available.</p>
+{% endif %}
diff --git a/htsworkflow/templates/experiments/sequencer.html b/htsworkflow/templates/experiments/sequencer.html
new file mode 100644 (file)
index 0000000..411288c
--- /dev/null
@@ -0,0 +1,25 @@
+{% extends "base_site.html" %}
+{% load humanize i18n %}
+{% load staticfiles %}
+{% block extrahead %}
+    <!-- App Stuff -->
+    <link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}" />
+    <script type="text/javascript" src="{% static "js/jquery.min.js" %}"></script>
+
+    {% block additional_javascript %}
+    {% endblock %}
+{% endblock %}
+
+{% block content %}
+    <h1>Sequencer</h1>
+    <dl about="{{sequencer.get_absolute_url}}" typeof="libns:sequencer">
+      <dt>Name</dt>
+      <dl property="libns:sequencer_name">{{sequencer.name}}</dl>
+      <dt>Instrument Name</dt>
+      <dl property="libns:insrument_name">{{sequencer.instrument_name}}</dl>
+      <dt>Model</dt>
+      <dl property="libns:model">{{sequencer.model}}</dl>
+      <dt>Comment</dt>
+      <dl></dl>
+    </dl>
+{% endblock %}
diff --git a/htsworkflow/templates/experiments/started_email.html b/htsworkflow/templates/experiments/started_email.html
new file mode 100644 (file)
index 0000000..180cde6
--- /dev/null
@@ -0,0 +1,19 @@
+<p>
+The following libraries are on the flowcell {{ flowcell.flowcell_id }}
+which is a {{ flowcell.read_length }} base pair {% if flowcell.paired_end %}paired end{% else %}single ended{% endif %} flowcell.
+</p>
+<p>{% for lane in lanes %}
+Lane #{{ lane.lane_number }} : 
+<a href="https://jumpgate.caltech.edu/library/{{lane.library.id}}">
+{{ lane.library.id }}</a>
+{{ lane.library.library_name }}<br/>
+{% endfor %}</p>
+<p>
+The data should be available at the following link when
+the pipeline finishes, probably in about {{ finish_low.days }} to {{ finish_high.days }} 
+days from {{ now|date:"D, M d Y" }}
+</p>
+<p>
+<a href="https://jumpgate.caltech.edu/runfolders/{{ flowcell.sequencer}}/">
+https://jumpgate.caltech.edu/runfolders/{{ flowcell.sequencer }}
+</a></p>
diff --git a/htsworkflow/templates/experiments/started_email.txt b/htsworkflow/templates/experiments/started_email.txt
new file mode 100644 (file)
index 0000000..7337ef8
--- /dev/null
@@ -0,0 +1,19 @@
+The following libraries are on the flowcell {{ flowcell.flowcell_id }}
+which is a {{ flowcell.read_length }} base pair {% if flowcell.paired_end %}paired end{% else %}single ended{% endif %} flowcell.
+
+Lane : (Library Id) Library Name (Cluster Estimate)
+{% for lane in lanes %}
+Lane #{{ lane.lane_number }} : ({{ lane.library.id }}) {{ lane.library.library_name }} ({{ lane.cluster_estimate }})
+     https://jumpgate.caltech.edu/library/{{ lane.library.id }}
+{% endfor %}
+
+The raw data should be available at the following link when the
+pipeline finishes, probably in about {{ finish_low.days }} to {{ finish_high.days }} 
+days from {{ now|date:"D, M d Y" }}
+
+https://jumpgate.caltech.edu/runfolders/{{ flowcell.sequencer}}
+
+Username: gec
+Password: gecilluminadata
+
+- Jumpgate
diff --git a/htsworkflow/templates/inventory/default.zpl b/htsworkflow/templates/inventory/default.zpl
new file mode 100644 (file)
index 0000000..802ac69
--- /dev/null
@@ -0,0 +1,25 @@
+^FX=========================
+^FX Harddrive Location Tracking Label
+^FX 300x375 dots
+^FX=========================
+
+^XA
+^LH 0,25
+
+^FO0,0
+^CF0,35
+^FB375,1,,C
+^FD{{ item.item_type.name }}:^FS
+
+^FX -------Text contains HD serial #-------------
+^FO15,75
+^CF0,42
+^FB325,3,,C
+^FD{% if use_uuid %}{{ item.uuid }}{% else %}{{ item.barcode_id }}{% endif %}^FS
+
+^FX -------Barcode contains HD serial #-----------
+^FO150,200
+^BXN,3,200
+^FD{% if use_uuid %}invu|{{ item.uuid }}{% else %}invb|{{ item.barcode_id }}{% endif %}^FS
+
+^XZ
diff --git a/htsworkflow/templates/inventory/hard_drive_shell.zpl b/htsworkflow/templates/inventory/hard_drive_shell.zpl
new file mode 100644 (file)
index 0000000..610df2e
--- /dev/null
@@ -0,0 +1,108 @@
+^FX=========================
+^FX 3"x3" Label
+^FX=========================
+^XA
+
+
+^FX======== Left Side ===========
+
+^FX------------
+^FX ^LH changes the 0,0 point of all subsequent location references
+^FX------------
+
+^LH0,50
+
+^FX ---Header---
+
+^FO25,0
+^CF0,50
+^FB250,2,,C
+^FD{{ item.barcode_id }}^FS
+
+^FX ---Column 1: Flowcells---
+
+^FX-----------------
+^FX FB command for automatic text formatting:
+^FX ^FB[dot width of area], [max # of lines], [change line spacing], [justification: L, C, R, J], [hanging indent]
+^FX-----------------
+
+^CF0,30,30
+^FO75,125
+^FB275,19,,L
+^FD{% for flowcell in flowcell_id_list %}{{ flowcell }}{% if not forloop.last %}\&{% endif %}{% endfor %}^FS
+^FX ---Date---
+
+^FO0,725
+^CF0,35
+^FB300,2,,C
+^FD{{ oldest_rundate|date:"YMd" }} - {{ latest_rundate|date:"YMd" }}^FS
+
+^FX ---Barcode---
+
+^FO135,795
+^BXN,3,200^FDinvb|{{ item.barcode_id }}^FS
+
+^FX======== Right Side ===========
+
+^LH300,60
+
+^FX ---Header---
+
+^FO0,0
+^CF0,50
+^FB600,2,,C
+^FD{{ barcode_id }}^FS
+
+^FX ---Dividing line---
+
+^FX---------------
+^FX GB command:
+^FX ^GB[box width], [box height], [border thickness], [color: B, W], [corner rounding: 0-8]^FS
+^FX---------------
+
+^FO0,100
+^GB0,600,10^FS
+
+^FX ---Column 2: Libraries 1-20---
+
+^CF0,30,30
+^FO75,100
+^FB100,20,,L
+^FD{% for lib_id in library_id_list_1_to_20 %}{{ lib_id }}{% if not forloop.last %}\&{% endif %}{% endfor %}^FS
+
+^FX ---Column 3: Libraries 21-40---
+
+^CF0,30,30
+^FO200,100
+^FB100,20,,L
+^FD{% for lib_id in library_id_list_21_to_40 %}{{ lib_id }}{% if not forloop.last %}\&{% endif %}{% endfor %}^FS
+
+^FX ---Column 4: Libraries 41-60---
+
+^CF0,30,30
+^FO325,100
+^FB100,20,,L
+^FD{% for lib_id in library_id_list_41_to_60 %}{{ lib_id }}{% if not forloop.last %}\&{% endif %}{% endfor %}^FS
+
+^FX ---Column 5: Libraries 61-80---
+
+^CF0,30,30
+^FO450,100
+^FB100,20,,L
+^FD{% for lib_id in library_id_list_61_to_80 %}{{ lib_id }}{% if not forloop.last %}\&{% endif %}{% endfor %}^FS
+
+^FX ---Date---
+
+^FO0,715
+^CF0,35
+^FB600,2,,C
+^FDRun Dates: {{ oldest_rundate|date:"YMd" }}-{{ latest_rundate|date:"YMd" }}^FS
+
+^FX ---Barcode---
+
+^FO255,785
+^BXN,3,200^FDinvb|{{ item.barcode_id }}^FS
+
+^LH0,0
+^FX ---End---
+^XZ
\ No newline at end of file
diff --git a/htsworkflow/templates/inventory/inventory_all_index.html b/htsworkflow/templates/inventory/inventory_all_index.html
new file mode 100644 (file)
index 0000000..c95a78b
--- /dev/null
@@ -0,0 +1,69 @@
+{% extends "base_site.html" %}
+{% load admin_list i18n %}
+{% block extrahead %}
+    <script type="text/javascript">
+      $(document).ready(function() {
+        $(window).resize(function() {
+           var window_height = $(window).height();
+           var position = $("#changelist table").position();
+           height = window_height - position.top;
+           $("#changelist table.filtered").height(height);
+           $("#changelist-filter").height(height);
+        });
+        $(window).resize();
+      });
+    </script>
+{% endblock %}
+{% block bodyclass %}change-list{% endblock %}
+{% block coltype %}flex{% endblock %}
+{% block content %}
+<div id="inventory-index-div" >
+  <div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
+    {% block search %}{% search_form item_changelist %}{% endblock %}
+    {% block pagination %}{% pagination item_changelist %}{% endblock %}
+
+    {% block filters %}
+    {% if item_changelist.has_filters %}
+    <div id="changelist-filter">
+      <h2 >{% trans 'Filter' %}</h2>
+      {% for spec in item_changelist.filter_specs %}
+         {% admin_list_filter cl spec %}
+         {% endfor %}
+       </div>
+    {% endif %}
+    {% endblock %}
+  {% block summary_stats %}
+  <table class="{% if cl.has_filters %} filtered{% endif %}">
+    <thead >
+      <tr >
+        <td >UUID</td>
+        <td >Barcode ID</td>
+        <td >Location</td>
+        <td >Model</td>
+        <td >Vendor</td>
+        <td >Created</td>
+        <td >Contains</td>
+      </tr>
+    </thead>
+    <tbody >
+      {% for item in item_changelist.get_query_set %}
+      <tr >
+        <td >{{ item.uuid }}</td>
+        <td >{{ item.barcode_id}}</td>
+        <td >{{ item.location }}</td>
+        <td >{{ item.item_type }}</td>
+        <td ></td>      
+        <td >{{ item.creation_date }}</td>      
+        <td >
+          {% for content in item.longtermstorage_set.all %}
+          {{ content.flowcell }}
+          {% endfor %}
+        </td>
+      </tr>
+      {% endfor %}
+    </tbody>
+  </table>
+  {% endblock %}
+</div>
+{% endblock %}
diff --git a/htsworkflow/templates/inventory/inventory_index.html b/htsworkflow/templates/inventory/inventory_index.html
new file mode 100644 (file)
index 0000000..7c7eb50
--- /dev/null
@@ -0,0 +1,55 @@
+{% extends "base_site.html" %}
+{% load admin_list i18n %}
+{% block extrahead %}
+    <script type="text/javascript">
+      $(document).ready(function() {
+        $(window).resize(function() {
+           var window_height = $(window).height();
+           var position = $("#changelist table").position();
+           height = window_height - position.top;
+           $("#changelist table.filtered").height(height);
+           $("#changelist-filter").height(height);
+        });
+        $(window).resize();
+      });
+    </script>
+{% endblock %}
+{% block bodyclass %}change-list{% endblock %}
+{% block coltype %}flex{% endblock %}
+{% block content %}
+<div id="inventory-index-div" >
+  <div class="module{% if item_changelist.has_filters %} filtered{% endif %}" id="changelist">
+    {% block search %}{% search_form item_changelist %}{% endblock %}
+    {% block pagination %}{% pagination item_changelist %}{% endblock %}
+
+    {% block filters %}
+    {% if item_changelist.has_filters %}
+    <div id="changelist-filter">
+      <h2 >{% trans 'Filter' %}</h2>
+      {% for spec in item_changelist.filter_specs %}
+         {% admin_list_filter item_changelist spec %}
+         {% endfor %}
+       </div>
+    {% endif %}
+    {% endblock %}
+  {% block summary_stats %}
+  <table class="{% if item_changelist.has_filters %} filtered{% endif %}">
+    <thead >
+      <tr >
+        <td >Name</td>
+        <td >Description</td>
+      </tr>
+    </thead>
+    <tbody >
+      {% for itemtype in item_changelist.result_list %}
+      <tr >
+        <td ><a href="/inventory/it/{{ itemtype.name }}/">{{ itemtype.name }}</a></td>
+        <td >{{ itemtype.description }}</td>
+      </tr>
+      {% endfor %}
+    </tbody>
+  </table>
+  {% endblock %}
+</div>
+{% endblock %}
diff --git a/htsworkflow/templates/inventory/inventory_itemtype_index.html b/htsworkflow/templates/inventory/inventory_itemtype_index.html
new file mode 100644 (file)
index 0000000..eb559b1
--- /dev/null
@@ -0,0 +1,70 @@
+{% extends "base_site.html" %}
+{% load admin_list i18n %}
+{% block extrahead %}
+    <script type="text/javascript">
+      $(document).ready(function() {
+        $(window).resize(function() {
+           var window_height = $(window).height();
+           var position = $("#changelist table").position();
+           height = window_height - position.top;
+           $("#changelist table.filtered").height(height);
+           $("#changelist-filter").height(height);
+        });
+        $(window).resize();
+      });
+    </script>
+{% endblock %}
+{% block bodyclass %}change-list{% endblock %}
+{% block coltype %}flex{% endblock %}
+{% block content %}
+<div id="inventory-index-div" >
+  <div class="module{% if item_changelist.has_filters %} filtered{% endif %}" id="changelist">
+    {% block search %}{% search_form item_changelist %}{% endblock %}
+
+    {% block pagination %}{% pagination item_changelist %}{% endblock %}
+
+    {% block filters %}
+    {% if item_changelist.has_filters %}
+    <div id="changelist-filter">
+      <h2 >{% trans 'Filter' %}</h2>
+      {% for spec in item_changelist.filter_specs %}
+         {% admin_list_filter item_changelist spec %}
+         {% endfor %}
+    </div>
+    {% endif %}
+    {% endblock %}
+  {% block summary_stats %}
+  <table class="{% if item_changelist.has_filters %} filtered{% endif %}">
+    <thead >
+      <tr >
+        <td >UUID</td>
+        <td >Barcode ID</td>
+        <td >Location</td>
+        <td >Model</td>
+        <td >Vendor</td>
+        <td >Created</td>
+        <td >Contains</td>
+      </tr>
+    </thead>
+    <tbody >
+      {% for item in item_changelist.result_list %}
+      <tr about="{{ item.get_absolute_url }}">
+        <td ><a href="{{ item.get_absolute_url}}" rel="invns:uuid">{{ item.uuid }}</a></td>
+        <td ><a href="/inventory/{{ item.barcode_id }}/" rel="invns:barcode">{{ item.barcode_id }}</a></td>
+        <td property="invns:location">{{ item.location }}</td>
+        <td property="invns:item_type">{{ item.item_type }}</td>
+        <td ></td>
+        <td property="invnfs:creation_date" content="{{item.creation_date|date:'Y-m-d\TH:i:s'}}" datatype="xsd:dateTime">{{ item.creation_date }}</td>
+        <td class="cell_list" >
+          {% for content in item.longtermstorage_set.all %}
+          <a href="{{content.flowcell.get_absolute_url}}" rel="libns:flowcell_id">{{ content.flowcell }}</a>
+          {% endfor %}
+        </td>
+      </tr>
+      {% endfor %}
+    </tbody>
+  </table>
+  {% endblock %}
+  </div>
+</div>
+{% endblock %}
diff --git a/htsworkflow/templates/inventory/inventory_summary.html b/htsworkflow/templates/inventory/inventory_summary.html
new file mode 100644 (file)
index 0000000..b520405
--- /dev/null
@@ -0,0 +1,47 @@
+{% extends "base_site.html" %}
+
+{% block content %}
+{% if item %}
+        <h2>Item Summary:</h2>
+        <a href="{% url "inventory.views.index" %}{{item.uuid}}/print/">Print</a><br />
+        <br />
+        <b>UUID:</b> <span property="invns:uuid">{{item.uuid}}</span><br />
+        <b>Barcode ID:</b> <span property="invns:barcode">{{ item.barcode_id }}</span><br />
+        <b>Type:</b> <span property="invns:item_type">{{ item.item_type.name }}</span><br />
+        <br />
+        <b>Location:</b> <span property="invns:location">{{ item.location.name }}</span><br />
+        <b>Status: </b> {% if item.status %}<span property="invns:status">{{ item.status.name }}</span>{% else %}N/A{% endif %}<br />
+        <br />
+        {% if item.item_info.model_id %}
+        <b>Model ID:</b> <span property="invns:model">{{ item.item_info.model_id }}</span><br />
+        {% endif %}
+        {% if item.item_info.part_number %}
+        <b>Part Number:</b> <span property="invns:part_number">{{ item.item_info.part_number }}</span><br />
+        {% endif %}
+        {% if item.item_info.lot_number %}
+        <b>Lot Number:</b> <span property="invns:lot_number">{{ item.item_info.lot_number }}</span><br />
+        {% endif %}
+        <br />
+        {% if item.item_info.url %}
+        <b>Item Website:</b> <a href="{{ item.item_info.url }}" rel="invns:vendor_link">Link</a><br />
+        {% endif %}
+        <b>Vendor:</b> {% if item.item_info.vendor.url %}<a href="{{ item.item_info.vendor.url }}">{% endif %}{{ item.item_info.vendor.name }}{% if item.item_info.vendor.url %}</a>{% endif %}<br />
+        <b>Purchase Date:</b>{% if item.item_info.purchase_date %}{{ item.item_info.purchase_date }}{% else %}N/A{% endif %}<br />
+        <b>Warenty (Months):</b>{% if item.item_info.warenty_months %}{{item.item_info.warenty_months}}{% else %}N/A{% endif %}<br />
+        <br />
+        <b>Item Info Notes:</b>
+        <p>
+                {% if item.item_info.notes %}{{ item.item_info.notes }}{% else %}No notes found{% endif %}
+        </p>
+        <br />
+        <b>Item Specific Notes:</b>
+        <p>
+                {% if item.notes %}{{ item.notes }}{% else %}No notes found{% endif %}
+        </p>
+        <br />
+        <center><div id="lts-grid"></div></center>
+        
+{% else %}
+        <h3>Item with UUID of {{ uuid }} not found.</h3>
+{% endif %}
+{% endblock %}
diff --git a/htsworkflow/templates/registration/login.html b/htsworkflow/templates/registration/login.html
new file mode 100644 (file)
index 0000000..d3d108b
--- /dev/null
@@ -0,0 +1,36 @@
+{% extends "base_site.html" %}
+{% load i18n %}
+
+{% block additional_css %}{% load staticfiles %}{{ block.super }}
+<link rel="stylesheet" type="text/css" href="{% static "css/base.css" %}"/>
+<link rel="stylesheet" type="text/css" href="{% static "css/login.css" %}"/>
+{% endblock %}
+
+{% block title %}Login{% endblock %}
+{% block bodyclass %}login{% endblock %}
+
+{% block content %}
+{% if error_message %}
+<p class="errornote">{{ error_message }}</p>
+{% endif %}
+<div id="container">
+    <h1>Login</h1>
+<form action="{{ app_path }}" method="post" id="login-form">
+  {% csrf_token %}
+  <div class="form-row">
+    <label for="id_username">{% trans 'Username:' %}</label> <input type="text" name="username" id="id_username" />
+  </div>
+  <div class="form-row">
+    <label for="id_password">{% trans 'Password:' %}</label> <input type="password" name="password" id="id_password" />
+    <input type="hidden" name="this_is_the_login_form" value="1" />
+  </div>
+  <div class="submit-row">
+    <label>&nbsp;</label><input type="submit" value="{% trans 'Log in' %}" />
+  </div>
+</form>
+
+<script type="text/javascript">
+document.getElementById('id_username').focus()
+</script>
+</div>
+{% endblock %}
diff --git a/htsworkflow/templates/registration/profile.html b/htsworkflow/templates/registration/profile.html
new file mode 100644 (file)
index 0000000..fec48b0
--- /dev/null
@@ -0,0 +1,9 @@
+{% extends "base_site.html" %}
+
+{% block content %}
+<table>
+    <tr><td>User Name:</td><td>{{ user.username }}</td></tr>
+    <tr><td>Full Name:</td><td>{{ user.get_full_name }}</td></tr>
+    <tr><td>E-mail:</td><td>{{ user.email }}</td></tr>
+</table>
+{% endblock %}
diff --git a/htsworkflow/templates/reports/report.html b/htsworkflow/templates/reports/report.html
new file mode 100644 (file)
index 0000000..c134377
--- /dev/null
@@ -0,0 +1,11 @@
+{% extends "admin/base_site.html" %}
+
+{% if main %}
+{% block content %}
+ {{ main|safe }}
+
+{% endblock %}
+{% else %}
+    <p>No content. Can't create report.</p>
+{% endif %}
diff --git a/htsworkflow/templates/sample_header.html b/htsworkflow/templates/sample_header.html
new file mode 100644 (file)
index 0000000..a198cef
--- /dev/null
@@ -0,0 +1,93 @@
+{% load staticfiles %}
+<div id="librarydetail"
+     about="{{lib.get_absolute_url}}"
+     typeof="libns:Library">
+  <div class="library_identity">
+    <h2>Library Name</h2>
+    <b>Library ID</b>:
+       <a href="{{lib.get_absolute_url}}"><span property="libns:library_id">{{ lib.id }}</span></a>
+       {% if user.is_staff %}<a href="{{lib.get_admin_url}}"><img class="icon_button" src="{% static "admin/img/icon_changelink.gif" %}" alt="Edit"/></a>{% endif %}
+       <br />
+    <b>Name</b>:
+      <span property="libns:name">{{ lib.library_name }}</span>
+    <br/>
+    <b>Affiliations</b>:
+    <ul>
+      {% for individual in lib.affiliations.all %}
+        <li property="libns:affiliation" content="{{individual.name}}">
+          {{ individual.name }} ( {{ individual.contact }} )
+        </li>
+      {% endfor %}
+    </ul>
+  </div>
+  <div class="library_sample_detail">
+    <h2>Sample Details</h2>
+    <b>Species</b>:
+      <span property="libns:species_name" content="{{lib.library_species.scientific_name}}"><a href="{{lib.library_species.get_absolute_url}}">{{ lib.library_species.scientific_name }}</a></span>
+    <br/>
+    <b>Experiment Type</b>:
+       <span property="libns:experiment_type">{{ lib.experiment_type }}</span>
+    <br/>
+    {% if lib.antibody %}
+    <b>Antibody</b>:
+       <span property="libns:antibody">{{ lib.antibody.antibodies }}</span>
+       {% if lib.antibody.antibodies.nickname %}
+       (<span property="libns:antibody_term">{{ lib.antibody.nickname }}</span>)
+       {% endif %}
+    <br/>
+    {% endif %}
+    {% if lib.cell_line %}
+    <b>Background or Cell Line</b>:
+       <span property="libns:cell_line">{{ lib.cell_line }}</span>
+    <br/>
+    {% endif %}
+    {% if lib.condition %}
+    <b>Condition</b>:
+       <span property="libns:condition">{{ lib.condition.condition_name }}</span>
+       {% if lib.condition.nickname %}
+       (<span property="libns:condition_term">{{ lib.condition.nickname }}</span>)
+       {% endif %}
+    <br/>
+    {% endif %}
+    {% if lib.replicate %}
+    <b>Replicate</b>:
+       <span property="libns:replicate">{{ lib.replicate }}</span>
+    <br/>
+    {% endif %}
+  </div>
+  <div class="library_library_detail">
+    <h2>Library Details</h2>
+    <b>Library Type</b>:
+       <span property="libns:library_type">{{ lib.library_type }}</span>
+    <br/>
+    <b>Multiplex Index</b>:
+       <span property="libns:multiplex_index">{{ lib.index_sequence_text }}</span>
+    <br/>
+    <b>Creation Date</b>
+      <span property="libns:date" content="{{lib.creation_date|date:'Y-m-d'}}T00:00:00" datatype="xsd:dateTime">{{ lib.creation_date }}</span>
+    <br/>
+    <b>Made By</b>:
+      <span property="libns:made_by">{{ lib.made_by }}</span>
+    <br/>
+    {% if lib.gel_cut_size %}
+    <b>Gel Cut Size</b>:
+      <span property="libns:gel_cut" datatype="xsd:integer">{{ lib.gel_cut_size }}</span>
+    <br/>
+    {% endif %}
+    {% if lib.insert_size %}
+    <b>Insert Size</b>:
+      <span property="libns:insert_size" datatype="xsd:integer">{{ lib.insert_size }}</span>
+    <br/>
+    {% endif %}
+    {% if lib.undiluted_concentration %}
+    <b>Concentration</b>:
+      <span property="libns:concentration">{{ lib.undiluted_concentration }} ng/µl</span>
+    <br/>
+    {% endif %}
+    {% if lib.stopping_point_name %}
+    <b>Protocol Stopping Point</b>
+      <span property="libns:stopping_point">{{ lib.stopping_point_name }}</span>
+    <br/>
+    {% endif %}
+  </div>
+</div>
diff --git a/htsworkflow/templates/samples/antibody_index.html b/htsworkflow/templates/samples/antibody_index.html
new file mode 100644 (file)
index 0000000..7ef6c54
--- /dev/null
@@ -0,0 +1,44 @@
+{% extends "base_site.html" %}
+{% load admin_list i18n %}
+
+{% block bodyclass %}change-list{% endblock %}
+{% block coltype %}flex{% endblock %}
+
+{% block content %}
+<div id="antibody-index-div">
+{% block body %}
+<table >
+  <thead >
+    <tr >
+      <td >Antigene</td>
+      <td >Nickname</td>
+      <td >Antibodies</td>
+      <td >Catalog</td>
+      <td >Source</td>
+  </tr>
+  </thead>
+  <tbody >
+    {% for antibody in antibodies %}
+    <tr >
+      <td >
+        {{ antibody.antigene }}
+      </td>
+      <td >
+        {{ antibody.nickname }}
+      </td>
+      <td >
+        {{ antibody.antibodies }}
+      </td>
+      <td >
+        {{ antibody.catalog }}
+      </td>
+      <td >
+        {{ antibody.source }}
+      </td>
+   </tr>
+    {% endfor %}
+  </tbody>
+</table>
+</div>
+{% endblock %}
+{% endblock %}
diff --git a/htsworkflow/templates/samples/lanes_for.html b/htsworkflow/templates/samples/lanes_for.html
new file mode 100644 (file)
index 0000000..b71d0be
--- /dev/null
@@ -0,0 +1,69 @@
+{% extends "base_site.html" %}
+{% load admin_list i18n %}
+
+{% block bodyclass %}change-list{% endblock %}
+{% block coltype %}flex{% endblock %}
+
+{% block content %}
+<div id="lanes-index-div">
+  <div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
+    {% block search %}{% search_form lanes %}{% endblock %}
+
+    {% block filters %}
+    {% if lanes.has_filters %}
+    <div id="changelist-filter">
+      <h2 >{% trans 'Filter' %}</h2>
+      {% for spec in lanes.filter_specs %}
+         {% admin_list_filter lanes spec %}
+         {% endfor %}
+       </div>
+       {% endif %}
+       {% endblock %}
+
+  
+ {% block pagination %}{% pagination lanes %}{% endblock %}
+
+{% block body %}
+<table >
+  <thead >
+    <tr >
+      <td >Run Date</td>
+      <td >Flowcell Type</td>
+      <td >Cycles</td>
+      <td >Flowcell ID</td>
+      <td >Lane</td>
+      <td >Library ID</td>
+      <td >Library Name</td>
+  </tr>
+  </thead>
+  <tbody >
+    {% for lane in lanes.query_set %}
+    <tr >
+      <td >
+        {{ lane.flowcell.run_date|date:"Y-M-d" }}
+      </td>
+      <td >
+        {{ lane.flowcell.flowcell_type }}
+      </td>
+      <td >
+        {{ lane.flowcell.read_length }}
+      </td>
+      <td >
+        {{ lane.flowcell.flowcell_id }}
+      </td>
+      <td >
+        {{ lane.lane_number }}
+      </td>
+      <td >
+        <a href="/library/{{ lane.library_id }}">{{ lane.library_id }}</a>
+      </td>
+      <td >
+        <a href="/library/{{ lane.library_id }}">{{ lane.library.library_name }}</a>
+      </td>
+   </tr>
+    {% endfor %}
+  </tbody>
+</table>
+</div>
+{% endblock %}
+{% endblock %}
diff --git a/htsworkflow/templates/samples/library_detail.html b/htsworkflow/templates/samples/library_detail.html
new file mode 100644 (file)
index 0000000..65747dc
--- /dev/null
@@ -0,0 +1,182 @@
+{% extends "base_site.html" %}
+{% load staticfiles %}
+{% load humanize i18n %}
+{% block extrahead %}
+    <!-- App Stuff -->
+    <link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}"/>
+    <script type="text/javascript" src="{% static "js/jquery.min.js" %}"></script>
+
+    {% block additional_javascript %}
+    {% endblock %}
+{% endblock %}
+
+{% block content %}
+  {% include "sample_header.html" %}
+  <hr/>
+  <div class="library_statistics">
+  <h2>Raw Result Files</h2>
+  <table>
+  <thead>
+    <tr>
+      <td>Run Start Date</td>
+      <td>Cycle</td>
+      <td>Flowcell</td>
+      <td>Lane</td>
+      <td>Summary</td>
+      <td>Eland</td>
+      <td>Bed</td>
+      <td>Archived</td>
+    </tr>
+  </thead>
+  <tbody>
+  {% if eland_results %}
+    {% for result in eland_results %}
+    <tr about="{{result.flowcell.get_absolute_url}}">
+      <td property="libns:date" content="{{result.run_date|date:'Y-m-d\TH:i:s'}}" datatype="xsd:dateTime">{{ result.run_date|date}}</td>
+      <td>{{ result.cycle }}</td>
+      <td><a href="{{result.flowcell.get_absolute_url}}"><span property="libns:flowcell_id">{{ result.flowcell_id }}</span></a>{% if user.is_staff %}<a href="{{result.flowcell.get_admin_url}}"><img class="icon_button" src="{% static "admin/img/icon_changelink.gif" %}" alt="Edit"/></a>{% endif%}</td>
+      <td>{{ result.lane.lane_number }}</td>
+      <td><a href="{{ result.summary_url }}">Summary</a></td>
+      <td><a href="{{ result.result_url }}">{{ result.result_label }}</a></td>
+      <td>
+      {% if result.bed_url %}
+        <a href="{{ result.bed_url }}">Bed</a>
+      {% endif %}
+      </td>
+      <td>
+        {% if result.storage_ids %}
+          {{ result.storage_ids|safe }}
+        {% endif %}
+      </td>
+    </tr>
+    {% endfor %}
+  {% else %}
+    <tr><td colspan="8">No data</td></tr>
+  {% endif %}
+  </tbody>
+  </table>
+
+  <h2>Lane Summary Statistics</h2>
+  {% block summary_stats %}
+  <table>
+    <thead>
+      <tr>
+        <td colspan="7"></td>
+        <td colspan="2">No Match</td>
+        <td colspan="2">QC Failed</td>
+        <td colspan="4">Unique</td>
+        <td colspan="4">Repeat</td>
+      </tr>
+      <tr>
+      <td>Cycles</td>
+      <td>Flowcell</td>
+      <td>Lane</td>
+      <td>End</td>
+      <td>Cluster / Tile</td>
+      <td>pM</td>
+      <td>Raw Reads</td>
+      <td>total</td>
+      <td>%</td>
+      <td>total</td>
+      <td>%</td>
+      <td>0 mismatch</td>
+      <td>1 mismatch</td>
+      <td>2 mismatch</td>
+      <td>Total</td>
+      <td>0 mismatch</td>
+      <td>1 mismatch</td>
+      <td>2 mismatch</td>
+      <td>Total</td>
+      </tr>
+    </thead>
+    <tbody>
+    {% if lane_summary_list %}
+      {# ls short for lane summary #}
+      {% for ls in lane_summary_list %}
+      <tr about="{{ls.lane.get_absolute_url}}">
+        <td>{{ ls.cycle_width }}</td>
+        <td><a href="{{ls.flowcell.get_absolute_url}}">{{ ls.flowcell_id }}</a>
+        </td>
+        <td><a href="{{ls.lane.get_absolute_url}}">{{ ls.lane_id }}</a></td>
+        <td>{% if ls.end %}{{ ls.end }}{% endif %}</td>
+        <td>{{ ls.clusters.0|intcomma }}</td>
+        <td>{{ ls.successful_pm }}</td>
+        <td>{{ ls.reads|intcomma }}</td>
+        <td>{{ ls.no_match|intcomma }}</td>
+        <td>{{ ls.no_match_percent|stringformat:".2f" }}</td>
+        <td>{{ ls.qc_failed|intcomma }}</td>
+        <td>{{ ls.qc_failed_percent|stringformat:".2f" }}</td>
+        <td>{{ ls.match_codes.U0|intcomma }}</td>
+        <td>{{ ls.match_codes.U1|intcomma }}</td>
+        <td>{{ ls.match_codes.U2|intcomma }}</td>
+        <td {% if ls.unique_reads %}property="libns:total_unique_locations" content="{{ls.unique_reads}}" datatype="xsd:decimal"{% endif %}>{{ ls.unique_reads|intcomma }}</td>
+        <td>{{ ls.match_codes.R0|intcomma }}</td>
+        <td>{{ ls.match_codes.R1|intcomma }}</td>
+        <td>{{ ls.match_codes.R2|intcomma }}</td>
+        <td>{{ ls.repeat_reads|intcomma }}</td>
+      </tr>
+      {% endfor %}
+      {% else %}
+       <tr><td colspan="20">No data</td></tr>
+    {% endif %}
+  </tbody>
+    </table>
+
+  <h2>Flowcell Notes</h2>
+  <table>
+    <thead>
+      <tr>
+       <td>Flowcell ID</td>
+       <td>Lane</td>
+       <td>Comment</td>
+      </tr>
+    </thead>
+    {% if lib.lane_set.all %}
+    <tbody>
+      {% for lane in lib.lane_set.all %}
+      <tr rel="libns:has_lane" 
+          about="{{lib.get_absolute_url}}"
+          resource="{{lane.get_absolute_url}}">
+        <td>
+          <a typeof="libns:IlluminaFlowcell" href="{{lane.flowcell.get_absolute_url}}">
+            <span property="libns:flowcell_id"
+                  >{{lane.flowcell.flowcell_id}}</span></a>
+          {% if user.is_staff %}
+            <a href="{{lane.flowcell.get_admin_url}}">
+               <img class="icon_button"
+                    src="{% static "admin/img/icon_changelink.gif" %}" alt="Edit"/>
+            </a>
+          {% endif%}
+        </td>
+        <td typeof="libns:IlluminaLane" about="{{lane.get_absolute_url}}">
+          <span rel="libns:flowcell" resource="{{lane.flowcell.get_absolute_url}}"></span>
+          <a href="{{lane.get_absolute_url}}">
+            <span property="libns:lane_number"
+               >{{ lane.lane_number }}</span>
+            </a></td>
+        <td>{{ lane.comment }}</td>
+      </tr>
+         {% endfor %}
+    </tbody>
+    {% endif %}
+  </table>
+  <br/>
+  <hr/>
+  <h2>Count of multi-reads</h2>
+  {% for eland_lane in lane_summary_list %}
+    {% if eland_lane.summarized_reads %}
+    <h3>{{eland_lane.cycle_width}} {{ eland_lane.flowcell_id }} lane {{ eland_lane.lane_id }}
+      {% if eland_lane.end %} end {{ eland_lane.end }}{% endif %}
+    </h3>
+    <ul about="{{eland_lane.lane.get_absolute_url}}">
+      {% for name, counts in eland_lane.summarized_reads.items %}
+      <li rel="libns:has_mappings">
+         <b property="libns:mapped_to">{{ name }}</b>:
+         <span property="libns:reads" content="{{counts}}" datatype="xsd:integer">{{ counts|intcomma }}</span></li>
+      {% endfor %}
+    </ul>
+    {% endif %}
+  {% endfor %}
+  {% endblock %}
+  </div>
+{% endblock %}
diff --git a/htsworkflow/templates/samples/library_index.html b/htsworkflow/templates/samples/library_index.html
new file mode 100644 (file)
index 0000000..6ee9750
--- /dev/null
@@ -0,0 +1,106 @@
+{% extends "base_site.html" %}
+{% load admin_list i18n %}
+{% load staticfiles %}
+{% block extrahead %}
+    <!-- App Stuff -->
+    <link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}"/>
+
+    {% block additional_javascript %}
+    <script type="text/javascript" src="{% static "js/jquery.min.js" %}"></script>
+    <script type="text/javascript" src="{% static "js/htsw.js" %}"></script>
+    <script type="text/javascript">
+      $(document).ready(function() {
+        $(window).resize(function() {
+           var window_height = $(window).height();
+           var position = $("#changelist table").position();
+           height = window_height - position.top;
+           $("#changelist table.filtered").height(height);
+           $("#changelist-filter").height(height);
+        });
+        $(window).resize();
+      });
+    </script>
+    {% endblock %}
+{% endblock %}
+{% block bodyclass %}change-list{% endblock %}
+{% block coltype %}flex{% endblock %}
+
+{% block content %}
+<div id="library_header_link">
+{% if todo_only %}<a href="..">All</a>{% else %}<a href="not_run/">Not run</a>
+{% endif %}
+</div>
+<div id="library-index-div" >
+  <div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
+    {% block search %}{% search_form cl %}{% endblock %}
+
+    {% block pagination %}{% pagination cl %}{% endblock %}
+
+    {% block filters %}
+    {% if cl.has_filters %}
+    <div id="changelist-filter">
+      <h2 >{% trans 'Filter' %}</h2>
+      {% for spec in cl.filter_specs %}
+         {% admin_list_filter cl spec %}
+         {% endfor %}
+    </div>
+    {% endif %}
+    {% endblock %}
+  {% block summary_stats %}
+  <table class="{% if cl.has_filters %} filtered{% endif %}">
+    <thead >
+      <tr >
+        <td >Parent</td>
+        <td >Library ID</td>
+        <td >Species</td>
+        <td >Library Name</td>
+        <td colspan="3" >Single</td>
+        <td colspan="3" >Paired</td>
+        <td >HD</td>
+      </tr>
+      <tr >
+        <td colspan="4"></td>
+        <td>&lt;40</td>
+        <td>&lt;100</td>
+        <td>100+</td>
+        <td>&lt;40</td>
+        <td>&lt;100</td>
+        <td>100+</td>
+        <td></td>
+      </tr>
+    </thead>
+    <tbody >
+      {% for lib in library_list %}
+      <tr typeof="libns:Library" about="{{lib.library.get_absolute_url}}">
+        <td ><a href="{{lib.library.get_absolute_url}}">{{ lib.amplified_from }}</a></td>
+        <td ><a href="{{lib.library.get_absolute_url}}"><span property="libns:library_id">{{ lib.library_id }}</span></a></td>
+        <td rel="libns:species">
+          <a typeof="libns:Species"
+             href="{{lib.library.library_species.get_absolute_url}}">
+            <span property="libns:species_name">{{ lib.species_name }}</span>
+          </a>
+        </td>
+        <td >
+          <a href="{{ lib.library.get_absolute_url }}">
+            <span property="libns:name">{{ lib.library_name }}</span>
+          </a>
+        </td>
+        <td  bgcolor="#00BFFF">{{ lib.lanes_run.0.0 }}</td>
+        <td  bgcolor="#00BFFF">{{ lib.lanes_run.0.1 }}</td>
+        <td  bgcolor="#00BFFF">{{ lib.lanes_run.0.2 }}</td>
+        <td  bgcolor="#66CDAA">{{ lib.lanes_run.1.0 }}</td>
+        <td  bgcolor="#66CDAA">{{ lib.lanes_run.1.1 }}</td>
+        <td  bgcolor="#66CDAA">{{ lib.lanes_run.1.2 }}</td>
+        {% if lib.is_archived %}
+          <td ><img src="{% static "img/hdd_unmount.png" %}" alt="Archived" /></td>
+        {% else %}
+          <td ></td>
+        {% endif %}
+      </tr>
+      {% endfor %}
+    </tbody>
+  </table>
+  </div>
+  {% endblock %}
+</div>
+{% endblock %}
diff --git a/htsworkflow/templates/samples/species_detail.html b/htsworkflow/templates/samples/species_detail.html
new file mode 100644 (file)
index 0000000..36561c7
--- /dev/null
@@ -0,0 +1,21 @@
+{% extends "base_site.html" %}
+{% load staticfiles %}
+{% load humanize i18n %}
+{% block extrahead %}
+    <!-- App Stuff -->
+    <link type="text/css" rel="stylesheet" href="{% static "css/app.css" %}" />
+    <script type="text/javascript" src="{% static "js/jquery.min.js" %}"></script>
+    
+    {% block additional_javascript %}
+    {% endblock %}
+{% endblock %}
+
+{% block content %}
+<div id="genome_detail">
+  <h2>About this Genome</h2>
+  <b>Common Name</b>: 
+     <span property="libns:species_name">{{ species.common_name}}</span><br/>
+  <b>Scientific Name</b>: 
+     <span property="libns:species_name">{{ species.scientific_name}}</span><br/>
+</div>  
+{% endblock %}
diff --git a/htsworkflow/templates/search_form.html b/htsworkflow/templates/search_form.html
new file mode 100644 (file)
index 0000000..3c66304
--- /dev/null
@@ -0,0 +1,18 @@
+{% load staticfiles %}
+{% load i18n %}
+{% if cl.search_fields %}
+<div id="toolbar"><form id="changelist-search" action="" method="get">
+<div><!-- DIV needed for valid HTML -->
+<label for="searchbar"><img src="{% static "img/admin/icon_searchbox.png" %}" alt="Search" /></label>
+<input type="text" size="40" name="{{ search_var }}" value="{{ cl.query }}" id="searchbar" />
+<input type="submit" value="{% trans 'Go' %}" />
+{% if show_result_count %}
+    <span class="small quiet">{% blocktrans count cl.result_count as counter %}1 result{% plural %}{{ counter }} results{% endblocktrans %} (<a href="?{% if cl.is_popup %}pop=1{% endif %}">{% blocktrans with cl.full_result_count as full_result_count %}{{ full_result_count }} total{% endblocktrans %}</a>)</span>
+{% endif %}
+{% for pair in cl.params.items %}
+    {% ifnotequal pair.0 search_var %}<input type="hidden" name="{{ pair.0 }}" value="{{ pair.1 }}"/>{% endifnotequal %}
+{% endfor %}
+</div>
+</form></div>
+<script type="text/javascript">document.getElementById("searchbar").focus();</script>
+{% endif %}
diff --git a/htsworkflow/urls.py b/htsworkflow/urls.py
new file mode 100644 (file)
index 0000000..1bfbf3d
--- /dev/null
@@ -0,0 +1,31 @@
+from django.conf.urls import include, patterns, url
+from django.contrib import admin
+import django
+admin.autodiscover()
+
+from django.conf import settings
+
+urlpatterns = patterns('',
+    url('^accounts/', include('django.contrib.auth.urls')),
+    # Base:
+    url(r'^eland_config/', include('eland_config.urls')),
+    # Experiments:
+    url(r'^experiments/', include('experiments.urls')),
+    url(r'^lane/(?P<lane_pk>\w+)',
+        'experiments.views.flowcell_lane_detail'),
+    url(r'^flowcell/(?P<flowcell_id>\w+)/((?P<lane_number>\w+)/)?$',
+        'experiments.views.flowcell_detail'),
+    url(r'^inventory/', include('inventory.urls')),
+    url(r'^library/', include('samples.urls')),
+    url(r'^lanes_for/$', 'samples.views.lanes_for'),
+    url(r'^lanes_for/(?P<username>\w+)', 'samples.views.lanes_for'),
+    ### library id to admin url
+    url(r'^library_id_to_admin_url/(?P<lib_id>\w+)/$',
+        'samples.views.library_id_to_admin_url'),
+    ### sample / library information
+    url(r'^samples/', include('samples.urls')),
+    url(r'^sequencer/(?P<sequencer_id>\w+)',
+        'experiments.views.sequencer'),
+
+    url(r'^admin/', include(admin.site.urls)),
+)
index c9383fed050e03dde1f62933ece42afdbab0c20b..895297b5e5bfe3fc0e7eab0db5e77612e2c5eba9 100644 (file)
@@ -154,7 +154,7 @@ def make_description(flowcell_id, lane):
     """
     compute a bedfile name and description from the django database
     """
-    from htsworkflow.frontend.experiments import models as experiments
+    from htsworkflow.experiments import models as experiments
 
     lane = int(lane)
     if lane < 1 or lane > 8:
diff --git a/inventory/__init__.py b/inventory/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/inventory/admin.py b/inventory/admin.py
new file mode 100644 (file)
index 0000000..b418f99
--- /dev/null
@@ -0,0 +1,61 @@
+from __future__ import absolute_import, print_function
+
+from django.contrib import admin
+
+from .models import Item, ItemInfo, ItemType, Vendor, Location, LongTermStorage, ItemStatus, ReagentFlowcell, ReagentLibrary, PrinterTemplate
+
+class ItemAdmin(admin.ModelAdmin):
+    save_as = True
+    save_on_top = True
+    list_display = ('uuid', 'barcode_id','item_type', 'item_info', 'location', 'force_use_uuid', 'creation_date')
+    list_filter = (
+        'item_type', 'status'
+    )
+    search_fields = [
+        'barcode_id',
+        'uuid',
+        'status__name',
+        'item_type__name',
+        'location__name',
+        'notes'
+    ]
+
+class ItemInfoAdmin(admin.ModelAdmin):
+    save_as = True
+    save_on_top = True
+
+class ItemTypeAdmin(admin.ModelAdmin):
+    pass
+
+class VendorAdmin(admin.ModelAdmin):
+    pass
+
+class LocationAdmin(admin.ModelAdmin):
+    pass
+
+class LongTermStorageAdmin(admin.ModelAdmin):
+    pass
+
+class ItemStatusAdmin(admin.ModelAdmin):
+    pass
+
+class ReagentFlowcellAdmin(admin.ModelAdmin):
+    pass
+
+class ReagentLibraryAdmin(admin.ModelAdmin):
+    pass
+
+class PrinterTemplateAdmin(admin.ModelAdmin):
+    list_display = ('item_type', 'printer', 'default')
+
+admin.site.register(Item, ItemAdmin)
+admin.site.register(ItemInfo, ItemInfoAdmin)
+admin.site.register(ItemType, ItemTypeAdmin)
+admin.site.register(Vendor, VendorAdmin)
+admin.site.register(Location, LocationAdmin)
+admin.site.register(LongTermStorage, LongTermStorageAdmin)
+admin.site.register(ItemStatus, ItemStatusAdmin)
+#admin.site.register(ReagentFlowcell, ReagentFlowcellAdmin)
+#admin.site.register(ReagentLibrary, ReagentLibraryAdmin)
+admin.site.register(PrinterTemplate, PrinterTemplateAdmin)
+
diff --git a/inventory/bcmagic.py b/inventory/bcmagic.py
new file mode 100644 (file)
index 0000000..218bc0c
--- /dev/null
@@ -0,0 +1,28 @@
+from __future__ import absolute_import, print_function
+
+from .models import Item
+
+from django.core.exceptions import ObjectDoesNotExist
+
+def item_search(search):
+    """
+    Searches 
+    """
+    hits = []
+    try:
+        item = Item.objects.get(uuid=search)
+    except ObjectDoesNotExist:
+        item = None
+    
+    if item is not None:
+        hits.append((str(item), item.get_absolute_url()))
+    
+    try:
+        item = Item.objects.get(barcode_id=search)
+    except ObjectDoesNotExist:
+        item = None
+    
+    if item is not None:
+        hits.append((str(item), item.get_absolute_url()))
+
+    return hits
diff --git a/inventory/fixtures/initial_data.json b/inventory/fixtures/initial_data.json
new file mode 100644 (file)
index 0000000..028c026
--- /dev/null
@@ -0,0 +1,26 @@
+[
+    {"pk": 1,
+     "model": "inventory.itemtype",
+     "fields": {"name": "Hard Drive"}
+    },
+    {"pk":   2,
+     "model": "inventory.itemtype",
+     "fields": {"name": "Illumina SR Cluster Generation Reagents"}
+    },
+    {"pk":   3,
+     "model": "inventory.itemtype",
+     "fields": {"name": "Illumina Library Creation Reagents"}
+    },
+    {"pk":   4,
+     "model": "inventory.itemtype",
+     "fields": {"name": "Illumina Sequencing Reagents"}
+    },
+    {"pk":   5,
+     "model": "inventory.itemtype",
+     "fields": {"name": "Illumina PE Cluster Generation Reagents"}
+    },
+    {"pk":   6,
+     "model": "inventory.itemtype",
+     "fields": {"name": "Library"}
+    }
+]
diff --git a/inventory/fixtures/test_harddisks.json b/inventory/fixtures/test_harddisks.json
new file mode 100644 (file)
index 0000000..c990260
--- /dev/null
@@ -0,0 +1,436 @@
+[
+ {"pk": 1,
+  "model": "bcmagic.printer",
+  "fields": {"name": "ZM400 1.25x1",
+             "label_height": 1.0,
+             "notes": "Everyday use labels",
+             "label_width": 1.25,
+             "label_shape": "Square",
+             "model": "Zebra ZM400",
+             "ip_address": "131.215.34.116"}},
+ {"pk": 2,
+  "model": "bcmagic.printer",
+  "fields": {"name": "ZM400 3x3",
+             "label_height": 3.0,
+             "notes": "Larger everyday use labels",
+             "label_width": 3.0,
+             "label_shape": "Square",
+             "model": "Zebra ZM400",
+             "ip_address": "131.215.34.117"}},
+  { "model": "experiments.Sequencer",
+    "pk": 7,
+    "fields": {
+      "name": "First sequencer",
+      "instrument_name": "USI-EAS99",
+      "serial_number": "",
+      "model": "Illumina Genome Analyzer I",
+      "active": false,
+      "isdefault": false,
+      "comment": "my first sequencer"
+    }
+  },
+  { "model": "experiments.ClusterStation",
+    "pk": 1,
+    "fields": {
+      "name": "Station",
+      "isdefault": true
+    }
+  },
+  {
+    "pk": 1,
+    "model": "inventory.vendor",
+    "fields": {
+      "url": "http://www.newegg.com/",
+      "name": "newegg.com"
+    }
+  },
+  {
+    "pk": 1,
+    "model": "inventory.location",
+    "fields": {
+      "uuid": "e344a4a2522211de99b00015172ce556",
+      "notes": "",
+      "location_description": "Office 1",
+      "name": "Dev Office"
+    }
+  },
+  {
+    "pk": 1,
+    "model": "inventory.iteminfo",
+    "fields": {
+      "model_id": "WD10EADS-00L5B1",
+      "vendor": 1,
+      "lot_number": "",
+      "url": "http://www.newegg.com/Product/Product.aspx?Item=N82E16822136317&Tpk=WD10EADS",
+      "warranty_months": 24,
+      "notes": "",
+      "part_number": "",
+      "purchase_date": "2009-05-19",
+      "qty_purchased": 17
+    }
+  },
+  {
+    "pk": 1,
+    "model": "inventory.itemtype",
+    "fields": {
+      "name": "Hard Drive",
+      "description": null
+    }
+  },
+  {
+    "pk": 1,
+    "model": "inventory.itemstatus",
+    "fields": {
+      "notes": "",
+      "name": "Used"
+    }
+  },
+  {
+    "pk": 2,
+    "model": "inventory.itemstatus",
+    "fields": {
+      "notes": "",
+      "name": "Unused"
+    }
+  },
+  {
+    "pk": 1,
+    "model": "inventory.item",
+    "fields": {
+      "status": null,
+      "modified_date": "2009-08-10T16:58:44-0800",
+      "uuid": "8a90b6ce522311de99b00015172ce556",
+      "barcode_id": "WCAU49183397",
+      "notes": "",
+      "item_info": 1,
+      "force_use_uuid": false,
+      "item_type": 1,
+      "location": 1,
+      "creation_date": "2009-06-05T15:52:26-0800"
+    }
+  },
+  {
+    "pk": 2,
+    "model": "inventory.item",
+    "fields": {
+      "status": null,
+      "modified_date": "2009-06-16T11:38:24-0800",
+      "uuid": "b0792d425aa411de99b00015172ce556",
+      "barcode_id": "WCAU49042470",
+      "notes": "",
+      "item_info": 1,
+      "force_use_uuid": false,
+      "item_type": 1,
+      "location": 1,
+      "creation_date": "2009-06-16T11:37:04-0800"
+    }
+  },
+  {
+    "pk": 1,
+    "model": "inventory.printertemplate",
+    "fields": {
+      "default": false,
+      "item_type": 1,
+      "printer": 2,
+      "template": "^FX=========================\r\n^FX 3\"x3\" Label\r\n^FX=========================\r\n^XA\r\n\r\n\r\n^FX======== Left Side ===========\r\n\r\n^FX------------\r\n^FX ^LH changes the 0,0 point of all subsequent location references\r\n^FX------------\r\n\r\n^LH0,50\r\n\r\n^FX ---Header---\r\n\r\n^FO25,0\r\n^CF0,50\r\n^FB250,2,,C\r\n^FD{{ item.barcode_id }}^FS\r\n\r\n^FX ---Column 1: Flowcells---\r\n\r\n^FX-----------------\r\n^FX FB command for automatic text formatting:\r\n^FX ^FB[dot width of area], [max # of lines], [change line spacing], [justification: L, C, R, J], [hanging indent]\r\n^FX-----------------\r\n\r\n^CF0,30,30\r\n^FO75,125\r\n^FB275,19,,L\r\n^FD{% for flowcell in flowcell_id_list %}{{ flowcell }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n^FX ---Date---\r\n\r\n^FO0,725\r\n^CF0,35\r\n^FB300,2,,C\r\n^FD{{ oldest_rundate|date:\"YMd\" }} - {{ latest_rundate|date:\"YMd\" }}^FS\r\n\r\n^FX ---Barcode---\r\n\r\n^FO135,795\r\n^BXN,3,200^FDinvb|{{ item.barcode_id }}^FS\r\n\r\n^FX======== Right Side ===========\r\n\r\n^LH300,60\r\n\r\n^FX ---Header---\r\n\r\n^FO0,0\r\n^CF0,50\r\n^FB600,2,,C\r\n^FD{{ barcode_id }}^FS\r\n\r\n^FX ---Dividing line---\r\n\r\n^FX---------------\r\n^FX GB command:\r\n^FX ^GB[box width], [box height], [border thickness], [color: B, W], [corner rounding: 0-8]^FS\r\n^FX---------------\r\n\r\n^FO0,100\r\n^GB0,600,10^FS\r\n\r\n^FX ---Column 2: Libraries 1-20---\r\n\r\n^CF0,30,30\r\n^FO75,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_1_to_20 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Column 3: Libraries 21-40---\r\n\r\n^CF0,30,30\r\n^FO200,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_21_to_40 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Column 4: Libraries 41-60---\r\n\r\n^CF0,30,30\r\n^FO325,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_41_to_60 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Column 5: Libraries 61-80---\r\n\r\n^CF0,30,30\r\n^FO450,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_61_to_80 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Date---\r\n\r\n^FO0,715\r\n^CF0,35\r\n^FB600,2,,C\r\n^FDRun Dates: {{ oldest_rundate|date:\"YMd\" }}-{{ latest_rundate|date:\"YMd\" }}^FS\r\n\r\n^FX ---Barcode---\r\n\r\n^FO255,785\r\n^BXN,3,200^FDinvb|{{ item.barcode_id }}^FS\r\n\r\n^LH0,0\r\n^FX ---End---\r\n^XZ\r\n"
+    }
+  },
+  {
+    "pk": 2,
+    "model": "inventory.printertemplate",
+    "fields": {
+      "default": true,
+      "item_type": 2,
+      "printer": 1,
+      "template": "^FX=========================\r\n^FX Harddrive Location Tracking Label\r\n^FX 300x375 dots\r\n^FX=========================\r\n\r\n^XA\r\n^LH 0,25\r\n\r\n^FO0,0\r\n^CF0,35\r\n^FB375,1,,C\r\n^FD{{ item.item_type.name }}:^FS\r\n\r\n^FX -------Text contains HD serial #-------------\r\n^FO15,75\r\n^CF0,42\r\n^FB325,3,,C\r\n^FD{% if use_uuid %}{{ item.uuid }}{% else %}{{ item.barcode_id }}{% endif %}^FS\r\n\r\n^FX -------Barcode contains HD serial #-----------\r\n^FO150,200\r\n^BXN,3,200\r\n^FD{% if use_uuid %}invu|{{ item.uuid }}{% else %}invb|{{ item.barcode_id }}{% endif %}^FS\r\n\r\n^XZ\r\n"
+    }
+  },
+  {
+    "pk": 3,
+    "model": "inventory.printertemplate",
+    "fields": {
+      "default": false,
+      "item_type": 6,
+      "printer": 1,
+      "template": "^XA\r\n\r\n^FX ---SIDE LABEL---\r\n^LH 190,40\r\n^CF 0,30\r\n\r\n^FX------Sideways ID------\r\n^FO 0,25\r\n^TB R,100,40\r\n^FD{{ library.id }}^FS\r\n^FX------Sideways Line------\r\n^FO 50,0\r\n^GB 5,200,5^FS\r\n\r\n^FX-------Name----------\r\n^FO 65,20\r\n^FB 325,4\r\n^FD{{ library.library_name }}^FS\r\n\r\n^FX ---TOP LABEL---\r\n^LH 12,28\r\n^CF 0,30\r\n\r\n^FX----ID #----\r\n^FO 5,25\r\n^FB 145,1,,C\r\n^FD{{ library.id }}^FS\r\n\r\n^FX----Name----\r\n^CF 0,16\r\n^FO 13,47\r\n^TB N,130,30\r\n^FD{{ library.library_name }}^FS\r\n\r\n^FX--------Barcode--------\r\n^FO 50,80\r\n^BXN ,3,200\r\n^FDl|0000000{{ library.id }}|woldlab^FS\r\n\r\n{% if not library.hidden %}\r\n^FX-----Border-------\r\n^FO 0,0\r\n^GC 150,10\r\n^FX ---End---\r\n{% endif %}\r\n^XZ\r\n"
+    }
+  },
+  {
+    "pk": 1,
+    "model": "inventory.longtermstorage",
+    "fields": {
+      "libraries": [
+        "10001",
+        "10002",
+        "10003"
+      ],
+      "modified_date": "2009-06-01T00:00:00-0800",
+      "storage_devices": [
+        1
+      ],
+      "flowcell": 1,
+      "creation_date": "2009-06-01T00:00:00-0800"
+    }
+  },
+  {
+    "pk": 2,
+    "model": "inventory.longtermstorage",
+    "fields": {
+      "libraries": [
+        "10001",
+        "10002",
+        "10003"
+      ],
+      "modified_date": "2009-06-01T00:00:00-0800",
+      "storage_devices": [
+        1
+      ],
+      "flowcell": 2,
+      "creation_date": "2009-06-01T00:00:00-0800"
+    }
+  },
+ {"pk": 1, "model": "experiments.flowcell",
+  "fields": {
+      "paired_end": true,
+      "run_date": "2009-09-11T22:12:13-0800",
+      "read_length": 75,
+      "notes": "",
+      "advanced_run": false,
+      "control_lane": 2,
+      "flowcell_id": "11ONEAAXX"
+      }
+  },
+  {"pk": 2, "model": "experiments.flowcell",
+  "fields": {
+      "paired_end": false,
+      "run_date": "2010-09-11T22:12:13-0800",
+      "read_length": 75,
+      "notes": "",
+      "advanced_run": false,
+      "control_lane": 2,
+      "flowcell_id": "22TWOAAXX"
+      }
+  },
+  {"pk": 3, "model": "experiments.flowcell",
+  "fields": {
+      "paired_end": false,
+      "run_date": "2010-09-11T22:12:13-0800",
+      "read_length": 75,
+      "notes": "",
+      "advanced_run": false,
+      "control_lane": 2,
+      "flowcell_id": "33THRAAXX (failed)"
+      }
+  },
+  {"pk": "10001", "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 400,
+            "library_name": "10001",
+            "creation_date": "2009-07-21",
+            "cell_line": 1,
+            "library_species": 2,
+            "library_type": null,
+            "made_by": "Igor",
+            "affiliations": [
+                1
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "Done",
+            "tags": [],
+            "made_for": "Test",
+            "amplified_from_sample": null,
+            "notes": "",
+            "undiluted_concentration": "1",
+            "successful_pM": null,
+            "experiment_type": 10,
+            "antibody": null
+        }
+    },
+  {"pk": "10002", "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 400,
+            "library_name": "10002",
+            "creation_date": "2009-07-21",
+            "cell_line": 1,
+            "library_species": 2,
+            "library_type": null,
+            "made_by": "Igor",
+            "affiliations": [
+                1
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "Done",
+            "tags": [],
+            "made_for": "Test",
+            "amplified_from_sample": null,
+            "notes": "",
+            "undiluted_concentration": "1",
+            "successful_pM": null,
+            "experiment_type": 10,
+            "antibody": null
+        }
+    },
+  {"pk": "10003", "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 400,
+            "library_name": "10003",
+            "creation_date": "2009-07-21",
+            "cell_line": 1,
+            "library_species": 2,
+            "library_type": null,
+            "made_by": "Igor",
+            "affiliations": [
+                1
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "Done",
+            "tags": [],
+            "made_for": "Test",
+            "amplified_from_sample": null,
+            "notes": "",
+            "undiluted_concentration": "1",
+            "successful_pM": null,
+            "experiment_type": 10,
+            "antibody": null
+        }
+    },
+  {"pk": 1, "model": "experiments.lane",
+   "fields": {
+       "comment": "10001 lane 1",
+       "library": "10001",
+       "cluster_estimate": 100000,
+       "flowcell": 1,
+       "lane_number": 1,
+       "pM": "8"
+       }
+   },
+  {"pk": 2, "model": "experiments.lane",
+   "fields": {
+       "comment": "10002 lane 2",
+       "library": "10002",
+       "cluster_estimate": 100000,
+       "flowcell": 1,
+       "lane_number": 2,
+       "pM": "8"
+       }
+   },
+  {"pk": 3, "model": "experiments.lane",
+   "fields": {
+       "comment": "10003 lane 3",
+       "library": "10003",
+       "cluster_estimate": 100000,
+       "flowcell": 1,
+       "lane_number": 3,
+       "pM": "8"
+       }
+   },
+  {"pk": 4, "model": "experiments.lane",
+   "fields": {
+       "comment": "10004 lane 4",
+       "library": "10001",
+       "cluster_estimate": 100000,
+       "flowcell": 2,
+       "lane_number": 4,
+       "pM": "8"
+       }
+   },
+  {"pk": 5, "model": "experiments.lane",
+   "fields": {
+       "comment": "10001 lane 1",
+       "library": "10001",
+       "cluster_estimate": 100000,
+       "flowcell": 2,
+       "lane_number": 1,
+       "pM": "8"
+       }
+   },
+  {"pk": 6, "model": "experiments.lane",
+   "fields": {
+       "comment": "10001 lane 1",
+       "library": "10003",
+       "cluster_estimate": 100000,
+       "flowcell": 2,
+       "lane_number": 2,
+       "pM": "8"
+       }
+   },
+  {"pk": 7, "model": "experiments.lane",
+   "fields": {
+       "comment": "10003 lane 8",
+       "library": "10003",
+       "cluster_estimate": 100000,
+       "flowcell": 2,
+       "lane_number": 8,
+       "pM": "8"
+       }
+   },
+  {"pk": 8, "model": "experiments.lane",
+   "fields": {
+       "comment": "10002 lane 8",
+       "library": "10001",
+       "cluster_estimate": 100000,
+       "flowcell": 2,
+       "lane_number": 8,
+       "pM": "8"
+       }
+   },
+  {"pk": 9, "model": "experiments.lane",
+   "fields": {
+       "comment": "10004 lane 4",
+       "library": "10001",
+       "cluster_estimate": 100000,
+       "flowcell": 3,
+       "lane_number": 4,
+       "pM": "8"
+       }
+   },
+  {"pk": 10, "model": "experiments.lane",
+   "fields": {
+       "comment": "10001 lane 1",
+       "library": "10001",
+       "cluster_estimate": 100000,
+       "flowcell": 3,
+       "lane_number": 1,
+       "pM": "8"
+       }
+   },
+  {"pk": 11, "model": "experiments.lane",
+   "fields": {
+       "comment": "10001 lane 1",
+       "library": "10003",
+       "cluster_estimate": 100000,
+       "flowcell": 3,
+       "lane_number": 2,
+       "pM": "8"
+       }
+   },
+  {"pk": 12, "model": "experiments.lane",
+   "fields": {
+       "comment": "10003 lane 8",
+       "library": "10003",
+       "cluster_estimate": 100000,
+       "flowcell": 3,
+       "lane_number": 8,
+       "pM": "8"
+       }
+   },
+  {"pk": 13, "model": "experiments.lane",
+   "fields": {
+       "comment": "10002 lane 8",
+       "library": "10001",
+       "cluster_estimate": 100000,
+       "flowcell": 3,
+       "lane_number": 8,
+       "pM": "8"
+       }
+   }
+]
diff --git a/inventory/fixtures/test_user.json b/inventory/fixtures/test_user.json
new file mode 100644 (file)
index 0000000..2d1a61b
--- /dev/null
@@ -0,0 +1,99 @@
+[
+    {"pk": 5, "model": "auth.user", 
+   "fields": {
+       "username": "test",
+       "first_name": "",
+       "last_name": "",
+       "is_active": true,
+       "is_superuser": false,
+       "is_staff": false,
+       "last_login": "2009-01-01T00:00:01-0800",
+       "groups": [],
+       "user_permissions": [],
+       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
+       "email": "",
+       "date_joined": "2009-01-01T00:01:01-0800"
+       }
+   },
+   {"pk": 5, "model": "samples.htsuser",
+    "fields" : {}
+   },
+   {"pk": 6, "model": "auth.user", 
+   "fields": {
+       "username": "admintest",
+       "first_name": "",
+       "last_name": "",
+       "is_active": true,
+       "is_superuser": false,
+       "is_staff": true,
+       "last_login": "2009-01-01T00:00:01-0800",
+       "groups": [],
+       "user_permissions": [],
+       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
+       "email": "",
+       "date_joined": "2009-01-01T00:01:01-0800"
+       }
+   },
+   {"pk": 6, "model": "samples.htsuser",
+    "fields" : {}
+   },
+   {"pk": 7, "model": "auth.user", 
+   "fields": {
+       "username": "supertest",
+       "first_name": "",
+       "last_name": "",
+       "is_active": true,
+       "is_superuser": true,
+       "is_staff": true,
+       "last_login": "2009-01-01T00:00:01-0800",
+       "groups": [],
+       "user_permissions": [],
+       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
+       "email": "",
+       "date_joined": "2009-01-01T00:01:01-0800"
+       }
+   },
+   {"pk": 7, "model": "samples.htsuser",
+    "fields" : {}
+   },
+   {"pk": 1, "model": "samples.affiliation",
+     "fields": {
+         "users": [5],
+         "contact": "group 1",
+         "name": "affiliation 1",
+         "email": "pk1@example.com"
+         }
+     },
+    {"pk": 2, "model": "samples.affiliation",
+     "fields": {
+         "users": [6],
+         "contact": "group 2",
+         "name": "affiliation 2",
+         "email": "pk2@example.com"
+         }
+     },
+    {"pk": 3, "model": "samples.affiliation",
+     "fields": {
+         "users": [],
+         "contact": "group 3",
+         "name": "affiliation 3",
+         "email": "pk3@example.com"
+         }
+     },
+    {"pk": 4, "model": "samples.affiliation",
+     "fields": {
+         "users": [],
+         "contact": "group 4",
+         "name": "affiliation 4",
+         "email": "pk1@example.com"
+         }
+     },
+    {"pk": 5, "model": "samples.affiliation",
+     "fields": {
+         "users": [],
+         "contact": "group 5",
+         "name": "affiliation 5",
+         "email": "pk5@example.com"
+         }
+     }
+]
diff --git a/inventory/fixtures/woldlab.json b/inventory/fixtures/woldlab.json
new file mode 100644 (file)
index 0000000..35568b5
--- /dev/null
@@ -0,0 +1,13 @@
+[{"pk": 1,
+     "model": "inventory.printertemplate",
+     "fields": {"default": false,
+                "item_type": 1,
+                "printer": 2,
+             "template": "^FX=========================\r\n^FX 3\"x3\" Label\r\n^FX=========================\r\n^XA\r\n\r\n\r\n^FX======== Left Side ===========\r\n\r\n^FX------------\r\n^FX ^LH changes the 0,0 point of all subsequent location references\r\n^FX------------\r\n\r\n^LH0,50\r\n\r\n^FX ---Header---\r\n\r\n^FO25,0\r\n^CF0,50\r\n^FB250,2,,C\r\n^FD{{ item.barcode_id }}^FS\r\n\r\n^FX ---Column 1: Flowcells---\r\n\r\n^FX-----------------\r\n^FX FB command for automatic text formatting:\r\n^FX ^FB[dot width of area], [max # of lines], [change line spacing], [justification: L, C, R, J], [hanging indent]\r\n^FX-----------------\r\n\r\n^CF0,30,30\r\n^FO75,125\r\n^FB275,19,,L\r\n^FD{% for flowcell in flowcell_id_list %}{{ flowcell }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n^FX ---Date---\r\n\r\n^FO0,725\r\n^CF0,35\r\n^FB300,2,,C\r\n^FD{{ oldest_rundate|date:\"YMd\" }} - {{ latest_rundate|date:\"YMd\" }}^FS\r\n\r\n^FX ---Barcode---\r\n\r\n^FO135,795\r\n^BXN,3,200^FDinvb|{{ item.barcode_id }}^FS\r\n\r\n^FX======== Right Side ===========\r\n\r\n^LH300,60\r\n\r\n^FX ---Header---\r\n\r\n^FO0,0\r\n^CF0,50\r\n^FB600,2,,C\r\n^FD{{ barcode_id }}^FS\r\n\r\n^FX ---Dividing line---\r\n\r\n^FX---------------\r\n^FX GB command:\r\n^FX ^GB[box width], [box height], [border thickness], [color: B, W], [corner rounding: 0-8]^FS\r\n^FX---------------\r\n\r\n^FO0,100\r\n^GB0,600,10^FS\r\n\r\n^FX ---Column 2: Libraries 1-20---\r\n\r\n^CF0,30,30\r\n^FO75,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_1_to_20 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Column 3: Libraries 21-40---\r\n\r\n^CF0,30,30\r\n^FO200,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_21_to_40 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Column 4: Libraries 41-60---\r\n\r\n^CF0,30,30\r\n^FO325,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_41_to_60 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Column 5: Libraries 61-80---\r\n\r\n^CF0,30,30\r\n^FO450,100\r\n^FB100,20,,L\r\n^FD{% for lib_id in library_id_list_61_to_80 %}{{ lib_id }}{% if not forloop.last %}\\&{% endif %}{% endfor %}^FS\r\n\r\n^FX ---Date---\r\n\r\n^FO0,715\r\n^CF0,35\r\n^FB600,2,,C\r\n^FDRun Dates: {{ oldest_rundate|date:\"YMd\" }}-{{ latest_rundate|date:\"YMd\" }}^FS\r\n\r\n^FX ---Barcode---\r\n\r\n^FO255,785\r\n^BXN,3,200^FDinvb|{{ item.barcode_id }}^FS\r\n\r\n^LH0,0\r\n^FX ---End---\r\n^XZ\r\n"}},
+ {"pk": 2,
+  "model": "inventory.printertemplate",
+  "fields": {"default": true,
+             "item_type": 2,
+             "printer": 1,
+             "template": "^FX=========================\r\n^FX Harddrive Location Tracking Label\r\n^FX 300x375 dots\r\n^FX=========================\r\n\r\n^XA\r\n^LH 0,25\r\n\r\n^FO0,0\r\n^CF0,35\r\n^FB375,1,,C\r\n^FD{{ item.item_type.name }}:^FS\r\n\r\n^FX -------Text contains HD serial #-------------\r\n^FO15,75\r\n^CF0,42\r\n^FB325,3,,C\r\n^FD{% if use_uuid %}{{ item.uuid }}{% else %}{{ item.barcode_id }}{% endif %}^FS\r\n\r\n^FX -------Barcode contains HD serial #-----------\r\n^FO150,200\r\n^BXN,3,200\r\n^FD{% if use_uuid %}invu|{{ item.uuid }}{% else %}invb|{{ item.barcode_id }}{% endif %}^FS\r\n\r\n^XZ\r\n"}}
+]
diff --git a/inventory/models.py b/inventory/models.py
new file mode 100644 (file)
index 0000000..7534c8a
--- /dev/null
@@ -0,0 +1,221 @@
+from __future__ import absolute_import, print_function
+
+import logging
+
+from django.db import models
+from django.db.models.signals import pre_save
+
+from samples.models import Library
+from experiments.models import FlowCell
+from bcmagic.models import Printer
+
+LOGGER = logging.getLogger(__name__)
+
+try:
+    import uuid
+except ImportError, e:
+    # Some systems are using python 2.4, which doesn't have uuid
+    # this is a stub
+    LOGGER.warning('Real uuid is not available, initializing fake uuid module')
+    class uuid:
+        def uuid1(self):
+            self.hex = None
+            return self
+
+def _assign_uuid(sender, instance, **kwargs):
+    """
+    Assigns a UUID to model on save
+    """
+    #print 'Entered _assign_uuid'
+    if instance.uuid is None or len(instance.uuid) != 32:
+        instance.uuid = uuid.uuid1().hex
+
+def _switch_default(sender, instance, **kwargs):
+    """
+    When new instance has default == True, uncheck all other defaults
+    """
+    if instance.default:
+        other_defaults = PrinterTemplate.objects.filter(default=True)
+
+        for other in other_defaults:
+            other.default = False
+            other.save()
+
+
+class Vendor(models.Model):
+    name = models.CharField(max_length=256)
+    url = models.URLField(blank=True, null=True)
+
+    def __unicode__(self):
+        return u"%s" % (self.name)
+
+
+class Location(models.Model):
+
+    name = models.CharField(max_length=256, unique=True)
+    location_description = models.TextField()
+
+    uuid = models.CharField(max_length=32, blank=True, help_text="Leave blank for automatic UUID generation", editable=False)
+
+    notes = models.TextField(blank=True, null=True)
+
+    def __unicode__(self):
+        if len(self.location_description) > 16:
+            return u"%s: %s" % (self.name, self.location_description[0:16]+u"...")
+        else:
+            return u"%s: %s" % (self.name, self.location_description)
+
+pre_save.connect(_assign_uuid, sender=Location)
+
+
+class ItemInfo(models.Model):
+    model_id = models.CharField(max_length=256, blank=True, null=True)
+    part_number = models.CharField(max_length=256, blank=True, null=True)
+    lot_number = models.CharField(max_length=256, blank=True, null=True)
+
+    url = models.URLField(blank=True, null=True)
+
+    qty_purchased = models.IntegerField(default=1)
+
+    vendor = models.ForeignKey(Vendor)
+    purchase_date = models.DateField(blank=True, null=True)
+    warranty_months = models.IntegerField(blank=True, null=True)
+
+    notes = models.TextField(blank=True, null=True)
+
+    def __unicode__(self):
+        name = u''
+        if self.model_id:
+            name += u"model:%s " % (self.model_id)
+        if self.part_number:
+            name += u"part:%s " % (self.part_number)
+        if self.lot_number:
+            name += u"lot:%s " % (self.lot_number)
+
+        return u"%s: %s" % (name, self.purchase_date)
+
+    class Meta:
+        verbose_name_plural = "Item Info"
+
+
+class ItemType(models.Model):
+
+    name = models.CharField(max_length=64, unique=True)
+    description = models.TextField(blank=True, null=True)
+
+    def __unicode__(self):
+        return u"%s" % (self.name)
+
+class ItemStatus(models.Model):
+    name = models.CharField(max_length=64, unique=True)
+    notes = models.TextField(blank=True, null=True)
+
+    def __unicode__(self):
+        return self.name
+
+    class Meta:
+        verbose_name_plural = "Item Status"
+
+
+class Item(models.Model):
+
+    item_type = models.ForeignKey(ItemType)
+
+    #Automatically assigned uuid; used for barcode if one is not provided in
+    # barcode_id
+    uuid = models.CharField(max_length=32, blank=True, help_text="Leave blank for automatic UUID generation", unique=True, editable=False)
+
+    # field for existing barcodes; used instead of uuid if provided
+    barcode_id = models.CharField(max_length=256, blank=True, null=True)
+    force_use_uuid = models.BooleanField(default=False)
+
+    item_info = models.ForeignKey(ItemInfo)
+
+    location = models.ForeignKey(Location)
+
+    status = models.ForeignKey(ItemStatus, blank=True, null=True)
+
+    creation_date = models.DateTimeField(auto_now_add=True)
+    modified_date = models.DateTimeField(auto_now=True)
+
+    notes = models.TextField(blank=True, null=True)
+
+    def __unicode__(self):
+        if self.barcode_id is None or len(self.barcode_id) == 0:
+            return u"invu|%s" % (self.uuid)
+        else:
+            return u"invb|%s" % (self.barcode_id)
+
+    def get_absolute_url(self):
+        return '/inventory/%s/' % (self.uuid)
+
+pre_save.connect(_assign_uuid, sender=Item)
+
+
+class PrinterTemplate(models.Model):
+    """
+    Maps templates to printer to use
+    """
+    item_type = models.ForeignKey(ItemType)
+    printer = models.ForeignKey(Printer)
+
+    default = models.BooleanField(default=False)
+
+    template = models.TextField()
+
+    def __unicode__(self):
+        if self.default:
+            return u'%s %s' % (self.item_type.name, self.printer.name)
+        else:
+            return u'%s %s (default)' % (self.item_type.name, self.printer.name)
+
+pre_save.connect(_switch_default, sender=PrinterTemplate)
+
+
+class LongTermStorage(models.Model):
+
+    flowcell = models.ForeignKey(FlowCell)
+    libraries = models.ManyToManyField(Library)
+
+    storage_devices = models.ManyToManyField(Item)
+
+    creation_date = models.DateTimeField(auto_now_add=True)
+    modified_date = models.DateTimeField(auto_now=True)
+
+    def __unicode__(self):
+        return u"%s: %s" % (str(self.flowcell), ', '.join([ str(s) for s in self.storage_devices.iterator() ]))
+
+    class Meta:
+        verbose_name_plural = "Long Term Storage"
+
+
+
+class ReagentBase(models.Model):
+
+    reagent = models.ManyToManyField(Item)
+
+    creation_date = models.DateTimeField(auto_now_add=True)
+    modified_date = models.DateTimeField(auto_now=True)
+
+    class Meta:
+        abstract = True
+
+
+class ReagentFlowcell(ReagentBase):
+    """
+    Links reagents and flowcells
+    """
+    flowcell = models.ForeignKey(FlowCell)
+
+    def __unicode__(self):
+        return u"%s: %s" % (str(self.flowcell), ', '.join([ str(s) for s in self.reagent.iterator() ]))
+
+
+class ReagentLibrary(ReagentBase):
+    """
+    Links libraries and flowcells
+    """
+    library = models.ForeignKey(Library)
+
+    def __unicode__(self):
+        return u"%s: %s" % (str(self.library), ', '.join([ str(s) for s in self.reagent.iterator() ]))
diff --git a/inventory/test_inventory.py b/inventory/test_inventory.py
new file mode 100644 (file)
index 0000000..59abcfd
--- /dev/null
@@ -0,0 +1,126 @@
+from __future__ import absolute_import, print_function
+
+import RDF
+
+from django.test import TestCase
+from django.test.utils import setup_test_environment, \
+     teardown_test_environment
+from django.db import connection
+from django.conf import settings
+
+from django.contrib.auth.models import User
+from django.core import urlresolvers
+
+from .models import Item, Vendor
+from htsworkflow.util.rdfhelp import get_model, load_string_into_model, get_serializer, inventoryOntology, libraryOntology, fromTypedNode
+
+def localhostNode(url):
+    return RDF.Node(RDF.Uri('http://localhost%s' % (url,)))
+
+class InventoryTestCase(TestCase):
+    fixtures = ['initial_data', 'test_user', 'test_harddisks']
+
+    def test_fixture(self):
+        # make sure that some of our test data is was loaded
+        # since there was no error message when I typoed the test fixture
+        hd1 = Item.objects.get(pk=1)
+        self.failUnlessEqual(hd1.uuid, '8a90b6ce522311de99b00015172ce556')
+
+        user = User.objects.get(pk=5)
+        self.failUnlessEqual(user.username, 'test')
+
+    def test_item(self):
+        url = '/inventory/8a90b6ce522311de99b00015172ce556/'
+        self.client.login(username='test', password='BJOKL5kAj6aFZ6A5')
+        response = self.client.get(url)
+        self.failUnlessEqual(response.status_code, 200)
+
+        model = get_model()
+        load_string_into_model(model, 'rdfa', response.content, url)
+
+        itemNode = RDF.Node(RDF.Uri(url))
+        item_type = fromTypedNode(model.get_target(itemNode, inventoryOntology['item_type']))
+        self.failUnlessEqual(item_type, u'Hard Drive')
+
+    def test_itemindex(self):
+        url = '/inventory/it/Hard Drive/'
+        indexNode = localhostNode(url)
+        diskNode = localhostNode('/inventory/8a90b6ce522311de99b00015172ce556/')
+        self.client.login(username='test', password='BJOKL5kAj6aFZ6A5')
+
+        flowcells = self.get_flowcells_from_content(url, indexNode, diskNode)
+        self.failUnlessEqual(len(flowcells), 2)
+        self.failUnless('http://localhost/flowcell/11ONEAAXX/' in flowcells)
+        self.failUnless('http://localhost/flowcell/22TWOAAXX/' in flowcells)
+
+    def test_add_disk(self):
+        url = '/inventory/it/Hard Drive/'
+        #url_disk = '/inventory/8a90b6ce522311de99b00015172ce556/'
+        url_disk = '/inventory/b0792d425aa411de99b00015172ce556/'
+        indexNode = localhostNode(url)
+        diskNode = localhostNode(url_disk)
+        self.client.login(username='test', password='BJOKL5kAj6aFZ6A5')
+
+        flowcells = self.get_flowcells_from_content(url, indexNode, diskNode)
+        self.failUnlessEqual(len(flowcells), 0)
+
+        # step two link the flowcell
+        flowcell = '22TWOAAXX'
+        serial = 'WCAU49042470'
+        link_url = urlresolvers.reverse(
+                'inventory.views.link_flowcell_and_device',
+                args=(flowcell, serial))
+        link_response = self.client.get(link_url)
+        self.failUnlessEqual(link_response.status_code, 200)
+
+        flowcells = self.get_flowcells_from_content(url, indexNode, diskNode)
+        self.failUnlessEqual(len(flowcells), 1)
+        self.failUnlessEqual('http://localhost/flowcell/%s/' % (flowcell),
+                             flowcells[0])
+
+    def test_add_disk_failed_flowcell(self):
+        url = '/inventory/it/Hard Drive/'
+        #url_disk = '/inventory/8a90b6ce522311de99b00015172ce556/'
+        url_disk = '/inventory/b0792d425aa411de99b00015172ce556/'
+        indexNode = localhostNode(url)
+        diskNode = localhostNode(url_disk)
+        self.client.login(username='test', password='BJOKL5kAj6aFZ6A5')
+
+        flowcells = self.get_flowcells_from_content(url, indexNode, diskNode)
+        self.failUnlessEqual(len(flowcells), 0)
+
+        # step two link the flowcell
+        flowcell = '33THRAAXX'
+        serial = 'WCAU49042470'
+        link_url = urlresolvers.reverse(
+                'inventory.views.link_flowcell_and_device',
+                args=(flowcell, serial))
+        link_response = self.client.get(link_url)
+        self.failUnlessEqual(link_response.status_code, 200)
+
+        flowcells = self.get_flowcells_from_content(url, indexNode, diskNode)
+        self.failUnlessEqual(len(flowcells), 1)
+        self.failUnlessEqual('http://localhost/flowcell/%s/' % (flowcell),
+                             flowcells[0])
+
+
+    def get_flowcells_from_content(self, url, rootNode, diskNode):
+        model = get_model()
+
+        response = self.client.get(url)
+        self.failUnlessEqual(response.status_code, 200)
+
+        load_string_into_model(model, 'rdfa', response.content, rootNode.uri)
+        targets = model.get_targets(diskNode, libraryOntology['flowcell_id'])
+        flowcells = [ str(x.uri) for x in targets]
+        return flowcells
+
+def suite():
+    from unittest import TestSuite, defaultTestLoader
+    suite = TestSuite()
+    suite.addTests(defaultTestLoader.loadTestsFromTestCase(InventoryTestCase))
+    return suite
+
+if __name__ == "__main__":
+    from unittest import main
+    main(defaultTest="suite")
diff --git a/inventory/urls.py b/inventory/urls.py
new file mode 100644 (file)
index 0000000..ff71a6b
--- /dev/null
@@ -0,0 +1,16 @@
+from django.conf.urls import patterns
+
+urlpatterns = patterns('',
+    # DATA
+     (r'^data/items/$', 'inventory.views.data_items'),
+    # REMOTE LINKING
+     (r'^lts/link/(?P<flowcell>.+)/(?P<serial>.+)/$', 'inventory.views.link_flowcell_and_device'),
+
+    # INDEX
+    (r'^it/(?P<name>.+)/$', 'inventory.views.itemtype_index'),
+    (r'^(?P<uuid>[a-fA-F0-9]{32})/$', 'inventory.views.item_summary_by_uuid'),
+    (r'^(?P<uuid>[a-fA-F0-9]{32})/print/$', 'inventory.views.item_print'),
+    (r'^(?P<barcode_id>.+)/$', 'inventory.views.item_summary_by_barcode'),
+    (r'^all_index/$', 'inventory.views.all_index'),
+    (r'^$', 'inventory.views.index')
+    )
diff --git a/inventory/views.py b/inventory/views.py
new file mode 100644 (file)
index 0000000..05f300a
--- /dev/null
@@ -0,0 +1,377 @@
+from __future__ import absolute_import, print_function
+
+from django.conf import settings
+from django.contrib.auth.decorators import login_required
+from django.core.exceptions import ObjectDoesNotExist
+from django.http import HttpResponse, HttpResponseRedirect
+from django.shortcuts import render_to_response
+from django.template import RequestContext, Template
+from django.template.loader import get_template
+
+from samples.changelist import HTSChangeList
+from .models import Item, LongTermStorage, ItemType
+from .admin import ItemAdmin, ItemTypeAdmin
+from .bcmagic import item_search
+from experiments.models import FlowCell
+from bcmagic.plugin import register_search_plugin
+from bcmagic.forms import BarcodeMagicForm
+from bcmagic.utils import print_zpl_socket
+
+register_search_plugin('Inventory Item', item_search)
+
+try:
+    import json
+except ImportError, e:
+    import simplejson as json
+
+INVENTORY_CONTEXT_DEFAULTS = {
+    'app_name': 'Inventory Tracker',
+    'bcmagic': BarcodeMagicForm()
+}
+
+def __flowcell_rundate_sort(x, y):
+    """
+    Sort by rundate
+    """
+    if x.run_date > y.run_date:
+        return 1
+    elif x.run_date == y.run_date:
+        return 0
+    else:
+        return -1
+
+def __expand_longtermstorage_context(context, item):
+    """
+    Expand information for LongTermStorage
+    """
+    flowcell_list = []
+    flowcell_id_list = []
+    library_id_list = []
+
+    for lts in item.longtermstorage_set.all():
+        flowcell_list.append(lts.flowcell)
+        flowcell_id_list.append(lts.flowcell.flowcell_id)
+        library_id_list.extend([ lib.id for lib in lts.libraries.all() ])
+
+    flowcell_list.sort(__flowcell_rundate_sort)
+    context['oldest_rundate'] = flowcell_list[0].run_date
+    context['latest_rundate'] = flowcell_list[-1].run_date
+
+    context['flowcell_id_list'] = flowcell_id_list
+    context['library_id_list_1_to_20'] = library_id_list[0:20]
+    context['library_id_list_21_to_40'] = library_id_list[20:40]
+    context['library_id_list_41_to_60'] = library_id_list[40:60]
+    context['library_id_list_61_to_80'] = library_id_list[60:80]
+
+
+EXPAND_CONTEXT = {
+    'Hard Drive': __expand_longtermstorage_context
+}
+
+#INVENTORY_ITEM_PRINT_DEFAULTS = {
+#    'Hard Drive': 'inventory/hard_drive_shell.zpl',
+#    'default': 'inventory/default.zpl',
+#    'host': settings.BCPRINTER_PRINTER1_HOST
+#}
+
+def getPrinterTemplateByType(item_type):
+    """
+    returns template to use given item_type
+    """
+    assert item_type.printertemplate_set.count() < 2
+
+    # Get the template for item_type
+    if item_type.printertemplate_set.count() > 0:
+        printer_template = item_type.printertemplate_set.all()[0]
+        return printer_template
+    # Get default
+    else:
+        try:
+            printer_template = PrinterTemplate.objects.get(default=True)
+        except ObjectDoesNotExist:
+            msg = "No template for item type (%s) and no default template found" % (item_type.name)
+            raise ValueError, msg
+
+        return printer_template
+
+
+@login_required
+def data_items(request):
+    """
+    Returns items in json format
+    """
+    item_list = Item.objects.all()
+    d = { 'results': len(item_list) }
+    rows = []
+
+    for item in item_list:
+        item_d = {}
+        item_d['uuid'] = item.uuid
+        item_d['barcode_id'] = item.barcode_id
+        item_d['model_id'] = item.item_info.model_id
+        item_d['part_number'] = item.item_info.part_number
+        item_d['lot_number'] = item.item_info.lot_number
+        item_d['vendor'] = item.item_info.vendor.name
+        item_d['creation_date'] = item.creation_date.strftime('%Y-%m-%d %H:%M:%S')
+        item_d['modified_date'] = item.modified_date.strftime('%Y-%m-%d %H:%M:%S')
+        item_d['location'] = item.location.name
+
+        # Item status if exists
+        if item.status is None:
+            item_d['status'] = ''
+        else:
+            item_d['status'] = item.status.name
+
+        # Stored flowcells on device
+        if item.longtermstorage_set.count() > 0:
+            item_d['flowcells'] = ','.join([ lts.flowcell.flowcell_id for lts in item.longtermstorage_set.all() ])
+        else:
+            item_d['flowcells'] = ''
+
+        item_d['type'] = item.item_type.name
+        rows.append(item_d)
+
+    d['rows'] = rows
+
+    return HttpResponse(json.dumps(d), content_type="application/javascript")
+
+@login_required
+def all_index(request):
+    """
+    Inventory Index View
+    """
+    # build changelist
+    item_changelist = HTSChangeList(request, Item,
+        list_filter=[],
+        search_fields=[],
+        list_per_page=200,
+        model_admin=ItemAdmin(Item, None)
+    )
+
+    context_dict = {
+        'item_changelist': item_changelist,
+        'page_name': 'Inventory Index'
+    }
+    context_dict.update(INVENTORY_CONTEXT_DEFAULTS)
+
+    return render_to_response('inventory/inventory_all_index.html',
+                              context_dict,
+                              context_instance=RequestContext(request))
+
+@login_required
+def index(request):
+    """
+    Inventory Index View
+    """
+    # build changelist
+    item_changelist = HTSChangeList(request, ItemType,
+        list_filter=[],
+        search_fields=['name', 'description'],
+        list_per_page=50,
+        model_admin=ItemTypeAdmin(ItemType, None)
+    )
+
+    context_dict = {
+        'item_changelist': item_changelist,
+        'page_name': 'Inventory Index'
+    }
+    context_dict.update(INVENTORY_CONTEXT_DEFAULTS)
+    return render_to_response('inventory/inventory_index.html',
+                              context_dict,
+                              context_instance=RequestContext(request))
+
+@login_required
+def itemtype_index(request, name):
+    """
+    Inventory Index View
+    """
+
+    name = name.replace('%20', ' ')
+
+    itemtype = ItemType.objects.get(name=name)
+
+    # build changelist
+    item_changelist = HTSChangeList(request, Item,
+        list_filter=[],
+        search_fields=[],
+        list_per_page=200,
+        model_admin=ItemAdmin(Item, None)
+    )
+
+    context_dict = {
+        'item_changelist': item_changelist,
+        'page_name': 'Inventory Index'
+    }
+    context_dict.update(INVENTORY_CONTEXT_DEFAULTS)
+
+    return render_to_response('inventory/inventory_itemtype_index.html',
+                              context_dict,
+                              context_instance=RequestContext(request))
+
+
+@login_required
+def item_summary_by_barcode(request, barcode_id, msg=''):
+    """
+    Display a summary for an item by barcode
+    """
+    try:
+        item = Item.objects.get(barcode_id=barcode_id)
+    except ObjectDoesNotExist, e:
+        item = None
+
+    return item_summary_by_uuid(request, None, msg, item)
+
+
+@login_required
+def item_summary_by_uuid(request, uuid, msg='', item=None):
+    """
+    Display a summary for an item
+    """
+    # Use item instead of looking it up if it is passed.
+    if item is None:
+        try:
+            item = Item.objects.get(uuid=uuid)
+        except ObjectDoesNotExist, e:
+            item = None
+
+    context_dict = {
+        'page_name': 'Item Summary',
+        'item': item,
+        'uuid': uuid,
+        'msg': msg
+    }
+    context_dict.update(INVENTORY_CONTEXT_DEFAULTS)
+
+    return render_to_response('inventory/inventory_summary.html',
+                              context_dict,
+                              context_instance=RequestContext(request))
+
+
+
+
+
+
+def __expand_context(context, item):
+    """
+    If EXPAND_CONTEXT dictionary has item.item_type.name function registered, use it to expand context
+    """
+    if item.item_type.name in EXPAND_CONTEXT:
+        expand_func = EXPAND_CONTEXT[item.item_type.name]
+        expand_func(context, item)
+
+def _item_print(item, request):
+    """
+    Prints an item given a type of item label to print
+    """
+    #FIXME: Hard coding this for now... need to abstract later.
+    context = {'item': item}
+    __expand_context(context, item)
+
+    # Print using barcode_id
+    if not item.force_use_uuid and (item.barcode_id is None or len(item.barcode_id.strip())):
+        context['use_uuid'] = False
+        msg = 'Printing item with barcode id: %s' % (item.barcode_id)
+    # Print using uuid
+    else:
+        context['use_uuid'] = True
+        msg = 'Printing item with UUID: %s' % (item.uuid)
+
+    printer_template = getPrinterTemplateByType(item.item_type)
+
+    c = RequestContext(request, context)
+    t = Template(printer_template.template)
+    print_zpl_socket(t.render(c), host=printer_template.printer.ip_address)
+
+    return msg
+
+@login_required
+def item_print(request, uuid):
+    """
+    Print a label for a given item
+    """
+    try:
+        item = Item.objects.get(uuid=uuid)
+    except ObjectDoesNotExist, e:
+        item = None
+        msg = "Item with UUID %s does not exist" % (uuid)
+
+    if item is not None:
+        msg = _item_print(item, request)
+
+    return item_summary_by_uuid(request, uuid, msg)
+
+
+def link_flowcell_and_device(request, flowcell, serial):
+    """
+    Updates database records of a flowcell being archived on a device with a particular serial #
+    """
+    assert flowcell is not None
+    assert serial is not None
+
+    LTS_UPDATED = False
+    SD_UPDATED = False
+    LIBRARY_UPDATED = False
+
+    ###########################################
+    # Retrieve Storage Device
+    try:
+        sd = Item.objects.get(barcode_id=serial)
+    except ObjectDoesNotExist, e:
+        msg = "Item with barcode_id of %s not found." % (serial)
+        raise ObjectDoesNotExist(msg)
+
+    ###########################################
+    # Retrieve FlowCell
+    try:
+        fc = FlowCell.objects.get(flowcell_id__startswith=flowcell)
+    except ObjectDoesNotExist, e:
+        msg = "FlowCell with flowcell_id of %s not found." % (flowcell)
+        raise ObjectDoesNotExist(msg)
+
+    ###########################################
+    # Retrieve or create LongTermStorage Object
+    count = fc.longtermstorage_set.count()
+    lts = None
+    if count > 1:
+        msg = "There really should only be one longtermstorage object per flowcell"
+        raise ValueError, msg
+    elif count == 1:
+        # lts already attached to flowcell
+        lts = fc.longtermstorage_set.all()[0]
+    else:
+        lts = LongTermStorage()
+        # Attach flowcell
+        lts.flowcell = fc
+        # Need a primary keey before linking to storage devices
+        lts.save()
+        LTS_UPDATED = True
+
+
+    ############################################
+    # Link Storage to Flowcell
+
+    # Add a link to this storage device if it is not already linked.
+    if sd not in lts.storage_devices.all():
+        lts.storage_devices.add(sd)
+        SD_UPDATED = True
+
+    ###########################################
+    # Add Library Links to LTS
+
+    for lane in fc.lane_set.all():
+        if lane.library not in lts.libraries.all():
+            lts.libraries.add(lane.library)
+            LIBRARY_UPDATED = True
+
+    # Save Changes
+    lts.save()
+
+    msg = ['Success:']
+    if LTS_UPDATED or SD_UPDATED or LIBRARY_UPDATED:
+        msg.append('  LongTermStorage (LTS) Created: %s' % (LTS_UPDATED))
+        msg.append('   Storage Device Linked to LTS: %s' % (SD_UPDATED))
+        msg.append('       Libraries updated in LTS: %s' % (LIBRARY_UPDATED))
+    else:
+        msg.append('  No Updates Needed.')
+
+    return HttpResponse('\n'.join(msg))
diff --git a/labels/__init__.py b/labels/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/labels/admin.py b/labels/admin.py
new file mode 100644 (file)
index 0000000..ba37739
--- /dev/null
@@ -0,0 +1,67 @@
+from django.template import Context, Template
+from django.contrib import admin
+
+from .models import LabelContent, LabelTemplate, LabelPrinter
+from inventory.models import PrinterTemplate
+from bcmagic.utils import print_zpl_socket
+
+class LabelContentOptions(admin.ModelAdmin):
+    save_as = True
+    save_on_top = True
+    search_fields = (
+        'title',
+        'subtitle',
+        'text',
+        'barcode',
+        'creator',
+    )
+    list_display = ('title','subtitle','text','barcode','template','creator')
+    list_filter = ('template','creator',)
+    fieldsets = (
+      (None, {
+          'fields': (('title','subtitle','text','barcode'),
+                     ('template','creator'))
+
+      }),
+    )
+    actions = ['action_print_labels']
+    
+    def action_print_labels(self, request, queryset):
+        """
+        Django action which prints labels for the selected set of labels from the
+        Django Admin interface.
+        """
+       
+        zpl_list = []
+        #Iterate over selected labels to print
+        for label in queryset.all():
+
+          template_used = LabelTemplate.objects.get(name=label.template.name)
+          # ZPL Template
+          t = Template(template_used.ZPL_code)
+
+          # Django Template Context
+          c = Context({'label': label})
+            
+          # Send rendered template to the printer that the template
+          #  object has been attached to in the database.
+          zpl_list.append(t.render(c))
+        
+        print_zpl_socket(zpl_list, host=template_used.printer.ip_address)
+    
+        self.message_user(request, "%s labels printed." % (len(queryset)))
+                          
+    action_print_labels.short_description = "Print Selected Labels"
+
+class LabelTemplateOptions(admin.ModelAdmin):
+    save_as = True
+    save_on_top = True
+    list_display = ('name', 'printer', 'ZPL_code')
+
+class LabelPrinterOptions(admin.ModelAdmin):
+    list_display = ('name', 'ip_address', 'labels')
+
+admin.site.register(LabelContent, LabelContentOptions)
+admin.site.register(LabelTemplate, LabelTemplateOptions)
+admin.site.register(LabelPrinter, LabelPrinterOptions)
+
diff --git a/labels/models.py b/labels/models.py
new file mode 100644 (file)
index 0000000..8794492
--- /dev/null
@@ -0,0 +1,35 @@
+from django.db import models
+
+class LabelPrinter(models.Model):
+    """
+    Barcode Printer Information
+    """
+    name = models.CharField(max_length=256)
+    model = models.CharField(max_length=64, default='ZM400')
+    ip_address = models.IPAddressField()
+    labels = models.CharField(max_length=200)
+    notes = models.TextField(null=True, blank=True)
+
+    def __unicode__(self):
+        return u'%s: %s' % (self.name, self.labels)
+
+class LabelTemplate(models.Model):
+    """
+    Maps templates to printer to use
+    """
+    name = models.CharField(max_length=200)
+    description = models.TextField(null=True, blank=True)
+    printer = models.ForeignKey(LabelPrinter)
+    
+    ZPL_code = models.TextField('template')
+    
+    def __unicode__(self):
+            return '%s %s' % (self.name, self.printer.name)
+
+class LabelContent(models.Model):
+    title = models.CharField(max_length=200, null=True, blank=True)
+    subtitle = models.CharField(max_length=200, null=True, blank=True)
+    text = models.CharField(max_length=200, null=True, blank=True)
+    barcode = models.CharField(max_length=200, null=True, blank=True)
+    template = models.ForeignKey(LabelTemplate)
+    creator = models.CharField(max_length=200)
diff --git a/labels/test_labels.py b/labels/test_labels.py
new file mode 100644 (file)
index 0000000..ca3633b
--- /dev/null
@@ -0,0 +1,32 @@
+"""
+This file demonstrates two different styles of tests (one doctest and one
+unittest). These will both pass when you run "manage.py test".
+
+Replace these with more appropriate tests for your application.
+"""
+
+from django.test import TestCase
+
+class SimpleTest(TestCase):
+    def test_basic_addition(self):
+        """
+        Tests that 1 + 1 always equals 2.
+        """
+        self.failUnlessEqual(1 + 1, 2)
+
+__test__ = {"doctest": """
+Another way to test that 1 + 1 is equal to 2.
+
+>>> 1 + 1 == 2
+True
+"""}
+
+def suite():
+    from unittest import TestSuite, defaultTestLoader
+    suite = TestSuite()
+    suite.addTests(defaultTestLoader.loadTestsFromTestCase(SimpleTest))
+    return suite
+
+if __name__ == "__main__":
+    from unittest import main
+    main(defaultTest="suite")
diff --git a/labels/views.py b/labels/views.py
new file mode 100644 (file)
index 0000000..60f00ef
--- /dev/null
@@ -0,0 +1 @@
+# Create your views here.
diff --git a/samples/__init__.py b/samples/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/samples/admin.py b/samples/admin.py
new file mode 100644 (file)
index 0000000..5b9b858
--- /dev/null
@@ -0,0 +1,252 @@
+from __future__ import absolute_import, print_function
+
+from django.contrib import admin
+from django.contrib.admin import widgets
+from django.contrib.auth.models import User
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.auth.forms import UserCreationForm, UserChangeForm
+from django.template import Context, Template
+from django.db import models
+from django.utils.translation import ugettext_lazy as _
+from django.forms import TextInput, Textarea
+
+from .models import \
+     Antibody, Cellline, Condition, ExperimentType, HTSUser, \
+     LibraryType, MultiplexIndex, Species, Affiliation, Library, Tag
+from experiments.models import Lane
+from inventory.models import PrinterTemplate
+from bcmagic.utils import print_zpl_socket
+
+# Let's disable those pesky delete everything by accident features.
+admin.site.disable_action('delete_selected')
+
+class AffiliationOptions(admin.ModelAdmin):
+    list_display = ('name','contact','email')
+    fieldsets = (
+      (None, {
+          'fields': (('name','contact','email','users'))
+      }),
+    )
+
+    # some post 1.0.2 version of django has formfield_overrides
+    # which would replace this code with:
+    # formfield_overrids = {
+    #   models.ManyToMany: { 'widget': widgets.FilteredSelectMultiple }
+    # }
+    def formfield_for_dbfield(self, db_field, **kwargs):
+      if db_field.name == 'users':
+        kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))
+      rv = super(AffiliationOptions, self).formfield_for_dbfield(db_field, **kwargs)
+    #  print db_field.name, kwargs
+      return rv
+
+class AntibodyOptions(admin.ModelAdmin):
+    search_fields = ('antigene','nickname','catalog','antibodies','source','biology','notes')
+    list_display = ('antigene','nickname','antibodies','catalog','source','biology','notes')
+    list_filter = ('antibodies','source')
+    fieldsets = (
+      (None, {
+          'fields': (('antigene','nickname','antibodies'),('catalog','source'),('biology'),('notes'))
+      }),
+     )
+
+class CelllineOptions(admin.ModelAdmin):
+    list_display = ('cellline_name', 'notes')
+    search_fields = ('cellline_name', 'nickname', 'notes')
+    fieldsets = (
+      (None, {
+          'fields': (('cellline_name','nickname',),('notes'),)
+      }),
+     )
+
+class ConditionOptions(admin.ModelAdmin):
+    list_display = (('condition_name'), ('notes'),)
+    fieldsets = (
+      (None, {
+          'fields': (('condition_name'),('nickname'),('notes'),)
+      }),
+     )
+
+class ExperimentTypeOptions(admin.ModelAdmin):
+  model = ExperimentType
+  #list_display = ('name',)
+  #fieldsets = ( (None, { 'fields': ('name',) }), )
+
+class HTSUserCreationForm(UserCreationForm):
+    class Meta:
+        model = HTSUser
+        fields = ("username",'first_name','last_name')
+
+class HTSUserChangeForm(UserChangeForm):
+    class Meta:
+        model = HTSUser
+        fields = ("username",'first_name','last_name')
+
+class HTSUserOptions(UserAdmin):
+    form = HTSUserChangeForm
+    add_form = HTSUserCreationForm
+
+class LaneLibraryInline(admin.StackedInline):
+  model = Lane
+  extra = 0
+
+class Library_Inline(admin.TabularInline):
+  model = Library
+
+class LibraryTypeOptions(admin.ModelAdmin):
+    list_display = ['name', 'is_paired_end', 'can_multiplex']
+    model = LibraryType
+
+class MultiplexIndexOptions(admin.ModelAdmin):
+    model = MultiplexIndex
+    list_display = ['adapter_type', 'multiplex_id', 'sequence']
+
+class LibraryOptions(admin.ModelAdmin):
+    class Media:
+        css = {
+            "all": ("css/wide_account_number.css",)
+            }
+
+    date_hierarchy = "creation_date"
+    save_as = True
+    save_on_top = True
+    search_fields = (
+        'id',
+        'library_name',
+        'cell_line__cellline_name',
+        'library_species__scientific_name',
+        'library_species__common_name',
+    )
+    list_display = (
+        'id',
+        'library_name',
+        'index_sequence_text',
+        'affiliation',
+        'undiluted_concentration',
+        'gel_cut_size',
+        'creation_date',
+    )
+    list_filter = (
+        'hidden',
+        'experiment_type',
+        'library_type',
+        #'cell_line',
+        'stopping_point',
+        'made_by',
+        'library_species',
+        'affiliations',
+        )
+    list_display_links = ('id', 'library_name',)
+    fieldsets = (
+      (None, {
+        'fields': (
+          ('id','library_name','hidden'),
+          ('library_species', 'experiment_type'),
+          ('library_type', 'multiplex_id'),
+          )
+         }),
+         ('Experiment Detail:', {
+            'fields': (('cell_line', 'replicate',),
+                       ('condition',),
+                       ('antibody', ),
+                       ),
+            'classes': ('collapse',),
+            }),
+         ('Creation Information:', {
+             'fields' : (('made_by', 'creation_date', 'stopping_point'),
+                         ('amplified_from_sample'),
+                         ('gel_cut_size', 'insert_size',
+                          'undiluted_concentration'),
+                         ('bioanalyzer_concentration','bioanalyzer_image_url'),
+                         ('bioanalyzer_summary'),
+                         ('notes'))
+         }),
+         ('Library/Project Affiliation:', {
+             'fields' : (('account_number', 'affiliations'),)
+         }),
+         )
+    inlines = [
+      LaneLibraryInline,
+    ]
+    actions = ['action_print_library_labels']
+
+    def action_print_library_labels(self, request, queryset):
+        """
+        Django action which prints labels for the selected set of labels from the
+        Django Admin interface.
+        """
+
+        #Probably should ask if the user really meant to print all selected
+        # libraries if the count is above X. X=10 maybe?
+
+        # Grab the library template
+        #FIXME: Hardcoding library template name. Not a good idea... *sigh*.
+        EVIL_HARDCODED_LIBRARY_TEMPLATE_NAME = "Library"
+
+        try:
+            template = PrinterTemplate.objects.get(item_type__name=EVIL_HARDCODED_LIBRARY_TEMPLATE_NAME)
+        except PrinterTemplate.DoesNotExist:
+            self.message_user(request, "Could not find a library template with ItemType.name of '%s'" % \
+                              (EVIL_HARDCODED_LIBRARY_TEMPLATE_NAME))
+            return
+
+        # ZPL Template
+        t = Template(template.template)
+
+        zpl_list = []
+        #Iterate over selected labels to print
+        for library in queryset.all():
+
+            # Django Template Context
+            c = Context({'library': library})
+
+            # Send rendered template to the printer that the template
+            #  object has been attached to in the database.
+            zpl_list.append(t.render(c))
+
+        print_zpl_socket(zpl_list, host=template.printer.ip_address)
+
+        self.message_user(request, "%s labels printed." % (len(queryset)))
+
+    action_print_library_labels.short_description = "Print Labels"
+
+    def formfield_for_dbfield(self, db_field, **kwargs):
+        # Override Field type
+        if db_field.name in ('affiliations', 'tags'):
+            kwargs['widget'] = widgets.FilteredSelectMultiple(
+                db_field.verbose_name,
+                (db_field.name in self.filter_vertical)
+            )
+        field = super(LibraryOptions, self).formfield_for_dbfield(db_field,
+                                                                  **kwargs)
+        # Override field attributes
+        if db_field.name == "bioanalyzer_summary":
+            field.widget.attrs["rows"] = "3"
+        return field
+
+class SpeciesOptions(admin.ModelAdmin):
+    fieldsets = (
+      (None, {
+          'fields': (('scientific_name', 'common_name'),)
+      }),
+    )
+
+class TagOptions(admin.ModelAdmin):
+    list_display = ('tag_name', 'context')
+    fieldsets = (
+        (None, {
+          'fields': ('tag_name', 'context')
+          }),
+        )
+
+admin.site.register(Library, LibraryOptions)
+admin.site.register(Affiliation, AffiliationOptions)
+admin.site.register(Antibody, AntibodyOptions)
+admin.site.register(Cellline, CelllineOptions)
+admin.site.register(Condition, ConditionOptions)
+admin.site.register(ExperimentType, ExperimentTypeOptions)
+#admin.site.register(HTSUser, HTSUserOptions)
+admin.site.register(LibraryType, LibraryTypeOptions)
+admin.site.register(MultiplexIndex, MultiplexIndexOptions)
+admin.site.register(Species, SpeciesOptions)
+#admin.site.register(Tag, TagOptions)
diff --git a/samples/auth_backend.py b/samples/auth_backend.py
new file mode 100644 (file)
index 0000000..a4c67ee
--- /dev/null
@@ -0,0 +1,36 @@
+from __future__ import absolute_import, print_function
+
+from django.conf import settings
+from django.contrib.auth.backends import ModelBackend
+from django.core.exceptions import ImproperlyConfigured
+from django.db.models import get_model
+
+import sys
+
+class HTSUserModelBackend(ModelBackend):
+    def authenticate(self, username=None, password=None):
+        try:
+            user = self.user_class.objects.get(username=username)
+            if user.check_password(password):
+                return user
+        #except self.user_class.DoesNotExist:
+        except Exception, e:
+            print >>sys.stderr, e
+            return None
+
+    def get_user(self, user_id):
+        try:
+            return self.user_class.objects.get(pk=user_id)
+        #except self.user_class.DoesNotExist:
+        except Exception, e:
+            print >>sys.stderr, e
+            return None
+
+    @property
+    def user_class(self):
+        if not hasattr(self, '_user_class'):
+            self._user_class = get_model(*settings.CUSTOM_USER_MODEL.split('.',2))
+            if not self._user_class:
+                raise ImproperlyConfigured('Could not get custom user model')
+            return self._user_class
+        
diff --git a/samples/changelist.py b/samples/changelist.py
new file mode 100644 (file)
index 0000000..83bbb78
--- /dev/null
@@ -0,0 +1,50 @@
+from __future__ import absolute_import, print_function
+
+import django
+from django.contrib.admin.views.main import ChangeList
+
+class HTSChangeList(ChangeList):
+    def __init__(self, request, model, list_filter, search_fields,
+                 list_per_page, model_admin, extra_filters=None):
+        """Simplification of the django model filter view
+
+        The new parameter "extra_filter" should be a mapping
+        of that will be passed as keyword arguments to
+        queryset.filter
+        """
+        self.extra_filters = extra_filters
+
+        args = {
+            'request': request, #request
+            'model': model, #model
+            'list_display': [], # list_display
+            'list_display_links': None, # list_display_links
+            'list_filter': list_filter, #list_filter
+            'date_hierarchy': None, # date_hierarchy
+            'search_fields': search_fields, #search_fields
+            'list_select_related': None, # list_select_related,
+            'list_per_page': list_per_page, #list_per_page
+            'list_editable': None, # list_editable
+            'model_admin': model_admin #model_admin
+        }
+        if django.VERSION[0] >= 1 and django.VERSION[1] >= 4:
+            args['list_max_show_all'] = 20000, #list_max_show_all
+        super(HTSChangeList, self).__init__(**args)
+
+        self.is_popup = False
+        # I removed to field in the first version
+
+        self.multi_page = True
+        self.can_show_all = False
+
+    def get_queryset(self, request=None):
+        args = {}
+        if django.VERSION[0] >= 1 and django.VERSION[1] >= 4:
+            args['request'] = request #list_max_show_all
+
+        qs = super(HTSChangeList, self).get_query_set(**args)
+        if self.extra_filters:
+            new_qs = qs.filter(**self.extra_filters)
+            if new_qs is not None:
+                qs = new_qs
+        return qs
diff --git a/samples/fixtures/initial_data.json b/samples/fixtures/initial_data.json
new file mode 100644 (file)
index 0000000..ae22c1d
--- /dev/null
@@ -0,0 +1,929 @@
+[
+  {
+     "model": "samples.Cellline",
+     "pk": 1,
+     "fields": {
+        "cellline_name": "Unknown",
+        "notes": "Unknown"
+     }
+  },
+  {
+     "model": "samples.Cellline",
+     "pk": 2,
+     "fields": {
+        "cellline_name": "C2C12",
+        "notes": ""
+     }
+  },
+  {
+     "model": "samples.Cellline",
+     "pk": 3,
+     "fields": {
+        "cellline_name": "C2C12 60 hrs",
+        "notes": "Unknown"
+     }
+  },
+  { "pk": 1, "model": "samples.Condition",
+    "fields": {
+        "condition_name": "Unknown",
+        "nickname": "",
+        "notes": "Unknown"
+    }
+  },
+  {
+     "model": "samples.LibraryType",
+     "pk": 1,
+     "fields": {
+        "name": "Single End (non-multiplexed)",
+        "can_multiplex": false,
+        "is_paired_end": false
+     }
+  },
+  {
+     "model": "samples.LibraryType",
+     "pk": 2,
+     "fields": {
+        "name": "Paired End (non-multiplexed)",
+        "can_multiplex": false,
+        "is_paired_end": true
+     }
+  },
+  {
+     "model": "samples.LibraryType",
+     "pk": 5,
+     "fields": {
+        "name": "Barcoded Illumina",
+        "can_multiplex": true,
+        "is_paired_end": true
+     }
+  },
+  {
+     "model": "samples.LibraryType",
+     "pk": 7,
+     "fields": {
+        "name": "Barcoded Small RNA",
+        "can_multiplex": true,
+        "is_paired_end": true
+     }
+  },
+  {
+     "model": "samples.LibraryType",
+     "pk": 8,
+     "fields": {
+        "name": "Nextera",
+        "can_multiplex": true,
+        "is_paired_end": true
+     }
+  },
+  {
+     "model": "samples.LibraryType",
+     "pk": 9,
+     "fields": {
+        "name": "Dual Index Illumina",
+        "can_multiplex": true,
+        "is_paired_end": true
+     }
+  },
+  {
+     "model": "samples.ExperimentType",
+     "pk": 1,
+     "fields": {
+        "name": "Unknown"
+     }
+  },
+  {
+     "model": "samples.ExperimentType",
+     "pk": 2,
+     "fields": {
+        "name": "ChIP-seq"
+     }
+  },
+  {
+     "model": "samples.ExperimentType",
+     "pk": 4,
+     "fields": {
+        "name": "RNA-seq"
+     }
+  },
+  {
+     "model": "samples.ExperimentType",
+     "pk": 7,
+     "fields": {
+        "name": "De Novo"
+     }
+  },
+  {
+     "model": "samples.ExperimentType",
+     "pk": 8,
+     "fields": {
+        "name": "Whole Genome"
+     }
+  },
+  {
+     "model": "samples.ExperimentType",
+     "pk": 9,
+     "fields": {
+        "name": "Small RNA"
+     }
+  },
+  {
+     "model": "samples.ExperimentType",
+     "pk": 10,
+     "fields": {
+        "name": "Multiplexed"
+     }
+  },
+  {
+     "model": "samples.Species",
+     "pk": 2,
+     "fields": {
+        "scientific_name": "Drosophila melanogaster",
+        "common_name": "fruit fly"
+     }
+  },
+  {
+     "model": "samples.Species",
+     "pk": 3,
+     "fields": {
+        "scientific_name": "Caenorhabditis elegans",
+        "common_name": ""
+     }
+  },
+  {
+     "model": "samples.Species",
+     "pk": 6,
+     "fields": {
+        "scientific_name": "Arabidopsis thaliana"
+     }
+  },
+  {
+     "model": "samples.Species",
+     "pk": 8,
+     "fields": {
+        "scientific_name": "Homo sapiens",
+        "common_name": "human"
+     }
+  },
+  {
+     "model": "samples.Species",
+     "pk": 9,
+     "fields": {
+        "scientific_name": "Mus musculus",
+        "common_name": "mouse"
+     }
+  },
+  {
+     "model": "samples.Species",
+     "pk": 10,
+     "fields": {
+        "scientific_name": "Strongylocentrotus purpuratus"
+     }
+  },
+  {
+    "pk": 1,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 1,
+      "adapter_type": 8,
+      "sequence": "ATCACG"
+    }
+  },
+  {
+    "pk": 2,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 2,
+      "adapter_type": 8,
+      "sequence": "CGATGT"
+    }
+  },
+  {
+    "pk": 3,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 3,
+      "adapter_type": 8,
+      "sequence": "TTAGGC"
+    }
+  },
+  {
+    "pk": 4,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 4,
+      "adapter_type": 8,
+      "sequence": "TGACCA"
+    }
+  },
+  {
+    "pk": 5,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 5,
+      "adapter_type": 8,
+      "sequence": "ACAGTG"
+    }
+  },
+  {
+    "pk": 6,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 6,
+      "adapter_type": 8,
+      "sequence": "GCCAAT"
+    }
+  },
+  {
+    "pk": 7,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 7,
+      "adapter_type": 8,
+      "sequence": "CAGATC"
+    }
+  },
+  {
+    "pk": 8,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 8,
+      "adapter_type": 8,
+      "sequence": "ACTTGA"
+    }
+  },
+  {
+    "pk": 9,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 9,
+      "adapter_type": 8,
+      "sequence": "GATCAG"
+    }
+  },
+  {
+    "pk": 10,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 10,
+      "adapter_type": 8,
+      "sequence": "TAGCTT"
+    }
+  },
+  {
+    "pk": 11,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 11,
+      "adapter_type": 8,
+      "sequence": "GGCTAC"
+    }
+  },
+  {
+    "pk": 12,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 12,
+      "adapter_type": 8,
+      "sequence": "CTTGTA"
+    }
+  },
+  {
+    "pk": 13,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 1,
+      "adapter_type": 7,
+      "sequence": "ATCACG"
+    }
+  },
+  {
+    "pk": 14,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 2,
+      "adapter_type": 7,
+      "sequence": "CGATGT"
+    }
+  },
+  {
+    "pk": 15,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 3,
+      "adapter_type": 7,
+      "sequence": "TTAGGC"
+    }
+  },
+  {
+    "pk": 16,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 4,
+      "adapter_type": 7,
+      "sequence": "TGACCA"
+    }
+  },
+  {
+    "pk": 17,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 5,
+      "adapter_type": 7,
+      "sequence": "ACAGTG"
+    }
+  },
+  {
+    "pk": 18,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 6,
+      "adapter_type": 7,
+      "sequence": "GCCAAT"
+    }
+  },
+  {
+    "pk": 19,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 7,
+      "adapter_type": 7,
+      "sequence": "CAGATC"
+    }
+  },
+  {
+    "pk": 20,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 8,
+      "adapter_type": 7,
+      "sequence": "ACTTGA"
+    }
+  },
+  {
+    "pk": 21,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 9,
+      "adapter_type": 7,
+      "sequence": "GATCAG"
+    }
+  },
+  {
+    "pk": 22,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 10,
+      "adapter_type": 7,
+      "sequence": "TAGCTT"
+    }
+  },
+  {
+    "pk": 23,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 11,
+      "adapter_type": 7,
+      "sequence": "GGCTAC"
+    }
+  },
+  {
+    "pk": 24,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 12,
+      "adapter_type": 7,
+      "sequence": "CTTGTA"
+    }
+  },
+  {
+    "pk": 25,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 13,
+      "adapter_type": 7,
+      "sequence": "AGTCAA"
+    }
+  },
+  {
+    "pk": 26,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 14,
+      "adapter_type": 7,
+      "sequence": "AGTTCC"
+    }
+  },
+  {
+    "pk": 27,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 15,
+      "adapter_type": 7,
+      "sequence": "ATGTCA"
+    }
+  },
+  {
+    "pk": 28,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 16,
+      "adapter_type": 7,
+      "sequence": "CCGTCC"
+    }
+  },
+  {
+    "pk": 29,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 17,
+      "adapter_type": 7,
+      "sequence": "GTAGAG"
+    }
+  },
+  {
+    "pk": 30,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 18,
+      "adapter_type": 7,
+      "sequence": "GTCCGC"
+    }
+  },
+  {
+    "pk": 31,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 19,
+      "adapter_type": 7,
+      "sequence": "GTGAAA"
+    }
+  },
+  {
+    "pk": 32,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 20,
+      "adapter_type": 7,
+      "sequence": "GTGGCC"
+    }
+  },
+  {
+    "pk": 33,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 21,
+      "adapter_type": 7,
+      "sequence": "GTTTCG"
+    }
+  },
+  {
+    "pk": 34,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 22,
+      "adapter_type": 7,
+      "sequence": "CGTACG"
+    }
+  },
+  {
+    "pk": 35,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 23,
+      "adapter_type": 7,
+      "sequence": "GAGTGG"
+    }
+  },
+  {
+    "pk": 36,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 24,
+      "adapter_type": 7,
+      "sequence": "GGTAGC"
+    }
+  },
+  {
+    "pk": 37,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 25,
+      "adapter_type": 7,
+      "sequence": "ACTGAT"
+    }
+  },
+  {
+    "pk": 38,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 26,
+      "adapter_type": 7,
+      "sequence": "ATGAGC"
+    }
+  },
+  {
+    "pk": 39,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 27,
+      "adapter_type": 7,
+      "sequence": "ATTCCT"
+    }
+  },
+  {
+    "pk": 40,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 28,
+      "adapter_type": 7,
+      "sequence": "CAAAAG"
+    }
+  },
+  {
+    "pk": 41,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 29,
+      "adapter_type": 7,
+      "sequence": "CAACTA"
+    }
+  },
+  {
+    "pk": 42,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 30,
+      "adapter_type": 7,
+      "sequence": "CACCGG"
+    }
+  },
+  {
+    "pk": 43,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 31,
+      "adapter_type": 7,
+      "sequence": "CACGAT"
+    }
+  },
+  {
+    "pk": 44,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 32,
+      "adapter_type": 7,
+      "sequence": "CACTCA"
+    }
+  },
+  {
+    "pk": 45,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 33,
+      "adapter_type": 7,
+      "sequence": "CAGGCG"
+    }
+  },
+  {
+    "pk": 46,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 34,
+      "adapter_type": 7,
+      "sequence": "CATGGC"
+    }
+  },
+  {
+    "pk": 47,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 35,
+      "adapter_type": 7,
+      "sequence": "CATTTT"
+    }
+  },
+  {
+    "pk": 48,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 36,
+      "adapter_type": 7,
+      "sequence": "CCAACA"
+    }
+  },
+  {
+    "pk": 49,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 37,
+      "adapter_type": 7,
+      "sequence": "CGGAAT"
+    }
+  },
+  {
+    "pk": 50,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 38,
+      "adapter_type": 7,
+      "sequence": "CTAGCT"
+    }
+  },
+  {
+    "pk": 51,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 39,
+      "adapter_type": 7,
+      "sequence": "CTATAC"
+    }
+  },
+  {
+    "pk": 52,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 40,
+      "adapter_type": 7,
+      "sequence": "CTCAGA"
+    }
+  },
+  {
+    "pk": 53,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 41,
+      "adapter_type": 7,
+      "sequence": "GACGAC"
+    }
+  },
+  {
+    "pk": 54,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 42,
+      "adapter_type": 7,
+      "sequence": "TAATCG"
+    }
+  },
+  {
+    "pk": 55,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 43,
+      "adapter_type": 7,
+      "sequence": "TACAGC"
+    }
+  },
+  {
+    "pk": 56,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 44,
+      "adapter_type": 7,
+      "sequence": "TATAAT"
+    }
+  },
+  {
+    "pk": 57,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 45,
+      "adapter_type": 7,
+      "sequence": "TCATTC"
+    }
+  },
+  {
+    "pk": 58,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 46,
+      "adapter_type": 7,
+      "sequence": "TCCCGA"
+    }
+  },
+  {
+    "pk": 59,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 47,
+      "adapter_type": 7,
+      "sequence": "TCGAAG"
+    }
+  },
+  {
+    "pk": 60,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 48,
+      "adapter_type": 7,
+      "sequence": "TCGGCA"
+    }
+  },
+  {
+    "pk": 61,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 1,
+      "adapter_type": 5,
+      "sequence": "ATCACG"
+    }
+  },
+  {
+    "pk": 62,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 2,
+      "adapter_type": 5,
+      "sequence": "CGATGT"
+    }
+  },
+  {
+    "pk": 63,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 3,
+      "adapter_type": 5,
+      "sequence": "TTAGGC"
+    }
+  },
+  {
+    "pk": 64,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 4,
+      "adapter_type": 5,
+      "sequence": "TGACCA"
+    }
+  },
+  {
+    "pk": 65,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 5,
+      "adapter_type": 5,
+      "sequence": "ACAGTG"
+    }
+  },
+  {
+    "pk": 66,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 6,
+      "adapter_type": 5,
+      "sequence": "GCCAAT"
+    }
+  },
+  {
+    "pk": 67,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 7,
+      "adapter_type": 5,
+      "sequence": "CAGATC"
+    }
+  },
+  {
+    "pk": 68,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 8,
+      "adapter_type": 5,
+      "sequence": "ACTTGA"
+    }
+  },
+  {
+    "pk": 69,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 9,
+      "adapter_type": 5,
+      "sequence": "GATCAG"
+    }
+  },
+  {
+    "pk": 70,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 10,
+      "adapter_type": 5,
+      "sequence": "TAGCTT"
+    }
+  },
+  {
+    "pk": 71,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 11,
+      "adapter_type": 5,
+      "sequence": "GGCTAC"
+    }
+  },
+  {
+    "pk": 72,
+    "model": "samples.MultiplexIndex",
+    "fields": {
+      "multiplex_id": 12,
+      "adapter_type": 5,
+      "sequence": "CTTGTA"
+    }
+  },
+  {"fields": {"adapter_type": 9,
+             "multiplex_id": "N501",
+             "sequence": "TAGATCGC"},
+  "model": "samples.multiplexindex",
+  "pk": 74
+  },
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N502",
+             "sequence": "CTCTCTAT"},
+  "model": "samples.multiplexindex",
+  "pk": 75},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N503",
+             "sequence": "TATCCTCT"},
+  "model": "samples.multiplexindex",
+  "pk": 76},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N504",
+             "sequence": "AGAGTAGA"},
+  "model": "samples.multiplexindex",
+  "pk": 77},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N505",
+             "sequence": "GTAAGGAG"},
+  "model": "samples.multiplexindex",
+  "pk": 78},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N506",
+             "sequence": "ACTGCATA"},
+  "model": "samples.multiplexindex",
+  "pk": 79},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N507",
+             "sequence": "AAGGAGTA"},
+  "model": "samples.multiplexindex",
+  "pk": 80},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N508",
+             "sequence": "CTAAGCCT"},
+  "model": "samples.multiplexindex",
+  "pk": 81},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N701",
+             "sequence": "TAAGGCGA"},
+  "model": "samples.multiplexindex",
+  "pk": 82},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N702",
+             "sequence": "CGTACTAG"},
+  "model": "samples.multiplexindex",
+  "pk": 83},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N703",
+             "sequence": "AGGCAGAA"},
+  "model": "samples.multiplexindex",
+  "pk": 84},
+ {"fields": {"adapter_type": 9, "multiplex_id": "N704", "sequence": "TCCTGA"},
+  "model": "samples.multiplexindex",
+  "pk": 85},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N705",
+             "sequence": "GGACTCCT"},
+  "model": "samples.multiplexindex",
+  "pk": 86},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N706",
+             "sequence": "TAGGCATG"},
+  "model": "samples.multiplexindex",
+  "pk": 87},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N707",
+             "sequence": "CTCTCTAC"},
+  "model": "samples.multiplexindex",
+  "pk": 88},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N708",
+             "sequence": "CAGAGAGG"},
+  "model": "samples.multiplexindex",
+  "pk": 89},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N709",
+             "sequence": "GCTACGCT"},
+  "model": "samples.multiplexindex",
+  "pk": 90},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N710",
+             "sequence": "CGAGGCTG"},
+  "model": "samples.multiplexindex",
+  "pk": 91},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N711",
+             "sequence": "AAGAGGCA"},
+  "model": "samples.multiplexindex",
+  "pk": 92},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N712",
+             "sequence": "GTAGAGGA"},
+  "model": "samples.multiplexindex",
+  "pk": 93}
+]
diff --git a/samples/fixtures/test_samples.json b/samples/fixtures/test_samples.json
new file mode 100644 (file)
index 0000000..41824e0
--- /dev/null
@@ -0,0 +1,235 @@
+[
+  {"pk": 5, "model": "auth.user",
+   "fields": {
+       "username": "test",
+       "first_name": "",
+       "last_name": "",
+       "is_active": true,
+       "is_superuser": false,
+       "is_staff": false,
+       "last_login": "2009-01-01T00:00:01-0800",
+       "groups": [],
+       "user_permissions": [],
+       "password": "sha1$foo$5e4eefec1144a04becfb7da79244f07c487fc345",
+       "email": "",
+       "date_joined": "2009-01-01T00:01:01-0800"
+       }
+   },
+   {"pk": 1, "model": "samples.affiliation",
+    "fields": {
+        "users": [5],
+        "name": "Alice",
+        "contact": "Lab Boss",
+        "email": "alice@some.where.else."
+        }
+    },
+    {"pk": 2, "model": "samples.affiliation",
+     "fields": { "name": "Bob",
+                 "contact": "Other Lab Boss",
+                 "email": "bob@some.where.else"
+               }
+    },
+    {"pk": 3, "model": "samples.affiliation",
+     "fields": {
+         "users": [],
+         "contact": "group 3",
+         "name": "affiliation 3",
+         "email": "pk3@example.com"
+         }
+     },
+    {"pk": 4, "model": "samples.affiliation",
+     "fields": {
+         "users": [],
+         "contact": "group 4",
+         "name": "affiliation 4",
+         "email": "pk1@example.com"
+         }
+     },
+    {"pk": 5, "model": "samples.affiliation",
+     "fields": {
+         "users": [],
+         "contact": "group 5",
+         "name": "affiliation 5",
+         "email": "pk5@example.com"
+         }
+     },
+ {"pk": 153, "model": "experiments.flowcell",
+  "fields": {
+      "paired_end": true,
+      "run_date": "2009-09-11T22:12:13-0800",
+      "read_length": 75,
+      "notes": "",
+      "advanced_run": false,
+      "control_lane": 2,
+      "cluster_station": 3,
+      "sequencer": 2,
+      "flowcell_id": "303TUAAXX"
+      }
+  },
+  {"pk": 1193, "model": "experiments.lane",
+   "fields": {
+       "comment": "No change in cluster numbers, despite slight increase in pM",
+       "library": "10981",
+       "cluster_estimate": 129000,
+       "flowcell": 153,
+       "lane_number": 1,
+       "pM": "8"
+       }
+   },
+  {"pk": 1197, "model": "experiments.lane",
+   "fields": {
+       "comment": "stuff",
+       "library": "11016",
+       "cluster_estimate": 140000,
+       "flowcell": 153,
+       "lane_number": 5,
+       "pM": "7",
+       "status": 2
+       }
+   },
+  {"pk": "10981", "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 400,
+            "library_name": "Paired End Multiplexed Sp-BAC",
+            "creation_date": "2009-07-21",
+            "cell_line": 1,
+            "library_species": 2,
+            "library_type": null,
+            "made_by": "Igor",
+            "affiliations": [
+                2
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "Done",
+            "tags": [],
+            "made_for": "Andy Cameron",
+            "amplified_from_sample": null,
+            "notes": "Combined 10957-10968",
+            "undiluted_concentration": "5.1",
+            "successful_pM": null,
+            "experiment_type": 10,
+            "antibody": null
+        }
+    },
+    {
+        "pk": "11016",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 325,
+            "library_name": "Paired End Pfl #3 MP 7/24/9 a",
+            "creation_date": "2009-08-06",
+            "cell_line": 1,
+            "library_species": 9,
+            "library_type": 2,
+            "made_by": "Lorian",
+            "affiliations": [
+                3
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": "11003",
+            "notes": "7/31/2009 16:08:22\tColor: Blue",
+            "undiluted_concentration": "35.5",
+            "successful_pM": null,
+            "experiment_type": 8,
+            "antibody": null
+        }
+    },
+    {
+        "pk": "11039",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 300,
+            "library_name": "Paired ends 99 GM12892",
+            "creation_date": "2009-08-25",
+            "cell_line": 1,
+            "library_species": 8,
+            "library_type": 2,
+            "made_by": "Brian Williams",
+            "affiliations": [
+                1,
+                2,
+                4
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": false,
+            "stopping_point": "1Aa",
+            "tags": [],
+            "made_for": "Brian Williams",
+            "amplified_from_sample": null,
+            "notes": "fragment size = 300 bp, Amicon filtered\r\nnanodrop: 56.3",
+            "undiluted_concentration": "28.7",
+            "successful_pM": null,
+            "experiment_type": 4,
+            "antibody": null
+        }
+    },
+    {
+        "pk": "11003",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 325,
+            "library_name": "Paired End Pfl #3 MP 7/24/9",
+            "creation_date": "2009-08-05",
+            "cell_line": 1,
+            "library_species": 8,
+            "library_type": 2,
+            "made_by": "Lorian",
+            "affiliations": [
+                4
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": true,
+            "stopping_point": "1A",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "7/31/2009 16:08:22\tColor: Blue",
+            "undiluted_concentration": null,
+            "successful_pM": null,
+            "experiment_type": 8,
+            "antibody": null
+        }
+    },
+    {
+        "pk": "11005",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 325,
+            "library_name": "null cell line",
+            "creation_date": "2009-08-05",
+            "cell_line": null,
+            "library_species": 8,
+            "library_type": 2,
+            "made_by": "Lorian",
+            "affiliations": [
+                4
+            ],
+            "replicate": 1,
+            "condition": 1,
+            "hidden": true,
+            "stopping_point": "1A",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": null,
+            "notes": "7/31/2009 16:08:22\tColor: Blue",
+            "undiluted_concentration": null,
+            "successful_pM": null,
+            "experiment_type": 8,
+            "antibody": null
+        }
+    }
+]
diff --git a/samples/models.py b/samples/models.py
new file mode 100644 (file)
index 0000000..5c5c27c
--- /dev/null
@@ -0,0 +1,402 @@
+import types
+import logging
+import urlparse
+from django.db import models
+from django.contrib.auth.models import User, UserManager
+from django.core import urlresolvers
+from django.db.models.signals import pre_save, post_save
+from django.db import connection
+
+logger = logging.getLogger(__name__)
+
+class Antibody(models.Model):
+    antigene = models.CharField(max_length=500, db_index=True)
+    # New field Aug/20/08
+    # SQL to add column:
+    # alter table fctracker_antibody add column "nickname" varchar(20) NULL;
+    nickname = models.CharField(
+        max_length=20,
+        blank=True,
+        null=True,
+        db_index=True
+    )
+    catalog = models.CharField(max_length=50, blank=True, null=True)
+    antibodies = models.CharField(max_length=500, db_index=True)
+    source = models.CharField(max_length=500, blank=True, null=True, db_index=True)
+    biology = models.TextField(blank=True, null=True)
+    notes = models.TextField(blank=True, null=True)
+    def __unicode__(self):
+        return u'%s - %s' % (self.antigene, self.antibodies)
+    class Meta:
+        verbose_name_plural = "antibodies"
+        ordering = ["antigene"]
+
+class Cellline(models.Model):
+    cellline_name = models.CharField(max_length=100, unique=True, db_index=True)
+    nickname = models.CharField(max_length=20,
+        blank=True,
+        null=True,
+        db_index=True)
+
+    notes = models.TextField(blank=True)
+    def __unicode__(self):
+        return unicode(self.cellline_name)
+
+    class Meta:
+        ordering = ["cellline_name"]
+
+class Condition(models.Model):
+    condition_name = models.CharField(
+        max_length=2000, unique=True, db_index=True)
+    nickname = models.CharField(max_length=20,
+        blank=True,
+        null=True,
+        db_index=True,
+        verbose_name = 'Short Name')
+    notes = models.TextField(blank=True)
+
+    def __unicode__(self):
+        return unicode(self.condition_name)
+
+    class Meta:
+        ordering = ["condition_name"]
+
+
+class ExperimentType(models.Model):
+  name = models.CharField(max_length=50, unique=True)
+
+  def __unicode__(self):
+    return unicode(self.name)
+
+class Tag(models.Model):
+  tag_name = models.CharField(max_length=100, db_index=True,blank=False,null=False)
+  TAG_CONTEXT = (
+      #('Antibody','Antibody'),
+      #('Cellline', 'Cellline'),
+      #('Condition', 'Condition'),
+      ('Library', 'Library'),
+      ('ANY','ANY'),
+  )
+  context = models.CharField(max_length=50,
+      choices=TAG_CONTEXT, default='Library')
+
+  def __unicode__(self):
+    return u'%s' % (self.tag_name)
+
+  class Meta:
+    ordering = ["context","tag_name"]
+
+class Species(models.Model):
+  scientific_name = models.CharField(max_length=256,
+      unique=False,
+      db_index=True
+  )
+  common_name = models.CharField(max_length=256, blank=True)
+  #use_genome_build = models.CharField(max_length=100, blank=False, null=False)
+
+  def __unicode__(self):
+    return u'%s (%s)' % (self.scientific_name, self.common_name)
+
+  class Meta:
+    verbose_name_plural = "species"
+    ordering = ["scientific_name"]
+
+  @models.permalink
+  def get_absolute_url(self):
+    return ('samples.views.species', [str(self.id)])
+
+class Affiliation(models.Model):
+  name = models.CharField(max_length=256, db_index=True, verbose_name='Name')
+  contact = models.CharField(max_length=256, null=True, blank=True,verbose_name='Lab Name')
+  email = models.EmailField(null=True,blank=True)
+  users = models.ManyToManyField('HTSUser', null=True, blank=True)
+  users.admin_order_field = "username"
+
+  def __unicode__(self):
+    str = unicode(self.name)
+    if self.contact is not None and len(self.contact) > 0:
+      str += u' ('+self.contact+u')'
+    return str
+
+  def Users(self):
+      users = self.users.all().order_by('username')
+      return ", ".join([unicode(a) for a in users ])
+
+  class Meta:
+    ordering = ["name","contact"]
+    unique_together = (("name", "contact"),)
+
+class LibraryType(models.Model):
+  name = models.CharField(max_length=255, unique=True,
+                          verbose_name="Adapter Type")
+  is_paired_end = models.BooleanField(default=True,
+                    help_text="can you do a paired end run with this adapter")
+  can_multiplex = models.BooleanField(default=True,
+                    help_text="Does this adapter provide multiplexing?")
+
+  def __unicode__(self):
+      return unicode(self.name)
+
+  class Meta:
+      ordering = ["-id"]
+
+
+class MultiplexIndex(models.Model):
+    """Map adapter types to the multiplex sequence"""
+    adapter_type = models.ForeignKey(LibraryType)
+    multiplex_id = models.CharField(max_length=6, null=False)
+    sequence = models.CharField(max_length=12, blank=True, null=True)
+
+    class Meta:
+        verbose_name_plural = "multiplex indicies"
+        unique_together = ('adapter_type', 'multiplex_id')
+
+class Library(models.Model):
+  id = models.CharField(max_length=10, primary_key=True)
+  library_name = models.CharField(max_length=100, unique=True)
+  library_species = models.ForeignKey(Species)
+  hidden = models.BooleanField(default=False)
+  account_number = models.CharField(max_length=100, null=True, blank=True)
+  cell_line = models.ForeignKey(Cellline, blank=True, null=True,
+                                verbose_name="Background")
+  condition = models.ForeignKey(Condition, blank=True, null=True)
+  antibody = models.ForeignKey(Antibody,blank=True,null=True)
+  affiliations = models.ManyToManyField(
+      Affiliation,related_name='library_affiliations',null=True)
+  tags = models.ManyToManyField(Tag,related_name='library_tags',
+                                blank=True,null=True)
+  REPLICATE_NUM = [(x,x) for x in range(1,7)]
+  replicate =  models.PositiveSmallIntegerField(choices=REPLICATE_NUM,
+                                                blank=True,null=True)
+  experiment_type = models.ForeignKey(ExperimentType)
+  library_type = models.ForeignKey(LibraryType, blank=True, null=True,
+                                   verbose_name="Adapter Type")
+  multiplex_id = models.CharField(max_length=128,
+                                  blank=True, null=True,
+                                  verbose_name="Index ID")
+  creation_date = models.DateField(blank=True, null=True)
+  made_for = models.CharField(max_length=50, blank=True,
+                              verbose_name='ChIP/DNA/RNA Made By')
+  made_by = models.CharField(max_length=50, blank=True, default="Lorian")
+
+  PROTOCOL_END_POINTS = (
+      ('?', 'Unknown'),
+      ('Sample', 'Raw sample'),
+      ('Progress', 'In progress'),
+      ('1A', 'Ligation, then gel'),
+      ('PCR', 'Ligation, then PCR'),
+      ('1Ab', 'Ligation, PCR, then gel'),
+      ('1Ac', 'Ligation, gel, then 12x PCR'),
+      ('1Aa', 'Ligation, gel, then 18x PCR'),
+      ('2A', 'Ligation, PCR, gel, PCR'),
+      ('Done', 'Completed'),
+    )
+  PROTOCOL_END_POINTS_DICT = dict(PROTOCOL_END_POINTS)
+  stopping_point = models.CharField(max_length=25,
+                                    choices=PROTOCOL_END_POINTS,
+                                    default='Done')
+
+  amplified_from_sample = models.ForeignKey('self',
+                            related_name='amplified_into_sample',
+                            blank=True, null=True)
+
+  undiluted_concentration = models.DecimalField("Concentration",
+      max_digits=5, decimal_places=2, blank=True, null=True,
+      help_text=u"Undiluted concentration (ng/\u00b5l)")
+      # note \u00b5 is the micro symbol in unicode
+  successful_pM = models.DecimalField(max_digits=9,
+                                      decimal_places=1, blank=True, null=True)
+  ten_nM_dilution = models.BooleanField(default=False)
+  gel_cut_size = models.IntegerField(default=225, blank=True, null=True)
+  insert_size = models.IntegerField(blank=True, null=True)
+  notes = models.TextField(blank=True)
+
+  bioanalyzer_summary = models.TextField(blank=True,default="")
+  bioanalyzer_concentration = models.DecimalField(max_digits=5,
+                                decimal_places=2, blank=True, null=True,
+                                help_text=u"(ng/\u00b5l)")
+  bioanalyzer_image_url = models.URLField(blank=True,default="")
+
+  def __unicode__(self):
+    return u'#%s: %s' % (self.id, self.library_name)
+
+  class Meta:
+      verbose_name_plural = "libraries"
+      #ordering = ["-creation_date"]
+      ordering = ["-id"]
+
+  def antibody_name(self):
+    str ='<a target=_self href="/admin/samples/antibody/'+self.antibody.id.__str__()+'/" title="'+self.antibody.__str__()+'">'+self.antibody.label+'</a>'
+    return str
+  antibody_name.allow_tags = True
+
+  def organism(self):
+    return self.library_species.common_name
+
+  def index_sequences(self):
+      """Return a dictionary of multiplex index id to sequence
+      Return None if the library can't multiplex,
+
+      """
+      if self.library_type is None:
+          return None
+      if not self.library_type.can_multiplex:
+          return None
+      if self.multiplex_id is None or len(self.multiplex_id) == 0:
+          return 'Err: id empty'
+      sequences = {}
+      multiplex_expressions = self.multiplex_id.split(',')
+      for multiplex_term in multiplex_expressions:
+          pairs = multiplex_term.split('-')
+          if len(pairs) == 1:
+              key = pairs[0]
+              seq = self._lookup_index(pairs[0])
+          elif len(pairs) == 2:
+              key = pairs[0] + '-' + pairs[1]
+              seq0 = self._lookup_index(pairs[0])
+              seq1 = self._lookup_index(pairs[1])
+              if seq0 is None or seq1 is None:
+                  seq = None
+              else:
+                  seq = seq0 + '-' + seq1
+          else:
+              raise RuntimeError("Too many - seperated sequences")
+          if seq is None:
+              seq = 'Err: index not found'
+          sequences[key] = seq
+      return sequences
+
+  def _lookup_index(self, multiplex_id):
+      try:
+          multiplex = MultiplexIndex.objects.get(
+              adapter_type = self.library_type.id,
+              multiplex_id = multiplex_id)
+          return multiplex.sequence
+      except MultiplexIndex.DoesNotExist, e:
+          return None
+
+  def index_sequence_text(self, seperator=' '):
+      """Return formatted multiplex index sequences"""
+      sequences = self.index_sequences()
+      if sequences is None:
+          return ""
+      if type(sequences) in types.StringTypes:
+          return sequences
+      multiplex_ids = sequences.keys()
+      multiplex_ids.sort()
+      return seperator.join(( "%s:%s" %(i,sequences[i]) for i in multiplex_ids))
+  index_sequence_text.short_description = "Index"
+
+
+  def affiliation(self):
+    affs = self.affiliations.all().order_by('name')
+    tstr = ''
+    ar = []
+    for t in affs:
+        ar.append(t.__unicode__())
+    return '%s' % (", ".join(ar))
+
+  def is_archived(self):
+    """
+    returns True if archived else False
+    """
+    if self.longtermstorage_set.count() > 0:
+        return True
+    else:
+        return False
+
+  def stopping_point_name(self):
+      end_points = Library.PROTOCOL_END_POINTS_DICT
+      name = end_points.get(self.stopping_point, None)
+      if name is None:
+          name = "Lookup Error"
+          logger.error("protocol stopping point in database didn't match names in library model")
+      return name
+
+
+  def libtags(self):
+    affs = self.tags.all().order_by('tag_name')
+    ar = []
+    for t in affs:
+      ar.append(t.__unicode__())
+    return u'%s' % ( ", ".join(ar))
+
+  def DataRun(self):
+    str ='<a target=_self href="/admin/experiments/datarun/?q='+self.id+'" title="Check All Data Runs for This Specific Library ..." ">Data Run</a>'
+    return str
+  DataRun.allow_tags = True
+
+  def aligned_m_reads(self):
+    return getLibReads(self.id)
+
+  def aligned_reads(self):
+    res = getLibReads(self.id)
+
+    # Check data sanity
+    if res[2] != "OK":
+      return u'<div style="border:solid red 2px">'+res[2]+'</div>'
+
+    rc = "%1.2f" % (res[1]/1000000.0)
+    # Color Scheme: green is more than 10M, blue is more than 5M, orange is more than 3M and red is less. For RNAseq, all those thresholds should be doubled
+    if res[0] > 0:
+      bgcolor = '#ff3300'  # Red
+      rc_thr = [10000000,5000000,3000000]
+      if self.experiment_type == 'RNA-seq':
+        rc_thr = [20000000,10000000,6000000]
+
+      if res[1] > rc_thr[0]:
+        bgcolor = '#66ff66'  # Green
+      else:
+        if res[1] > rc_thr[1]:
+          bgcolor ='#00ccff'  # Blue
+        else:
+           if res[1] > rc_thr[2]:
+             bgcolor ='#ffcc33'  # Orange
+      tstr = '<div style="background-color:'+bgcolor+';color:black">'
+      tstr += res[0].__unicode__()+' Lanes, '+rc+' M Reads'
+      tstr += '</div>'
+    else: tstr = 'not processed yet'
+    return tstr
+  aligned_reads.allow_tags = True
+
+  def public(self):
+    SITE_ROOT = '/'
+    summary_url = self.get_absolute_url()
+    return '<a href="%s">S</a>' % (summary_url,)
+  public.allow_tags = True
+
+  @models.permalink
+  def get_absolute_url(self):
+    return ('samples.views.library_to_flowcells', [str(self.id)])
+
+  def get_admin_url(self):
+      return urlresolvers.reverse('admin:samples_library_change',
+                                  args=(self.id,))
+
+class HTSUser(User):
+    """
+    Provide some site-specific customization for the django user class
+    """
+    #objects = UserManager()
+
+    class Meta:
+        ordering = ['first_name', 'last_name', 'username']
+
+    def admin_url(self):
+        return '/admin/%s/%s/%d' % (self._meta.app_label, self._meta.module_name, self.id)
+
+    def __unicode__(self):
+        #return unicode(self.username) + u" (" + unicode(self.get_full_name()) + u")"
+        return unicode(self.get_full_name()) + u' (' + unicode(self.username) + ')'
+
+def HTSUserInsertID(sender, instance, **kwargs):
+    """
+    Force addition of HTSUsers when someone just modifies the auth_user object
+    """
+    u = HTSUser.objects.filter(pk=instance.id)
+    if len(u) == 0:
+        cursor = connection.cursor()
+        cursor.execute('INSERT INTO samples_htsuser (user_ptr_id) VALUES (%s);' % (instance.id,))
+        cursor.close()
+
+post_save.connect(HTSUserInsertID, sender=User)
diff --git a/samples/results.py b/samples/results.py
new file mode 100644 (file)
index 0000000..2724a37
--- /dev/null
@@ -0,0 +1,122 @@
+from django.conf import settings
+
+import glob
+import os
+import re
+
+s_paren = re.compile("^\w+")
+
+def get_flowcell_result_dict(flowcell_id):
+    """
+    returns a dictionary following the following pattern for
+    a given flowcell_id:
+    
+     
+    d['C1-33']['summary']           # Summary.htm file path
+    d['C1-33']['eland_results'][5]  # C1-33 lane 5 file eland results file path
+    d['C1-33']['run_xml']           # run_*.xml file path
+    d['C1-33']['scores']            # scores.tar.gz file path
+    """
+    flowcell_id = flowcell_id.strip()
+    
+    d = {}
+    
+    ################################
+    # Flowcell Directory
+    fc_dir = glob.glob(os.path.join(settings.RESULT_HOME_DIR, flowcell_id))
+    
+    # Not found
+    if len(fc_dir) == 0:
+        return None
+    
+    # No duplicates!
+    assert len(fc_dir) <= 1
+    
+    # Found fc dir
+    fc_dir = fc_dir[0]
+    
+    ################################
+    # C#-## dirs
+    c_dir_list = glob.glob(os.path.join(fc_dir, 'C*'))
+    
+    # Not found
+    if len(c_dir_list) == 0:
+        return d
+    
+    for c_dir_path in c_dir_list:
+        summary_file = glob.glob(os.path.join(c_dir_path, 'Summary.htm'))
+        pathdir, c_dir = os.path.split(c_dir_path)
+        
+        # Create sub-dictionary
+        d[c_dir] = {}
+        
+        
+        ###############################
+        # Summary.htm file
+        
+        # Not found
+        if len(summary_file) == 0:
+            d[c_dir]['summary'] = None
+            
+        # Found
+        else:
+            # No duplicates!
+            assert len(summary_file) == 1
+            
+            summary_file = summary_file[0]
+            d[c_dir]['summary'] = summary_file
+            
+        ###############################
+        # Result files
+        
+        d[c_dir]['eland_results'] = {}
+        
+        result_filepaths = glob.glob(os.path.join(c_dir_path, 's_*_eland_*'))
+        
+        for filepath in result_filepaths:
+            
+            junk, result_name = os.path.split(filepath)
+            
+            #lanes 1-8, single digit, therefore s_#; # == index 2
+            lane = int(result_name[2])
+            d[c_dir]['eland_results'][lane] = filepath
+            
+        ###############################
+        # run*.xml file
+        run_xml_filepath = glob.glob(os.path.join(c_dir_path, 'run_*.xml'))
+        
+        if len(run_xml_filepath) == 0:
+            d[c_dir]['run_xml'] = None
+        else:
+            # No duplicates
+            assert len(run_xml_filepath) == 1
+            
+            d[c_dir]['run_xml'] = run_xml_filepath[0]
+            
+        ###############################
+        # scores.tar.gz
+        # restrict to only compressed files, so in case there are *.md5 files
+        # we don't get confused.
+        scores_filepath = []
+        for pattern in ['scores*.tar.bz2', 'scores*.tar.gz', 'scores*.tgz']:
+            scores_filepath += glob.glob(os.path.join(c_dir_path, pattern))
+        
+        if len(scores_filepath) == 0:
+            d[c_dir]['scores'] = None
+        else:
+            # No duplicates
+            assert len(scores_filepath) == 1
+            
+            d[c_dir]['scores'] = scores_filepath[0]
+        
+    return d
+
+    
+def cn_mTobp(cn_m):
+    """
+    Converts CN-M (i.e. C1-33, C1-26, C4-28) cycle information into
+    number of base pairs.
+    """
+    pass
+
+
diff --git a/samples/test_samples.py b/samples/test_samples.py
new file mode 100644 (file)
index 0000000..b11fb94
--- /dev/null
@@ -0,0 +1,347 @@
+from __future__ import absolute_import, print_function
+
+import datetime
+
+try:
+    import json
+except ImportError, e:
+    import simplejson as json
+
+from django.test import TestCase
+from django.test.utils import setup_test_environment, \
+     teardown_test_environment
+from django.db import connection
+from django.conf import settings
+
+from .models import Affiliation, ExperimentType, Species, Library
+
+from .views import library_dict, library_json
+
+from htsworkflow.auth import apidata
+from htsworkflow.util.conversion import unicode_or_none
+from htsworkflow.util.ethelp import validate_xhtml
+
+class LibraryTestCase(TestCase):
+    fixtures = ['initial_data.json',
+                'woldlab.json',
+                'test_samples.json']
+
+    def setUp(self):
+        create_db(self)
+
+    def testOrganism(self):
+        self.assertEquals(self.library_10001.organism(), 'human')
+
+    def testAffiliations(self):
+        self.library_10001.affiliations.add(self.affiliation_alice)
+        self.library_10002.affiliations.add(
+                self.affiliation_alice,
+                self.affiliation_bob
+        )
+        self.failUnless(len(self.library_10001.affiliations.all()), 1)
+        self.failUnless(self.library_10001.affiliation(), 'Alice')
+
+        self.failUnless(len(self.library_10002.affiliations.all()), 2)
+        self.failUnless(self.library_10001.affiliation(), 'Alice, Bob')
+
+
+class SampleWebTestCase(TestCase):
+    """
+    Test returning data from our database in rest like ways.
+    (like returning json objects)
+    """
+    fixtures = ['initial_data.json',
+                'woldlab.json',
+                'test_samples.json']
+
+    def test_library_info(self):
+        for lib in Library.objects.all():
+            lib_dict = library_dict(lib.id)
+            url = '/samples/library/%s/json' % (lib.id,)
+            lib_response = self.client.get(url, apidata)
+            self.failUnlessEqual(lib_response.status_code, 200)
+            lib_json = json.loads(lib_response.content)
+
+            for d in [lib_dict, lib_json]:
+                # amplified_from_sample is a link to the library table,
+                # I want to use the "id" for the data lookups not
+                # the embedded primary key.
+                # It gets slightly confusing on how to implement sending the right id
+                # since amplified_from_sample can be null
+                #self.failUnlessEqual(d['amplified_from_sample'], lib.amplified_from_sample)
+                self.failUnlessEqual(d['antibody_id'], lib.antibody_id)
+                self.failUnlessEqual(d['cell_line_id'], lib.cell_line_id)
+                self.failUnlessEqual(d['cell_line'], unicode_or_none(lib.cell_line))
+                self.failUnlessEqual(d['experiment_type'], lib.experiment_type.name)
+                self.failUnlessEqual(d['experiment_type_id'], lib.experiment_type_id)
+                self.failUnlessEqual(d['gel_cut_size'], lib.gel_cut_size)
+                self.failUnlessEqual(d['hidden'], lib.hidden)
+                self.failUnlessEqual(d['id'], lib.id)
+                self.failUnlessEqual(d['insert_size'], lib.insert_size)
+                self.failUnlessEqual(d['library_name'], lib.library_name)
+                self.failUnlessEqual(d['library_species'], lib.library_species.scientific_name)
+                self.failUnlessEqual(d['library_species_id'], lib.library_species_id)
+                self.failUnlessEqual(d['library_type_id'], lib.library_type_id)
+                if lib.library_type_id is not None:
+                    self.failUnlessEqual(d['library_type'], lib.library_type.name)
+                else:
+                    self.failUnlessEqual(d['library_type'], None)
+                    self.failUnlessEqual(d['made_for'], lib.made_for)
+                    self.failUnlessEqual(d['made_by'], lib.made_by)
+                    self.failUnlessEqual(d['notes'], lib.notes)
+                    self.failUnlessEqual(d['replicate'], lib.replicate)
+                    self.failUnlessEqual(d['stopping_point'], lib.stopping_point)
+                    self.failUnlessEqual(d['successful_pM'], lib.successful_pM)
+                    self.failUnlessEqual(d['undiluted_concentration'],
+                                         unicode(lib.undiluted_concentration))
+                # some specific tests
+                if lib.id == '10981':
+                    # test a case where there is no known status
+                    lane_set = {u'status': u'Unknown',
+                                u'paired_end': True,
+                                u'read_length': 75,
+                                u'lane_number': 1,
+                                u'lane_id': 1193,
+                                u'flowcell': u'303TUAAXX',
+                                u'status_code': None}
+                    self.failUnlessEqual(len(d['lane_set']), 1)
+                    self.failUnlessEqual(d['lane_set'][0], lane_set)
+                elif lib.id == '11016':
+                    # test a case where there is a status
+                    lane_set = {u'status': 'Good',
+                                u'paired_end': True,
+                                u'read_length': 75,
+                                u'lane_number': 5,
+                                u'lane_id': 1197,
+                                u'flowcell': u'303TUAAXX',
+                                u'status_code': 2}
+                    self.failUnlessEqual(len(d['lane_set']), 1)
+                    self.failUnlessEqual(d['lane_set'][0], lane_set)
+
+
+    def test_invalid_library_json(self):
+        """
+        Make sure we get a 404 if we request an invalid library id
+        """
+        response = self.client.get('/samples/library/nottheone/json', apidata)
+        self.failUnlessEqual(response.status_code, 404)
+
+
+    def test_invalid_library(self):
+        response = self.client.get('/library/nottheone/')
+        self.failUnlessEqual(response.status_code, 404)
+
+
+    def test_library_no_key(self):
+        """
+        Make sure we get a 302 if we're not logged in
+        """
+        response = self.client.get('/samples/library/10981/json')
+        self.failUnlessEqual(response.status_code, 403)
+        response = self.client.get('/samples/library/10981/json', apidata)
+        self.failUnlessEqual(response.status_code, 200)
+
+    def test_library_rdf(self):
+        import RDF
+        from htsworkflow.util.rdfhelp import get_model, \
+             dump_model, \
+             fromTypedNode, \
+             load_string_into_model, \
+             rdfNS, \
+             libraryOntology
+        model = get_model()
+
+        response = self.client.get('/library/10981/')
+        self.assertEqual(response.status_code, 200)
+        content = response.content
+        load_string_into_model(model, 'rdfa', content)
+
+        body = """prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+        prefix libns: <http://jumpgate.caltech.edu/wiki/LibraryOntology#>
+
+        select ?library ?name ?library_id ?gel_cut ?made_by
+        where {
+           ?library a libns:library ;
+                    libns:name ?name ;
+                    libns:library_id ?library_id ;
+                    libns:gel_cut ?gel_cut ;
+                    libns:made_by ?made_by
+        }"""
+        query = RDF.SPARQLQuery(body)
+        for r in query.execute(model):
+            self.assertEqual(fromTypedNode(r['library_id']), u'10981')
+            self.assertEqual(fromTypedNode(r['name']),
+                             u'Paired End Multiplexed Sp-BAC')
+            self.assertEqual(fromTypedNode(r['gel_cut']), 400)
+            self.assertEqual(fromTypedNode(r['made_by']), u'Igor')
+
+        state = validate_xhtml(content)
+        if state is not None:
+            self.assertTrue(state)
+
+        # validate a library page.
+        from htsworkflow.util.rdfhelp import add_default_schemas
+        from htsworkflow.util.rdfinfer import Infer
+        add_default_schemas(model)
+        inference = Infer(model)
+        errmsgs = list(inference.run_validation())
+        self.assertEqual(len(errmsgs), 0)
+
+    def test_library_index_rdfa(self):
+        from htsworkflow.util.rdfhelp import \
+             add_default_schemas, get_model, load_string_into_model, \
+             dump_model
+        from htsworkflow.util.rdfinfer import Infer
+
+        model = get_model()
+        add_default_schemas(model)
+        inference = Infer(model)
+
+        response = self.client.get('/library/')
+        self.assertEqual(response.status_code, 200)
+        load_string_into_model(model, 'rdfa', response.content)
+
+        errmsgs = list(inference.run_validation())
+        self.assertEqual(len(errmsgs), 0)
+
+        body =  """prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+        prefix libns: <http://jumpgate.caltech.edu/wiki/LibraryOntology#>
+
+        select ?library ?library_id ?name ?species ?species_name
+        where {
+           ?library a libns:Library .
+           OPTIONAL { ?library libns:library_id ?library_id . }
+           OPTIONAL { ?library libns:species ?species .
+                      ?species libns:species_name ?species_name . }
+           OPTIONAL { ?library libns:name ?name . }
+        }"""
+        bindings = set(['library', 'library_id', 'name', 'species', 'species_name'])
+        query = RDF.SPARQLQuery(body)
+        count = 0
+        for r in query.execute(model):
+            count += 1
+            for name, value in r.items():
+                self.assertTrue(name in bindings)
+                self.assertTrue(value is not None)
+
+        self.assertEqual(count, len(Library.objects.filter(hidden=False)))
+
+        state = validate_xhtml(response.content)
+        if state is not None: self.assertTrue(state)
+
+
+# The django test runner flushes the database between test suites not cases,
+# so to be more compatible with running via nose we flush the database tables
+# of interest before creating our sample data.
+def create_db(obj):
+    obj.species_human = Species.objects.get(pk=8)
+    obj.experiment_rna_seq = ExperimentType.objects.get(pk=4)
+    obj.affiliation_alice = Affiliation.objects.get(pk=1)
+    obj.affiliation_bob = Affiliation.objects.get(pk=2)
+
+    Library.objects.all().delete()
+    obj.library_10001 = Library(
+        id = "10001",
+        library_name = 'C2C12 named poorly',
+        library_species = obj.species_human,
+        experiment_type = obj.experiment_rna_seq,
+        creation_date = datetime.datetime.now(),
+        made_for = 'scientist unit 2007',
+        made_by = 'microfludics system 7321',
+        stopping_point = '2A',
+        undiluted_concentration = '5.01',
+        hidden = False,
+    )
+    obj.library_10001.save()
+    obj.library_10002 = Library(
+        id = "10002",
+        library_name = 'Worm named poorly',
+        library_species = obj.species_human,
+        experiment_type = obj.experiment_rna_seq,
+        creation_date = datetime.datetime.now(),
+        made_for = 'scientist unit 2007',
+        made_by = 'microfludics system 7321',
+        stopping_point = '2A',
+        undiluted_concentration = '5.01',
+        hidden = False,
+    )
+    obj.library_10002.save()
+
+try:
+    import RDF
+    HAVE_RDF = True
+
+    rdfNS = RDF.NS("http://www.w3.org/1999/02/22-rdf-syntax-ns#")
+    xsdNS = RDF.NS("http://www.w3.org/2001/XMLSchema#")
+    libNS = RDF.NS("http://jumpgate.caltech.edu/wiki/LibraryOntology#")
+except ImportError,e:
+    HAVE_RDF = False
+
+
+class TestRDFaLibrary(TestCase):
+    fixtures = ['initial_data.json',
+                'woldlab.json',
+                'test_samples.json']
+
+    def test_parse_rdfa(self):
+        model = get_rdf_memory_model()
+        parser = RDF.Parser(name='rdfa')
+        url = '/library/10981/'
+        lib_response = self.client.get(url)
+        self.failIfEqual(len(lib_response.content), 0)
+
+        parser.parse_string_into_model(model,
+                                       lib_response.content,
+                                       'http://localhost'+url)
+        # http://jumpgate.caltech.edu/wiki/LibraryOntology#affiliation>
+        self.check_literal_object(model, ['Bob'], p=libNS['affiliation'])
+        self.check_literal_object(model, ['Multiplexed'], p=libNS['experiment_type'])
+        self.check_literal_object(model, ['400'], p=libNS['gel_cut'])
+        self.check_literal_object(model, ['Igor'], p=libNS['made_by'])
+        self.check_literal_object(model, ['Paired End Multiplexed Sp-BAC'], p=libNS['name'])
+        self.check_literal_object(model, ['Drosophila melanogaster'], p=libNS['species_name'])
+
+        self.check_uri_object(model,
+                              [u'http://localhost/lane/1193'],
+                              p=libNS['has_lane'])
+
+        fc_uri = RDF.Uri('http://localhost/flowcell/303TUAAXX/')
+        self.check_literal_object(model,
+                                  [u"303TUAAXX"],
+                                  s=fc_uri, p=libNS['flowcell_id'])
+
+    def check_literal_object(self, model, values, s=None, p=None, o=None):
+        statements = list(model.find_statements(
+            RDF.Statement(s,p,o)))
+        self.failUnlessEqual(len(statements), len(values),
+                        "Couln't find %s %s %s" % (s,p,o))
+        for s in statements:
+            self.failUnless(s.object.literal_value['string'] in values)
+
+
+    def check_uri_object(self, model, values, s=None, p=None, o=None):
+        statements = list(model.find_statements(
+            RDF.Statement(s,p,o)))
+        self.failUnlessEqual(len(statements), len(values),
+                        "Couln't find %s %s %s" % (s,p,o))
+        for s in statements:
+            self.failUnless(unicode(s.object.uri) in values)
+
+
+
+def get_rdf_memory_model():
+    storage = RDF.MemoryStorage()
+    model = RDF.Model(storage)
+    return model
+
+def suite():
+    from unittest import TestSuite, defaultTestLoader
+    suite = TestSuite()
+    suite.addTests(defaultTestLoader.loadTestsFromTestCase(LibraryTestCase))
+    suite.addTests(defaultTestLoader.loadTestsFromTestCase(SampleWebTestCase))
+    suite.addTests(defaultTestLoader.loadTestsFromTestCase(TestRDFaLibrary))
+    return suite
+
+if __name__ == "__main__":
+    from unittest import main
+    main(defaultTest="suite")
diff --git a/samples/urls.py b/samples/urls.py
new file mode 100644 (file)
index 0000000..3d09dd4
--- /dev/null
@@ -0,0 +1,14 @@
+from django.conf.urls import patterns, url
+
+urlpatterns = patterns('samples.views',
+    # View livrary list
+    url(r'^$', 'library'),
+    url(r'^not_run/$', 'library_not_run'),
+    url(r'^(?P<lib_id>\w+)/$',
+        'library_to_flowcells'),
+
+    url(r"^library/(?P<library_id>\w+)/json$", 'library_json'),
+    url(r"^species/(?P<species_id>\w+)/json$", 'species_json'),
+    url(r"^species/(?P<species_id>\w+)$", 'species'),
+    url(r"^antibody/$", 'antibodies'),
+)
diff --git a/samples/views.py b/samples/views.py
new file mode 100644 (file)
index 0000000..3e35898
--- /dev/null
@@ -0,0 +1,566 @@
+from __future__ import absolute_import, print_function
+
+# Create your views here.
+import StringIO
+import logging
+import os
+import sys
+
+try:
+    import json
+except ImportError, e:
+    import simplejson as json
+
+from django.views.decorators.csrf import csrf_exempt
+from django.core.exceptions import ObjectDoesNotExist
+from django.http import HttpResponse, HttpResponseRedirect, Http404
+from django.shortcuts import render_to_response, get_object_or_404
+from django.template import RequestContext
+from django.template.loader import get_template
+from django.contrib.auth.decorators import login_required
+from django.conf import settings
+
+from htsworkflow.auth import require_api_key
+from experiments.models import FlowCell, Lane, LANE_STATUS_MAP
+from experiments.admin import LaneOptions
+from .changelist import HTSChangeList
+from .models import Antibody, Library, Species, HTSUser
+from .admin import LibraryOptions
+from .results import get_flowcell_result_dict
+from bcmagic.forms import BarcodeMagicForm
+from htsworkflow.pipelines import runfolder
+from htsworkflow.pipelines.eland import ResultLane
+from htsworkflow.pipelines.samplekey import SampleKey
+from htsworkflow.util.conversion import unicode_or_none, parse_flowcell_id
+from htsworkflow.util import makebed
+from htsworkflow.util import opener
+
+
+
+LANE_LIST = [1,2,3,4,5,6,7,8]
+SAMPLES_CONTEXT_DEFAULTS = {
+    'app_name': 'Flowcell/Library Tracker',
+    'bcmagic': BarcodeMagicForm()
+}
+
+LOGGER = logging.getLogger(__name__)
+
+def count_lanes(lane_set):
+    single = 0
+    paired = 1
+    short_read = 0
+    medium_read = 1
+    long_read = 2
+    counts = [[0,0,0,],[0,0,0]]
+
+    for lane in lane_set.all():
+        if lane.flowcell.paired_end:
+            lane_type = paired
+        else:
+            lane_type = single
+        if lane.flowcell.read_length < 40:
+            read_type = short_read
+        elif lane.flowcell.read_length < 100:
+            read_type = medium_read
+        else:
+            read_type = long_read
+        counts[lane_type][read_type] += 1
+
+    return counts
+
+def create_library_context(cl):
+    """
+     Create a list of libraries that includes how many lanes were run
+    """
+    records = []
+    #for lib in library_items.object_list:
+    for lib in cl.result_list:
+       summary = {}
+       summary['library'] = lib
+       summary['library_id'] = lib.id
+       summary['library_name'] = lib.library_name
+       summary['species_name' ] = lib.library_species.scientific_name
+       if lib.amplified_from_sample is not None:
+           summary['amplified_from'] = lib.amplified_from_sample.id
+       else:
+           summary['amplified_from'] = ''
+       lanes_run = count_lanes(lib.lane_set)
+       # suppress zeros
+       for row in xrange(len(lanes_run)):
+           for col in xrange(len(lanes_run[row])):
+               if lanes_run[row][col] == 0:
+                   lanes_run[row][col] = ''
+       summary['lanes_run'] = lanes_run
+       summary['is_archived'] = lib.is_archived()
+       records.append(summary)
+    cl.result_count = unicode(cl.paginator._count)
+    return {'library_list': records }
+
+
+def library(request, todo_only=False):
+    queryset = Library.objects.filter(hidden__exact=0)
+    filters = {'hidden__exact': 0}
+    if todo_only:
+        filters['lane'] = None
+    # build changelist
+    fcl = HTSChangeList(request, Library,
+        list_filter=['affiliations', 'library_species'],
+        search_fields=['id', 'library_name', 'amplified_from_sample__id'],
+        list_per_page=200,
+        model_admin=LibraryOptions(Library, None),
+        extra_filters=filters
+    )
+
+    context = { 'cl': fcl, 'title': 'Library Index', 'todo_only': todo_only}
+    context.update(create_library_context(fcl))
+    t = get_template('samples/library_index.html')
+    c = RequestContext(request, context)
+    return HttpResponse( t.render(c) )
+
+
+def library_not_run(request):
+    return library(request, todo_only=True)
+
+
+def library_to_flowcells(request, lib_id):
+    """
+    Display information about all the flowcells a library has been run on.
+    """
+    try:
+        lib = Library.objects.get(id=lib_id)
+    except:
+        raise Http404('Library %s does not exist' % (lib_id,))
+
+    flowcell_list = []
+    flowcell_run_results = {} # aka flowcells we're looking at
+    for lane in lib.lane_set.all():
+        fc = lane.flowcell
+        flowcell_id, id = parse_flowcell_id(fc.flowcell_id)
+        if flowcell_id not in flowcell_run_results:
+            flowcell_run_results[flowcell_id] = get_flowcell_result_dict(flowcell_id)
+        flowcell_list.append((fc.flowcell_id, lane.lane_number))
+
+    flowcell_list.sort()
+    lane_summary_list = []
+    eland_results = []
+    for fc, lane_number in flowcell_list:
+        lane_summary, err_list = _summary_stats(fc, lane_number, lib_id)
+        lane_summary_list.extend(lane_summary)
+
+        eland_results.extend(_make_eland_results(fc, lane_number, flowcell_run_results))
+
+    context = {
+        'page_name': 'Library Details',
+        'lib': lib,
+        'eland_results': eland_results,
+        'lane_summary_list': lane_summary_list,
+    }
+    context.update(SAMPLES_CONTEXT_DEFAULTS)
+
+    return render_to_response(
+        'samples/library_detail.html',
+        context,
+        context_instance = RequestContext(request))
+
+def lanes_for(request, username=None):
+    """
+    Generate a report of recent activity for a user
+    """
+    query = {}
+    if username is not None:
+        user = HTSUser.objects.get(username=username)
+        query.update({'library__affiliations__users__id':user.id})
+    fcl = HTSChangeList(request, Lane,
+        list_filter=[],
+        search_fields=['flowcell__flowcell_id', 'library__id', 'library__library_name'],
+        list_per_page=200,
+        model_admin=LaneOptions,
+        queryset=Lane.objects.filter(**query)
+    )
+
+    context = { 'lanes': fcl, 'title': 'Lane Index'}
+
+    return render_to_response(
+        'samples/lanes_for.html',
+        context,
+        context_instance = RequestContext(request)
+    )
+
+
+def summaryhtm_fc_cnm(request, flowcell_id, cnm):
+    """
+    returns a Summary.htm file if it exists.
+    """
+    fc_id, status = parse_flowcell_id(flowcell_id)
+    d = get_flowcell_result_dict(fc_id)
+
+    if d is None:
+        return HttpResponse('<b>Results for Flowcell %s not found.</b>' % (fc_id))
+
+    if cnm not in d:
+        return HttpResponse('<b>Results for Flowcell %s; %s not found.</b>' % (fc_id, cnm))
+
+    summary_filepath = d[cnm]['summary']
+
+    if summary_filepath is None:
+        return HttpResponse('<b>Summary.htm for Flowcell %s; %s not found.</b>' % (fc_id, cnm))
+
+    f = open(summary_filepath, 'r')
+
+    return HttpResponse(f)
+
+
+def result_fc_cnm_eland_lane(request, flowcell_id, cnm, lane):
+    """
+    returns an eland_file upon calling.
+    """
+    fc_id, status = parse_flowcell_id(flowcell_id)
+    d = get_flowcell_result_dict(fc_id)
+
+    if d is None:
+        return HttpResponse('<b>Results for Flowcell %s not found.</b>' % (fc_id))
+
+    if cnm not in d:
+        return HttpResponse('<b>Results for Flowcell %s; %s not found.</b>' % (fc_id, cnm))
+
+    erd = d[cnm]['eland_results']
+    lane = int(lane)
+
+    if lane not in erd:
+        return HttpResponse('<b>Results for Flowcell %s; %s; lane %s not found.</b>' % (fc_id, cnm, lane))
+
+    filepath = erd[lane]
+
+    #f = opener.autoopen(filepath, 'r')
+    # return HttpResponse(f, content_type="application/x-elandresult")
+
+    f = open(filepath, 'r')
+    return HttpResponse(f, content_type='application/x-bzip2')
+
+
+
+def bedfile_fc_cnm_eland_lane_ucsc(request, fc_id, cnm, lane):
+    """
+    returns a bed file for a given flowcell, CN-M (i.e. C1-33), and lane (ucsc compatible)
+    """
+    return bedfile_fc_cnm_eland_lane(request, fc_id, cnm, lane, ucsc_compatible=True)
+
+
+def bedfile_fc_cnm_eland_lane(request, flowcell_id, cnm, lane, ucsc_compatible=False):
+    """
+    returns a bed file for a given flowcell, CN-M (i.e. C1-33), and lane
+    """
+    fc_id, status = parse_flowcell_id(flowcell_id)
+    d = get_flowcell_result_dict(fc_id)
+
+    if d is None:
+        return HttpResponse('<b>Results for Flowcell %s not found.</b>' % (fc_id))
+
+    if cnm not in d:
+        return HttpResponse('<b>Results for Flowcell %s; %s not found.</b>' % (fc_id, cnm))
+
+    erd = d[cnm]['eland_results']
+    lane = int(lane)
+
+    if lane not in erd:
+        return HttpResponse('<b>Results for Flowcell %s; %s; lane %s not found.</b>' % (fc_id, cnm, lane))
+
+    filepath = erd[lane]
+
+    # Eland result file
+    fi = opener.autoopen(filepath, 'r')
+    # output memory file
+
+    name, description = makebed.make_description( fc_id, lane )
+
+    bedgen = makebed.make_bed_from_eland_generator(fi, name, description)
+
+    if ucsc_compatible:
+        return HttpResponse(bedgen)
+    else:
+        return HttpResponse(bedgen, content_type="application/x-bedfile")
+
+
+def _summary_stats(flowcell_id, lane_id, library_id):
+    """
+    Return the summary statistics for a given flowcell, lane, and end.
+    """
+    fc_id, status = parse_flowcell_id(flowcell_id)
+    fc_result_dict = get_flowcell_result_dict(fc_id)
+
+    summary_list = []
+    err_list = []
+
+    if fc_result_dict is None:
+        err_list.append('Results for Flowcell %s not found.' % (fc_id))
+        return (summary_list, err_list)
+
+    for cycle_width in fc_result_dict:
+        xmlpath = fc_result_dict[cycle_width]['run_xml']
+
+        if xmlpath is None:
+            err_list.append('Run xml for Flowcell %s(%s) not found.' % (fc_id, cycle_width))
+            continue
+
+        run = runfolder.load_pipeline_run_xml(xmlpath)
+        # skip if we don't have available metadata.
+        if run.gerald is None or run.gerald.summary is None:
+            continue
+        
+        gerald_summary = run.gerald.summary.lane_results
+        key = SampleKey(lane=lane_id, sample='s')
+        eland_results = list(run.gerald.eland_results.find_keys(key))
+        key = SampleKey(lane=lane_id, sample=library_id)
+        eland_results.extend(run.gerald.eland_results.find_keys(key))
+        for key in eland_results:
+            eland_summary = run.gerald.eland_results.results[key]
+            # add information to lane_summary
+            eland_summary.flowcell_id = flowcell_id
+
+            read = key.read-1 if key.read is not None else 0
+            try:
+                eland_summary.clusters = gerald_summary[read][key.lane].cluster
+            except (IndexError, KeyError) as e:
+                eland_summary.clustes = None
+            eland_summary.cycle_width = cycle_width
+            if hasattr(eland_summary, 'genome_map'):
+                eland_summary.summarized_reads = runfolder.summarize_mapped_reads(
+                                                   eland_summary.genome_map,
+                                                   eland_summary.mapped_reads)
+
+            # grab some more information out of the flowcell db
+            flowcell = FlowCell.objects.get(flowcell_id=flowcell_id)
+            #pm_field = 'lane_%d_pM' % (lane_id)
+            lanes = flowcell.lane_set.filter(lane_number=lane_id)
+            eland_summary.flowcell = flowcell
+            eland_summary.lanes = lanes
+
+            summary_list.append(eland_summary)
+
+        #except Exception, e:
+        #    summary_list.append("Summary report needs to be updated.")
+        #    LOGGER.error("Exception: " + str(e))
+
+    return (summary_list, err_list)
+
+
+def get_eland_result_type(pathname):
+    """
+    Guess the eland result file type from the filename
+    """
+    path, filename = os.path.split(pathname)
+    if 'extended' in filename:
+        return 'extended'
+    elif 'multi' in filename:
+        return 'multi'
+    elif 'result' in filename:
+        return 'result'
+    else:
+        return 'unknown'
+
+def _make_eland_results(flowcell_id, lane_number, interesting_flowcells):
+    fc_id, status = parse_flowcell_id(flowcell_id)
+    cur_fc = interesting_flowcells.get(fc_id, None)
+    if cur_fc is None:
+      return []
+
+    flowcell = FlowCell.objects.get(flowcell_id=flowcell_id)
+    lanes = flowcell.lane_set.filter(lane_number=lane_number)
+    # Loop throw storage devices if a result has been archived
+    storage_id_list = []
+    if cur_fc is not None:
+        for lts in flowcell.longtermstorage_set.all():
+            for sd in lts.storage_devices.all():
+                # Use barcode_id if it exists
+                if sd.barcode_id is not None and sd.barcode_id != '':
+                    storage_id_list.append(sd.barcode_id)
+                # Otherwise use UUID
+                else:
+                    storage_id_list.append(sd.uuid)
+
+    # Formatting for template use
+    if len(storage_id_list) == 0:
+        storage_ids = None
+    else:
+        storage_ids = ', '.join([ '<a href="/inventory/%s/">%s</a>' % (s,s) for s in storage_id_list ])
+
+    results = []
+    for cycle in cur_fc.keys():
+        result_path = cur_fc[cycle]['eland_results'].get(lanes[0], None)
+        result_link = make_result_link(fc_id, cycle, lanes[0], result_path)
+        results.append({'flowcell_id': fc_id,
+                        'flowcell': flowcell,
+                        'run_date': flowcell.run_date,
+                        'cycle': cycle,
+                        'lane': lanes[0],
+                        'summary_url': make_summary_url(flowcell_id, cycle),
+                        'result_url': result_link[0],
+                        'result_label': result_link[1],
+                        'bed_url': result_link[2],
+                        'storage_ids': storage_ids
+        })
+    return results
+
+def make_summary_url(flowcell_id, cycle_name):
+    url = '/results/%s/%s/summary/' % (flowcell_id, cycle_name)
+    return url
+
+def make_result_link(flowcell_id, cycle_name, lane, eland_result_path):
+    if eland_result_path is None:
+        return ("", "", "")
+
+    result_type = get_eland_result_type(eland_result_path)
+    result_url = '/results/%s/%s/eland_result/%s' % (flowcell_id, cycle_name, lane)
+    result_label = 'eland %s' % (result_type,)
+    bed_url = None
+    if result_type == 'result':
+       bed_url_pattern = '/results/%s/%s/bedfile/%s'
+       bed_url = bed_url_pattern % (flowcell_id, cycle_name, lane)
+
+    return (result_url, result_label, bed_url)
+
+def _files(flowcell_id, lane):
+    """
+    Sets up available files for download
+    """
+    lane = int(lane)
+
+    flowcell_id, id = parse_flowcell_id(flowcell_id)
+    d = get_flowcell_result_dict(flowcell_id)
+
+    if d is None:
+        return ''
+
+    output = []
+
+    # c_name == 'CN-M' (i.e. C1-33)
+    for c_name in d:
+
+        if d[c_name]['summary'] is not None:
+            output.append('<a href="/results/%s/%s/summary/">summary(%s)</a>' \
+                          % (flowcell_id, c_name, c_name))
+
+        erd = d[c_name]['eland_results']
+        if lane in erd:
+            result_type = get_eland_result_type(erd[lane])
+            result_url_pattern = '<a href="/results/%s/%s/eland_result/%s">eland %s(%s)</a>'
+            output.append(result_url_pattern % (flowcell_id, c_name, lane, result_type, c_name))
+            if result_type == 'result':
+                bed_url_pattern = '<a href="/results/%s/%s/bedfile/%s">bedfile(%s)</a>'
+                output.append(bed_url_pattern % (flowcell_id, c_name, lane, c_name))
+
+    if len(output) == 0:
+        return ''
+
+    return '(' + '|'.join(output) + ')'
+
+def library_id_to_admin_url(request, lib_id):
+    lib = Library.objects.get(id=lib_id)
+    return HttpResponseRedirect('/admin/samples/library/%s' % (lib.id,))
+
+def library_dict(library_id):
+    """
+    Given a library id construct a dictionary containing important information
+    return None if nothing was found
+    """
+    try:
+        lib = Library.objects.get(id = library_id)
+    except Library.DoesNotExist, e:
+        return None
+
+    #lane_info = lane_information(lib.lane_set)
+    lane_info = []
+    for lane in lib.lane_set.all():
+        lane_info.append( {'flowcell':lane.flowcell.flowcell_id,
+                           'lane_number': lane.lane_number,
+                           'lane_id': lane.id,
+                           'paired_end': lane.flowcell.paired_end,
+                           'read_length': lane.flowcell.read_length,
+                           'status_code': lane.status,
+                           'status': LANE_STATUS_MAP[lane.status]} )
+
+    info = {
+        # 'affiliations'?
+        # 'aligned_reads': lib.aligned_reads,
+        #'amplified_into_sample': lib.amplified_into_sample, # into is a colleciton...
+        #'amplified_from_sample_id': lib.amplified_from_sample,
+        #'antibody_name': lib.antibody_name(), # we have no antibodies.
+        'antibody_id': lib.antibody_id,
+        'cell_line_id': lib.cell_line_id,
+        'cell_line': unicode_or_none(lib.cell_line),
+        'experiment_type': lib.experiment_type.name,
+        'experiment_type_id': lib.experiment_type_id,
+        'gel_cut_size': lib.gel_cut_size,
+        'hidden': lib.hidden,
+        'id': lib.id,
+        'insert_size': lib.insert_size,
+        'lane_set': lane_info,
+        'library_id': lib.id,
+        'library_name': lib.library_name,
+        'library_species': lib.library_species.scientific_name,
+        'library_species_id': lib.library_species_id,
+        #'library_type': lib.library_type.name,
+        'library_type_id': lib.library_type_id,
+        'made_for': lib.made_for,
+        'made_by': lib.made_by,
+        'notes': lib.notes,
+        'replicate': lib.replicate,
+        'stopping_point': lib.stopping_point,
+        'successful_pM': unicode_or_none(lib.successful_pM),
+        'undiluted_concentration': unicode_or_none(lib.undiluted_concentration)
+        }
+    if lib.library_type_id is None:
+        info['library_type'] = None
+    else:
+        info['library_type'] = lib.library_type.name
+    return info
+
+@csrf_exempt
+def library_json(request, library_id):
+    """
+    Return a json formatted library dictionary
+    """
+    require_api_key(request)
+    # what validation should we do on library_id?
+
+    lib = library_dict(library_id)
+    if lib is None:
+        raise Http404
+
+    lib_json = json.dumps(lib)
+    return HttpResponse(lib_json, content_type='application/json')
+
+@csrf_exempt
+def species_json(request, species_id):
+    """
+    Return information about a species.
+    """
+    raise Http404
+
+def species(request, species_id):
+    species = get_object_or_404(Species, id=species_id)
+
+    context = RequestContext(request,
+                             { 'species': species })
+
+    return render_to_response("samples/species_detail.html", context)
+
+def antibodies(request):
+    context = RequestContext(request,
+                             {'antibodies': Antibody.objects.order_by('antigene')})
+    return render_to_response("samples/antibody_index.html", context)
+
+@login_required
+def user_profile(request):
+    """
+    Information about the user
+    """
+    context = {
+                'page_name': 'User Profile',
+                'media': '',
+                #'bcmagic': BarcodeMagicForm(),
+                #'select': 'settings',
+            }
+    context.update(SAMPLES_CONTEXT_DEFAULTS)
+    return render_to_response('registration/profile.html', context,
+                              context_instance=RequestContext(request))