From b38d84f663f628e7cd0ca6eb9f2dad8c3810bae7 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 2 Dec 2011 02:51:15 -0400 Subject: [PATCH 01/23] South schema and data migrations to support document versions --- ...unique_documentversion_document_mayor_m.py | 188 ++++++++++++++++ .../migrations/0005_document_versions.py | 181 ++++++++++++++++ .../migrations/0006_remove_old_file_fields.py | 202 ++++++++++++++++++ 3 files changed, 571 insertions(+) create mode 100644 apps/documents/migrations/0004_auto__add_documentversion__add_unique_documentversion_document_mayor_m.py create mode 100644 apps/documents/migrations/0005_document_versions.py create mode 100644 apps/documents/migrations/0006_remove_old_file_fields.py diff --git a/apps/documents/migrations/0004_auto__add_documentversion__add_unique_documentversion_document_mayor_m.py b/apps/documents/migrations/0004_auto__add_documentversion__add_unique_documentversion_document_mayor_m.py new file mode 100644 index 0000000000..e6b0c9bf10 --- /dev/null +++ b/apps/documents/migrations/0004_auto__add_documentversion__add_unique_documentversion_document_mayor_m.py @@ -0,0 +1,188 @@ +# encoding: utf-8 +import 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 'DocumentVersion' + db.create_table('documents_documentversion', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('document', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.Document'], null=True, blank=True)), + ('mayor', self.gf('django.db.models.fields.PositiveIntegerField')(default=1)), + ('minor', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('micro', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('release_level', self.gf('django.db.models.fields.PositiveIntegerField')(default=1)), + ('serial', self.gf('django.db.models.fields.PositiveIntegerField')(default=0)), + ('timestamp', self.gf('django.db.models.fields.DateTimeField')()), + ('file', self.gf('django.db.models.fields.files.FileField')(max_length=100)), + ('mimetype', self.gf('django.db.models.fields.CharField')(default='', max_length=64)), + ('encoding', self.gf('django.db.models.fields.CharField')(default='', max_length=64)), + ('filename', self.gf('django.db.models.fields.CharField')(default=u'', max_length=255, db_index=True)), + ('checksum', self.gf('django.db.models.fields.TextField')(null=True, blank=True)), + )) + db.send_create_signal('documents', ['DocumentVersion']) + + # Adding unique constraint on 'DocumentVersion', fields ['document', 'mayor', 'minor', 'micro', 'release_level', 'serial'] + db.create_unique('documents_documentversion', ['document_id', 'mayor', 'minor', 'micro', 'release_level', 'serial']) + + # Adding field 'DocumentPage.document_version' + db.add_column('documents_documentpage', 'document_version', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.DocumentVersion'], null=True, blank=True), keep_default=False) + + + def backwards(self, orm): + + # Removing unique constraint on 'DocumentVersion', fields ['document', 'mayor', 'minor', 'micro', 'release_level', 'serial'] + db.delete_unique('documents_documentversion', ['document_id', 'mayor', 'minor', 'micro', 'release_level', 'serial']) + + # Deleting model 'DocumentVersion' + db.delete_table('documents_documentversion') + + # Deleting field 'DocumentPage.document_version' + db.delete_column('documents_documentpage', 'document_version_id') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + '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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + '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', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + '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', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}), + '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'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'date_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'file_filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'file_mime_encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file_mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'default': "u'a8389d7d-b9f4-4e51-ac24-dd9dd310fd8c'", 'max_length': '48', 'blank': 'True'}) + }, + 'documents.documentpage': { + 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, + 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'page_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}) + }, + 'documents.documentpagetransformation': { + 'Meta': {'ordering': "('order',)", 'object_name': 'DocumentPageTransformation'}, + 'arguments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_page': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentPage']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True', 'blank': 'True'}), + 'transformation': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'documents.documenttypefilename': { + 'Meta': {'ordering': "['filename']", 'object_name': 'DocumentTypeFilename'}, + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'documents.documentversion': { + 'Meta': {'unique_together': "(('document', 'mayor', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']", 'null': 'True', 'blank': 'True'}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mayor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {}) + }, + 'documents.recentdocument': { + 'Meta': {'ordering': "('-datetime_accessed',)", 'object_name': 'RecentDocument'}, + 'datetime_accessed': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['documents'] diff --git a/apps/documents/migrations/0005_document_versions.py b/apps/documents/migrations/0005_document_versions.py new file mode 100644 index 0000000000..738dfe9147 --- /dev/null +++ b/apps/documents/migrations/0005_document_versions.py @@ -0,0 +1,181 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + def forwards(self, orm): + for document in orm.Document.objects.all(): + document_version = document.documentversion_set.create( + document = document, + #mayor = 1 + #minor = models.PositiveIntegerField(verbose_name=_(u'minor'), default=0) + #micro = models.PositiveIntegerField(verbose_name=_(u'micro'), default=0) + #release_level = models.PositiveIntegerField(choices=RELEASE_LEVEL_CHOICES, default=RELEASE_LEVEL_FINAL, verbose_name=_(u'release level')) + #serial = models.PositiveIntegerField(verbose_name=_(u'serial'), default=0) + timestamp = document.date_added, + file = document.file, + mimetype = document.file_mimetype, + encoding = document.file_mime_encoding, + filename = document.file_filename, + checksum = document.checksum, + ) + document_version.save() + for document_page in document.documentpage_set.all(): + document_page.document_version = document_version + document_page.save() + + def backwards(self, orm): + for document in orm.Document.objects.all(): + document_version = document.documentversion_set.all()[0] + document.date_added = document_version.timestamp + document.file = document_version.file + document.file_mimetype = document_version.mimetype + document.file_mime_encoding = document_version.encoding + document.filename = document_version.filename + document.checksum = document_version.checksum + document.save() + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + '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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + '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', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + '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', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}), + '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'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'date_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'file_filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'file_mime_encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file_mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'default': "u'6c189f1f-1d85-48b5-9b7d-e8e319603e77'", 'max_length': '48', 'blank': 'True'}) + }, + 'documents.documentpage': { + 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, + 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'page_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}) + }, + 'documents.documentpagetransformation': { + 'Meta': {'ordering': "('order',)", 'object_name': 'DocumentPageTransformation'}, + 'arguments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_page': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentPage']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True', 'blank': 'True'}), + 'transformation': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'documents.documenttypefilename': { + 'Meta': {'ordering': "['filename']", 'object_name': 'DocumentTypeFilename'}, + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'documents.documentversion': { + 'Meta': {'unique_together': "(('document', 'mayor', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']", 'null': 'True', 'blank': 'True'}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mayor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {}) + }, + 'documents.recentdocument': { + 'Meta': {'ordering': "('-datetime_accessed',)", 'object_name': 'RecentDocument'}, + 'datetime_accessed': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['documents'] diff --git a/apps/documents/migrations/0006_remove_old_file_fields.py b/apps/documents/migrations/0006_remove_old_file_fields.py new file mode 100644 index 0000000000..203532d012 --- /dev/null +++ b/apps/documents/migrations/0006_remove_old_file_fields.py @@ -0,0 +1,202 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Changing field 'DocumentVersion.document' + db.alter_column('documents_documentversion', 'document_id', self.gf('django.db.models.fields.related.ForeignKey')(default='', to=orm['documents.Document'])) + + # Deleting field 'Document.date_updated' + db.delete_column('documents_document', 'date_updated') + + # Deleting field 'Document.file' + db.delete_column('documents_document', 'file') + + # Deleting field 'Document.file_filename' + db.delete_column('documents_document', 'file_filename') + + # Deleting field 'Document.file_mimetype' + db.delete_column('documents_document', 'file_mimetype') + + # Deleting field 'Document.checksum' + db.delete_column('documents_document', 'checksum') + + # Deleting field 'Document.file_mime_encoding' + db.delete_column('documents_document', 'file_mime_encoding') + + # Deleting field 'DocumentPage.document' + db.delete_column('documents_documentpage', 'document_id') + + # Changing field 'DocumentPage.document_version' + db.alter_column('documents_documentpage', 'document_version_id', self.gf('django.db.models.fields.related.ForeignKey')(default='', to=orm['documents.DocumentVersion'])) + + + def backwards(self, orm): + + # Changing field 'DocumentVersion.document' + db.alter_column('documents_documentversion', 'document_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.Document'], null=True)) + + # Adding field 'Document.date_updated' + db.add_column('documents_document', 'date_updated', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, default=datetime.datetime(2011, 12, 2, 2, 17, 25, 53565), blank=True), keep_default=False) + + # Adding field 'Document.file' + db.add_column('documents_document', 'file', self.gf('django.db.models.fields.files.FileField')(default='', max_length=100), keep_default=False) + + # Adding field 'Document.file_filename' + db.add_column('documents_document', 'file_filename', self.gf('django.db.models.fields.CharField')(default=u'', max_length=255, db_index=True), keep_default=False) + + # Adding field 'Document.file_mimetype' + db.add_column('documents_document', 'file_mimetype', self.gf('django.db.models.fields.CharField')(default='', max_length=64), keep_default=False) + + # Adding field 'Document.checksum' + db.add_column('documents_document', 'checksum', self.gf('django.db.models.fields.TextField')(null=True, blank=True), keep_default=False) + + # Adding field 'Document.file_mime_encoding' + db.add_column('documents_document', 'file_mime_encoding', self.gf('django.db.models.fields.CharField')(default='', max_length=64), keep_default=False) + + # Adding field 'DocumentPage.document' + db.add_column('documents_documentpage', 'document', self.gf('django.db.models.fields.related.ForeignKey')(default='', to=orm['documents.Document']), keep_default=False) + + # Changing field 'DocumentPage.document_version' + db.alter_column('documents_documentpage', 'document_version_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.DocumentVersion'], null=True)) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + '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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + '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', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + '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', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}), + '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'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'default': "u'83100718-e901-4880-95f8-3618749c8a99'", 'max_length': '48', 'blank': 'True'}) + }, + 'documents.documentpage': { + 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, + 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'page_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}) + }, + 'documents.documentpagetransformation': { + 'Meta': {'ordering': "('order',)", 'object_name': 'DocumentPageTransformation'}, + 'arguments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_page': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentPage']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True', 'blank': 'True'}), + 'transformation': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'documents.documenttypefilename': { + 'Meta': {'ordering': "['filename']", 'object_name': 'DocumentTypeFilename'}, + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'documents.documentversion': { + 'Meta': {'unique_together': "(('document', 'mayor', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mayor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {}) + }, + 'documents.recentdocument': { + 'Meta': {'ordering': "('-datetime_accessed',)", 'object_name': 'RecentDocument'}, + 'datetime_accessed': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['documents'] From d83e8b5428e0e79e7b6ab7d0b1624343f21e699e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 2 Dec 2011 02:51:59 -0400 Subject: [PATCH 02/23] Initial set of model, form and API changes to support document versions --- apps/documents/__init__.py | 2 +- apps/documents/admin.py | 33 ++++--- apps/documents/forms.py | 6 +- apps/documents/models.py | 180 +++++++++++++++++++++++++++++++------ apps/ocr/api.py | 2 +- 5 files changed, 182 insertions(+), 41 deletions(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index 14ff0b07a3..f47ab4bab9 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -35,7 +35,7 @@ def is_first_page(context): def is_last_page(context): - return context['page'].page_number >= context['page'].document.documentpage_set.count() + return context['page'].page_number >= context['page'].document_version.pages.count() def is_min_zoom(context): diff --git a/apps/documents/admin.py b/apps/documents/admin.py index 71d0fab939..8ef02b1cea 100644 --- a/apps/documents/admin.py +++ b/apps/documents/admin.py @@ -2,11 +2,29 @@ from django.contrib import admin from metadata.admin import DocumentMetadataInline -from documents.models import DocumentType, Document, \ - DocumentTypeFilename, DocumentPage, \ - DocumentPageTransformation, RecentDocument +from documents.models import (DocumentType, Document, + DocumentTypeFilename, DocumentPage, + DocumentPageTransformation, RecentDocument, + DocumentVersion) +class DocumentPageInline(admin.StackedInline): + model = DocumentPage + extra = 1 + classes = ('collapse-open',) + allow_add = True + + +class DocumentVersionInline(admin.StackedInline): + model = DocumentVersion + extra = 1 + classes = ('collapse-open',) + allow_add = True + inlines = [ + DocumentPageInline, + ] + + class DocumentTypeFilenameInline(admin.StackedInline): model = DocumentTypeFilename extra = 1 @@ -24,16 +42,9 @@ class DocumentPageTransformationAdmin(admin.ModelAdmin): model = DocumentPageTransformation -class DocumentPageInline(admin.StackedInline): - model = DocumentPage - extra = 1 - classes = ('collapse-open',) - allow_add = True - - class DocumentAdmin(admin.ModelAdmin): inlines = [ - DocumentMetadataInline, DocumentPageInline + DocumentMetadataInline, DocumentVersionInline ] list_display = ('uuid', 'file_filename',) diff --git a/apps/documents/forms.py b/apps/documents/forms.py index 320b60bc71..47ac8215da 100644 --- a/apps/documents/forms.py +++ b/apps/documents/forms.py @@ -100,7 +100,7 @@ class DocumentPagesCarouselWidget(forms.widgets.Widget): output = [] output.append(u'
') - for page in value.documentpage_set.all(): + for page in value.pages.all(): output.append(u'
') output.append( document_html_widget( @@ -128,7 +128,7 @@ class DocumentPreviewForm(forms.Form): document = kwargs.pop('document', None) super(DocumentPreviewForm, self).__init__(*args, **kwargs) self.fields['preview'].initial = document - self.fields['preview'].label = _(u'Document pages (%s)') % document.documentpage_set.count() + self.fields['preview'].label = _(u'Document pages (%s)') % document.pages.count() preview = forms.CharField(widget=DocumentPagesCarouselWidget()) @@ -198,7 +198,7 @@ class DocumentContentForm(forms.Form): super(DocumentContentForm, self).__init__(*args, **kwargs) content = [] self.fields['contents'].initial = u'' - for page in self.document.documentpage_set.all(): + for page in self.document.pages.all(): if page.content: content.append(page.content) content.append(u'\n\n\n - Page %s - \n\n\n' % page.page_number) diff --git a/apps/documents/models.py b/apps/documents/models.py index ed578c36b9..6d68e03ae6 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -72,17 +72,20 @@ class Document(models.Model): """ Defines a single document with it's fields and properties """ + # Base fields document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type'), null=True, blank=True) - file = models.FileField(upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'file')) uuid = models.CharField(max_length=48, default=UUID_FUNCTION(), blank=True, editable=False) - file_mimetype = models.CharField(max_length=64, default='', editable=False) - file_mime_encoding = models.CharField(max_length=64, default='', editable=False) - #FAT filename can be up to 255 using LFN - file_filename = models.CharField(max_length=255, default=u'', editable=False, db_index=True) - date_added = models.DateTimeField(verbose_name=_(u'added'), auto_now_add=True, db_index=True) - date_updated = models.DateTimeField(verbose_name=_(u'updated'), auto_now=True) - checksum = models.TextField(blank=True, null=True, verbose_name=_(u'checksum'), editable=False) description = models.TextField(blank=True, null=True, verbose_name=_(u'description'), db_index=True) + date_added = models.DateTimeField(verbose_name=_(u'added'), auto_now_add=True, db_index=True) + + ## Fields to migrate + #file = models.FileField(upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'file')) + #file_mimetype = models.CharField(max_length=64, default='', editable=False) + #file_mime_encoding = models.CharField(max_length=64, default='', editable=False) + ##FAT filename can be up to 255 using LFN + #file_filename = models.CharField(max_length=255, default=u'', editable=False, db_index=True) + #date_updated = models.DateTimeField(verbose_name=_(u'updated'), auto_now=True) + #checksum = models.TextField(blank=True, null=True, verbose_name=_(u'checksum'), editable=False) tags = TaggableManager() @@ -155,7 +158,8 @@ class Document(models.Model): Return a file descriptor to a document's file irrespective of the storage backend """ - return self.file.storage.open(self.file.path) + #return self.file.storage.open(self.file.path) + return self.get_latest_version().file.storage.open(self.get_latest_version().file.path) def update_checksum(self, save=True): """ @@ -163,11 +167,11 @@ class Document(models.Model): user provided checksum function """ if self.exists(): - source = self.open() - self.checksum = unicode(CHECKSUM_FUNCTION(source.read())) + source = self.get_latest_version().open() + self.get_latest_version().checksum = unicode(CHECKSUM_FUNCTION(source.read())) source.close() if save: - self.save() + self.get_latest_version().save() def update_page_count(self, save=True): handle, filepath = tempfile.mkstemp() @@ -204,7 +208,8 @@ class Document(models.Model): @property def page_count(self): - return self.documentpage_set.count() + #return self.documentpage_set.count() + return self.get_latest_version().documentpage_set.count() def save_to_file(self, filepath, buffer_size=1024 * 1024): """ @@ -229,13 +234,13 @@ class Document(models.Model): Returns a boolean value that indicates if the document's file exists in storage """ - return self.file.storage.exists(self.file.path) + return self.get_latest_version().file.storage.exists(self.get_latest_version().file.path) def apply_default_transformations(self, transformations): #Only apply default transformations on new documents - if reduce(lambda x, y: x + y, [page.documentpagetransformation_set.count() for page in self.documentpage_set.all()]) == 0: + if reduce(lambda x, y: x + y, [page.documentpagetransformation_set.count() for page in self.pages.all()]) == 0: for transformation in transformations: - for document_page in self.documentpage_set.all(): + for document_page in self.pages.all(): page_transformation = DocumentPageTransformation( document_page=document_page, order=0, @@ -246,7 +251,7 @@ class Document(models.Model): page_transformation.save() def get_cached_image_name(self, page): - document_page = self.documentpage_set.get(page_number=page) + document_page = self.pages.get(page_number=page) transformations, warnings = document_page.get_transformation_list() hash_value = HASH_FUNCTION(u''.join([self.checksum, unicode(page), unicode(transformations)])) return os.path.join(CACHE_PATH, hash_value), transformations @@ -300,15 +305,129 @@ class Document(models.Model): def delete(self, *args, **kwargs): super(Document, self).delete(*args, **kwargs) - return self.file.storage.delete(self.file.path) + for version in self.documentversion_set.all(): + version.file.storage.delete(version.file.path) + #return self.get_latest_version().file.storage.delete(self.get_latest_version().file.path) @property def size(self): if self.exists(): - return self.file.storage.size(self.file.path) + return self.get_latest_version().file.storage.size(self.get_latest_version().file.path) else: return None - + + # Compatibiliy methods + @property + def file(self): + return self.get_latest_version().file + + @property + def file_mimetype(self): + return self.get_latest_version().mimetype + + @property + def file_mime_encoding(self): + return self.get_latest_version().encoding + + @property + def file_filename(self): + return self.get_latest_version().filename + + @property + def date_updated(self): + return self.get_latest_version().timestamp + + #@property + #def date_added(self): + # return self.get_latest_version().timestamp + + @property + def checksum(self): + return self.get_latest_version().checksum + + @property + def pages(self): + return self.get_latest_version().pages + + + #file = models.FileField(upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'file')) + #file_mimetype = models.CharField(max_length=64, default='', editable=False) + #file_mime_encoding = models.CharField(max_length=64, default='', editable=False) + ##FAT filename can be up to 255 using LFN + #file_filename = models.CharField(max_length=255, default=u'', editable=False, db_index=True) + #date_updated = models.DateTimeField(verbose_name=_(u'updated'), auto_now=True) + #checksum = models.TextField(blank=True, null=True, verbose_name=_(u'checksum'), editable=False) + + def get_latest_version(self): + return self.documentversion_set.order_by('-timestamp')[0] + + +RELEASE_LEVEL_FINAL = 1 +RELEASE_LEVEL_ALPHA = 2 +RELEASE_LEVEL_BETA = 3 +RELEASE_LEVEL_RC = 4 +RELEASE_LEVEL_HF = 5 + +RELEASE_LEVEL_CHOICES = ( + (RELEASE_LEVEL_FINAL, _(u'final')), + (RELEASE_LEVEL_ALPHA, _(u'alpha')), + (RELEASE_LEVEL_BETA, _(u'beta')), + (RELEASE_LEVEL_RC, _(u'release candidate')), + (RELEASE_LEVEL_HF, _(u'hotfix')), +) + +class DocumentVersion(models.Model): + ''' + Model that describes a document version and it properties + ''' + document = models.ForeignKey(Document, verbose_name=_(u'document')) + mayor = models.PositiveIntegerField(verbose_name=_(u'mayor'), default=1) + minor = models.PositiveIntegerField(verbose_name=_(u'minor'), default=0) + micro = models.PositiveIntegerField(verbose_name=_(u'micro'), default=0) + release_level = models.PositiveIntegerField(choices=RELEASE_LEVEL_CHOICES, default=RELEASE_LEVEL_FINAL, verbose_name=_(u'release level')) + serial = models.PositiveIntegerField(verbose_name=_(u'serial'), default=0) + timestamp = models.DateTimeField(verbose_name=_(u'timestamp')) + + # File related fields + file = models.FileField(upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'file')) + mimetype = models.CharField(max_length=64, default='', editable=False) + encoding = models.CharField(max_length=64, default='', editable=False) + filename = models.CharField(max_length=255, default=u'', editable=False, db_index=True) + checksum = models.TextField(blank=True, null=True, verbose_name=_(u'checksum'), editable=False) + + class Meta: + unique_together = ('document', 'mayor', 'minor', 'micro', 'release_level', 'serial') + verbose_name = _(u'document version') + verbose_name_plural = _(u'document version') + + def __unicode__(self): + return self.get_version() + + # TODO: Update timestamp + + def get_version(): + ''' + Return the formatted version information + ''' + vers = [u'%(major)i.%(minor)i' % self, ] + + if self.micro: + vers.append(u'.%(micro)i' % self) + if self.releaselevel != RELEASE_LEVEL_FINAL: + vers.append(u'%(releaselevel)s%(serial)i' % self) + return u''.join(vers) + + @property + def pages(self): + return self.documentpage_set + + def open(self): + ''' + Return a file descriptor to a document version's file irrespective of + the storage backend + ''' + return self.file.storage.open(self.file.path) + class DocumentTypeFilename(models.Model): """ @@ -332,7 +451,13 @@ class DocumentPage(models.Model): """ Model that describes a document page including it's content """ - document = models.ForeignKey(Document, verbose_name=_(u'document')) + ## This field is to be removed + #document = models.ForeignKey(Document, verbose_name=_(u'document')) + + # New parent field + document_version = models.ForeignKey(DocumentVersion, verbose_name=_(u'document version'))#, null=True, blank=True) # TODO: Remove these after datamigration + + # Unchanged fields content = models.TextField(blank=True, null=True, verbose_name=_(u'content'), db_index=True) page_label = models.CharField(max_length=32, blank=True, null=True, verbose_name=_(u'page label')) page_number = models.PositiveIntegerField(default=1, editable=False, verbose_name=_(u'page number'), db_index=True) @@ -341,7 +466,7 @@ class DocumentPage(models.Model): return _(u'Page %(page_num)d out of %(total_pages)d of %(document)s') % { 'document': unicode(self.document), 'page_num': self.page_number, - 'total_pages': self.document.documentpage_set.count() + 'total_pages': self.document_version.documentpage_set.count() } class Meta: @@ -355,6 +480,11 @@ class DocumentPage(models.Model): @models.permalink def get_absolute_url(self): return ('document_page_view', [self.pk]) + + # Compatibility methods + @property + def document(self): + return self.document_version.document class ArgumentsValidator(object): @@ -421,10 +551,10 @@ class RecentDocument(models.Model): # Register the fields that will be searchable register('document', Document, _(u'document'), [ {'name': u'document_type__name', 'title': _(u'Document type')}, - {'name': u'file_mimetype', 'title': _(u'MIME type')}, - {'name': u'file_filename', 'title': _(u'Filename')}, + {'name': u'documentversion__mimetype', 'title': _(u'MIME type')}, + {'name': u'documentversion__filename', 'title': _(u'Filename')}, {'name': u'documentmetadata__value', 'title': _(u'Metadata value')}, - {'name': u'documentpage__content', 'title': _(u'Content')}, + {'name': u'documentversion__documentpage__content', 'title': _(u'Content')}, {'name': u'description', 'title': _(u'Description')}, {'name': u'tags__name', 'title': _(u'Tags')}, {'name': u'comments__comment', 'title': _(u'Comments')}, diff --git a/apps/ocr/api.py b/apps/ocr/api.py index 4d70443f92..e568ecf6c8 100644 --- a/apps/ocr/api.py +++ b/apps/ocr/api.py @@ -88,7 +88,7 @@ def do_document_ocr(queue_document): parser, if the parser fails or if there is no parser registered for the document mimetype do a visual OCR by calling tesseract """ - for document_page in queue_document.document.documentpage_set.all(): + for document_page in queue_document.document.pages.all(): try: # Try to extract text by means of a parser parse_document_page(document_page) From 640a1c2966f5f1f76c6374f0bb888825c1976f5d Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 2 Dec 2011 05:53:12 -0400 Subject: [PATCH 03/23] Add two new migrations, one to fix a field name, the other to add a comment field to the document versions --- .../migrations/0007_fix_mayor_field_name.py | 172 ++++++++++++++++++ .../migrations/0008_add_comment_field.py | 155 ++++++++++++++++ 2 files changed, 327 insertions(+) create mode 100644 apps/documents/migrations/0007_fix_mayor_field_name.py create mode 100644 apps/documents/migrations/0008_add_comment_field.py diff --git a/apps/documents/migrations/0007_fix_mayor_field_name.py b/apps/documents/migrations/0007_fix_mayor_field_name.py new file mode 100644 index 0000000000..dc540dfbec --- /dev/null +++ b/apps/documents/migrations/0007_fix_mayor_field_name.py @@ -0,0 +1,172 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Removing unique constraint on 'DocumentVersion', fields ['release_level', 'micro', 'serial', 'document', 'mayor', 'minor'] + db.delete_unique('documents_documentversion', ['release_level', 'micro', 'serial', 'document_id', 'mayor', 'minor']) + + # Deleting field 'DocumentVersion.mayor' + db.delete_column('documents_documentversion', 'mayor') + + # Adding field 'DocumentVersion.major' + db.add_column('documents_documentversion', 'major', self.gf('django.db.models.fields.PositiveIntegerField')(default=1), keep_default=False) + + # Adding unique constraint on 'DocumentVersion', fields ['major', 'release_level', 'micro', 'serial', 'document', 'minor'] + db.create_unique('documents_documentversion', ['major', 'release_level', 'micro', 'serial', 'document_id', 'minor']) + + + def backwards(self, orm): + + # Removing unique constraint on 'DocumentVersion', fields ['major', 'release_level', 'micro', 'serial', 'document', 'minor'] + db.delete_unique('documents_documentversion', ['major', 'release_level', 'micro', 'serial', 'document_id', 'minor']) + + # Adding field 'DocumentVersion.mayor' + db.add_column('documents_documentversion', 'mayor', self.gf('django.db.models.fields.PositiveIntegerField')(default=1), keep_default=False) + + # Deleting field 'DocumentVersion.major' + db.delete_column('documents_documentversion', 'major') + + # Adding unique constraint on 'DocumentVersion', fields ['release_level', 'micro', 'serial', 'document', 'mayor', 'minor'] + db.create_unique('documents_documentversion', ['release_level', 'micro', 'serial', 'document_id', 'mayor', 'minor']) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + '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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + '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', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + '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', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}), + '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'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'default': "u'750a3848-39cf-45a5-9a96-e948d09833d7'", 'max_length': '48', 'blank': 'True'}) + }, + 'documents.documentpage': { + 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, + 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'page_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}) + }, + 'documents.documentpagetransformation': { + 'Meta': {'ordering': "('order',)", 'object_name': 'DocumentPageTransformation'}, + 'arguments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_page': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentPage']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True', 'blank': 'True'}), + 'transformation': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'documents.documenttypefilename': { + 'Meta': {'ordering': "['filename']", 'object_name': 'DocumentTypeFilename'}, + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'documents.documentversion': { + 'Meta': {'unique_together': "(('document', 'major', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'major': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {}) + }, + 'documents.recentdocument': { + 'Meta': {'ordering': "('-datetime_accessed',)", 'object_name': 'RecentDocument'}, + 'datetime_accessed': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['documents'] diff --git a/apps/documents/migrations/0008_add_comment_field.py b/apps/documents/migrations/0008_add_comment_field.py new file mode 100644 index 0000000000..2010270407 --- /dev/null +++ b/apps/documents/migrations/0008_add_comment_field.py @@ -0,0 +1,155 @@ +# encoding: utf-8 +import 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 'DocumentVersion.comment' + db.add_column('documents_documentversion', 'comment', self.gf('django.db.models.fields.TextField')(default='', blank=True), keep_default=False) + + + def backwards(self, orm): + + # Deleting field 'DocumentVersion.comment' + db.delete_column('documents_documentversion', 'comment') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + '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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + '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', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + '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', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}), + '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'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'default': "u'123068ef-26d2-45bb-8933-cb6818cd87e4'", 'max_length': '48', 'blank': 'True'}) + }, + 'documents.documentpage': { + 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, + 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'page_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}) + }, + 'documents.documentpagetransformation': { + 'Meta': {'ordering': "('order',)", 'object_name': 'DocumentPageTransformation'}, + 'arguments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_page': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentPage']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True', 'blank': 'True'}), + 'transformation': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'documents.documenttypefilename': { + 'Meta': {'ordering': "['filename']", 'object_name': 'DocumentTypeFilename'}, + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'documents.documentversion': { + 'Meta': {'unique_together': "(('document', 'major', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'major': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {}) + }, + 'documents.recentdocument': { + 'Meta': {'ordering': "('-datetime_accessed',)", 'object_name': 'RecentDocument'}, + 'datetime_accessed': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['documents'] From 3e471f702e4fbbfd703953313512f3f44196ae7c Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 2 Dec 2011 05:54:00 -0400 Subject: [PATCH 04/23] Add document version list view and document version download --- apps/documents/__init__.py | 17 ++++++++++--- apps/documents/admin.py | 6 ++--- apps/documents/models.py | 19 +++++++++------ apps/documents/urls.py | 3 +++ apps/documents/views.py | 50 ++++++++++++++++++++++++++++++++++++-- 5 files changed, 80 insertions(+), 15 deletions(-) diff --git a/apps/documents/__init__.py b/apps/documents/__init__.py index f47ab4bab9..1a39e01ac8 100644 --- a/apps/documents/__init__.py +++ b/apps/documents/__init__.py @@ -13,8 +13,9 @@ from history.api import register_history_type from metadata.api import get_metadata_string from project_setup.api import register_setup -from documents.models import Document, DocumentPage, \ - DocumentPageTransformation, DocumentType, DocumentTypeFilename +from documents.models import (Document, DocumentPage, + DocumentPageTransformation, DocumentType, DocumentTypeFilename, + DocumentVersion) from documents.literals import PERMISSION_DOCUMENT_CREATE, \ PERMISSION_DOCUMENT_PROPERTIES_EDIT, PERMISSION_DOCUMENT_VIEW, \ PERMISSION_DOCUMENT_DELETE, PERMISSION_DOCUMENT_DOWNLOAD, \ @@ -78,6 +79,7 @@ document_multiple_delete = {'text': _(u'delete'), 'view': 'document_multiple_del document_edit = {'text': _(u'edit'), 'view': 'document_edit', 'args': 'object.id', 'famfam': 'page_edit', 'permissions': [PERMISSION_DOCUMENT_PROPERTIES_EDIT]} document_preview = {'text': _(u'preview'), 'class': 'fancybox', 'view': 'document_preview', 'args': 'object.id', 'famfam': 'magnifier', 'permissions': [PERMISSION_DOCUMENT_VIEW]} document_download = {'text': _(u'download'), 'view': 'document_download', 'args': 'object.id', 'famfam': 'page_save', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]} +document_version_download = {'text': _(u'download'), 'view': 'document_version_download', 'args': 'object.pk', 'famfam': 'page_save', 'permissions': [PERMISSION_DOCUMENT_DOWNLOAD]} document_find_duplicates = {'text': _(u'find duplicates'), 'view': 'document_find_duplicates', 'args': 'object.id', 'famfam': 'page_refresh', 'permissions': [PERMISSION_DOCUMENT_VIEW]} document_find_all_duplicates = {'text': _(u'find all duplicates'), 'view': 'document_find_all_duplicates', 'famfam': 'page_refresh', 'permissions': [PERMISSION_DOCUMENT_VIEW], 'description': _(u'Search all the documents\' checksums and return a list of the exact matches.')} document_update_page_count = {'text': _(u'update office documents\' page count'), 'view': 'document_update_page_count', 'famfam': 'page_white_csharp', 'permissions': [PERMISSION_DOCUMENT_TOOLS], 'description': _(u'Update the page count of the office type documents. This is useful when enabling office document support after there were already office type documents in the database.')} @@ -85,8 +87,12 @@ document_clear_transformations = {'text': _(u'clear transformations'), 'view': ' document_multiple_clear_transformations = {'text': _(u'clear transformations'), 'view': 'document_multiple_clear_transformations', 'famfam': 'page_paintbrush', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} document_print = {'text': _(u'print'), 'view': 'document_print', 'args': 'object.id', 'famfam': 'printer', 'permissions': [PERMISSION_DOCUMENT_VIEW]} document_history_view = {'text': _(u'history'), 'view': 'history_for_object', 'args': ['"documents"', '"document"', 'object.id'], 'famfam': 'book_go', 'permissions': [PERMISSION_DOCUMENT_VIEW]} +document_missing_list = {'text': _(u'Find missing document files'), 'view': 'document_missing_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_VIEW]} + +# Tools document_clear_image_cache = {'text': _(u'Clear the document image cache'), 'view': 'document_clear_image_cache', 'famfam': 'camera_delete', 'permissions': [PERMISSION_DOCUMENT_TOOLS], 'description': _(u'Clear the graphics representations used to speed up the documents\' display and interactive transformations results.')} +# Document pages document_page_transformation_list = {'text': _(u'page transformations'), 'class': 'no-parent-history', 'view': 'document_page_transformation_list', 'args': 'page.pk', 'famfam': 'pencil_go', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} document_page_transformation_create = {'text': _(u'create new transformation'), 'class': 'no-parent-history', 'view': 'document_page_transformation_create', 'args': 'page.pk', 'famfam': 'pencil_add', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} document_page_transformation_edit = {'text': _(u'edit'), 'class': 'no-parent-history', 'view': 'document_page_transformation_edit', 'args': 'transformation.pk', 'famfam': 'pencil_go', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]} @@ -105,7 +111,8 @@ document_page_rotate_right = {'text': _(u'rotate right'), 'class': 'no-parent-hi document_page_rotate_left = {'text': _(u'rotate left'), 'class': 'no-parent-history', 'view': 'document_page_rotate_left', 'args': 'page.pk', 'famfam': 'arrow_turn_left', 'permissions': [PERMISSION_DOCUMENT_VIEW]} document_page_view_reset = {'text': _(u'reset view'), 'class': 'no-parent-history', 'view': 'document_page_view_reset', 'args': 'page.pk', 'famfam': 'page_white', 'permissions': [PERMISSION_DOCUMENT_VIEW]} -document_missing_list = {'text': _(u'Find missing document files'), 'view': 'document_missing_list', 'famfam': 'folder_page', 'permissions': [PERMISSION_DOCUMENT_VIEW]} +# Document versions +document_version_list = {'text': _(u'versions'), 'view': 'document_version_list', 'args': 'object.pk', 'famfam': 'page_world', 'permissions': [PERMISSION_DOCUMENT_VIEW]} # Document type related links document_type_list = {'text': _(u'document type list'), 'view': 'document_type_list', 'famfam': 'layout', 'permissions': [PERMISSION_DOCUMENT_VIEW]} @@ -133,6 +140,9 @@ register_links(['document_type_filename_create', 'document_type_filename_list', register_links(Document, [document_edit, document_print, document_delete, document_download, document_find_duplicates, document_clear_transformations, document_create_siblings]) register_multi_item_links(['document_find_duplicates', 'folder_view', 'index_instance_list', 'document_type_document_list', 'search', 'results', 'document_group_view', 'document_list', 'document_list_recent'], [document_multiple_clear_transformations, document_multiple_delete]) +# Document Version links +register_links(DocumentVersion, [document_version_download]) + secondary_menu_links = [document_list_recent, document_list, document_create_multiple] register_links(['document_list_recent', 'document_list', 'document_create', 'document_create_multiple', 'upload_interactive', 'staging_file_delete'], secondary_menu_links, menu_name='secondary_menu') @@ -198,6 +208,7 @@ register_sidebar_template(['document_type_list'], 'document_types_help.html') register_links(Document, [document_view_simple], menu_name='form_header', position=0) register_links(Document, [document_view_advanced], menu_name='form_header', position=1) register_links(Document, [document_history_view], menu_name='form_header') +register_links(Document, [document_version_list], menu_name='form_header') if (validate_path(document_settings.CACHE_PATH) == False) or (not document_settings.CACHE_PATH): setattr(document_settings, 'CACHE_PATH', tempfile.mkdtemp()) diff --git a/apps/documents/admin.py b/apps/documents/admin.py index 8ef02b1cea..8fc0e838bb 100644 --- a/apps/documents/admin.py +++ b/apps/documents/admin.py @@ -20,9 +20,9 @@ class DocumentVersionInline(admin.StackedInline): extra = 1 classes = ('collapse-open',) allow_add = True - inlines = [ - DocumentPageInline, - ] + #inlines = [ + # DocumentPageInline, + #] class DocumentTypeFilenameInline(admin.StackedInline): diff --git a/apps/documents/models.py b/apps/documents/models.py index 6d68e03ae6..ab1165bf5f 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -361,6 +361,10 @@ class Document(models.Model): def get_latest_version(self): return self.documentversion_set.order_by('-timestamp')[0] + @property + def versions(self): + return self.documentversion_set + RELEASE_LEVEL_FINAL = 1 RELEASE_LEVEL_ALPHA = 2 @@ -381,12 +385,13 @@ class DocumentVersion(models.Model): Model that describes a document version and it properties ''' document = models.ForeignKey(Document, verbose_name=_(u'document')) - mayor = models.PositiveIntegerField(verbose_name=_(u'mayor'), default=1) + major = models.PositiveIntegerField(verbose_name=_(u'mayor'), default=1) minor = models.PositiveIntegerField(verbose_name=_(u'minor'), default=0) micro = models.PositiveIntegerField(verbose_name=_(u'micro'), default=0) release_level = models.PositiveIntegerField(choices=RELEASE_LEVEL_CHOICES, default=RELEASE_LEVEL_FINAL, verbose_name=_(u'release level')) serial = models.PositiveIntegerField(verbose_name=_(u'serial'), default=0) timestamp = models.DateTimeField(verbose_name=_(u'timestamp')) + comment = models.TextField(blank=True, verbose_name=_(u'comment')) # File related fields file = models.FileField(upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'file')) @@ -396,7 +401,7 @@ class DocumentVersion(models.Model): checksum = models.TextField(blank=True, null=True, verbose_name=_(u'checksum'), editable=False) class Meta: - unique_together = ('document', 'mayor', 'minor', 'micro', 'release_level', 'serial') + unique_together = ('document', 'major', 'minor', 'micro', 'release_level', 'serial') verbose_name = _(u'document version') verbose_name_plural = _(u'document version') @@ -405,16 +410,16 @@ class DocumentVersion(models.Model): # TODO: Update timestamp - def get_version(): + def get_version(self): ''' Return the formatted version information ''' - vers = [u'%(major)i.%(minor)i' % self, ] + vers = [u'%i.%i' % (self.major, self.minor), ] if self.micro: - vers.append(u'.%(micro)i' % self) - if self.releaselevel != RELEASE_LEVEL_FINAL: - vers.append(u'%(releaselevel)s%(serial)i' % self) + vers.append(u'.%i' % self.micro) + if self.release_level != RELEASE_LEVEL_FINAL: + vers.append(u'%s%i' % (self.release_level, self.serial)) return u''.join(vers) @property diff --git a/apps/documents/urls.py b/apps/documents/urls.py index e3cfbf598d..88650155a7 100644 --- a/apps/documents/urls.py +++ b/apps/documents/urls.py @@ -33,6 +33,9 @@ urlpatterns = patterns('documents.views', url(r'^(?P\d+)/create/siblings/$', 'document_create_siblings', (), 'document_create_siblings'), url(r'^(?P\d+)/find_duplicates/$', 'document_find_duplicates', (), 'document_find_duplicates'), url(r'^(?P\d+)/clear_transformations/$', 'document_clear_transformations', (), 'document_clear_transformations'), + + url(r'^(?P\d+)/version/all/$', 'document_version_list', (), 'document_version_list'), + url(r'^document/version/(?P\d+)/download/$', 'document_version_download', (), 'document_version_download'), url(r'^multiple/clear_transformations/$', 'document_multiple_clear_transformations', (), 'document_multiple_clear_transformations'), url(r'^duplicates/list/$', 'document_find_all_duplicates', (), 'document_find_all_duplicates'), diff --git a/apps/documents/views.py b/apps/documents/views.py index ba0e18e315..efaaf3e2da 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -53,8 +53,9 @@ from documents.forms import DocumentTypeSelectForm, \ DocumentPageForm_text, PrintForm, DocumentTypeForm, \ DocumentTypeFilenameForm, DocumentTypeFilenameForm_create from documents.wizards import DocumentCreateWizard -from documents.models import Document, DocumentType, DocumentPage, \ - DocumentPageTransformation, RecentDocument, DocumentTypeFilename +from documents.models import (Document, DocumentType, DocumentPage, + DocumentPageTransformation, RecentDocument, DocumentTypeFilename, + DocumentVersion) # Document type permissions from documents.literals import PERMISSION_DOCUMENT_TYPE_EDIT, \ @@ -294,6 +295,10 @@ def get_document_image(request, document_id, size=PREVIEW_SIZE, base64_version=F return sendfile.sendfile(request, document.get_image(size=size, page=page, zoom=zoom, rotation=rotation), mimetype=DEFAULT_FILE_FORMAT_MIMETYPE) +def document_version_download(request, document_version_pk): + document_version = get_object_or_404(DocumentVersion, pk=document_version_pk) + return document_download(request, document_version.document.pk) + def document_download(request, document_id): check_permissions(request.user, [PERMISSION_DOCUMENT_DOWNLOAD]) @@ -1142,3 +1147,44 @@ def document_clear_image_cache(request): 'title': _(u'Are you sure you wish to clear the document image cache?'), 'form_icon': u'camera_delete.png', }, context_instance=RequestContext(request)) + + +def document_version_list(request, document_pk): + check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) + document = get_object_or_404(Document, pk=document_pk) + + context = { + 'object_list': document.versions.all(), + 'title': _(u'versions for document: %s') % document, + 'hide_object': True, + 'object': document, + 'extra_columns': [ + { + 'name': _(u'version'), + 'attribute': 'get_version', + }, + { + 'name': _(u'time and date'), + 'attribute': 'timestamp', + }, + { + 'name': _(u'mimetype'), + 'attribute': 'mimetype', + }, + { + 'name': _(u'encoding'), + 'attribute': 'encoding', + }, + { + 'name': _(u'filename'), + 'attribute': 'filename', + }, + { + 'name': _(u'comment'), + 'attribute': 'comment', + }, + ] + } + + return render_to_response('generic_list.html', context, + context_instance=RequestContext(request)) From 5905dbd3e0786ffca4df987c2d9ee491b5f05bad Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 2 Dec 2011 05:54:36 -0400 Subject: [PATCH 05/23] Updated changelog --- docs/changelog.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 6f5cd78643..17106351dd 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,3 +1,7 @@ +2011-12-2 +--------- +* Added migrations and model updated to support document versions + 2011-12-1 --------- * OCR queue processing improvements From e92a0f79964477dfb18a5dc1c3aa4ded9ad05778 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 2 Dec 2011 05:55:01 -0400 Subject: [PATCH 06/23] Updated version to 0.11beta2 and add python authoring structures --- apps/main/__init__.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/apps/main/__init__.py b/apps/main/__init__.py index 0532245481..582747e0d5 100644 --- a/apps/main/__init__.py +++ b/apps/main/__init__.py @@ -8,24 +8,33 @@ from project_tools.api import register_tool from main.conf.settings import SIDE_BAR_SEARCH from main.conf.settings import DISABLE_HOME_VIEW +__author__ = 'Roberto Rosario' +__copyright__ = 'Copyright 2011 Roberto Rosario' +__credits__ = ['Roberto Rosario',] +__license__ = 'GPL' +__maintainer__ = 'Roberto Rosario' +__email__ = 'roberto.rosario.gonzalez@gmail.com' +__status__ = 'Production' + +__version_info__ = { + 'major': 0, + 'minor': 11, + 'micro': 0, + 'releaselevel': 'beta', + 'serial': 2 +} + def is_superuser(context): return context['request'].user.is_staff or context['request'].user.is_superuser + maintenance_menu = {'text': _(u'maintenance'), 'view': 'maintenance_menu', 'famfam': 'wrench', 'icon': 'wrench.png'} statistics = {'text': _(u'statistics'), 'view': 'statistics', 'famfam': 'table', 'icon': 'blackboard_sum.png'} diagnostics = {'text': _(u'diagnostics'), 'view': 'diagnostics', 'famfam': 'pill', 'icon': 'pill.png'} sentry = {'text': _(u'sentry'), 'view': 'sentry', 'famfam': 'bug', 'icon': 'bug.png', 'condition': is_superuser} admin_site = {'text': _(u'admin site'), 'view': 'admin:index', 'famfam': 'keyboard', 'icon': 'keyboard.png', 'condition': is_superuser} -__version_info__ = { - 'major': 0, - 'minor': 10, - 'micro': 0, - 'releaselevel': 'final', - 'serial': 0 -} - if not DISABLE_HOME_VIEW: register_top_menu('home', link={'text': _(u'home'), 'view': 'home', 'famfam': 'house'}, position=0) if not SIDE_BAR_SEARCH: @@ -36,14 +45,15 @@ def get_version(): """ Return the formatted version information """ - vers = ["%(major)i.%(minor)i" % __version_info__, ] + vers = ['%(major)i.%(minor)i' % __version_info__, ] if __version_info__['micro']: - vers.append(".%(micro)i" % __version_info__) + vers.append('.%(micro)i' % __version_info__) if __version_info__['releaselevel'] != 'final': vers.append('%(releaselevel)s%(serial)i' % __version_info__) return ''.join(vers) + __version__ = get_version() register_setup(admin_site) From 8c02c4c426d436e635aea5fcd976583e66039dbf Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 2 Dec 2011 05:55:42 -0400 Subject: [PATCH 07/23] Disable ocr document queue signal It appears Django executes signals using the same process as the caller, effectively blocking the view until the OCR process completes which could take several minutes :/ --- apps/ocr/__init__.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/ocr/__init__.py b/apps/ocr/__init__.py index def0d7064b..b07fa07d72 100644 --- a/apps/ocr/__init__.py +++ b/apps/ocr/__init__.py @@ -108,11 +108,14 @@ def document_post_save(sender, instance, **kwargs): post_save.connect(document_post_save, sender=Document) -@receiver(post_save, dispatch_uid='call_queue', sender=QueueDocument) -def call_queue(sender, **kwargs): - if kwargs.get('created', False): - logger.debug('got call_queue signal: %s' % kwargs) - task_process_document_queues() +# Disabled because it appears Django execute signals using the same +# process effectively blocking the view until the OCR process completes +# which could take several minutes :/ +#@receiver(post_save, dispatch_uid='call_queue', sender=QueueDocument) +#def call_queue(sender, **kwargs): +# if kwargs.get('created', False): +# logger.debug('got call_queue signal: %s' % kwargs) +# task_process_document_queues() create_default_queue() From 1e38369919e71945aae04819b63a51f36a3f0531 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 2 Dec 2011 05:56:34 -0400 Subject: [PATCH 08/23] Update parser to use the latest version of a document when extracting text --- apps/ocr/parsers/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/ocr/parsers/__init__.py b/apps/ocr/parsers/__init__.py index 8fac71c084..3d5a39635e 100644 --- a/apps/ocr/parsers/__init__.py +++ b/apps/ocr/parsers/__init__.py @@ -26,7 +26,7 @@ def register_parser(function, mimetype=None, mimetypes=None): def pdf_parser(document_page, descriptor=None): if not descriptor: - descriptor = document_page.document.open() + descriptor = document_page.document_version.open() pdf_pages = slate.PDF(descriptor) descriptor.close() From d4a70c0fc12c6434428f024a8506fbfcedf53af2 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 3 Dec 2011 19:31:59 -0400 Subject: [PATCH 09/23] Cleanup remarks from migration --- apps/documents/migrations/0005_document_versions.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/documents/migrations/0005_document_versions.py b/apps/documents/migrations/0005_document_versions.py index 738dfe9147..7244593da3 100644 --- a/apps/documents/migrations/0005_document_versions.py +++ b/apps/documents/migrations/0005_document_versions.py @@ -10,11 +10,6 @@ class Migration(DataMigration): for document in orm.Document.objects.all(): document_version = document.documentversion_set.create( document = document, - #mayor = 1 - #minor = models.PositiveIntegerField(verbose_name=_(u'minor'), default=0) - #micro = models.PositiveIntegerField(verbose_name=_(u'micro'), default=0) - #release_level = models.PositiveIntegerField(choices=RELEASE_LEVEL_CHOICES, default=RELEASE_LEVEL_FINAL, verbose_name=_(u'release level')) - #serial = models.PositiveIntegerField(verbose_name=_(u'serial'), default=0) timestamp = document.date_added, file = document.file, mimetype = document.file_mimetype, From 9f7e5de5ac154e7838745aaafbd9082c789933f7 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 3 Dec 2011 19:32:40 -0400 Subject: [PATCH 10/23] Add migration to remove old file fields --- apps/documents/migrations/0006_remove_old_file_fields.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/documents/migrations/0006_remove_old_file_fields.py b/apps/documents/migrations/0006_remove_old_file_fields.py index 203532d012..7abf68d028 100644 --- a/apps/documents/migrations/0006_remove_old_file_fields.py +++ b/apps/documents/migrations/0006_remove_old_file_fields.py @@ -9,7 +9,7 @@ class Migration(SchemaMigration): def forwards(self, orm): # Changing field 'DocumentVersion.document' - db.alter_column('documents_documentversion', 'document_id', self.gf('django.db.models.fields.related.ForeignKey')(default='', to=orm['documents.Document'])) + db.alter_column('documents_documentversion', 'document_id', self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['documents.Document'])) # Deleting field 'Document.date_updated' db.delete_column('documents_document', 'date_updated') @@ -33,7 +33,8 @@ class Migration(SchemaMigration): db.delete_column('documents_documentpage', 'document_id') # Changing field 'DocumentPage.document_version' - db.alter_column('documents_documentpage', 'document_version_id', self.gf('django.db.models.fields.related.ForeignKey')(default='', to=orm['documents.DocumentVersion'])) + #db.alter_column('documents_documentpage', 'document_version_id', self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['documents.DocumentVersion'])) + db.alter_column('documents_documentpage', 'document_version_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.DocumentVersion'])) def backwards(self, orm): @@ -60,7 +61,7 @@ class Migration(SchemaMigration): db.add_column('documents_document', 'file_mime_encoding', self.gf('django.db.models.fields.CharField')(default='', max_length=64), keep_default=False) # Adding field 'DocumentPage.document' - db.add_column('documents_documentpage', 'document', self.gf('django.db.models.fields.related.ForeignKey')(default='', to=orm['documents.Document']), keep_default=False) + db.add_column('documents_documentpage', 'document', self.gf('django.db.models.fields.related.ForeignKey')(default=0, to=orm['documents.Document']), keep_default=False) # Changing field 'DocumentPage.document_version' db.alter_column('documents_documentpage', 'document_version_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.DocumentVersion'], null=True)) From 11725c943b70938b016ad32e4a44d885a5450c98 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 3 Dec 2011 19:35:03 -0400 Subject: [PATCH 11/23] Update documents app to support multiple versions --- apps/documents/forms.py | 55 ++++- apps/documents/literals.py | 18 ++ apps/documents/models.py | 490 +++++++++++++++++++++---------------- apps/documents/urls.py | 2 +- apps/documents/views.py | 48 ++-- 5 files changed, 373 insertions(+), 240 deletions(-) diff --git a/apps/documents/forms.py b/apps/documents/forms.py index 47ac8215da..1033692bfe 100644 --- a/apps/documents/forms.py +++ b/apps/documents/forms.py @@ -11,9 +11,11 @@ from common.conf.settings import DEFAULT_PAPER_SIZE from common.conf.settings import DEFAULT_PAGE_ORIENTATION from common.widgets import TextAreaDiv -from documents.models import Document, DocumentType, \ - DocumentPage, DocumentPageTransformation, DocumentTypeFilename +from documents.models import (Document, DocumentType, + DocumentPage, DocumentPageTransformation, DocumentTypeFilename, + DocumentVersion) from documents.widgets import document_html_widget +from documents.literals import (RELEASE_LEVEL_FINAL, RELEASE_LEVEL_CHOICES) # Document page forms class DocumentPageTransformationForm(forms.ModelForm): @@ -147,6 +149,8 @@ class DocumentForm(forms.ModelForm): instance = kwargs.pop('instance', None) super(DocumentForm, self).__init__(*args, **kwargs) + if instance: + self.version_fields(instance) if 'document_type' in self.fields: # To allow merging with DocumentForm_edit @@ -164,11 +168,51 @@ class DocumentForm(forms.ModelForm): queryset=filenames_qs, required=False, label=_(u'Quick document rename')) + + def version_fields(self, document): + self.fields['comment'] = forms.CharField( + label=_(u'Comment'), + required=False, + widget=forms.widgets.Textarea(attrs={'rows': 4}), + ) + + self.fields['version_update'] = forms.ChoiceField( + label=_(u'Version update'), + #widget=forms.widgets.RadioSelect(), + choices=DocumentVersion.get_version_update_choices(document.latest_version) + ) + + self.fields['release_level'] = forms.ChoiceField( + label=_(u'Release level'), + choices=RELEASE_LEVEL_CHOICES, + initial=RELEASE_LEVEL_FINAL, + #required=False, + ) + + self.fields['serial'] = forms.IntegerField( + label=_(u'Release level serial'), + initial=0, + widget=forms.widgets.TextInput( + attrs = {'style': 'width: auto;'} + ), + #required=False + ) new_filename = forms.CharField( label=_('New document filename'), required=False ) + + def clean(self): + cleaned_data = self.cleaned_data + cleaned_data['new_version_data'] = { + 'comment': self.cleaned_data.get('comment'), + 'version_update': self.cleaned_data.get('version_update'), + 'release_level': self.cleaned_data.get('release_level'), + 'serial': self.cleaned_data.get('serial'), + } + # Always return the full collection of cleaned data. + return cleaned_data class DocumentForm_edit(DocumentForm): """ @@ -177,6 +221,13 @@ class DocumentForm_edit(DocumentForm): class Meta: model = Document exclude = ('file', 'document_type', 'tags') + + def __init__(self, *args, **kwargs): + super(DocumentForm_edit, self).__init__(*args, **kwargs) + self.fields.pop('serial') + self.fields.pop('release_level') + self.fields.pop('version_update') + self.fields.pop('comment') class DocumentPropertiesForm(DetailForm): diff --git a/apps/documents/literals.py b/apps/documents/literals.py index cbb3b919d9..30b0284f5f 100644 --- a/apps/documents/literals.py +++ b/apps/documents/literals.py @@ -44,3 +44,21 @@ HISTORY_DOCUMENT_DELETED = { 'details': _(u'Document "%(document)s" deleted on %(datetime)s by %(fullname)s.'), 'expressions': {'fullname': 'user.get_full_name() if user.get_full_name() else user.username'} } + +RELEASE_LEVEL_FINAL = 1 +RELEASE_LEVEL_ALPHA = 2 +RELEASE_LEVEL_BETA = 3 +RELEASE_LEVEL_RC = 4 +RELEASE_LEVEL_HF = 5 + +RELEASE_LEVEL_CHOICES = ( + (RELEASE_LEVEL_FINAL, _(u'final')), + (RELEASE_LEVEL_ALPHA, _(u'alpha')), + (RELEASE_LEVEL_BETA, _(u'beta')), + (RELEASE_LEVEL_RC, _(u'release candidate')), + (RELEASE_LEVEL_HF, _(u'hotfix')), +) + +VERSION_UPDATE_MAJOR = u'major' +VERSION_UPDATE_MINOR = u'minor' +VERSION_UPDATE_MICRO = u'micro' diff --git a/apps/documents/models.py b/apps/documents/models.py index ab1165bf5f..04c633556f 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -4,6 +4,8 @@ import hashlib from ast import literal_eval import base64 from StringIO import StringIO +import datetime +import logging from django.db import models from django.utils.translation import ugettext_lazy as _ @@ -21,6 +23,8 @@ from converter.api import convert from converter.exceptions import UnknownFileFormat, UnkownConvertError from mimetype.api import get_mimetype, get_icon_file_path, \ get_error_icon_file_path +from converter.literals import (DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, + DEFAULT_PAGE_NUMBER) from documents.conf.settings import CHECKSUM_FUNCTION from documents.conf.settings import UUID_FUNCTION @@ -30,26 +34,25 @@ from documents.conf.settings import DISPLAY_SIZE from documents.conf.settings import CACHE_PATH from documents.conf.settings import ZOOM_MAX_LEVEL from documents.conf.settings import ZOOM_MIN_LEVEL - from documents.managers import RecentDocumentManager, \ DocumentPageTransformationManager from documents.utils import document_save_to_temp_dir -from converter.literals import DEFAULT_ZOOM_LEVEL, DEFAULT_ROTATION, \ - DEFAULT_PAGE_NUMBER +from documents.literals import (RELEASE_LEVEL_FINAL, RELEASE_LEVEL_CHOICES, + VERSION_UPDATE_MAJOR, VERSION_UPDATE_MINOR, VERSION_UPDATE_MICRO) # document image cache name hash function HASH_FUNCTION = lambda x: hashlib.sha256(x).hexdigest() +logger = logging.getLogger(__name__) + def get_filename_from_uuid(instance, filename): """ Store the orignal filename of the uploaded file and replace it with a UUID """ - instance.file_filename = filename - uuid = UUID_FUNCTION() - instance.uuid = uuid - return uuid + instance.filename = filename + return UUID_FUNCTION() class DocumentType(models.Model): @@ -69,24 +72,15 @@ class DocumentType(models.Model): class Document(models.Model): - """ + ''' Defines a single document with it's fields and properties - """ - # Base fields + ''' + uuid = models.CharField(max_length=48, blank=True, editable=False) document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type'), null=True, blank=True) - uuid = models.CharField(max_length=48, default=UUID_FUNCTION(), blank=True, editable=False) description = models.TextField(blank=True, null=True, verbose_name=_(u'description'), db_index=True) + #TODO: remove date_added, it is the timestamp of the first version date_added = models.DateTimeField(verbose_name=_(u'added'), auto_now_add=True, db_index=True) - ## Fields to migrate - #file = models.FileField(upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'file')) - #file_mimetype = models.CharField(max_length=64, default='', editable=False) - #file_mime_encoding = models.CharField(max_length=64, default='', editable=False) - ##FAT filename can be up to 255 using LFN - #file_filename = models.CharField(max_length=255, default=u'', editable=False, db_index=True) - #date_updated = models.DateTimeField(verbose_name=_(u'updated'), auto_now=True) - #checksum = models.TextField(blank=True, null=True, verbose_name=_(u'checksum'), editable=False) - tags = TaggableManager() comments = generic.GenericRelation( @@ -108,147 +102,16 @@ class Document(models.Model): ordering = ['-date_added'] def __unicode__(self): - return self.get_fullname() - - def save(self, *args, **kwargs): - """ - Overloaded save method that updates the document's checksum, - mimetype, page count and transformation when originally created - """ - new_document = not self.pk - transformations = kwargs.pop('transformations', None) - super(Document, self).save(*args, **kwargs) - - if new_document: - #Only do this for new documents - self.update_checksum(save=False) - self.update_mimetype(save=False) - self.save() - self.update_page_count(save=False) - if transformations: - self.apply_default_transformations(transformations) + return self.latest_version.filename @models.permalink def get_absolute_url(self): return ('document_view_simple', [self.pk]) - def get_fullname(self): - """ - Return the fullname of the document's file - """ - return self.file_filename - - def update_mimetype(self, save=True): - """ - Read a document's file and determine the mimetype by calling the - get_mimetype wrapper - """ - if self.exists(): - try: - self.file_mimetype, self.file_mime_encoding = get_mimetype(self.open(), self.get_fullname()) - except: - self.file_mimetype = u'' - self.file_mime_encoding = u'' - finally: - if save: - self.save() - - def open(self): - """ - Return a file descriptor to a document's file irrespective of - the storage backend - """ - #return self.file.storage.open(self.file.path) - return self.get_latest_version().file.storage.open(self.get_latest_version().file.path) - - def update_checksum(self, save=True): - """ - Open a document's file and update the checksum field using the - user provided checksum function - """ - if self.exists(): - source = self.get_latest_version().open() - self.get_latest_version().checksum = unicode(CHECKSUM_FUNCTION(source.read())) - source.close() - if save: - self.get_latest_version().save() - - def update_page_count(self, save=True): - handle, filepath = tempfile.mkstemp() - # Just need the filepath, close the file description - os.close(handle) - - self.save_to_file(filepath) - try: - detected_pages = get_page_count(filepath) - except UnknownFileFormat: - # If converter backend doesn't understand the format, - # use 1 as the total page count - detected_pages = 1 - self.description = ugettext(u'This document\'s file format is not known, the page count has therefore defaulted to 1.') - self.save() - try: - os.remove(filepath) - except OSError: - pass - - current_pages = DocumentPage.objects.filter(document=self).order_by('page_number',) - if current_pages.count() > detected_pages: - for page in current_pages[detected_pages:]: - page.delete() - - for page_number in range(detected_pages): - DocumentPage.objects.get_or_create( - document=self, page_number=page_number + 1) - - if save: - self.save() - - return detected_pages - - @property - def page_count(self): - #return self.documentpage_set.count() - return self.get_latest_version().documentpage_set.count() - - def save_to_file(self, filepath, buffer_size=1024 * 1024): - """ - Save a copy of the document from the document storage backend - to the local filesystem - """ - input_descriptor = self.open() - output_descriptor = open(filepath, 'wb') - while True: - copy_buffer = input_descriptor.read(buffer_size) - if copy_buffer: - output_descriptor.write(copy_buffer) - else: - break - - output_descriptor.close() - input_descriptor.close() - return filepath - - def exists(self): - """ - Returns a boolean value that indicates if the document's file - exists in storage - """ - return self.get_latest_version().file.storage.exists(self.get_latest_version().file.path) - - def apply_default_transformations(self, transformations): - #Only apply default transformations on new documents - if reduce(lambda x, y: x + y, [page.documentpagetransformation_set.count() for page in self.pages.all()]) == 0: - for transformation in transformations: - for document_page in self.pages.all(): - page_transformation = DocumentPageTransformation( - document_page=document_page, - order=0, - transformation=transformation.get('transformation'), - arguments=transformation.get('arguments') - ) - - page_transformation.save() + def save(self, *args, **kwargs): + if not self.pk: + self.uuid = UUID_FUNCTION() + super(Document, self).save(*args, **kwargs) def get_cached_image_name(self, page): document_page = self.pages.get(page_number=page) @@ -302,95 +165,154 @@ class Document(models.Model): def add_as_recent_document_for_user(self, user): RecentDocument.objects.add_document_for_user(user, self) - - def delete(self, *args, **kwargs): - super(Document, self).delete(*args, **kwargs) - for version in self.documentversion_set.all(): - version.file.storage.delete(version.file.path) - #return self.get_latest_version().file.storage.delete(self.get_latest_version().file.path) + + # TODO: investigate if Document's save method calls all of it + # DocumentVersion's delete methods + #def delete(self, *args, **kwargs): + # super(Document, self).delete(*args, **kwargs) + # for version in self.documentversion_set.all(): + # version.file.storage.delete(version.file.path) @property def size(self): if self.exists(): - return self.get_latest_version().file.storage.size(self.get_latest_version().file.path) + return self.latest_version.exists() else: return None + + def new_version(self, file, comment=None, version_update=None, release_level=None, serial=None): + logger.debug('creating new document version') + if version_update: + new_version_dict = self.latest_version.get_new_version_dict(version_update) + new_version = DocumentVersion( + document=self, + file=file, + major = new_version_dict.get('major'), + minor = new_version_dict.get('minor'), + micro = new_version_dict.get('micro'), + release_level = release_level, + serial = serial, + comment = comment, + ) + new_version.save() + else: + new_version_dict = {} + new_version = DocumentVersion( + document=self, + file=file, + #major = new_version_dict.get('major'), + #minor = new_version_dict.get('minor'), + #micro = new_version_dict.get('micro'), + #release_level = release_level, + #serial = serial, + #comment = comment, + ) + new_version.save() - # Compatibiliy methods + + logger.debug('new_version_dict: %s' % new_version_dict) + + logger.debug('new_version saved') + return new_version + + # Proxy methods + def open(self): + ''' + Return a file descriptor to a document's file irrespective of + the storage backend + ''' + return self.latest_version.open() + + def save_to_file(self, *args, **kwargs): + return self.latest_version.save_to_file(*args, **kwargs) + + def exists(self): + ''' + Returns a boolean value that indicates if the document's + latest version file exists in storage + ''' + return self.latest_version.exists() + + # Compatibility methods @property def file(self): - return self.get_latest_version().file + return self.latest_version.file @property def file_mimetype(self): - return self.get_latest_version().mimetype + return self.latest_version.mimetype @property def file_mime_encoding(self): - return self.get_latest_version().encoding + return self.latest_version.encoding @property def file_filename(self): - return self.get_latest_version().filename + return self.latest_version.filename @property def date_updated(self): - return self.get_latest_version().timestamp + return self.latest_version.timestamp + # TODO: uncomment when date_added is removed #@property #def date_added(self): - # return self.get_latest_version().timestamp + # return self.first_version.timestamp @property def checksum(self): - return self.get_latest_version().checksum + return self.latest_version.checksum @property def pages(self): - return self.get_latest_version().pages + return self.latest_version.pages - - #file = models.FileField(upload_to=get_filename_from_uuid, storage=STORAGE_BACKEND(), verbose_name=_(u'file')) - #file_mimetype = models.CharField(max_length=64, default='', editable=False) - #file_mime_encoding = models.CharField(max_length=64, default='', editable=False) - ##FAT filename can be up to 255 using LFN - #file_filename = models.CharField(max_length=255, default=u'', editable=False, db_index=True) - #date_updated = models.DateTimeField(verbose_name=_(u'updated'), auto_now=True) - #checksum = models.TextField(blank=True, null=True, verbose_name=_(u'checksum'), editable=False) + @property + def page_count(self): + return self.pages.count() - def get_latest_version(self): + @property + def latest_version(self): return self.documentversion_set.order_by('-timestamp')[0] + @property + def first_version(self): + return self.documentversion_set.order_by('timestamp')[0] + @property def versions(self): return self.documentversion_set + def _get_filename(self): + return self.latest_version.filename -RELEASE_LEVEL_FINAL = 1 -RELEASE_LEVEL_ALPHA = 2 -RELEASE_LEVEL_BETA = 3 -RELEASE_LEVEL_RC = 4 -RELEASE_LEVEL_HF = 5 + def _set_filename(self, value): + version = self.latest_version + version.filename = value + return version.save() -RELEASE_LEVEL_CHOICES = ( - (RELEASE_LEVEL_FINAL, _(u'final')), - (RELEASE_LEVEL_ALPHA, _(u'alpha')), - (RELEASE_LEVEL_BETA, _(u'beta')), - (RELEASE_LEVEL_RC, _(u'release candidate')), - (RELEASE_LEVEL_HF, _(u'hotfix')), -) + filename = property(_get_filename, _set_filename) + class DocumentVersion(models.Model): ''' - Model that describes a document version and it properties + Model that describes a document version and its properties ''' - document = models.ForeignKey(Document, verbose_name=_(u'document')) - major = models.PositiveIntegerField(verbose_name=_(u'mayor'), default=1) - minor = models.PositiveIntegerField(verbose_name=_(u'minor'), default=0) - micro = models.PositiveIntegerField(verbose_name=_(u'micro'), default=0) - release_level = models.PositiveIntegerField(choices=RELEASE_LEVEL_CHOICES, default=RELEASE_LEVEL_FINAL, verbose_name=_(u'release level')) - serial = models.PositiveIntegerField(verbose_name=_(u'serial'), default=0) - timestamp = models.DateTimeField(verbose_name=_(u'timestamp')) + @staticmethod + def get_version_update_choices(document_version): + return ( + (VERSION_UPDATE_MAJOR, _(u'Major %(major)i.%(minor)i, (new release)') % document_version.get_new_version_dict(VERSION_UPDATE_MAJOR)), + (VERSION_UPDATE_MINOR, _(u'Minor %(major)i.%(minor)i, (some updates)') % document_version.get_new_version_dict(VERSION_UPDATE_MINOR)), + (VERSION_UPDATE_MICRO, _(u'Micro %(major)i.%(minor)i.%(micro)i, (fixes)') % document_version.get_new_version_dict(VERSION_UPDATE_MICRO)) + ) + + document = models.ForeignKey(Document, verbose_name=_(u'document'), editable=False) + major = models.PositiveIntegerField(verbose_name=_(u'mayor'), default=1, editable=False) + minor = models.PositiveIntegerField(verbose_name=_(u'minor'), default=0, editable=False) + micro = models.PositiveIntegerField(verbose_name=_(u'micro'), default=0, editable=False) + release_level = models.PositiveIntegerField(choices=RELEASE_LEVEL_CHOICES, default=RELEASE_LEVEL_FINAL, verbose_name=_(u'release level'), editable=False) + serial = models.PositiveIntegerField(verbose_name=_(u'serial'), default=0, editable=False) + timestamp = models.DateTimeField(verbose_name=_(u'timestamp'), editable=False) comment = models.TextField(blank=True, verbose_name=_(u'comment')) # File related fields @@ -406,11 +328,31 @@ class DocumentVersion(models.Model): verbose_name_plural = _(u'document version') def __unicode__(self): - return self.get_version() + return self.get_formated_version() - # TODO: Update timestamp + def get_new_version_dict(self, version_update_type): + logger.debug('version_update_type: %s' % version_update_type) - def get_version(self): + if version_update_type == VERSION_UPDATE_MAJOR: + return { + 'major': self.major + 1, + 'minor': 0, + 'micro': 0, + } + elif version_update_type == VERSION_UPDATE_MINOR: + return { + 'major': self.major, + 'minor': self.minor + 1, + 'micro': 0, + } + elif version_update_type == VERSION_UPDATE_MICRO: + return { + 'major': self.major, + 'minor': self.minor, + 'micro': self.micro + 1, + } + + def get_formated_version(self): ''' Return the formatted version information ''' @@ -419,26 +361,151 @@ class DocumentVersion(models.Model): if self.micro: vers.append(u'.%i' % self.micro) if self.release_level != RELEASE_LEVEL_FINAL: - vers.append(u'%s%i' % (self.release_level, self.serial)) + vers.append(u'%s%i' % (self.get_release_level_display(), self.serial)) return u''.join(vers) @property def pages(self): return self.documentpage_set + def save(self, *args, **kwargs): + ''' + Overloaded save method that updates the document version's checksum, + mimetype, page count and transformation when created + ''' + new_document = not self.pk + if not self.pk: + self.timestamp = datetime.datetime.now() + + #Only do this for new documents + transformations = kwargs.pop('transformations', None) + super(DocumentVersion, self).save(*args, **kwargs) + + if new_document: + #Only do this for new documents + self.update_checksum(save=False) + self.update_mimetype(save=False) + self.save() + self.update_page_count(save=False) + if transformations: + self.apply_default_transformations(transformations) + + def update_checksum(self, save=True): + ''' + Open a document version's file and update the checksum field using the + user provided checksum function + ''' + if self.exists(): + source = self.open() + self.checksum = unicode(CHECKSUM_FUNCTION(source.read())) + source.close() + if save: + self.save() + + def update_page_count(self, save=True): + handle, filepath = tempfile.mkstemp() + # Just need the filepath, close the file description + os.close(handle) + + self.save_to_file(filepath) + try: + detected_pages = get_page_count(filepath) + except UnknownFileFormat: + # If converter backend doesn't understand the format, + # use 1 as the total page count + detected_pages = 1 + self.description = ugettext(u'This document\'s file format is not known, the page count has therefore defaulted to 1.') + self.save() + try: + os.remove(filepath) + except OSError: + pass + + current_pages = self.documentpage_set.order_by('page_number',) + if current_pages.count() > detected_pages: + for page in current_pages[detected_pages:]: + page.delete() + + for page_number in range(detected_pages): + DocumentPage.objects.get_or_create( + document_version=self, page_number=page_number + 1) + + if save: + self.save() + + return detected_pages + + def apply_default_transformations(self, transformations): + #Only apply default transformations on new documents + if reduce(lambda x, y: x + y, [page.documentpagetransformation_set.count() for page in self.pages.all()]) == 0: + for transformation in transformations: + for document_page in self.pages.all(): + page_transformation = DocumentPageTransformation( + document_page=document_page, + order=0, + transformation=transformation.get('transformation'), + arguments=transformation.get('arguments') + ) + + page_transformation.save() + + def update_mimetype(self, save=True): + ''' + Read a document verions's file and determine the mimetype by calling the + get_mimetype wrapper + ''' + if self.exists(): + try: + self.mimetype, self.encoding = get_mimetype(self.open(), self.filename) + except: + self.mimetype = u'' + self.encoding = u'' + finally: + if save: + self.save() + + def delete(self, *args, **kwargs): + super(Document, self).delete(*args, **kwargs) + return self.file.storage.delete(self.file.path) + + def exists(self): + ''' + Returns a boolean value that indicates if the document's file + exists in storage + ''' + return self.file.storage.exists(self.file.path) + def open(self): ''' Return a file descriptor to a document version's file irrespective of the storage backend ''' return self.file.storage.open(self.file.path) + + def save_to_file(self, filepath, buffer_size=1024 * 1024): + ''' + Save a copy of the document from the document storage backend + to the local filesystem + ''' + input_descriptor = self.open() + output_descriptor = open(filepath, 'wb') + while True: + copy_buffer = input_descriptor.read(buffer_size) + if copy_buffer: + output_descriptor.write(copy_buffer) + else: + break + + output_descriptor.close() + input_descriptor.close() + return filepath class DocumentTypeFilename(models.Model): - """ + ''' List of filenames available to a specific document type for the quick rename functionality - """ + ''' document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type')) filename = models.CharField(max_length=128, verbose_name=_(u'filename'), db_index=True) enabled = models.BooleanField(default=True, verbose_name=_(u'enabled')) @@ -453,12 +520,9 @@ class DocumentTypeFilename(models.Model): class DocumentPage(models.Model): - """ - Model that describes a document page including it's content - """ - ## This field is to be removed - #document = models.ForeignKey(Document, verbose_name=_(u'document')) - + ''' + Model that describes a document version page including it's content + ''' # New parent field document_version = models.ForeignKey(DocumentVersion, verbose_name=_(u'document version'))#, null=True, blank=True) # TODO: Remove these after datamigration diff --git a/apps/documents/urls.py b/apps/documents/urls.py index 88650155a7..239ec62df4 100644 --- a/apps/documents/urls.py +++ b/apps/documents/urls.py @@ -35,7 +35,7 @@ urlpatterns = patterns('documents.views', url(r'^(?P\d+)/clear_transformations/$', 'document_clear_transformations', (), 'document_clear_transformations'), url(r'^(?P\d+)/version/all/$', 'document_version_list', (), 'document_version_list'), - url(r'^document/version/(?P\d+)/download/$', 'document_version_download', (), 'document_version_download'), + url(r'^document/version/(?P\d+)/download/$', 'document_download', (), 'document_version_download'), url(r'^multiple/clear_transformations/$', 'document_multiple_clear_transformations', (), 'document_multiple_clear_transformations'), url(r'^duplicates/list/$', 'document_find_all_duplicates', (), 'document_find_all_duplicates'), diff --git a/apps/documents/views.py b/apps/documents/views.py index efaaf3e2da..bb74f6c62a 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -45,13 +45,13 @@ from documents.literals import PERMISSION_DOCUMENT_CREATE, \ from documents.literals import HISTORY_DOCUMENT_CREATED, \ HISTORY_DOCUMENT_EDITED, HISTORY_DOCUMENT_DELETED -from documents.forms import DocumentTypeSelectForm, \ - DocumentForm_edit, DocumentPropertiesForm, \ - DocumentPreviewForm, \ - DocumentPageForm, DocumentPageTransformationForm, \ - DocumentContentForm, DocumentPageForm_edit, \ - DocumentPageForm_text, PrintForm, DocumentTypeForm, \ - DocumentTypeFilenameForm, DocumentTypeFilenameForm_create +from documents.forms import (DocumentTypeSelectForm, + DocumentForm_edit, DocumentPropertiesForm, + DocumentPreviewForm, DocumentPageForm, + DocumentPageTransformationForm, DocumentContentForm, + DocumentPageForm_edit, DocumentPageForm_text, PrintForm, + DocumentTypeForm, DocumentTypeFilenameForm, + DocumentTypeFilenameForm_create) from documents.wizards import DocumentCreateWizard from documents.models import (Document, DocumentType, DocumentPage, DocumentPageTransformation, RecentDocument, DocumentTypeFilename, @@ -242,12 +242,12 @@ def document_edit(request, document_id): for warning in warnings: messages.warning(request, warning) - document.file_filename = form.cleaned_data['new_filename'] + document.filename = form.cleaned_data['new_filename'] document.description = form.cleaned_data['description'] if 'document_type_available_filenames' in form.cleaned_data: if form.cleaned_data['document_type_available_filenames']: - document.file_filename = form.cleaned_data['document_type_available_filenames'].filename + document.filename = form.cleaned_data['document_type_available_filenames'].filename document.save() create_history(HISTORY_DOCUMENT_EDITED, document, {'user': request.user, 'diff': return_diff(old_document, document, ['file_filename', 'description'])}) @@ -291,27 +291,27 @@ def get_document_image(request, document_id, size=PREVIEW_SIZE, base64_version=F if base64_version: return HttpResponse(u'' % document.get_image(size=size, page=page, zoom=zoom, rotation=rotation, as_base64=True)) else: - # TODO: hardcoded MIMETYPE + # TODO: fix hardcoded MIMETYPE return sendfile.sendfile(request, document.get_image(size=size, page=page, zoom=zoom, rotation=rotation), mimetype=DEFAULT_FILE_FORMAT_MIMETYPE) -def document_version_download(request, document_version_pk): - document_version = get_object_or_404(DocumentVersion, pk=document_version_pk) - return document_download(request, document_version.document.pk) - - -def document_download(request, document_id): +def document_download(request, document_id=None, document_version_pk=None): check_permissions(request.user, [PERMISSION_DOCUMENT_DOWNLOAD]) - document = get_object_or_404(Document, pk=document_id) + if document_version_pk: + document_version = get_object_or_404(DocumentVersion, pk=document_version_pk) + else: + document_version = get_object_or_404(Document, pk=document_id).latest_version + try: - #Test permissions and trigger exception - document.open() + # Test permissions and trigger exception + fd = document_version.open() + fd.close() return serve_file( request, - document.file, - save_as=u'"%s"' % document.get_fullname(), - content_type=document.file_mimetype if document.file_mimetype else 'application/octet-stream' + document_version.file, + save_as=u'"%s"' % document_version.filename, + content_type=document_version.mimetype if document_version.mimetype else 'application/octet-stream' ) except Exception, e: messages.error(request, e) @@ -1154,14 +1154,14 @@ def document_version_list(request, document_pk): document = get_object_or_404(Document, pk=document_pk) context = { - 'object_list': document.versions.all(), + 'object_list': document.versions.order_by('-timestamp'), 'title': _(u'versions for document: %s') % document, 'hide_object': True, 'object': document, 'extra_columns': [ { 'name': _(u'version'), - 'attribute': 'get_version', + 'attribute': 'get_formated_version', }, { 'name': _(u'time and date'), From 28208c4a2abc2dce72e95e1b1deb6b421522b003 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 3 Dec 2011 19:35:36 -0400 Subject: [PATCH 12/23] Update sources app to support multiple versions --- apps/sources/__init__.py | 7 ++ apps/sources/forms.py | 8 +- apps/sources/models.py | 48 +++++---- apps/sources/urls.py | 7 +- apps/sources/views.py | 212 +++++++++++++++++++++++++-------------- 5 files changed, 183 insertions(+), 99 deletions(-) diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index ad34940468..3257c12c1e 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -5,6 +5,8 @@ from navigation.api import register_links, \ from permissions.api import register_permission, set_namespace_title from common.utils import encapsulate from project_setup.api import register_setup +from documents.models import Document +from documents import PERMISSION_DOCUMENT_CREATE from sources.staging import StagingFile from sources.models import WebForm, StagingFolder, SourceTransformation, \ @@ -41,6 +43,8 @@ setup_source_transformation_delete = {'text': _(u'delete'), 'view': 'setup_sourc source_list = {'text': _(u'Document sources'), 'view': 'setup_web_form_list', 'famfam': 'page_add', 'children_url_regex': [r'sources/setup']} +upload_interactive_version = {'text': _(u'upload new version'), 'view': 'upload_interactive_version', 'args': 'object.pk', 'famfam': 'page_add', 'permissions': [PERMISSION_DOCUMENT_CREATE]} + register_links(StagingFile, [staging_file_delete]) register_links(SourceTransformation, [setup_source_transformation_edit, setup_source_transformation_delete]) @@ -61,6 +65,9 @@ register_links(StagingFolder, [setup_source_transformation_list, setup_source_ed register_links(WatchFolder, [setup_web_form_list, setup_staging_folder_list, setup_watch_folder_list], menu_name='form_header') register_links(WatchFolder, [setup_source_transformation_list, setup_source_edit, setup_source_delete]) +# Document version +register_links(Document, [upload_interactive_version]) + register_links(['setup_source_transformation_create', 'setup_source_transformation_edit', 'setup_source_transformation_delete', 'setup_source_transformation_list'], [setup_source_transformation_create], menu_name='sidebar') source_views = ['setup_web_form_list', 'setup_staging_folder_list', 'setup_watch_folder_list', 'setup_source_edit', 'setup_source_delete', 'setup_source_create', 'setup_source_transformation_list', 'setup_source_transformation_edit', 'setup_source_transformation_delete', 'setup_source_transformation_create'] diff --git a/apps/sources/forms.py b/apps/sources/forms.py index de9b7ee1ce..4b046994cf 100644 --- a/apps/sources/forms.py +++ b/apps/sources/forms.py @@ -37,7 +37,7 @@ class StagingDocumentForm(DocumentForm): staging_list_index = self.fields.keyOrder.index('staging_file_id') staging_list = self.fields.keyOrder.pop(staging_list_index) self.fields.keyOrder.insert(0, staging_list) - + staging_file_id = forms.ChoiceField(label=_(u'Staging file')) class Meta(DocumentForm.Meta): @@ -45,6 +45,8 @@ class StagingDocumentForm(DocumentForm): class WebFormForm(DocumentForm): + file = forms.FileField(label=_(u'File')) + def __init__(self, *args, **kwargs): show_expand = kwargs.pop('show_expand', False) self.source = kwargs.pop('source') @@ -56,6 +58,10 @@ class WebFormForm(DocumentForm): help_text=ugettext(u'Upload a compressed file\'s contained files as individual documents') ) + # Move the file filed to the top + self.fields.keyOrder.remove('file') + self.fields.keyOrder.insert(0, 'file') + def clean_file(self): data = self.cleaned_data['file'] validate_whitelist_blacklist(data.name, self.source.whitelist.split(','), self.source.blacklist.split(',')) diff --git a/apps/sources/models.py b/apps/sources/models.py index c97f2f4ca4..44822ee0ba 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -52,7 +52,7 @@ class BaseModel(models.Model): def get_transformation_list(self): return SourceTransformation.transformations.get_for_object_as_list(self) - def upload_file(self, file_object, filename=None, document_type=None, expand=False, metadata_dict_list=None, user=None): + def upload_file(self, file_object, filename=None, document_type=None, expand=False, metadata_dict_list=None, user=None, document=None, new_version_data=None): if expand: try: cf = CompressedFile(file_object) @@ -63,31 +63,39 @@ class BaseModel(models.Model): except NotACompressedFile: self.upload_single_file(file_object, filename, document_type, metadata_dict_list, user) else: - self.upload_single_file(file_object, filename, document_type, metadata_dict_list, user) + self.upload_single_file(file_object, filename, document_type, metadata_dict_list, user, document, new_version_data) file_object.close() - def upload_single_file(self, file_object, filename=None, document_type=None, metadata_dict_list=None, user=None): - transformations, errors = self.get_transformation_list() - document = Document(file=file_object) - if document_type: - document.document_type = document_type - document.save() + def upload_single_file(self, file_object, filename=None, document_type=None, metadata_dict_list=None, user=None, document=None, new_version_data=None): + if not document: + document = Document() + if document_type: + document.document_type = document_type + document.save() + + if metadata_dict_list: + save_metadata_list(metadata_dict_list, document, create=True) + warnings = update_indexes(document) + + if user: + document.add_as_recent_document_for_user(user) + create_history(HISTORY_DOCUMENT_CREATED, document, {'user': user}) + else: + create_history(HISTORY_DOCUMENT_CREATED, document) + + if not new_version_data: + new_version_data = {} + + new_version = document.new_version(file=file_object, **new_version_data) if filename: - document.file_filename = filename - document.save() + new_version.filename = filename + new_version.save() - document.apply_default_transformations(transformations) + transformations, errors = self.get_transformation_list() - if metadata_dict_list: - save_metadata_list(metadata_dict_list, document, create=True) - warnings = update_indexes(document) - - if user: - document.add_as_recent_document_for_user(user) - create_history(HISTORY_DOCUMENT_CREATED, document, {'user': user}) - else: - create_history(HISTORY_DOCUMENT_CREATED, document) + new_version.apply_default_transformations(transformations) + #TODO: new HISTORY for version updates class Meta: ordering = ('title',) diff --git a/apps/sources/urls.py b/apps/sources/urls.py index b75573382d..cd42328138 100644 --- a/apps/sources/urls.py +++ b/apps/sources/urls.py @@ -8,8 +8,11 @@ urlpatterns = patterns('sources.views', url(r'^staging_file/type/(?P\w+)/(?P\d+)/(?P\w+)/delete/$', 'staging_file_delete', (), 'staging_file_delete'), url(r'^staging_file/type/staging_folder/(?P\d+)/(?P\w+)/thumbnail/$', 'staging_file_thumbnail', (), 'staging_file_thumbnail'), - url(r'^upload/interactive/(?P\w+)/(?P\d+)/$', 'upload_interactive', (), 'upload_interactive'), - url(r'^upload/interactive/$', 'upload_interactive', (), 'upload_interactive'), + url(r'^upload/document/new/interactive/(?P\w+)/(?P\d+)/$', 'upload_interactive', (), 'upload_interactive'), + url(r'^upload/document/new/interactive/$', 'upload_interactive', (), 'upload_interactive'), + + url(r'^upload/document/(?P\d+)/version/interactive/(?P\w+)/(?P\d+)/$', 'upload_interactive', (), 'upload_interactive_version'), + url(r'^upload/document/(?P\d+)/version/interactive/$', 'upload_interactive', (), 'upload_interactive_version'), #Setup views diff --git a/apps/sources/views.py b/apps/sources/views.py index c2cde5e7d8..c668b23909 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -8,7 +8,7 @@ from django.utils.translation import ugettext from django.utils.safestring import mark_safe from documents.literals import PERMISSION_DOCUMENT_CREATE -from documents.models import DocumentType +from documents.models import DocumentType, Document from documents.conf.settings import THUMBNAIL_SIZE from metadata.api import decode_metadata_from_url, metadata_repr_as_list from permissions.api import check_permissions @@ -35,30 +35,34 @@ def return_function(obj): return lambda context: context['source'].source_type == obj.source_type and context['source'].pk == obj.pk -def get_active_tab_links(): - tab_links = [] +def get_tab_link_for_source(source, document=None): + if document: + view = u'upload_interactive_version' + args = [document.pk, u'"%s"' % source.source_type, source.pk] + else: + view = u'upload_interactive' + args = [u'"%s"' % source.source_type, source.pk] + + return { + 'text': source.title, + 'view': view, + 'args': args, + 'famfam': source.icon, + 'keep_query': True, + 'conditional_highlight': return_function(source), + } + +def get_active_tab_links(document=None): + tab_links = [] + web_forms = WebForm.objects.filter(enabled=True) for web_form in web_forms: - tab_links.append({ - 'text': web_form.title, - 'view': 'upload_interactive', - 'args': [u'"%s"' % web_form.source_type, web_form.pk], - 'famfam': web_form.icon, - 'keep_query': True, - 'conditional_highlight': return_function(web_form), - }) + tab_links.append(get_tab_link_for_source(web_form, document)) staging_folders = StagingFolder.objects.filter(enabled=True) for staging_folder in staging_folders: - tab_links.append({ - 'text': staging_folder.title, - 'view': 'upload_interactive', - 'args': [u'"%s"' % staging_folder.source_type, staging_folder.pk], - 'famfam': staging_folder.icon, - 'keep_query': True, - 'conditional_highlight': return_function(staging_folder), - }) + tab_links.append(get_tab_link_for_source(staging_folder, document)) return { 'tab_links': tab_links, @@ -66,15 +70,19 @@ def get_active_tab_links(): SOURCE_CHOICE_STAGING: staging_folders } - -def upload_interactive(request, source_type=None, source_id=None): +def upload_interactive(request, source_type=None, source_id=None, document_pk=None): check_permissions(request.user, [PERMISSION_DOCUMENT_CREATE]) subtemplates_list = [] - context = {} + if document_pk: + document = get_object_or_404(Document, pk=document_pk) + results = get_active_tab_links(document) + else: + document = None + results = get_active_tab_links() - results = get_active_tab_links() + context = {} if results[SOURCE_CHOICE_WEB_FORM].count() == 0 and results[SOURCE_CHOICE_STAGING].count() == 0: source_setup_link = mark_safe('%s' % (reverse('setup_web_form_list'), ugettext(u'here'))) @@ -113,43 +121,57 @@ def upload_interactive(request, source_type=None, source_id=None): if request.method == 'POST': form = WebFormForm(request.POST, request.FILES, document_type=document_type, - show_expand=(web_form.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK), - source=web_form + show_expand=(web_form.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK) and not document, + source=web_form, + instance=document ) if form.is_valid(): - try: + #try: + if document: + expand = False + else: if web_form.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK: - expand = form.cleaned_data['expand'] + expand = form.cleaned_data.get('expand') else: if web_form.uncompress == SOURCE_UNCOMPRESS_CHOICE_Y: expand = True else: expand = False - - new_filename = get_form_filename(form) - web_form.upload_file(request.FILES['file'], - new_filename, document_type=document_type, - expand=expand, - metadata_dict_list=decode_metadata_from_url(request.GET), - user=request.user - ) + + new_filename = get_form_filename(form) + web_form.upload_file(request.FILES['file'], + new_filename, document_type=document_type, + expand=expand, + metadata_dict_list=decode_metadata_from_url(request.GET), + user=request.user, + document=document, + new_version_data=form.cleaned_data.get('new_version_data') + ) + #except Exception, e: + # messages.error(request, _(u'Unhandled exception: %s') % e) + if document: + messages.success(request, _(u'Document version uploaded successfully.')) + return HttpResponseRedirect(reverse('document_view_simple', args=[document.pk])) + else: messages.success(request, _(u'Document uploaded successfully.')) - except Exception, e: - messages.error(request, e) - - return HttpResponseRedirect(request.get_full_path()) + return HttpResponseRedirect(request.get_full_path()) else: form = WebFormForm( - show_expand=(web_form.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK), + show_expand=(web_form.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK) and not document, document_type=document_type, - source=web_form + source=web_form, + instance=document ) - + if document: + title = _(u'upload a new version from source: %s') % web_form.title + else: + title = _(u'upload a local document from source: %s') % web_form.title + subtemplates_list.append({ 'name': 'generic_form_subtemplate.html', 'context': { 'form': form, - 'title': _(u'upload a local document from source: %s') % web_form.title, + 'title': title, }, }) elif source_type == SOURCE_CHOICE_STAGING: @@ -159,41 +181,54 @@ def upload_interactive(request, source_type=None, source_id=None): if request.method == 'POST': form = StagingDocumentForm(request.POST, request.FILES, cls=StagingFile, document_type=document_type, - show_expand=(staging_folder.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK), - source=staging_folder + show_expand=(staging_folder.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK) and not document, + source=staging_folder, + instance=document ) if form.is_valid(): - try: - staging_file = StagingFile.get(form.cleaned_data['staging_file_id']) + #try: + staging_file = StagingFile.get(form.cleaned_data['staging_file_id']) + if document: + expand = False + else: if staging_folder.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK: - expand = form.cleaned_data['expand'] + expand = form.cleaned_dataget('expand') else: if staging_folder.uncompress == SOURCE_UNCOMPRESS_CHOICE_Y: expand = True else: expand = False - new_filename = get_form_filename(form) - staging_folder.upload_file(staging_file.upload(), - new_filename, document_type=document_type, - expand=expand, - metadata_dict_list=decode_metadata_from_url(request.GET), - user=request.user - ) + + new_filename = get_form_filename(form) + staging_folder.upload_file(staging_file.upload(), + new_filename, document_type=document_type, + expand=expand, + metadata_dict_list=decode_metadata_from_url(request.GET), + user=request.user, + document=document, + new_version_data=form.cleaned_data.get('new_version_data') + ) + if document: + messages.success(request, _(u'Document version from staging file: %s, uploaded successfully.') % staging_file.filename) + else: messages.success(request, _(u'Staging file: %s, uploaded successfully.') % staging_file.filename) - if staging_folder.delete_after_upload: - transformations, errors = staging_folder.get_transformation_list() - staging_file.delete(preview_size=staging_folder.get_preview_size(), transformations=transformations) - messages.success(request, _(u'Staging file: %s, deleted successfully.') % staging_file.filename) - except Exception, e: - messages.error(request, e) - - return HttpResponseRedirect(request.get_full_path()) + if staging_folder.delete_after_upload: + transformations, errors = staging_folder.get_transformation_list() + staging_file.delete(preview_size=staging_folder.get_preview_size(), transformations=transformations) + messages.success(request, _(u'Staging file: %s, deleted successfully.') % staging_file.filename) + #except Exception, e: + # messages.error(request, _(u'Unhandled exception: %s') % e) + if document: + return HttpResponseRedirect(reverse('document_view_simple', args=[document.pk])) + else: + return HttpResponseRedirect(request.get_full_path()) else: form = StagingDocumentForm(cls=StagingFile, document_type=document_type, - show_expand=(staging_folder.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK), - source=staging_folder + show_expand=(staging_folder.uncompress == SOURCE_UNCOMPRESS_CHOICE_ASK) and not document, + source=staging_folder, + instance=document ) try: staging_filelist = StagingFile.get_all() @@ -201,12 +236,17 @@ def upload_interactive(request, source_type=None, source_id=None): messages.error(request, e) staging_filelist = [] finally: + if document: + title = _(u'upload a new version from staging source: %s') % staging_folder.title + else: + title = _(u'upload a document from staging source: %s') % staging_folder.title + subtemplates_list = [ { 'name': 'generic_form_subtemplate.html', 'context': { 'form': form, - 'title': _(u'upload a document from staging source: %s') % staging_folder.title, + 'title': title, } }, { @@ -219,20 +259,40 @@ def upload_interactive(request, source_type=None, source_id=None): }, ] + if document: + context['object'] = document + context.update({ 'document_type_id': document_type_id, 'subtemplates_list': subtemplates_list, - 'sidebar_subtemplates_list': [ - { - 'name': 'generic_subtemplate.html', - 'context': { - 'title': _(u'Current metadata'), - 'paragraphs': metadata_repr_as_list(decode_metadata_from_url(request.GET)), - 'side_bar': True, - } - }], - 'temporary_navigation_links': {'form_header': {'upload_interactive': {'links': results['tab_links']}}}, + 'temporary_navigation_links': { + 'form_header': { + 'upload_interactive_version': { + 'links': results['tab_links'] + }, + 'upload_interactive': { + 'links': results['tab_links'] + } + } + }, }) + + if not document: + context.update( + { + 'sidebar_subtemplates_list': [ + { + 'name': 'generic_subtemplate.html', + 'context': { + 'title': _(u'Current metadata'), + 'paragraphs': metadata_repr_as_list(decode_metadata_from_url(request.GET)), + 'side_bar': True, + } + } + ], + } + ) + return render_to_response('generic_form.html', context, context_instance=RequestContext(request)) From a3befc6b7d7ce793e4d8ec75293e3c2cb8fed50a Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 3 Dec 2011 20:09:44 -0400 Subject: [PATCH 13/23] Remove remarked code --- apps/documents/models.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/documents/models.py b/apps/documents/models.py index 04c633556f..a9c0b8f917 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -200,12 +200,6 @@ class Document(models.Model): new_version = DocumentVersion( document=self, file=file, - #major = new_version_dict.get('major'), - #minor = new_version_dict.get('minor'), - #micro = new_version_dict.get('micro'), - #release_level = release_level, - #serial = serial, - #comment = comment, ) new_version.save() From d81e734f592afea647a1bf4ebdf6890599feb41e Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 3 Dec 2011 20:10:08 -0400 Subject: [PATCH 14/23] Update REST API to new document multi version methods and structures --- apps/rest_api/resources.py | 39 ++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/apps/rest_api/resources.py b/apps/rest_api/resources.py index 99a5c26613..869c78e407 100644 --- a/apps/rest_api/resources.py +++ b/apps/rest_api/resources.py @@ -8,15 +8,46 @@ from converter.exceptions import UnknownFileFormat, UnkownConvertError class DocumentResourceSimple(ModelResource): model = Document - fields = ('url', 'pk', 'document_type', 'uuid', 'date_added', 'description', 'tags', 'comments', 'expensive_methods', 'files') + fields = ('url', 'pk', 'document_type', 'uuid', 'date_added', 'description', 'tags', 'comments', 'expensive_methods', 'versions') - def files(self, instance): + def versions(self, instance): + return [ + { + 'version': version.get_formated_version(), + 'major': version.major, + 'minor': version.minor, + 'micro': version.micro, + 'release_level': version.release_level, + 'serial': version.serial, + 'timestamp': version.timestamp, + 'comment': version.comment, + 'mimetype': version.mimetype, + 'encoding': version.encoding, + 'filename': version.filename, + 'checksum': version.checksum, + 'download': reverse('document_version_download', args=[version.pk]), + 'stored_filename': version.file.name, + # TODO: Add transformations + 'pages': [ + { + 'content': page.content, + 'page_label': page.page_label, + 'page_number': page.page_number, + } + for page in version.pages.all() + ] + + } + for version in instance.versions.all() + ] + + ''' return [ { 'version': 1, 'mimetype': instance.file_mimetype, 'encoding': instance.file_mime_encoding, - 'filename': instance.get_fullname(), + 'filename': instance.filename, 'date_updated': instance.date_updated, 'checksum': instance.checksum, 'size': instance.size, @@ -33,6 +64,6 @@ class DocumentResourceSimple(ModelResource): ] } ] - + ''' def expensive_methods(self, instance): return [] From 0cf8d68db0f0e8c084f7852f8352e741a7326f14 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 3 Dec 2011 20:30:44 -0400 Subject: [PATCH 15/23] Add the page number on top of the page widget in the multiple page carousel widget --- apps/documents/forms.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/documents/forms.py b/apps/documents/forms.py index 1033692bfe..e680121bb2 100644 --- a/apps/documents/forms.py +++ b/apps/documents/forms.py @@ -103,7 +103,9 @@ class DocumentPagesCarouselWidget(forms.widgets.Widget): output.append(u'
') for page in value.pages.all(): + output.append(u'
') + output.append(u'
%(page_string)s %(page)s
' % {'page_string': ugettext(u'Page'), 'page': page.page_number}) output.append( document_html_widget( page.document, @@ -178,7 +180,6 @@ class DocumentForm(forms.ModelForm): self.fields['version_update'] = forms.ChoiceField( label=_(u'Version update'), - #widget=forms.widgets.RadioSelect(), choices=DocumentVersion.get_version_update_choices(document.latest_version) ) @@ -186,7 +187,6 @@ class DocumentForm(forms.ModelForm): label=_(u'Release level'), choices=RELEASE_LEVEL_CHOICES, initial=RELEASE_LEVEL_FINAL, - #required=False, ) self.fields['serial'] = forms.IntegerField( @@ -195,7 +195,6 @@ class DocumentForm(forms.ModelForm): widget=forms.widgets.TextInput( attrs = {'style': 'width: auto;'} ), - #required=False ) new_filename = forms.CharField( From 4bbf5d3514aa63287759d88d44766281b0c5e97b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 3 Dec 2011 20:43:30 -0400 Subject: [PATCH 16/23] Add 'siblings' convenience method to the DocumentPage model --- apps/documents/models.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/documents/models.py b/apps/documents/models.py index a9c0b8f917..c5104dee7c 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -543,6 +543,10 @@ class DocumentPage(models.Model): @models.permalink def get_absolute_url(self): return ('document_page_view', [self.pk]) + + @property + def siblings(self): + return DocumentPage.objects.filter(document_version=self.document_version) # Compatibility methods @property From 699f7e7caa7515e8d505fc4a8199b66f3ab41faf Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 3 Dec 2011 20:44:04 -0400 Subject: [PATCH 17/23] Update document page navigation views to use the new 'siblings' DocumentPage method --- apps/documents/views.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/documents/views.py b/apps/documents/views.py index bb74f6c62a..894818547c 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -531,7 +531,7 @@ def document_clear_transformations(request, document_id=None, document_id_list=N if request.method == 'POST': for document in documents: try: - for document_page in document.documentpage_set.all(): + for document_page in document.pages.all(): document_page.document.invalidate_cached_image(document_page.page_number) for transformation in document_page.documentpagetransformation_set.all(): transformation.delete() @@ -667,11 +667,11 @@ def document_page_navigation_next(request, document_page_id): view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) document_page = get_object_or_404(DocumentPage, pk=document_page_id) - if document_page.page_number >= document_page.document.documentpage_set.count(): + if document_page.page_number >= document_page.siblings.count(): messages.warning(request, _(u'There are no more pages in this document')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', u'/')) else: - document_page = get_object_or_404(DocumentPage, document=document_page.document, page_number=document_page.page_number + 1) + document_page = get_object_or_404(document_page.siblings, page_number=document_page.page_number + 1) return HttpResponseRedirect(reverse(view, args=[document_page.pk])) @@ -684,7 +684,7 @@ def document_page_navigation_previous(request, document_page_id): messages.warning(request, _(u'You are already at the first page of this document')) return HttpResponseRedirect(request.META.get('HTTP_REFERER', u'/')) else: - document_page = get_object_or_404(DocumentPage, document=document_page.document, page_number=document_page.page_number - 1) + document_page = get_object_or_404(document_page.siblings, page_number=document_page.page_number - 1) return HttpResponseRedirect(reverse(view, args=[document_page.pk])) @@ -693,7 +693,7 @@ def document_page_navigation_first(request, document_page_id): view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) document_page = get_object_or_404(DocumentPage, pk=document_page_id) - document_page = get_object_or_404(DocumentPage, document=document_page.document, page_number=1) + document_page = get_object_or_404(document_page.siblings, page_number=1) return HttpResponseRedirect(reverse(view, args=[document_page.pk])) @@ -702,7 +702,7 @@ def document_page_navigation_last(request, document_page_id): view = resolve_to_name(urlparse.urlparse(request.META.get('HTTP_REFERER', u'/')).path) document_page = get_object_or_404(DocumentPage, pk=document_page_id) - document_page = get_object_or_404(DocumentPage, document=document_page.document, page_number=document_page.document.documentpage_set.count()) + document_page = get_object_or_404(document_page.siblings, page_number=document_page.siblings.count()) return HttpResponseRedirect(reverse(view, args=[document_page.pk])) @@ -856,9 +856,9 @@ def document_hard_copy(request, document_id): if page_range: page_range = parse_range(page_range) - pages = document.documentpage_set.filter(page_number__in=page_range) + pages = document.pages.filter(page_number__in=page_range) else: - pages = document.documentpage_set.all() + pages = document.pages.all() return render_to_response('document_print.html', { 'object': document, From 90863025d8b2e793ff418c8403ee8b2b0d677daa Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 3 Dec 2011 20:54:35 -0400 Subject: [PATCH 18/23] Fix permission import --- apps/sources/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sources/__init__.py b/apps/sources/__init__.py index 3257c12c1e..94d2727c9c 100644 --- a/apps/sources/__init__.py +++ b/apps/sources/__init__.py @@ -6,7 +6,7 @@ from permissions.api import register_permission, set_namespace_title from common.utils import encapsulate from project_setup.api import register_setup from documents.models import Document -from documents import PERMISSION_DOCUMENT_CREATE +from documents.literals import PERMISSION_DOCUMENT_CREATE from sources.staging import StagingFile from sources.models import WebForm, StagingFolder, SourceTransformation, \ From e81a02b18d7896f04fc95adce8b5c55e58f38c30 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 3 Dec 2011 23:29:52 -0400 Subject: [PATCH 19/23] Improve document multi version migrations --- ...06_fix_invalid_document_version_id_keys.py | 159 ++++++++++++++++++ ...elds.py => 0007_remove_old_file_fields.py} | 3 +- ...d_name.py => 0008_fix_mayor_field_name.py} | 0 ...ent_field.py => 0009_add_comment_field.py} | 0 4 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 apps/documents/migrations/0006_fix_invalid_document_version_id_keys.py rename apps/documents/migrations/{0006_remove_old_file_fields.py => 0007_remove_old_file_fields.py} (98%) rename apps/documents/migrations/{0007_fix_mayor_field_name.py => 0008_fix_mayor_field_name.py} (100%) rename apps/documents/migrations/{0008_add_comment_field.py => 0009_add_comment_field.py} (100%) diff --git a/apps/documents/migrations/0006_fix_invalid_document_version_id_keys.py b/apps/documents/migrations/0006_fix_invalid_document_version_id_keys.py new file mode 100644 index 0000000000..03f4ba4133 --- /dev/null +++ b/apps/documents/migrations/0006_fix_invalid_document_version_id_keys.py @@ -0,0 +1,159 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import DataMigration +from django.db import models + +class Migration(DataMigration): + + def forwards(self, orm): + qs = orm.DocumentPage.objects.filter(document_version=None) + #print 'Invalid document pages to delete: %s' % qs.count() + for document_page in qs: + document_page.delete() + + def backwards(self, orm): + def backwards(self, orm): + raise RuntimeError('Cannot reverse this migration.') + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + '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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + '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', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + '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', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}), + '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'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}), + 'date_updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'file_filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'file_mime_encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file_mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'default': "u'6c189f1f-1d85-48b5-9b7d-e8e319603e77'", 'max_length': '48', 'blank': 'True'}) + }, + 'documents.documentpage': { + 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, + 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'page_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}) + }, + 'documents.documentpagetransformation': { + 'Meta': {'ordering': "('order',)", 'object_name': 'DocumentPageTransformation'}, + 'arguments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_page': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentPage']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True', 'blank': 'True'}), + 'transformation': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'documents.documenttypefilename': { + 'Meta': {'ordering': "['filename']", 'object_name': 'DocumentTypeFilename'}, + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'documents.documentversion': { + 'Meta': {'unique_together': "(('document', 'mayor', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']", 'null': 'True', 'blank': 'True'}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'mayor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {}) + }, + 'documents.recentdocument': { + 'Meta': {'ordering': "('-datetime_accessed',)", 'object_name': 'RecentDocument'}, + 'datetime_accessed': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['documents'] diff --git a/apps/documents/migrations/0006_remove_old_file_fields.py b/apps/documents/migrations/0007_remove_old_file_fields.py similarity index 98% rename from apps/documents/migrations/0006_remove_old_file_fields.py rename to apps/documents/migrations/0007_remove_old_file_fields.py index 7abf68d028..02c074fcfd 100644 --- a/apps/documents/migrations/0006_remove_old_file_fields.py +++ b/apps/documents/migrations/0007_remove_old_file_fields.py @@ -9,7 +9,7 @@ class Migration(SchemaMigration): def forwards(self, orm): # Changing field 'DocumentVersion.document' - db.alter_column('documents_documentversion', 'document_id', self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['documents.Document'])) + db.alter_column('documents_documentversion', 'document_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.Document'])) # Deleting field 'Document.date_updated' db.delete_column('documents_document', 'date_updated') @@ -33,7 +33,6 @@ class Migration(SchemaMigration): db.delete_column('documents_documentpage', 'document_id') # Changing field 'DocumentPage.document_version' - #db.alter_column('documents_documentpage', 'document_version_id', self.gf('django.db.models.fields.related.ForeignKey')(default=1, to=orm['documents.DocumentVersion'])) db.alter_column('documents_documentpage', 'document_version_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.DocumentVersion'])) diff --git a/apps/documents/migrations/0007_fix_mayor_field_name.py b/apps/documents/migrations/0008_fix_mayor_field_name.py similarity index 100% rename from apps/documents/migrations/0007_fix_mayor_field_name.py rename to apps/documents/migrations/0008_fix_mayor_field_name.py diff --git a/apps/documents/migrations/0008_add_comment_field.py b/apps/documents/migrations/0009_add_comment_field.py similarity index 100% rename from apps/documents/migrations/0008_add_comment_field.py rename to apps/documents/migrations/0009_add_comment_field.py From 986b7e39e4b523fc8d9a6fd2f99290e19d5153ac Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 3 Dec 2011 23:37:00 -0400 Subject: [PATCH 20/23] Fix the new version fields in the upload form --- apps/documents/forms.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/documents/forms.py b/apps/documents/forms.py index e680121bb2..60d69506ac 100644 --- a/apps/documents/forms.py +++ b/apps/documents/forms.py @@ -151,8 +151,6 @@ class DocumentForm(forms.ModelForm): instance = kwargs.pop('instance', None) super(DocumentForm, self).__init__(*args, **kwargs) - if instance: - self.version_fields(instance) if 'document_type' in self.fields: # To allow merging with DocumentForm_edit @@ -170,14 +168,11 @@ class DocumentForm(forms.ModelForm): queryset=filenames_qs, required=False, label=_(u'Quick document rename')) + + if instance: + self.version_fields(instance) def version_fields(self, document): - self.fields['comment'] = forms.CharField( - label=_(u'Comment'), - required=False, - widget=forms.widgets.Textarea(attrs={'rows': 4}), - ) - self.fields['version_update'] = forms.ChoiceField( label=_(u'Version update'), choices=DocumentVersion.get_version_update_choices(document.latest_version) @@ -197,6 +192,12 @@ class DocumentForm(forms.ModelForm): ), ) + self.fields['comment'] = forms.CharField( + label=_(u'Comment'), + required=False, + widget=forms.widgets.Textarea(attrs={'rows': 4}), + ) + new_filename = forms.CharField( label=_('New document filename'), required=False ) From 43b17456d1cb4fbe14fab226cddc542dd3e0ed50 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sat, 3 Dec 2011 23:42:29 -0400 Subject: [PATCH 21/23] Remove the auto_add_now property from the date_added document field --- ...010_auto__chg_field_document_date_added.py | 155 ++++++++++++++++++ apps/documents/models.py | 9 +- 2 files changed, 157 insertions(+), 7 deletions(-) create mode 100644 apps/documents/migrations/0010_auto__chg_field_document_date_added.py diff --git a/apps/documents/migrations/0010_auto__chg_field_document_date_added.py b/apps/documents/migrations/0010_auto__chg_field_document_date_added.py new file mode 100644 index 0000000000..6220ef13ad --- /dev/null +++ b/apps/documents/migrations/0010_auto__chg_field_document_date_added.py @@ -0,0 +1,155 @@ +# encoding: utf-8 +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + +class Migration(SchemaMigration): + + def forwards(self, orm): + + # Changing field 'Document.date_added' + db.alter_column('documents_document', 'date_added', self.gf('django.db.models.fields.DateTimeField')()) + + + def backwards(self, orm): + + # Changing field 'Document.date_added' + db.alter_column('documents_document', 'date_added', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True)) + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + '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': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + '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', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + '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', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'comments.comment': { + 'Meta': {'ordering': "('submit_date',)", 'object_name': 'Comment', 'db_table': "'django_comments'"}, + 'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'content_type_set_for_comment'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'null': 'True', 'blank': 'True'}), + 'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_removed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'object_pk': ('django.db.models.fields.TextField', [], {}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'submit_date': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comment_comments'", 'null': 'True', 'to': "orm['auth.User']"}), + 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'user_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}) + }, + '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'}), + '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'}) + }, + 'documents.document': { + 'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'}, + 'date_added': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '48', 'blank': 'True'}) + }, + 'documents.documentpage': { + 'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'}, + 'content': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), + 'document_version': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentVersion']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'page_label': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), + 'page_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'}) + }, + 'documents.documentpagetransformation': { + 'Meta': {'ordering': "('order',)", 'object_name': 'DocumentPageTransformation'}, + 'arguments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'document_page': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentPage']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'null': 'True', 'db_index': 'True', 'blank': 'True'}), + 'transformation': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'documents.documenttype': { + 'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '32'}) + }, + 'documents.documenttypefilename': { + 'Meta': {'ordering': "['filename']", 'object_name': 'DocumentTypeFilename'}, + 'document_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.DocumentType']"}), + 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'filename': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'documents.documentversion': { + 'Meta': {'unique_together': "(('document', 'major', 'minor', 'micro', 'release_level', 'serial'),)", 'object_name': 'DocumentVersion'}, + 'checksum': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), + 'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'encoding': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}), + 'filename': ('django.db.models.fields.CharField', [], {'default': "u''", 'max_length': '255', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'major': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'micro': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'mimetype': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}), + 'minor': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'release_level': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}), + 'serial': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), + 'timestamp': ('django.db.models.fields.DateTimeField', [], {}) + }, + 'documents.recentdocument': { + 'Meta': {'ordering': "('-datetime_accessed',)", 'object_name': 'RecentDocument'}, + 'datetime_accessed': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100', 'db_index': 'True'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['documents'] diff --git a/apps/documents/models.py b/apps/documents/models.py index c5104dee7c..581e1eea4f 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -78,8 +78,7 @@ class Document(models.Model): uuid = models.CharField(max_length=48, blank=True, editable=False) document_type = models.ForeignKey(DocumentType, verbose_name=_(u'document type'), null=True, blank=True) description = models.TextField(blank=True, null=True, verbose_name=_(u'description'), db_index=True) - #TODO: remove date_added, it is the timestamp of the first version - date_added = models.DateTimeField(verbose_name=_(u'added'), auto_now_add=True, db_index=True) + date_added = models.DateTimeField(verbose_name=_(u'added'), db_index=True) tags = TaggableManager() @@ -111,6 +110,7 @@ class Document(models.Model): def save(self, *args, **kwargs): if not self.pk: self.uuid = UUID_FUNCTION() + self.date_added = datetime.datetime.now() super(Document, self).save(*args, **kwargs) def get_cached_image_name(self, page): @@ -248,11 +248,6 @@ class Document(models.Model): def date_updated(self): return self.latest_version.timestamp - # TODO: uncomment when date_added is removed - #@property - #def date_added(self): - # return self.first_version.timestamp - @property def checksum(self): return self.latest_version.checksum From e6d3453800e8ff0e9ba6d3c1c98fe9d4f45f47e1 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 4 Dec 2011 00:00:07 -0400 Subject: [PATCH 22/23] Update the linking app to be compatible with the new document versioning fields --- apps/linking/forms.py | 2 +- apps/linking/managers.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/linking/forms.py b/apps/linking/forms.py index 9568994b89..1e90e16c8a 100644 --- a/apps/linking/forms.py +++ b/apps/linking/forms.py @@ -45,7 +45,7 @@ class SmartLinkImageWidget(forms.widgets.Widget): for document in value['documents']: output.append(u'
' % (u'border: 5px solid black; padding: 3px;' if value['current_document'] == document else u'')) output.append(u'
%s
' % document) - output.append(u'
%s: %d
' % (ugettext(u'Pages'), document.documentpage_set.count())) + output.append(u'
%s: %d
' % (ugettext(u'Pages'), document.pages.count())) output.append(get_tags_inline_widget(document)) output.append(u'
' % document) output.append(document_html_widget(document, click_view='document_display', view='document_preview_multipage', fancybox_class='fancybox-noscaling', gallery_name=u'smart_link_%d_documents_gallery' % value['smart_link_instance'].pk)) diff --git a/apps/linking/managers.py b/apps/linking/managers.py index 03f9203b24..050ddffea2 100644 --- a/apps/linking/managers.py +++ b/apps/linking/managers.py @@ -59,7 +59,7 @@ class SmartLinkManager(models.Manager): if total_query: try: document_qs = Document.objects.filter(total_query) - result[smart_link] = {'documents': document_qs.order_by('file_filename') or []} + result[smart_link] = {'documents': document_qs.order_by('date_added') or []} except Exception, e: result[smart_link] = {'documents': []} errors.append(e) From aa660851651270c761db802028e7fb6691ac8e7b Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Sun, 4 Dec 2011 00:01:21 -0400 Subject: [PATCH 23/23] Update the document list view, the page update view and the remaining references of 'file_filename' to 'filename' --- apps/documents/views.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/documents/views.py b/apps/documents/views.py index 894818547c..4b08e9f5ee 100644 --- a/apps/documents/views.py +++ b/apps/documents/views.py @@ -66,7 +66,7 @@ def document_list(request, object_list=None, title=None, extra_context=None): check_permissions(request.user, [PERMISSION_DOCUMENT_VIEW]) context = { - 'object_list': object_list if not (object_list is None) else Document.objects.only('file_filename',).all(), + 'object_list': object_list if not (object_list is None) else Document.objects.all(), 'title': title if title else _(u'documents'), 'multi_select_as_buttons': True, 'hide_links': True, @@ -115,7 +115,7 @@ def document_view(request, document_id, advanced=False): if advanced: document_properties_form = DocumentPropertiesForm(instance=document, extra_fields=[ - {'label': _(u'Filename'), 'field': 'file_filename'}, + {'label': _(u'Filename'), 'field': 'filename'}, {'label': _(u'File mimetype'), 'field': 'file_mimetype'}, {'label': _(u'File mime encoding'), 'field': 'file_mime_encoding'}, {'label': _(u'File size'), 'field':lambda x: pretty_size(x.size) if x.size else '-'}, @@ -250,7 +250,7 @@ def document_edit(request, document_id): document.filename = form.cleaned_data['document_type_available_filenames'].filename document.save() - create_history(HISTORY_DOCUMENT_EDITED, document, {'user': request.user, 'diff': return_diff(old_document, document, ['file_filename', 'description'])}) + create_history(HISTORY_DOCUMENT_EDITED, document, {'user': request.user, 'diff': return_diff(old_document, document, ['filename', 'description'])}) RecentDocument.objects.add_document_for_user(request.user, document) messages.success(request, _(u'Document "%s" edited successfully.') % document) @@ -263,7 +263,7 @@ def document_edit(request, document_id): return HttpResponseRedirect(document.get_absolute_url()) else: form = DocumentForm_edit(instance=document, initial={ - 'new_filename': document.file_filename}) + 'new_filename': document.filename}) return render_to_response('generic_form.html', { 'form': form, @@ -486,16 +486,16 @@ def document_update_page_count(request): previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) office_converter = OfficeConverter() - qs = Document.objects.exclude(file_filename__iendswith='dxf').filter(file_mimetype__in=office_converter.mimetypes()) + qs = DocumentVersion.objects.exclude(filename__iendswith='dxf').filter(mimetype__in=office_converter.mimetypes()) if request.method == 'POST': updated = 0 processed = 0 - for document in qs: - old_page_count = document.page_count - document.update_page_count() + for document_version in qs: + old_page_count = document_version.pages.count() + document_version.update_page_count() processed += 1 - if old_page_count != document.page_count: + if old_page_count != document_version.pages.count(): updated += 1 messages.success(request, _(u'Page count update complete. Documents processed: %(total)d, documents with changed page count: %(change)d') % {