summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFilipp Lepalaan <f@230.to>2014-02-19 09:29:17 +0200
committerFilipp Lepalaan <f@230.to>2014-02-19 09:29:17 +0200
commitcfc7c3f52544af8a71d3fa3988a06fee200d2c24 (patch)
treef5eecbb882aea800e9b0707a831f6569de07a853
parentd3e089b71b64cfc1f9f96be141f41806ce5b9e77 (diff)
downloadpudding-cfc7c3f52544af8a71d3fa3988a06fee200d2c24.tar.gz
pudding-cfc7c3f52544af8a71d3fa3988a06fee200d2c24.tar.bz2
pudding-cfc7c3f52544af8a71d3fa3988a06fee200d2c24.zip
better
-rw-r--r--apps/it/migrations/0005_auto__add_field_issue_created_at.py98
-rw-r--r--apps/it/migrations/0006_auto__add_field_issue_updated_at__add_field_task_updated_at.py108
-rw-r--r--apps/it/migrations/0007_auto__add_article__add_field_issue_created_by__chg_field_task_created_.py128
-rw-r--r--apps/it/migrations/0008_auto__add_field_asset_kind__add_field_asset_contact__add_field_article.py128
-rw-r--r--apps/it/migrations/0009_auto__add_field_issue_state.py113
-rw-r--r--apps/it/migrations/0010_auto__add_taggeditem__add_unique_taggeditem_content_type_object_id_tag.py136
-rw-r--r--apps/it/models.py102
-rwxr-xr-xapps/it/static/images/arrow-down-512.pngbin0 -> 106895 bytes
-rwxr-xr-xapps/it/static/js/sb-admin.js2
-rwxr-xr-xapps/it/templates/default.html573
-rw-r--r--apps/it/templates/edit_issue.html10
-rw-r--r--apps/it/templates/edit_task.html2
-rw-r--r--apps/it/templates/list_issues.html30
-rw-r--r--apps/it/templates/list_stuff.html29
-rw-r--r--apps/it/templates/view_issue.html72
-rw-r--r--apps/it/templatetags/__init__.py0
-rw-r--r--apps/it/templatetags/it_tags.py13
-rw-r--r--apps/it/views.py105
-rw-r--r--it/settings.py3
-rw-r--r--it/urls.py9
-rw-r--r--requirements.txt3
-rw-r--r--uploads/attachments/Screen_Shot_2014-01-21_at_20.40.39.pngbin0 -> 250360 bytes
-rw-r--r--uploads/attachments/Screen_Shot_2014-01-26_at_13.11.35.pngbin0 -> 86901 bytes
-rw-r--r--uploads/attachments/Screen_Shot_2014-01-26_at_13.11.35_1.pngbin0 -> 86901 bytes
-rw-r--r--uploads/attachments/Screen_Shot_2014-02-01_at_10.47.31.pngbin0 -> 69570 bytes
-rw-r--r--uploads/attachments/arrow-down-512.pngbin0 -> 106895 bytes
-rw-r--r--uploads/attachments/arrow-down-512_1.pngbin0 -> 106895 bytes
27 files changed, 1313 insertions, 351 deletions
diff --git a/apps/it/migrations/0005_auto__add_field_issue_created_at.py b/apps/it/migrations/0005_auto__add_field_issue_created_at.py
new file mode 100644
index 0000000..aaf6045
--- /dev/null
+++ b/apps/it/migrations/0005_auto__add_field_issue_created_at.py
@@ -0,0 +1,98 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Issue.created_at'
+ db.add_column(u'it_issue', 'created_at',
+ self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, default=datetime.datetime(2014, 2, 17, 0, 0), blank=True),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Issue.created_at'
+ db.delete_column(u'it_issue', 'created_at')
+
+
+ models = {
+ u'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ u'auth.permission': {
+ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ u'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ u'it.asset': {
+ 'Meta': {'object_name': 'Asset'},
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_address': ('django.db.models.fields.IPAddressField', [], {'default': "''", 'max_length': '15'}),
+ 'issues': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['it.Issue']", 'null': 'True', 'symmetrical': 'False'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
+ 'name': ('django.db.models.fields.CharField', [], {'default': "'New Asset'", 'max_length': '256'})
+ },
+ u'it.attachment': {
+ 'Meta': {'object_name': 'Attachment'},
+ 'attachment': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ u'it.issue': {
+ 'Meta': {'ordering': "['priority', 'created_at']", 'object_name': 'Issue'},
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'priority': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'users': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'metoo'", 'null': 'True', 'symmetrical': 'False', 'to': u"orm['auth.User']"})
+ },
+ u'it.task': {
+ 'Meta': {'object_name': 'Task'},
+ 'assigned_to': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tasks'", 'null': 'True', 'to': u"orm['auth.User']"}),
+ 'completed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'due_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issue': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['it.Issue']", 'null': 'True'}),
+ 'step': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ }
+ }
+
+ complete_apps = ['it'] \ No newline at end of file
diff --git a/apps/it/migrations/0006_auto__add_field_issue_updated_at__add_field_task_updated_at.py b/apps/it/migrations/0006_auto__add_field_issue_updated_at__add_field_task_updated_at.py
new file mode 100644
index 0000000..50954eb
--- /dev/null
+++ b/apps/it/migrations/0006_auto__add_field_issue_updated_at__add_field_task_updated_at.py
@@ -0,0 +1,108 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Issue.updated_at'
+ db.add_column(u'it_issue', 'updated_at',
+ self.gf('django.db.models.fields.DateTimeField')(auto_now=True, default=datetime.datetime(2014, 2, 17, 0, 0), blank=True),
+ keep_default=False)
+
+ # Adding field 'Task.updated_at'
+ db.add_column(u'it_task', 'updated_at',
+ self.gf('django.db.models.fields.DateTimeField')(auto_now=True, default=datetime.datetime(2014, 2, 17, 0, 0), blank=True),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Issue.updated_at'
+ db.delete_column(u'it_issue', 'updated_at')
+
+ # Deleting field 'Task.updated_at'
+ db.delete_column(u'it_task', 'updated_at')
+
+
+ models = {
+ u'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ u'auth.permission': {
+ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ u'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ u'it.asset': {
+ 'Meta': {'object_name': 'Asset'},
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_address': ('django.db.models.fields.IPAddressField', [], {'default': "''", 'max_length': '15'}),
+ 'issues': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['it.Issue']", 'null': 'True', 'symmetrical': 'False'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
+ 'name': ('django.db.models.fields.CharField', [], {'default': "'New Asset'", 'max_length': '256'})
+ },
+ u'it.attachment': {
+ 'Meta': {'object_name': 'Attachment'},
+ 'attachment': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ u'it.issue': {
+ 'Meta': {'ordering': "['-priority', 'created_at']", 'object_name': 'Issue'},
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'priority': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'metoo'", 'null': 'True', 'to': u"orm['auth.User']"})
+ },
+ u'it.task': {
+ 'Meta': {'object_name': 'Task'},
+ 'assigned_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tasks'", 'null': 'True', 'to': u"orm['auth.User']"}),
+ 'completed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'due_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issue': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['it.Issue']", 'null': 'True'}),
+ 'step': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['it'] \ No newline at end of file
diff --git a/apps/it/migrations/0007_auto__add_article__add_field_issue_created_by__chg_field_task_created_.py b/apps/it/migrations/0007_auto__add_article__add_field_issue_created_by__chg_field_task_created_.py
new file mode 100644
index 0000000..bfe9e67
--- /dev/null
+++ b/apps/it/migrations/0007_auto__add_article__add_field_issue_created_by__chg_field_task_created_.py
@@ -0,0 +1,128 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'Article'
+ db.create_table(u'it_article', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('note', self.gf('django.db.models.fields.TextField')()),
+ ('created_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+ ))
+ db.send_create_signal(u'it', ['Article'])
+
+ # Adding field 'Issue.created_by'
+ db.add_column(u'it_issue', 'created_by',
+ self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['auth.User']),
+ keep_default=False)
+
+
+ # Changing field 'Task.created_by'
+ db.alter_column(u'it_task', 'created_by_id', self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['auth.User']))
+
+ def backwards(self, orm):
+ # Deleting model 'Article'
+ db.delete_table(u'it_article')
+
+ # Deleting field 'Issue.created_by'
+ db.delete_column(u'it_issue', 'created_by_id')
+
+
+ # Changing field 'Task.created_by'
+ db.alter_column(u'it_task', 'created_by_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True))
+
+ models = {
+ u'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ u'auth.permission': {
+ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ u'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ u'it.article': {
+ 'Meta': {'object_name': 'Article'},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'note': ('django.db.models.fields.TextField', [], {}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ u'it.asset': {
+ 'Meta': {'object_name': 'Asset'},
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_address': ('django.db.models.fields.IPAddressField', [], {'default': "''", 'max_length': '15'}),
+ 'issues': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['it.Issue']", 'null': 'True', 'symmetrical': 'False'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
+ 'name': ('django.db.models.fields.CharField', [], {'default': "'New Asset'", 'max_length': '256'})
+ },
+ u'it.attachment': {
+ 'Meta': {'object_name': 'Attachment'},
+ 'attachment': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ u'it.issue': {
+ 'Meta': {'ordering': "['-priority', 'created_at']", 'object_name': 'Issue'},
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'priority': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'metoo'", 'null': 'True', 'to': u"orm['auth.User']"})
+ },
+ u'it.task': {
+ 'Meta': {'ordering': "['-created_at']", 'object_name': 'Task'},
+ 'assigned_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tasks'", 'null': 'True', 'to': u"orm['auth.User']"}),
+ 'completed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'due_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issue': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['it.Issue']", 'null': 'True'}),
+ 'step': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['it'] \ No newline at end of file
diff --git a/apps/it/migrations/0008_auto__add_field_asset_kind__add_field_asset_contact__add_field_article.py b/apps/it/migrations/0008_auto__add_field_asset_kind__add_field_asset_contact__add_field_article.py
new file mode 100644
index 0000000..86677c8
--- /dev/null
+++ b/apps/it/migrations/0008_auto__add_field_asset_kind__add_field_asset_contact__add_field_article.py
@@ -0,0 +1,128 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Asset.kind'
+ db.add_column(u'it_asset', 'kind',
+ self.gf('django.db.models.fields.CharField')(default='SERVER', max_length=128),
+ keep_default=False)
+
+ # Adding field 'Asset.contact'
+ db.add_column(u'it_asset', 'contact',
+ self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True),
+ keep_default=False)
+
+ # Adding field 'Article.title'
+ db.add_column(u'it_article', 'title',
+ self.gf('django.db.models.fields.CharField')(default='New Article', max_length=256),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Asset.kind'
+ db.delete_column(u'it_asset', 'kind')
+
+ # Deleting field 'Asset.contact'
+ db.delete_column(u'it_asset', 'contact_id')
+
+ # Deleting field 'Article.title'
+ db.delete_column(u'it_article', 'title')
+
+
+ models = {
+ u'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ u'auth.permission': {
+ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ u'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ u'it.article': {
+ 'Meta': {'object_name': 'Article'},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'note': ('django.db.models.fields.TextField', [], {}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "'New Article'", 'max_length': '256'})
+ },
+ u'it.asset': {
+ 'Meta': {'object_name': 'Asset'},
+ 'contact': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_address': ('django.db.models.fields.IPAddressField', [], {'default': "''", 'max_length': '15'}),
+ 'issues': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['it.Issue']", 'null': 'True', 'symmetrical': 'False'}),
+ 'kind': ('django.db.models.fields.CharField', [], {'default': "'SERVER'", 'max_length': '128'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
+ 'name': ('django.db.models.fields.CharField', [], {'default': "'New Asset'", 'max_length': '256'})
+ },
+ u'it.attachment': {
+ 'Meta': {'object_name': 'Attachment'},
+ 'attachment': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ u'it.issue': {
+ 'Meta': {'ordering': "['-priority', 'created_at']", 'object_name': 'Issue'},
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'priority': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'metoo'", 'null': 'True', 'to': u"orm['auth.User']"})
+ },
+ u'it.task': {
+ 'Meta': {'ordering': "['-created_at']", 'object_name': 'Task'},
+ 'assigned_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tasks'", 'null': 'True', 'to': u"orm['auth.User']"}),
+ 'completed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'due_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issue': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['it.Issue']", 'null': 'True'}),
+ 'step': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['it'] \ No newline at end of file
diff --git a/apps/it/migrations/0009_auto__add_field_issue_state.py b/apps/it/migrations/0009_auto__add_field_issue_state.py
new file mode 100644
index 0000000..93c3755
--- /dev/null
+++ b/apps/it/migrations/0009_auto__add_field_issue_state.py
@@ -0,0 +1,113 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Issue.state'
+ db.add_column(u'it_issue', 'state',
+ self.gf('django.db.models.fields.CharField')(default='NEW', max_length=32),
+ keep_default=False)
+
+
+ def backwards(self, orm):
+ # Deleting field 'Issue.state'
+ db.delete_column(u'it_issue', 'state')
+
+
+ models = {
+ u'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ u'auth.permission': {
+ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ u'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ u'it.article': {
+ 'Meta': {'object_name': 'Article'},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'note': ('django.db.models.fields.TextField', [], {}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "'New Article'", 'max_length': '256'})
+ },
+ u'it.asset': {
+ 'Meta': {'object_name': 'Asset'},
+ 'contact': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_address': ('django.db.models.fields.IPAddressField', [], {'default': "''", 'max_length': '15'}),
+ 'issues': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['it.Issue']", 'null': 'True', 'symmetrical': 'False'}),
+ 'kind': ('django.db.models.fields.CharField', [], {'default': "'SERVER'", 'max_length': '128'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
+ 'name': ('django.db.models.fields.CharField', [], {'default': "'New Asset'", 'max_length': '256'})
+ },
+ u'it.attachment': {
+ 'Meta': {'object_name': 'Attachment'},
+ 'attachment': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ u'it.issue': {
+ 'Meta': {'ordering': "['-priority', 'created_at']", 'object_name': 'Issue'},
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'priority': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'state': ('django.db.models.fields.CharField', [], {'default': "'NEW'", 'max_length': '32'}),
+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'metoo'", 'null': 'True', 'to': u"orm['auth.User']"})
+ },
+ u'it.task': {
+ 'Meta': {'ordering': "['-created_at']", 'object_name': 'Task'},
+ 'assigned_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tasks'", 'null': 'True', 'to': u"orm['auth.User']"}),
+ 'completed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'due_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issue': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['it.Issue']", 'null': 'True'}),
+ 'step': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['it'] \ No newline at end of file
diff --git a/apps/it/migrations/0010_auto__add_taggeditem__add_unique_taggeditem_content_type_object_id_tag.py b/apps/it/migrations/0010_auto__add_taggeditem__add_unique_taggeditem_content_type_object_id_tag.py
new file mode 100644
index 0000000..6312a3c
--- /dev/null
+++ b/apps/it/migrations/0010_auto__add_taggeditem__add_unique_taggeditem_content_type_object_id_tag.py
@@ -0,0 +1,136 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'TaggedItem'
+ db.create_table(u'it_taggeditem', (
+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('created_by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
+ ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
+ ('tag', self.gf('django.db.models.fields.CharField')(max_length=128)),
+ ('slug', self.gf('django.db.models.fields.SlugField')(max_length=50)),
+ ('color', self.gf('django.db.models.fields.CharField')(default='', max_length=8)),
+ ))
+ db.send_create_signal(u'it', ['TaggedItem'])
+
+ # Adding unique constraint on 'TaggedItem', fields ['content_type', 'object_id', 'tag']
+ db.create_unique(u'it_taggeditem', ['content_type_id', 'object_id', 'tag'])
+
+
+ def backwards(self, orm):
+ # Removing unique constraint on 'TaggedItem', fields ['content_type', 'object_id', 'tag']
+ db.delete_unique(u'it_taggeditem', ['content_type_id', 'object_id', 'tag'])
+
+ # Deleting model 'TaggedItem'
+ db.delete_table(u'it_taggeditem')
+
+
+ models = {
+ u'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ u'auth.permission': {
+ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ u'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ u'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ u'it.article': {
+ 'Meta': {'object_name': 'Article'},
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'note': ('django.db.models.fields.TextField', [], {}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "'New Article'", 'max_length': '256'})
+ },
+ u'it.asset': {
+ 'Meta': {'object_name': 'Asset'},
+ 'contact': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_address': ('django.db.models.fields.IPAddressField', [], {'default': "''", 'max_length': '15'}),
+ 'issues': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['it.Issue']", 'null': 'True', 'symmetrical': 'False'}),
+ 'kind': ('django.db.models.fields.CharField', [], {'default': "'SERVER'", 'max_length': '128'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
+ 'name': ('django.db.models.fields.CharField', [], {'default': "'New Asset'", 'max_length': '256'})
+ },
+ u'it.attachment': {
+ 'Meta': {'object_name': 'Attachment'},
+ 'attachment': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {})
+ },
+ u'it.issue': {
+ 'Meta': {'ordering': "['-priority', 'created_at']", 'object_name': 'Issue'},
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'priority': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'state': ('django.db.models.fields.CharField', [], {'default': "'NEW'", 'max_length': '32'}),
+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
+ 'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'metoo'", 'null': 'True', 'to': u"orm['auth.User']"})
+ },
+ u'it.taggeditem': {
+ 'Meta': {'unique_together': "(('content_type', 'object_id', 'tag'),)", 'object_name': 'TaggedItem'},
+ 'color': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '8'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}),
+ 'tag': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ u'it.task': {
+ 'Meta': {'ordering': "['-created_at']", 'object_name': 'Task'},
+ 'assigned_to': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'tasks'", 'null': 'True', 'to': u"orm['auth.User']"}),
+ 'completed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'due_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'issue': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['it.Issue']", 'null': 'True'}),
+ 'step': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['it'] \ No newline at end of file
diff --git a/apps/it/models.py b/apps/it/models.py
index d7922e4..0ebc5d0 100644
--- a/apps/it/models.py
+++ b/apps/it/models.py
@@ -1,24 +1,53 @@
from django.db import models
+
from django.contrib.contenttypes import generic
+from django.utils.translation import ugettext as _
+from django.template.defaultfilters import slugify
from django.contrib.auth.models import User, Group
from django.contrib.contenttypes.models import ContentType
-class Attachment(models.Model):
- attachment = models.FileField(upload_to='attachments')
- created_by = models.ForeignKey(User)
- object_id = models.PositiveIntegerField()
- content_type = models.ForeignKey(ContentType)
+class AbstractGenericItem(models.Model):
+ created_by = models.ForeignKey(User, editable=False)
+ object_id = models.PositiveIntegerField(editable=False)
+ content_type = models.ForeignKey(ContentType, editable=False)
content_object = generic.GenericForeignKey("content_type", "object_id")
- @classmethod
- def get_content_type(cls, model):
- return ContentType.objects.get(app_label='it', model=model)
+ class Meta:
+ abstract = True
+
+
+class TaggedItem(AbstractGenericItem):
+ "A generic tagged item"
+ tag = models.CharField(max_length=128)
+ slug = models.SlugField()
+ color = models.CharField(max_length=8, default="")
+
+ def save(self, *args, **kwargs):
+ self.slug = slugify(self.tag)
+ super(TaggedItem, self).save(*args, **kwargs)
+
+ def __unicode__(self):
+ return self.tag
+
+ class Meta:
+ unique_together = ("content_type", "object_id", "tag",)
+
+
+class Attachment(AbstractGenericItem):
+ attachment = models.FileField(upload_to='attachments')
+
+ def __unicode__(self):
+ import os
+ return os.path.basename(self.attachment.name)
+
+
+class Article(AbstractGenericItem):
+ note = models.TextField()
+ tags = generic.GenericRelation(TaggedItem)
+ title = models.CharField(max_length=256, default='New Article')
+
- @classmethod
- def get_files(cls, model):
- ct = ContentType.objects.get_for_model()
- return cls.objects.filter(content_type=ct, object_id=model.pk)
class Issue(models.Model):
description = models.TextField()
@@ -26,9 +55,20 @@ class Issue(models.Model):
users = models.ManyToManyField(
User,
null=True,
- blank=True,
+ editable=False,
related_name='metoo'
)
+ STATES = (
+ ('NEW', _('New')),
+ ('OPEN', _('Open')),
+ ('CLOSED', _('Closed')),
+ )
+ state = models.CharField(max_length=32, choices=STATES, default=STATES[0][0])
+ files = generic.GenericRelation(Attachment)
+ tags = generic.GenericRelation(TaggedItem)
+ created_by = models.ForeignKey(User, editable=False)
+ created_at = models.DateTimeField(auto_now_add=True)
+ updated_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.description
@@ -36,20 +76,29 @@ class Issue(models.Model):
def get_absolute_url(self):
return '/issues/%d/' % self.pk
+ class Meta:
+ ordering = ['-priority', 'created_at']
class Task(models.Model):
description = models.TextField()
- issue = models.ForeignKey(Issue, null=True)
- step = models.PositiveIntegerField(default=0)
- created_by = models.ForeignKey(User, null=True)
- assigned_to = models.ForeignKey(User, null=True, related_name='tasks')
+ issue = models.ForeignKey(Issue, null=True, editable=False)
+ step = models.PositiveIntegerField(default=0, editable=False)
+ created_by = models.ForeignKey(User, editable=False)
+ assigned_to = models.ForeignKey(User,
+ null=True,
+ blank=True,
+ related_name='tasks')
created_at = models.DateTimeField(auto_now_add=True)
- due_date = models.DateField(null=True, blank=True)
- completed_at = models.DateTimeField(null=True, blank=True)
+ due_date = models.DateField(null=True, blank=True, editable=False)
+ updated_at = models.DateTimeField(auto_now=True)
+ completed_at = models.DateTimeField(null=True, blank=True, editable=False)
+ files = generic.GenericRelation(Attachment)
def __unicode__(self):
return self.description
+ class Meta:
+ ordering = ['-created_at']
class Asset(models.Model):
name = models.CharField(max_length=256, default='New Asset')
@@ -57,6 +106,21 @@ class Asset(models.Model):
location = models.CharField(max_length=256)
ip_address = models.IPAddressField(default='')
issues = models.ManyToManyField(Issue, null=True)
+ files = generic.GenericRelation(Attachment)
+ KINDS = (
+ ('SERVER', _('Server')),
+ ('WORKSTATION', _('Workstation')),
+ ('NETWORK', _('Networking')),
+ ('SOFTWARE', _('Software')),
+ ('PRINTER', _('Printer')),
+ ('SERVICE', _('Service')),
+ )
+ kind = models.CharField(choices=KINDS, max_length=128, default=KINDS[0][0])
+ tags = generic.GenericRelation(TaggedItem)
+ contact = models.ForeignKey(User, null=True, blank=True)
def __unicode__(self):
return self.name
+
+ def get_absolute_url(self):
+ return '/stuff/%d/' % self.pk
diff --git a/apps/it/static/images/arrow-down-512.png b/apps/it/static/images/arrow-down-512.png
new file mode 100755
index 0000000..7af1770
--- /dev/null
+++ b/apps/it/static/images/arrow-down-512.png
Binary files differ
diff --git a/apps/it/static/js/sb-admin.js b/apps/it/static/js/sb-admin.js
index ae676aa..70f2a3f 100755
--- a/apps/it/static/js/sb-admin.js
+++ b/apps/it/static/js/sb-admin.js
@@ -8,7 +8,7 @@ $(function() {
//collapses the sidebar on window resize.
$(function() {
$(window).bind("load resize", function() {
- console.log($(this).width())
+ //console.log($(this).width())
if ($(this).width() < 768) {
$('div.sidebar-collapse').addClass('collapse')
} else {
diff --git a/apps/it/templates/default.html b/apps/it/templates/default.html
index 18498ef..49b818b 100755
--- a/apps/it/templates/default.html
+++ b/apps/it/templates/default.html
@@ -1,320 +1,301 @@
+{% load bootstrap3 %}
<!DOCTYPE html>
<html>
-
<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
-
- <title>IT</title>
-
- <!-- Core CSS - Include with every page -->
- <link href="{{ STATIC_URL }}css/bootstrap.min.css" rel="stylesheet">
- <link href="{{ STATIC_URL }}font-awesome/css/font-awesome.css" rel="stylesheet">
+ <title>IT</title>
- <!-- Page-Level Plugin CSS - Blank -->
+ <!-- Core CSS - Include with every page -->
+ <link href="{{ STATIC_URL }}css/bootstrap.min.css" rel="stylesheet">
+ <link href="{{ STATIC_URL }}font-awesome/css/font-awesome.css" rel="stylesheet">
- <!-- SB Admin CSS - Include with every page -->
- <link href="{{ STATIC_URL }}css/sb-admin.css" rel="stylesheet">
+ <!-- Page-Level Plugin CSS - Blank -->
+ <link href="{{ STATIC_URL }}css/plugins/timeline/timeline.css" rel="stylesheet">
+ <!-- SB Admin CSS - Include with every page -->
+ <link href="{{ STATIC_URL }}css/sb-admin.css" rel="stylesheet">
+ <style type="text/css">
+ .dropzone {
+ height: 100px;
+ width: 100%;
+ padding: 10px;
+ border: 1px #ccc dashed;
+ border-radius: 13px;
+ background: url({{ STATIC_URL }}images/arrow-down-512.png) no-repeat;
+ background-size: 80px 80px;
+ background-position: center;
+ background-color: #eee;
+ }
+ #page-wrapper {
+ margin-right: 300px;
+ border-right: 1px solid #e7e7e7;
+ }
+ .sidebar-right {
+ width: 290px;
+ right: 0;
+ top: 60px;
+ padding-right: 10px;
+ }
+ .tasks {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ }
+ </style>
</head>
<body>
- <div id="wrapper">
+ <div id="wrapper">
- <nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0">
- <div class="navbar-header">
- <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".sidebar-collapse">
- <span class="sr-only">Toggle navigation</span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </button>
- <a class="navbar-brand" href="{% url 'home' %}">IT</a>
- </div>
- <!-- /.navbar-header -->
+ <nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0">
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".sidebar-collapse">
+ <span class="sr-only">Toggle navigation</span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <a class="navbar-brand" href="{% url 'home' %}">IT</a>
+ </div>
+ <!-- /.navbar-header -->
- <ul class="nav navbar-top-links navbar-right">
- <li class="dropdown">
- <a class="dropdown-toggle" data-toggle="dropdown" href="#">
- <i class="fa fa-envelope fa-fw"></i> <i class="fa fa-caret-down"></i>
- </a>
- <ul class="dropdown-menu dropdown-messages">
- <li>
- <a href="#">
- <div>
- <strong>John Smith</strong>
- <span class="pull-right text-muted">
- <em>Yesterday</em>
- </span>
- </div>
- <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend...</div>
- </a>
- </li>
- <li class="divider"></li>
- <li>
- <a href="#">
- <div>
- <strong>John Smith</strong>
- <span class="pull-right text-muted">
- <em>Yesterday</em>
- </span>
- </div>
- <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend...</div>
- </a>
- </li>
- <li class="divider"></li>
- <li>
- <a href="#">
- <div>
- <strong>John Smith</strong>
- <span class="pull-right text-muted">
- <em>Yesterday</em>
- </span>
- </div>
- <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend...</div>
- </a>
- </li>
- <li class="divider"></li>
- <li>
- <a class="text-center" href="#">
- <strong>Read All Messages</strong>
- <i class="fa fa-angle-right"></i>
- </a>
- </li>
- </ul>
- <!-- /.dropdown-messages -->
- </li>
- <!-- /.dropdown -->
- <li class="dropdown">
- <a class="dropdown-toggle" data-toggle="dropdown" href="#">
- <i class="fa fa-tasks fa-fw"></i> <i class="fa fa-caret-down"></i>
- </a>
- <ul class="dropdown-menu dropdown-tasks">
- <li>
- <a href="#">
- <div>
- <p>
- <strong>Task 1</strong>
- <span class="pull-right text-muted">40% Complete</span>
- </p>
- <div class="progress progress-striped active">
- <div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 40%">
- <span class="sr-only">40% Complete (success)</span>
- </div>
- </div>
- </div>
- </a>
- </li>
- <li class="divider"></li>
- <li>
- <a href="#">
- <div>
- <p>
- <strong>Task 2</strong>
- <span class="pull-right text-muted">20% Complete</span>
- </p>
- <div class="progress progress-striped active">
- <div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100" style="width: 20%">
- <span class="sr-only">20% Complete</span>
- </div>
- </div>
- </div>
- </a>
- </li>
- <li class="divider"></li>
- <li>
- <a href="#">
- <div>
- <p>
- <strong>Task 3</strong>
- <span class="pull-right text-muted">60% Complete</span>
- </p>
- <div class="progress progress-striped active">
- <div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%">
- <span class="sr-only">60% Complete (warning)</span>
- </div>
- </div>
- </div>
- </a>
- </li>
- <li class="divider"></li>
- <li>
- <a href="#">
- <div>
- <p>
- <strong>Task 4</strong>
- <span class="pull-right text-muted">80% Complete</span>
- </p>
- <div class="progress progress-striped active">
- <div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100" style="width: 80%">
- <span class="sr-only">80% Complete (danger)</span>
- </div>
- </div>
- </div>
- </a>
- </li>
- <li class="divider"></li>
- <li>
- <a class="text-center" href="#">
- <strong>See All Tasks</strong>
- <i class="fa fa-angle-right"></i>
- </a>
- </li>
- </ul>
- <!-- /.dropdown-tasks -->
- </li>
- <!-- /.dropdown -->
- <li class="dropdown">
- <a class="dropdown-toggle" data-toggle="dropdown" href="#">
- <i class="fa fa-bell fa-fw"></i> <i class="fa fa-caret-down"></i>
- </a>
- <ul class="dropdown-menu dropdown-alerts">
- <li>
- <a href="#">
- <div>
- <i class="fa fa-comment fa-fw"></i> New Comment
- <span class="pull-right text-muted small">4 minutes ago</span>
- </div>
- </a>
- </li>
- <li class="divider"></li>
- <li>
- <a href="#">
- <div>
- <i class="fa fa-twitter fa-fw"></i> 3 New Followers
- <span class="pull-right text-muted small">12 minutes ago</span>
- </div>
- </a>
- </li>
- <li class="divider"></li>
- <li>
- <a href="#">
- <div>
- <i class="fa fa-envelope fa-fw"></i> Message Sent
- <span class="pull-right text-muted small">4 minutes ago</span>
- </div>
- </a>
- </li>
- <li class="divider"></li>
- <li>
- <a href="#">
- <div>
- <i class="fa fa-tasks fa-fw"></i> New Task
- <span class="pull-right text-muted small">4 minutes ago</span>
- </div>
- </a>
- </li>
- <li class="divider"></li>
- <li>
- <a href="#">
- <div>
- <i class="fa fa-upload fa-fw"></i> Server Rebooted
- <span class="pull-right text-muted small">4 minutes ago</span>
- </div>
- </a>
- </li>
- <li class="divider"></li>
- <li>
- <a class="text-center" href="#">
- <strong>See All Alerts</strong>
- <i class="fa fa-angle-right"></i>
- </a>
- </li>
- </ul>
- <!-- /.dropdown-alerts -->
- </li>
- <!-- /.dropdown -->
- <li class="dropdown">
- <a class="dropdown-toggle" data-toggle="dropdown" href="#">
- <i class="fa fa-user fa-fw"></i> <i class="fa fa-caret-down"></i>
- </a>
- <ul class="dropdown-menu dropdown-user">
- <li><a href="#"><i class="fa fa-user fa-fw"></i> User Profile</a>
- </li>
- <li><a href="#"><i class="fa fa-gear fa-fw"></i> Settings</a>
- </li>
- <li class="divider"></li>
- <li><a href="login.html"><i class="fa fa-sign-out fa-fw"></i> Logout</a>
- </li>
- </ul>
- <!-- /.dropdown-user -->
- </li>
- <!-- /.dropdown -->
- </ul>
- <!-- /.navbar-top-links -->
-
- </nav>
- <!-- /.navbar-static-top -->
+ <ul class="nav navbar-top-links navbar-right">
+ <li class="dropdown">
+ <a class="dropdown-toggle" data-toggle="dropdown" href="#">
+ <i class="fa fa-envelope fa-fw"></i> <i class="fa fa-caret-down"></i>
+ </a>
+ <ul class="dropdown-menu dropdown-messages">
+ <li>
+ <a href="#">
+ <div>
+ <strong>John Smith</strong>
+ <span class="pull-right text-muted">
+ <em>Yesterday</em>
+ </span>
+ </div>
+ <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend...</div>
+ </a>
+ </li>
+ <li class="divider"></li>
+ <li>
+ <a href="#">
+ <div>
+ <strong>John Smith</strong>
+ <span class="pull-right text-muted">
+ <em>Yesterday</em>
+ </span>
+ </div>
+ <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend...</div>
+ </a>
+ </li>
+ <li class="divider"></li>
+ <li>
+ <a href="#">
+ <div>
+ <strong>John Smith</strong>
+ <span class="pull-right text-muted">
+ <em>Yesterday</em>
+ </span>
+ </div>
+ <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend...</div>
+ </a>
+ </li>
+ <li class="divider"></li>
+ <li>
+ <a class="text-center" href="#">
+ <strong>Read All Messages</strong>
+ <i class="fa fa-angle-right"></i>
+ </a>
+ </li>
+ </ul>
+ <!-- /.dropdown-messages -->
+ </li>
+ <!-- /.dropdown -->
+ <li class="dropdown">
+ <a class="dropdown-toggle" data-toggle="dropdown" href="#">
+ <i class="fa fa-tasks fa-fw"></i> <i class="fa fa-caret-down"></i>
+ </a>
+ <ul class="dropdown-menu dropdown-tasks">
+ <li>
+ <a href="#">
+ <div>
+ <p>
+ <strong>Task 1</strong>
+ <span class="pull-right text-muted">40% Complete</span>
+ </p>
+ <div class="progress progress-striped active">
+ <div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 40%">
+ <span class="sr-only">40% Complete (success)</span>
+ </div>
+ </div>
+ </div>
+ </a>
+ </li>
+ <li class="divider"></li>
+ <li>
+ <a href="#">
+ <div>
+ <p>
+ <strong>Task 2</strong>
+ <span class="pull-right text-muted">20% Complete</span>
+ </p>
+ <div class="progress progress-striped active">
+ <div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100" style="width: 20%">
+ <span class="sr-only">20% Complete</span>
+ </div>
+ </div>
+ </div>
+ </a>
+ </li>
+ <li class="divider"></li>
+ <li>
+ <a href="#">
+ <div>
+ <p>
+ <strong>Task 3</strong>
+ <span class="pull-right text-muted">60% Complete</span>
+ </p>
+ <div class="progress progress-striped active">
+ <div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%">
+ <span class="sr-only">60% Complete (warning)</span>
+ </div>
+ </div>
+ </div>
+ </a>
+ </li>
+ <li class="divider"></li>
+ <li>
+ <a href="#">
+ <div>
+ <p>
+ <strong>Task 4</strong>
+ <span class="pull-right text-muted">80% Complete</span>
+ </p>
+ <div class="progress progress-striped active">
+ <div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100" style="width: 80%">
+ <span class="sr-only">80% Complete (danger)</span>
+ </div>
+ </div>
+ </div>
+ </a>
+ </li>
+ <li class="divider"></li>
+ <li>
+ <a class="text-center" href="#">
+ <strong>See All Tasks</strong>
+ <i class="fa fa-angle-right"></i>
+ </a>
+ </li>
+ </ul>
+ <!-- /.dropdown-tasks -->
+ </li>
+ <!-- /.dropdown -->
+ <li class="dropdown">
+ <a class="dropdown-toggle" data-toggle="dropdown" href="#">
+ <i class="fa fa-user fa-fw"></i> <i class="fa fa-caret-down"></i>
+ </a>
+ <ul class="dropdown-menu dropdown-user">
+ <li><a href="#"><i class="fa fa-user fa-fw"></i> User Profile</a>
+ </li>
+ <li><a href="#"><i class="fa fa-gear fa-fw"></i> Settings</a>
+ </li>
+ <li class="divider"></li>
+ <li><a href="login.html"><i class="fa fa-sign-out fa-fw"></i> Logout</a>
+ </li>
+ </ul>
+ <!-- /.dropdown-user -->
+ </li>
+ <!-- /.dropdown -->
+ </ul>
+ <!-- /.navbar-top-links -->
+ </nav>
+ <!-- /.navbar-static-top -->
- <nav class="navbar-default navbar-static-side" role="navigation">
- <div class="sidebar-collapse">
- <ul class="nav" id="side-menu">
- <li class="sidebar-search">
- <div class="input-group custom-search-form">
- <input type="text" class="form-control searchfield" placeholder="Search...">
- <span class="input-group-btn">
- <button class="btn btn-default" type="button">
- <i class="fa fa-search"></i>
- </button>
- </span>
- </div>
- <!-- /input-group -->
- </li>
- <li class="active">
- <a href="{% url 'home' %}"><i class="fa fa-dashboard fa-fw"></i> Issues</a>
- </li>
- </ul>
- <!-- /#side-menu -->
+ <nav class="navbar-default navbar-static-side" role="navigation">
+ <div class="sidebar-collapse">
+ <ul class="nav" id="side-menu">
+ <li class="sidebar-search">
+ <div class="input-group custom-search-form">
+ <input type="text" class="form-control searchfield" placeholder="Search...">
+ <span class="input-group-btn">
+ <button class="btn btn-default" type="button">
+ <i class="fa fa-search"></i>
+ </button>
+ </span>
</div>
- <!-- /.sidebar-collapse -->
- </nav>
- <!-- /.navbar-static-side -->
+ <!-- /input-group -->
+ </li>
+ <li class="active">
+ <a href="{% url 'home' %}?state=NEW"><i class="fa fa-dashboard fa-fw"></i> Issues <span class="badge pull-right">{{ issue_count }}</span></a>
+ </li>
+ <li><a href="{% url 'list_stuff' %}?kind=SERVER"><i class="fa fa-hdd-o fa-fw"></i> Assets</a></li>
+ <li><a href="{% url 'home' %}"><i class="fa fa-book fa-fw"></i> Documentation</a></li>
+ <li><a href="{% url 'home' %}"><i class="fa fa-users fa-fw"></i> Users</a></li>
+ </ul>
+ <!-- /#side-menu -->
+ </div>
+ <!-- /.sidebar-collapse -->
+ </nav>
+ <!-- /.navbar-static-side -->
- <div id="page-wrapper">
- <div class="row">
- <div class="col-lg-12">
- <a class="btn btn-default" href="{% url 'add_issue' %}">New Issue</a>
- {% block main %}
- <h1 class="page-header">Blank</h1>
- {% endblock main %}
- </div>
- <!-- /.col-lg-12 -->
- </div>
- <!-- /.row -->
+ <div id="page-wrapper">
+ <div class="row">
+ <div class="col-lg-12">
+ {% block main %}
+ <h1 class="page-header">Blank</h1>
+ {% endblock main %}
</div>
- <!-- /#page-wrapper -->
-
+ <!-- /.col-lg-12 -->
+ </div>
+ <!-- /.row -->
+ <nav class="navbar-default navbar-static-side sidebar-right" role="navigation">
+ <div class="sidebar-collapse">
+ {% bootstrap_messages %}
+ {% block inspector %}
+ INSPECTOR CONTENT
+ {% endblock inspector %}
+ <!-- /#side-menu -->
+ </div>
+ <!-- /.sidebar-collapse -->
+ </nav>
</div>
- <!-- /#wrapper -->
+ <!-- /#page-wrapper -->
+ <!-- /.navbar-static-side -->
+ </div>
+ <!-- /#wrapper -->
- <!-- Core Scripts - Include with every page -->
- <script src="{{ STATIC_URL }}js/jquery-1.10.2.js"></script>
- <script src="{{ STATIC_URL }}js/dropzone.js"></script>
- <script src="{{ STATIC_URL }}js/bootstrap.min.js"></script>
- <script src="{{ STATIC_URL }}js/plugins/metisMenu/jquery.metisMenu.js"></script>
+ <!-- Core Scripts - Include with every page -->
+ <script src="{{ STATIC_URL }}js/jquery-1.10.2.js"></script>
+ <script src="{{ STATIC_URL }}js/dropzone.js"></script>
+ <script src="{{ STATIC_URL }}js/bootstrap.min.js"></script>
+ <script src="{{ STATIC_URL }}js/plugins/metisMenu/jquery.metisMenu.js"></script>
- <!-- Page-Level Plugin Scripts - Blank -->
+ <!-- Page-Level Plugin Scripts - Blank -->
- <!-- SB Admin Scripts - Include with every page -->
- <script src="{{ STATIC_URL }}js/sb-admin.js"></script>
+ <!-- SB Admin Scripts - Include with every page -->
+ <script src="{{ STATIC_URL }}js/sb-admin.js"></script>
- <!-- Page-Level Demo Scripts - Blank - Use for reference -->
- <script type="text/javascript">
- Dropzone.options.myAwesomeDropzone = {
- paramName: "attachment", // The name that will be used to transfer the file
- maxFilesize: 2, // MB
- };
- $('.metoo').click(function(e){
- e.preventDefault();
- });
- $('.searchfield').on('keyup', function(e){
- if(e.keyCode == 13) {
- document.location = '/search/?q=' + $(this).val();
- }
- });
- </script>
-</body>
+ <!-- Page-Level Demo Scripts - Blank - Use for reference -->
+ <script type="text/javascript">
+ Dropzone.options.myAwesomeDropzone = {
+ paramName: "attachment", // The name that will be used to transfer the file
+ maxFilesize: 2, // MB
+ };
+ $('.confirm').click(function(e){
+ if(confirm('Are you sure?')) {
+ return true;
+ }
+ e.preventDefault();
+ });
+ $('.searchfield').on('keyup', function(e){
+ if(e.keyCode == 13) {
+ document.location = '/search/?q=' + $(this).val();
+ }
+ });
+ </script>
+ </body>
</html>
diff --git a/apps/it/templates/edit_issue.html b/apps/it/templates/edit_issue.html
index e1be666..aaedee2 100644
--- a/apps/it/templates/edit_issue.html
+++ b/apps/it/templates/edit_issue.html
@@ -3,9 +3,9 @@
{% load i18n %}
{% block main %}
- <form action="" method="post" class="form">
- {% csrf_token %}
- {% bootstrap_form form %}
- <button type="submit" class="btn btn-primary">{% trans "Submit" %}</button>
- </form>
+<form action="" method="post" class="form">
+ {% csrf_token %}
+ {% bootstrap_form form %}
+ <button type="submit" class="btn btn-primary">{% trans "Save" %}</button>
+</form>
{% endblock main %}
diff --git a/apps/it/templates/edit_task.html b/apps/it/templates/edit_task.html
index e1be666..30435e4 100644
--- a/apps/it/templates/edit_task.html
+++ b/apps/it/templates/edit_task.html
@@ -6,6 +6,6 @@
<form action="" method="post" class="form">
{% csrf_token %}
{% bootstrap_form form %}
- <button type="submit" class="btn btn-primary">{% trans "Submit" %}</button>
+ <button type="submit" class="btn btn-primary">{% trans "Save" %}</button>
</form>
{% endblock main %}
diff --git a/apps/it/templates/list_issues.html b/apps/it/templates/list_issues.html
index c52058d..56d05b0 100644
--- a/apps/it/templates/list_issues.html
+++ b/apps/it/templates/list_issues.html
@@ -1,12 +1,26 @@
{% extends "default.html" %}
+{% load bootstrap3 %}
+{% load i18n %}
{% block main %}
- <table class="table">
- {% for i in issues %}
- <tr>
- <td><a href="{% url 'view_issue' i.pk %}">{{ i.description }}</a></td>
- <td><a class="btn btn-default btn-sm metoo" href="{% url 'metoo' i.pk 1 %}">Me too!</a></td>
- </tr>
- {% endfor %}
- </table>
+<ul class="nav nav-tabs">
+{% for k, v in states %}
+ <li{%if k == state %} class="active"{% endif %}><a href="?state={{ k }}">{{ v }}</a></li>
+{% endfor %}
+</ul>
+<table class="table">
+ {% for i in issues %}
+ <tr>
+ <td><a href="{% url 'view_issue' i.pk %}">{{ i.description }}</a></td>
+ </tr>
+ {% endfor %}
+</table>
{% endblock main %}
+
+{% block inspector %}
+<form action="" method="post" class="form">
+ {% csrf_token %}
+ {% bootstrap_form form %}
+ <button type="submit" class="btn btn-primary">{% trans "Add Issue" %}</button>
+</form>
+{% endblock inspector %}
diff --git a/apps/it/templates/list_stuff.html b/apps/it/templates/list_stuff.html
new file mode 100644
index 0000000..2ed2d6b
--- /dev/null
+++ b/apps/it/templates/list_stuff.html
@@ -0,0 +1,29 @@
+{% extends "default.html" %}
+{% load bootstrap3 %}
+{% load i18n %}
+
+{% block main %}
+
+<ul class="nav nav-tabs">
+{% for k, v in categories %}
+ <li{%if k == kind %} class="active"{% endif %}><a href="?kind={{ k }}">{{ v }}</a></li>
+{% endfor %}
+</ul>
+
+<table>
+ <tbody>
+ {% for i in object_list %}
+ <td>{{ i.name }}</td>
+ <td>{{ i.description }}</td>
+ {% endfor %}
+ </tbody>
+</table>
+{% endblock main %}
+
+{% block inspector %}
+ <form method="post">
+ {% csrf_token %}
+ {% bootstrap_form form %}
+ <button class="btn btn-default btn-primary">{% trans "Add Asset" %}</button>
+ </form>
+{% endblock inspector %}
diff --git a/apps/it/templates/view_issue.html b/apps/it/templates/view_issue.html
index fe36f34..cf33b22 100644
--- a/apps/it/templates/view_issue.html
+++ b/apps/it/templates/view_issue.html
@@ -1,18 +1,66 @@
{% extends "default.html" %}
{% load bootstrap3 %}
+{% load humanize %}
{% load i18n %}
+{% load it_tags %}
{% block main %}
- <p>{{ issue.description }}</p>
- {% for i in issue.task_set.all %}
- <p>{{ i.description }}</p>
- {% endfor %}
- {% for f in files %}
- <span class="label">{{ f.attachment.name }}</span>
- {% endfor %}
- <form action="{% url 'add_files' issue.pk %}" class="dropzone" id="my-awesome-dropzone">
- </form>
- <a class="btn btn-default" href="{% url 'edit_issue' issue.pk %}">Edit</a>
- <a class="btn btn-default" href="{% url 'add_task' issue.pk %}">Add Task</a>
- <a class="btn btn-default metoo" href="{% url 'metoo' issue.pk 1 %}">Me too!</a>
+{{ issue.description|markdown }}
+<span>{{ issue.created_by}} @ {{ issue.created_at }}</span>
+<hr/>
+<a class="btn btn-default" href="{% url 'edit_issue' issue.pk %}">{% bootstrap_icon "pencil" %} Edit</a>
+<a class="btn btn-default metoo" href="{% url 'metoo' issue.pk 1 %}">{% bootstrap_icon "star" %} Me too!</a>
+{% for i in issue.task_set.all %}
+<div class="panel panel-default">
+ <div class="panel-heading">
+ <i class="fa fa-user fa-fw"></i> <span class="muted">{{ i.created_by }}</span> <i class="fa fa-clock-o fa-fw"></i> {{ i.created_at|naturaltime }}
+ </div>
+ <div class="panel-body">
+ {{ i.description|markdown }}
+ <hr/>
+ <div class="btn-group">
+ <button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown">
+ <i class="fa fa-cog"></i>
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu" role="menu">
+ <li><a href="{% url 'edit_task' issue.pk i.pk %}">Edit</a>
+ </li>
+ <li><a href="{% url 'delete_task' i.pk %}" class="confirm">Delete</a>
+ </li>
+ <li><a href="#">Something else here</a>
+ </li>
+ <li class="divider"></li>
+ <li><a href="#">Separated link</a>
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+{% endfor %}
+</div>
{% endblock main %}
+
+{% block inspector %}
+<h4>Users</h4>
+{% for f in issue.users.all %}
+ <a href=""><span class="label label-info label"><i class="fa fa-user fa-fw"></i> {{ f }}</span></a>
+ <a class="btn btn-default btn-sm" href="{% url 'remove_user' issue.pk f.pk %}">{% bootstrap_icon "trash" %}</a>
+{% endfor %}
+<hr/>
+<h4>Files</h4>
+{% for f in issue.files.all %}
+ <a href=""><span class="label label-info"><i class="fa fa-file"></i> {{ f }}</span></a>
+ <a class="btn btn-default btn-sm" href="{% url 'delete_file' f.pk %}">{% bootstrap_icon "trash" %}</a>
+{% endfor %}
+<hr/>
+<form action="{% url 'add_files' issue.pk %}" class="dropzone" id="my-awesome-dropzone">
+ {% csrf_token %}
+</form>
+<hr/>
+<form action="{% url 'add_task' issue.pk %}" method="post">
+ {% csrf_token %}
+ {% bootstrap_form form %}
+ <button class="btn btn-primary" type="submit">Add Task</button>
+</form>
+{% endblock inspector %}
diff --git a/apps/it/templatetags/__init__.py b/apps/it/templatetags/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apps/it/templatetags/__init__.py
diff --git a/apps/it/templatetags/it_tags.py b/apps/it/templatetags/it_tags.py
new file mode 100644
index 0000000..62b5db3
--- /dev/null
+++ b/apps/it/templatetags/it_tags.py
@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+
+from django import template
+from django.utils import safestring, timezone
+from django.utils.translation import ugettext as _
+
+register = template.Library()
+
+@register.filter
+def markdown(text):
+ import markdown
+ result = markdown.markdown(text)
+ return safestring.mark_safe(result)
diff --git a/apps/it/views.py b/apps/it/views.py
index fa13ed0..47afe63 100644
--- a/apps/it/views.py
+++ b/apps/it/views.py
@@ -1,11 +1,20 @@
from django import forms
+from django.contrib import messages
from django.http import HttpResponse
from django.shortcuts import render, redirect
-from django.views.decorators.csrf import csrf_exempt
-from apps.it.models import Issue, Task, Attachment
+from apps.it.models import Issue, Task, Attachment, User, Asset
+class AssetForm(forms.ModelForm):
+ class Meta:
+ model = Asset
+
+class SimpleAssetForm(forms.ModelForm):
+ class Meta:
+ model = Asset
+ fields = ['name', 'description', 'kind']
+
class AttachmentForm(forms.ModelForm):
class Meta:
model = Attachment
@@ -14,28 +23,52 @@ class IssueForm(forms.ModelForm):
class Meta:
model = Issue
+
+class SimpleIssueForm(forms.ModelForm):
+ class Meta:
+ model = Issue
+ fields = ['description', 'priority']
+
class TaskForm(forms.ModelForm):
class Meta:
model = Task
def home(request):
+ state = request.GET.get('state')
issues = Issue.objects.all()
+ issue_count = issues.count()
+
+ if state:
+ issues = issues.filter(state=state)
+
+ form = SimpleIssueForm()
+ states = Issue.STATES
+ issue = Issue(created_by_id=1)
+
+ if request.method == 'POST':
+ form = SimpleIssueForm(request.POST, instance=issue)
+ if form.is_valid():
+ issue = form.save()
+ messages.success(request, 'Issue saved')
+ return redirect(issue)
return render(request, "list_issues.html", locals())
def search(request):
query = request.GET['q']
- results = Issue.objects.filter(description__icontains=query)
- return render(request, "default.html", locals())
+ form = IssueForm()
+ issues = Issue.objects.filter(description__icontains=query)
+ return render(request, "list_issues.html", locals())
def view_issue(request, pk):
issue = Issue.objects.get(pk=pk)
- files = Attachment.objects.filter(content_object=issue)
+ task = Task(issue=issue, created_by_id=1)
+ form = TaskForm(instance=task)
return render(request, "view_issue.html", locals())
def edit_issue(request, pk=None):
if pk is None:
- issue = Issue()
+ issue = Issue(created_by_id=1)
else:
issue = Issue.objects.get(pk=pk)
@@ -45,6 +78,7 @@ def edit_issue(request, pk=None):
form = IssueForm(request.POST, instance=issue)
if form.is_valid():
issue = form.save()
+ messages.success(request, 'Issue saved')
return redirect(issue)
return render(request, "edit_issue.html", locals())
@@ -52,6 +86,7 @@ def edit_issue(request, pk=None):
def edit_task(request, issue, pk=None):
if pk is None:
task = Task()
+ task.created_by_id = 1
task.issue = Issue.objects.get(pk=issue)
else:
task = Task.objects.get(pk=pk)
@@ -70,16 +105,70 @@ def edit_task(request, issue, pk=None):
def metoo(request, issue, user):
issue = Issue.objects.get(pk=issue)
+ user = User.objects.get(pk=user)
+
+ if user in issue.users.all():
+ issue.users.remove(user)
+ else:
+ issue.users.add(user)
+
+ messages.success(request, 'Issue updated')
+ return redirect(issue)
-@csrf_exempt
def add_files(request, pk):
issue = Issue.objects.get(pk=pk)
att = Attachment(content_object=issue, created_by_id=1)
form = AttachmentForm(request.POST, request.FILES, instance=att)
- if form.is_valid:
+ if form.is_valid():
form.save()
else:
print form.errors
return HttpResponse('Cheerio!')
+
+def delete_issue(request, pk):
+ pass
+
+def delete_task(request, pk):
+ task = Task.objects.get(pk=pk)
+ task.delete()
+ messages.info(request, 'Task deleted')
+ return redirect(task.issue)
+
+def list_assets(request):
+ pass
+
+def list_stuff(request):
+ if request.method == 'POST':
+ form = SimpleAssetForm(request.POST)
+ if form.is_valid():
+ asset = form.save()
+ return redirect(asset)
+
+ categories = Asset.KINDS
+ object_list = Asset.objects.all()
+ kind = request.GET.get('kind')
+
+ if kind:
+ object_list = object_list.filter(kind=kind)
+
+ form = SimpleAssetForm(initial={'kind': kind})
+ return render(request, "list_stuff.html", locals())
+
+def view_asset(request, pk):
+ return render(request, "view_asset.html", locals())
+
+
+def delete_file(request, pk):
+ file = Attachment.objects.get(pk=pk)
+ file.delete()
+ messages.success(request, 'File deleted')
+ return redirect(file.content_object)
+
+def remove_user(request, issue, user):
+ issue = Issue.objects.get(pk=issue)
+ user = User.objects.get(pk=user)
+ issue.users.remove(user)
+ messages.success(request, 'User removed from issue')
+ return redirect(issue)
diff --git a/it/settings.py b/it/settings.py
index 9512a31..5b348d7 100644
--- a/it/settings.py
+++ b/it/settings.py
@@ -36,6 +36,7 @@ INSTALLED_APPS = (
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
+ 'django.contrib.humanize',
'south', 'bootstrap3',
'apps.it',
)
@@ -86,3 +87,5 @@ STATIC_URL = '/static/'
TEMPLATE_LOADERS = (
'django.template.loaders.app_directories.Loader',
)
+
+MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
diff --git a/it/urls.py b/it/urls.py
index e57ae45..3a26f43 100644
--- a/it/urls.py
+++ b/it/urls.py
@@ -12,6 +12,13 @@ urlpatterns = patterns('apps.it',
url(r'^issues/(\d+)/edit/$', 'views.edit_issue', name='edit_issue'),
url(r'^issues/(\d+)/tasks/add/$', 'views.edit_task', name='add_task'),
url(r'^issues/(\d+)/tasks/(\d+)/$', 'views.edit_task', name='edit_task'),
- url(r'^issues/(\d+)/metoo/(\d+)/$', 'views.metoo', name='metoo'),
+ url(r'^tasks/(\d+)/delete/$', 'views.delete_task', name='delete_task'),
+ url(r'^issues/(\d+)/users/(\d+)/add/$', 'views.metoo', name='metoo'),
+ url(r'^issues/(\d+)/users/(\d+)/remove/$', 'views.remove_user', name='remove_user'),
url(r'^issues/(\d+)/files/add/$', 'views.add_files', name='add_files'),
+
+ url(r'^stuff/$', 'views.list_stuff', name='list_stuff'),
+ url(r'^stuff/(\d+)/$', 'views.view_asset', name='view_asset'),
+
+ url(r'^files/(\d+)/delete/$', 'views.delete_file', name='delete_file'),
)
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..d84d38a
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+django
+django-bootstrap3
+markdown
diff --git a/uploads/attachments/Screen_Shot_2014-01-21_at_20.40.39.png b/uploads/attachments/Screen_Shot_2014-01-21_at_20.40.39.png
new file mode 100644
index 0000000..6bc2fd2
--- /dev/null
+++ b/uploads/attachments/Screen_Shot_2014-01-21_at_20.40.39.png
Binary files differ
diff --git a/uploads/attachments/Screen_Shot_2014-01-26_at_13.11.35.png b/uploads/attachments/Screen_Shot_2014-01-26_at_13.11.35.png
new file mode 100644
index 0000000..11b6ae8
--- /dev/null
+++ b/uploads/attachments/Screen_Shot_2014-01-26_at_13.11.35.png
Binary files differ
diff --git a/uploads/attachments/Screen_Shot_2014-01-26_at_13.11.35_1.png b/uploads/attachments/Screen_Shot_2014-01-26_at_13.11.35_1.png
new file mode 100644
index 0000000..11b6ae8
--- /dev/null
+++ b/uploads/attachments/Screen_Shot_2014-01-26_at_13.11.35_1.png
Binary files differ
diff --git a/uploads/attachments/Screen_Shot_2014-02-01_at_10.47.31.png b/uploads/attachments/Screen_Shot_2014-02-01_at_10.47.31.png
new file mode 100644
index 0000000..33bd3cd
--- /dev/null
+++ b/uploads/attachments/Screen_Shot_2014-02-01_at_10.47.31.png
Binary files differ
diff --git a/uploads/attachments/arrow-down-512.png b/uploads/attachments/arrow-down-512.png
new file mode 100644
index 0000000..7af1770
--- /dev/null
+++ b/uploads/attachments/arrow-down-512.png
Binary files differ
diff --git a/uploads/attachments/arrow-down-512_1.png b/uploads/attachments/arrow-down-512_1.png
new file mode 100644
index 0000000..7af1770
--- /dev/null
+++ b/uploads/attachments/arrow-down-512_1.png
Binary files differ