Initial commit adding document checkout support
This commit is contained in:
39
apps/checkouts/__init__.py
Normal file
39
apps/checkouts/__init__.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from navigation.api import (register_links, register_top_menu,
|
||||||
|
register_multi_item_links, register_sidebar_template)
|
||||||
|
|
||||||
|
from documents.models import Document
|
||||||
|
from documents.permissions import PERMISSION_DOCUMENT_VIEW
|
||||||
|
from acls.api import class_permissions
|
||||||
|
|
||||||
|
from .permissions import (PERMISSION_DOCUMENT_CHECKOUT, PERMISSION_DOCUMENT_CHECKIN)
|
||||||
|
from .links import checkout_list, checkout_document, checkout_info, checkin_document
|
||||||
|
from .models import DocumentCheckout
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_document_checkout_extra_methods():
|
||||||
|
Document.add_to_class('is_checked_out', lambda document: DocumentCheckout.objects.is_document_checked_out(document))
|
||||||
|
Document.add_to_class('check_in', lambda document: DocumentCheckout.objects.check_in_document(document))
|
||||||
|
|
||||||
|
#register_multi_item_links(['folder_view'], [folder_document_multiple_remove])
|
||||||
|
#register_links(Folder, [folder_view, folder_edit, folder_delete, folder_acl_list])
|
||||||
|
#register_links([Folder, 'folder_list', 'folder_create'], [folder_list, folder_create], menu_name='secondary_menu')
|
||||||
|
register_top_menu(name='checkouts', link=checkout_list)#, children_views=['folder_list', 'folder_create', 'folder_edit', 'folder_delete', 'folder_view', 'folder_document_multiple_remove'])
|
||||||
|
register_links(Document, [checkout_info], menu_name='form_header')
|
||||||
|
#register_sidebar_template(['folder_list'], 'folders_help.html')
|
||||||
|
register_links(['checkout_info', 'checkout_document', 'checkin_document'], [checkout_document, checkin_document], menu_name="sidebar")
|
||||||
|
|
||||||
|
class_permissions(Document, [
|
||||||
|
PERMISSION_DOCUMENT_CHECKOUT,
|
||||||
|
PERMISSION_DOCUMENT_CHECKIN,
|
||||||
|
])
|
||||||
|
|
||||||
|
initialize_document_checkout_extra_methods()
|
||||||
|
|
||||||
|
|
||||||
|
#TODO: default checkout time
|
||||||
|
#TODO: forcefull check in
|
||||||
|
#TODO: specify checkout option check (document.allows_new_versions())
|
||||||
11
apps/checkouts/exceptions.py
Normal file
11
apps/checkouts/exceptions.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
class DocumentNotCheckedOut(Exception):
|
||||||
|
"""
|
||||||
|
Raised when trying to checkin a document that is not checkedout
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
class DocumentAlreadyCheckedOut(Exception):
|
||||||
|
"""
|
||||||
|
Raised when trying to checkout an already checkedout document
|
||||||
|
"""
|
||||||
|
pass
|
||||||
21
apps/checkouts/forms.py
Normal file
21
apps/checkouts/forms.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from .models import DocumentCheckout
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentCheckoutForm(forms.ModelForm):
|
||||||
|
days = forms.IntegerField(min_value=0, label=_(u'Days'), help_text=_(u'Amount of time to hold the document checked out in days.'), required=False, widget=forms.widgets.TextInput(attrs={'maxlength': 3, 'style':'width: 10em;'}))
|
||||||
|
hours = forms.IntegerField(min_value=0, label=_(u'Hours'), help_text=_(u'Amount of time to hold the document checked out in hours.'), required=False, widget=forms.widgets.TextInput(attrs={'maxlength': 3, 'style':'width: 10em;'}))
|
||||||
|
minutes = forms.IntegerField(min_value=0, label=_(u'Minutes'), help_text=_(u'Amount of time to hold the document checked out in minutes.'), required=False, widget=forms.widgets.TextInput(attrs={'maxlength': 3, 'style':'width: 10em;'}))
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = DocumentCheckout
|
||||||
|
exclude = ('expiration_datetime', )
|
||||||
|
#fields = ('username', 'first_name', 'last_name', 'email', 'is_staff', 'is_superuser', 'last_login', 'date_joined', 'groups')
|
||||||
|
|
||||||
|
#def clean(self):
|
||||||
|
|
||||||
|
|
||||||
12
apps/checkouts/links.py
Normal file
12
apps/checkouts/links.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from documents.permissions import PERMISSION_DOCUMENT_VIEW
|
||||||
|
|
||||||
|
from .permissions import (PERMISSION_DOCUMENT_CHECKOUT, PERMISSION_DOCUMENT_CHECKIN)
|
||||||
|
|
||||||
|
checkout_list = {'text': _(u'check in/out'), 'view': 'checkout_list', 'famfam': 'basket'}
|
||||||
|
checkout_document = {'text': _('check out document'), 'view': 'checkout_document', 'args': 'object.pk', 'famfam': 'basket_put'}#, 'permissions': [PERMISSION_DOCUMENT_CHECKOUT]}
|
||||||
|
checkin_document = {'text': _('check out document'), 'view': 'checkout_document', 'args': 'object.pk', 'famfam': 'basket_remove'}#, 'permissions': [PERMISSION_DOCUMENT_CHECKIN]}
|
||||||
|
checkout_info = {'text': _('check in/out'), 'view': 'checkout_info', 'args': 'object.pk', 'famfam': 'basket', 'children_views': ['checkout_document', 'checkin_document']}#, 'permissions': [PERMISSION_DOCUMENT_CHECKIN]}
|
||||||
1
apps/checkouts/literals.py
Normal file
1
apps/checkouts/literals.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
26
apps/checkouts/managers.py
Normal file
26
apps/checkouts/managers.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
from documents.models import Document
|
||||||
|
|
||||||
|
from .exceptions import DocumentNotCheckedOut
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentCheckoutManager(models.Manager):
|
||||||
|
def checked_out(self):
|
||||||
|
return Document.objects.filter(pk__in=self.model.objects.all().values_list('pk', flat=True))
|
||||||
|
|
||||||
|
def is_document_checked_out(self, document):
|
||||||
|
if self.model.objects.filter(document=document):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def check_in_document(self, document):
|
||||||
|
try:
|
||||||
|
document_checkout = self.model.objects.get(document=document)
|
||||||
|
except self.model.DoesNotExist:
|
||||||
|
raise DocumentNotCheckedOut
|
||||||
|
else:
|
||||||
|
document_checkout.delete()
|
||||||
122
apps/checkouts/migrations/0001_initial.py
Normal file
122
apps/checkouts/migrations/0001_initial.py
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
# -*- coding: 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 'DocumentCheckout'
|
||||||
|
db.create_table('checkouts_documentcheckout', (
|
||||||
|
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||||
|
('document', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['documents.Document'])),
|
||||||
|
('checkout_datetime', self.gf('django.db.models.fields.DateTimeField')()),
|
||||||
|
('expiration_datetime', self.gf('django.db.models.fields.DateTimeField')()),
|
||||||
|
('block_new_version', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||||
|
))
|
||||||
|
db.send_create_signal('checkouts', ['DocumentCheckout'])
|
||||||
|
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
# Deleting model 'DocumentCheckout'
|
||||||
|
db.delete_table('checkouts_documentcheckout')
|
||||||
|
|
||||||
|
|
||||||
|
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'})
|
||||||
|
},
|
||||||
|
'checkouts.documentcheckout': {
|
||||||
|
'Meta': {'object_name': 'DocumentCheckout'},
|
||||||
|
'block_new_version': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'checkout_datetime': ('django.db.models.fields.DateTimeField', [], {}),
|
||||||
|
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']"}),
|
||||||
|
'expiration_datetime': ('django.db.models.fields.DateTimeField', [], {}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'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', [], {'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.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'})
|
||||||
|
},
|
||||||
|
'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'})
|
||||||
|
},
|
||||||
|
'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 = ['checkouts']
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# -*- coding: 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 unique constraint on 'DocumentCheckout', fields ['document']
|
||||||
|
db.create_unique('checkouts_documentcheckout', ['document_id'])
|
||||||
|
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
# Removing unique constraint on 'DocumentCheckout', fields ['document']
|
||||||
|
db.delete_unique('checkouts_documentcheckout', ['document_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'})
|
||||||
|
},
|
||||||
|
'checkouts.documentcheckout': {
|
||||||
|
'Meta': {'object_name': 'DocumentCheckout'},
|
||||||
|
'block_new_version': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'checkout_datetime': ('django.db.models.fields.DateTimeField', [], {}),
|
||||||
|
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['documents.Document']", 'unique': 'True'}),
|
||||||
|
'expiration_datetime': ('django.db.models.fields.DateTimeField', [], {}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||||
|
},
|
||||||
|
'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', [], {'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.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'})
|
||||||
|
},
|
||||||
|
'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'})
|
||||||
|
},
|
||||||
|
'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 = ['checkouts']
|
||||||
0
apps/checkouts/migrations/__init__.py
Normal file
0
apps/checkouts/migrations/__init__.py
Normal file
48
apps/checkouts/models.py
Normal file
48
apps/checkouts/models.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from django.db import models, IntegrityError
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from documents.models import Document
|
||||||
|
|
||||||
|
from .managers import DocumentCheckoutManager
|
||||||
|
from .exceptions import DocumentAlreadyCheckedOut
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentCheckout(models.Model):
|
||||||
|
"""
|
||||||
|
Model to store the state and information of a document checkout
|
||||||
|
"""
|
||||||
|
document = models.ForeignKey(Document, verbose_name=_(u'document'), unique=True, editable=False)
|
||||||
|
checkout_datetime = models.DateTimeField(verbose_name=_(u'checkout date and time'), editable=False)
|
||||||
|
expiration_datetime = models.DateTimeField(verbose_name=_(u'checkout expiration date and time'))
|
||||||
|
block_new_version = models.BooleanField(verbose_name=_(u'block new version upload'), help_text=_(u'Do not allow new version of this document to be uploaded.'))
|
||||||
|
#block_metadata
|
||||||
|
#block_editing
|
||||||
|
#block tag add/remove
|
||||||
|
|
||||||
|
objects = DocumentCheckoutManager()
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return unicode(self.document)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if not self.pk:
|
||||||
|
self.checkout_date = datetime.datetime.now()
|
||||||
|
try:
|
||||||
|
return super(DocumentCheckout, self).save(*args, **kwargs)
|
||||||
|
except IntegrityError:
|
||||||
|
raise DocumentAlreadyCheckedOut
|
||||||
|
|
||||||
|
@models.permalink
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return ('checkout_info', [self.document.pk])
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _(u'document checkout')
|
||||||
|
verbose_name_plural = _(u'document checkouts')
|
||||||
12
apps/checkouts/permissions.py
Normal file
12
apps/checkouts/permissions.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from permissions.models import PermissionNamespace, Permission
|
||||||
|
|
||||||
|
namespace = PermissionNamespace('checkouts', _(u'Document checkout'))
|
||||||
|
|
||||||
|
PERMISSION_DOCUMENT_CHECKOUT = Permission.objects.register(namespace, 'checkout_document', _(u'Check out documents'))
|
||||||
|
PERMISSION_DOCUMENT_CHECKIN = Permission.objects.register(namespace, 'checkin_document', _(u'Check in documents'))
|
||||||
|
PERMISSION_DOCUMENT_CHECKIN_OVERRIDE = Permission.objects.register(namespace, 'checkin_document_override', _(u'Forcefully check in documents'))
|
||||||
|
|
||||||
8
apps/checkouts/urls.py
Normal file
8
apps/checkouts/urls.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from django.conf.urls.defaults import patterns, url
|
||||||
|
|
||||||
|
urlpatterns = patterns('checkouts.views',
|
||||||
|
url(r'^list/$', 'checkout_list', (), 'checkout_list'),
|
||||||
|
url(r'^(?P<document_pk>\d+)/check/out/$', 'checkout_document', (), 'checkout_document'),
|
||||||
|
url(r'^(?P<document_pk>\d+)/check/in/$', 'checkin_document', (), 'checkin_document'),
|
||||||
|
url(r'^(?P<document_pk>\d+)/check/info/$', 'checkout_info', (), 'checkout_info'),
|
||||||
|
)
|
||||||
103
apps/checkouts/views.py
Normal file
103
apps/checkouts/views.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.shortcuts import render_to_response, get_object_or_404
|
||||||
|
from django.template import RequestContext
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
#from django.utils.html import mark_safe
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from documents.views import document_list
|
||||||
|
from documents.models import Document
|
||||||
|
from permissions.exceptions import PermissionDenied
|
||||||
|
from permissions.models import Permission
|
||||||
|
from acls.models import AccessEntry
|
||||||
|
|
||||||
|
from .models import DocumentCheckout
|
||||||
|
from .permissions import PERMISSION_DOCUMENT_CHECKOUT, PERMISSION_DOCUMENT_CHECKIN
|
||||||
|
from .forms import DocumentCheckoutForm
|
||||||
|
from .exceptions import DocumentAlreadyCheckedOut
|
||||||
|
|
||||||
|
|
||||||
|
def checkout_list(request):
|
||||||
|
return document_list(request, object_list=DocumentCheckout.objects.checked_out(), title=_(u'checked out documents'))
|
||||||
|
|
||||||
|
|
||||||
|
def checkout_info(request, document_pk):
|
||||||
|
document = get_object_or_404(Document, pk=document_pk)
|
||||||
|
try:
|
||||||
|
Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CHECKOUT, PERMISSION_DOCUMENT_CHECKIN])
|
||||||
|
except PermissionDenied:
|
||||||
|
AccessEntry.objects.check_access([PERMISSION_DOCUMENT_CHECKOUT, PERMISSION_DOCUMENT_CHECKIN], request.user, document)
|
||||||
|
|
||||||
|
if document.is_checked_out():
|
||||||
|
content = 'checkedout'
|
||||||
|
else:
|
||||||
|
content = _(u'Document has not been checked out.')
|
||||||
|
#<p>{{ content|safe }}</p>
|
||||||
|
#{% endif %}
|
||||||
|
|
||||||
|
#{% for paragraph in paragraphs %}
|
||||||
|
#<p>{{ paragraph|safe }}</p>#
|
||||||
|
|
||||||
|
return render_to_response('generic_template.html', {
|
||||||
|
'content': content,
|
||||||
|
'object': document,
|
||||||
|
'title': _(u'Check out details for document: %s') % document
|
||||||
|
}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
|
def checkout_document(request, document_pk):
|
||||||
|
document = get_object_or_404(Document, pk=document_pk)
|
||||||
|
try:
|
||||||
|
Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CHECKOUT])
|
||||||
|
except PermissionDenied:
|
||||||
|
AccessEntry.objects.check_access(PERMISSION_DOCUMENT_CHECKOUT, request.user, document)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = DocumentCheckoutForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
try:
|
||||||
|
document_checkout = form.save()
|
||||||
|
except DocumentAlreadyCheckedOut:
|
||||||
|
messages.error(request, _(u'Document already checked out.'))
|
||||||
|
except Exception, exc:
|
||||||
|
messages.error(request, _(u'Error trying to check out document; %s') % exc)
|
||||||
|
else:
|
||||||
|
messages.success(request, _(u'Document "%s" checked out successfully.') % document)
|
||||||
|
return HttpResponseRedirect(document_checkout.get_absolute_url())
|
||||||
|
else:
|
||||||
|
form = DocumentCheckoutForm()#document=document, initial={
|
||||||
|
#'new_filename': document.filename})
|
||||||
|
|
||||||
|
return render_to_response('generic_form.html', {
|
||||||
|
'form': form,
|
||||||
|
'object': document,
|
||||||
|
'title': _(u'Check out document: %s') % document
|
||||||
|
}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
|
def checkin_document(request, document_pk):
|
||||||
|
document = get_object_or_404(Document, pk=document_pk)
|
||||||
|
try:
|
||||||
|
Permission.objects.check_permissions(request.user, [PERMISSION_DOCUMENT_CHECKIN])
|
||||||
|
except PermissionDenied:
|
||||||
|
AccessEntry.objects.check_access(PERMISSION_DOCUMENT_CHECKIN, request.user, document)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
try:
|
||||||
|
document.check_in()
|
||||||
|
except DocumentAlreadyCheckedOut:
|
||||||
|
messages.error(request, _(u'Document already checked out.'))
|
||||||
|
except Exception, exc:
|
||||||
|
messages.error(request, _(u'Error trying to check in document; %s') % exc)
|
||||||
|
else:
|
||||||
|
messages.success(request, _(u'Document "%s" checked out successfully.') % document)
|
||||||
|
return HttpResponseRedirect(reverse('checkout_info', args=[document.pk]))
|
||||||
|
|
||||||
|
return render_to_response('generic_form.html', {
|
||||||
|
'object': document,
|
||||||
|
'title': _(u'Check in document: %s') % document
|
||||||
|
}, context_instance=RequestContext(request))
|
||||||
5
apps/permissions/exceptions.py
Normal file
5
apps/permissions/exceptions.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from django.core.exceptions import PermissionDenied as DjangoPermissionDenied
|
||||||
|
|
||||||
|
|
||||||
|
class PermissionDenied(DjangoPermissionDenied):
|
||||||
|
pass
|
||||||
@@ -174,6 +174,7 @@ INSTALLED_APPS = (
|
|||||||
'main',
|
'main',
|
||||||
'rest_api',
|
'rest_api',
|
||||||
'document_signatures',
|
'document_signatures',
|
||||||
|
'checkouts',
|
||||||
|
|
||||||
# Has to be last so the other apps can register it's signals
|
# Has to be last so the other apps can register it's signals
|
||||||
'signaler',
|
'signaler',
|
||||||
|
|||||||
1
urls.py
1
urls.py
@@ -32,6 +32,7 @@ urlpatterns = patterns('',
|
|||||||
(r'^gpg/', include('django_gpg.urls')),
|
(r'^gpg/', include('django_gpg.urls')),
|
||||||
(r'^documents/signatures/', include('document_signatures.urls')),
|
(r'^documents/signatures/', include('document_signatures.urls')),
|
||||||
(r'^feedback/', include('feedback.urls')),
|
(r'^feedback/', include('feedback.urls')),
|
||||||
|
(r'^checkouts/', include('checkouts.urls')),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user