Finish the move to the new events app

This commit is contained in:
Roberto Rosario
2015-01-11 04:51:02 -04:00
parent ba4f1860cd
commit 305c1aaa6e
31 changed files with 441 additions and 416 deletions

View File

@@ -5,36 +5,6 @@ from django.utils.translation import ugettext_lazy as _
from events.classes import Event
event_document_check_out = Event(name='checkouts_document_check_out', label=_('Document checked out'))
HISTORY_DOCUMENT_CHECKED_OUT = {
'namespace': 'checkouts', 'name': 'document_checked_out',
'label': _(u'Document checked out'),
'summary': _(u'Document "%(document)s" checked out by %(fullname)s.'),
'expressions': {'fullname': 'user.get_full_name() if user.get_full_name() else user'}
}
event_document_check_in = Event(name='checkouts_document_check_in', label=_('Document checked in'))
HISTORY_DOCUMENT_CHECKED_IN = {
'namespace': 'checkouts', 'name': 'document_checked_in',
'label': _(u'Document checked in'),
'summary': _(u'Document "%(document)s" checked in by %(fullname)s.'),
'expressions': {'fullname': 'user.get_full_name() if user.get_full_name() else user'}
}
event_document_auto_check_in = Event(name='checkouts_document_auto_check_in', label=_('Document automatically checked in'))
HISTORY_DOCUMENT_AUTO_CHECKED_IN = {
'namespace': 'checkouts', 'name': 'document_auto_checked_in',
'label': _(u'Document automatically checked in'),
'summary': _(u'Document "%(document)s" automatically checked in.'),
}
event_document_forceful_check_in = Event(name='checkouts_document_forceful_check_in', label=_('Document forcefully checked in'))
HISTORY_DOCUMENT_FORCEFUL_CHECK_IN = {
'namespace': 'checkouts', 'name': 'document_forefull_check_in',
'label': _(u'Document forcefully checked in'),
'summary': _(u'Document "%(document)s" forcefully checked in by %(fullname)s.'),
'expressions': {'fullname': 'user.get_full_name() if user.get_full_name() else user'}
}

View File

@@ -8,7 +8,7 @@ from acls.api import class_permissions
from common.classes import ModelAttribute
from common.utils import encapsulate, validate_path
from dynamic_search.classes import SearchModel
from history.permissions import PERMISSION_HISTORY_VIEW
from events.permissions import PERMISSION_EVENTS_VIEW
from main.api import register_maintenance_links
from navigation.api import (register_links, register_model_list_columns)
from navigation.links import link_spacer
@@ -21,8 +21,9 @@ from .links import (document_clear_image_cache,
document_clear_transformations, document_content,
document_delete,
document_document_type_edit,
document_events_view,
document_multiple_document_type_edit, document_download,
document_edit, document_history_view, document_list,
document_edit, document_list,
document_list_recent, document_multiple_delete,
document_multiple_clear_transformations,
document_multiple_download,
@@ -72,8 +73,7 @@ register_links([Document], [document_multiple_clear_transformations, document_mu
register_links(Document, [document_preview], menu_name='form_header', position=0)
register_links(Document, [document_content], menu_name='form_header', position=1)
register_links(Document, [document_properties], menu_name='form_header', position=2)
register_links(Document, [document_history_view], menu_name='form_header')
register_links(Document, [document_version_list], menu_name='form_header')
register_links(Document, [document_events_view, document_version_list], menu_name='form_header')
# Document Version links
register_links(DocumentVersion, [document_version_revert, document_version_download])
@@ -124,7 +124,7 @@ class_permissions(Document, [PERMISSION_DOCUMENT_DELETE,
PERMISSION_DOCUMENT_TRANSFORM,
PERMISSION_DOCUMENT_VERSION_REVERT,
PERMISSION_DOCUMENT_VIEW,
PERMISSION_HISTORY_VIEW])
PERMISSION_EVENTS_VIEW])
document_search = SearchModel('documents', 'Document', permission=PERMISSION_DOCUMENT_VIEW, serializer_string='documents.serializers.DocumentSerializer')

View File

@@ -5,23 +5,4 @@ from django.utils.translation import ugettext_lazy as _
from events.classes import Event
event_document_create = Event(name='documents_document_create', label=_('Document created'))
HISTORY_DOCUMENT_CREATED = {
'namespace': 'documents', 'name': 'document_created',
'label': _(u'Document creation'),
'summary': _(u'Document "%(content_object)s" created by %(fullname)s.'),
'details': _(u'Document "%(content_object)s" created on %(datetime)s by %(fullname)s.'),
'expressions': {'fullname': 'user[0]["fields"]["username"] if isinstance(user, list) else user.get_full_name() if user.get_full_name() else user.username'}
}
event_document_edited = Event(name='documents_document_edit', label=_('Document edited'))
HISTORY_DOCUMENT_EDITED = {
'namespace': 'documents', 'name': 'document_edited',
'label': _(u'Document edited'),
'summary': _(u'Document "%(content_object)s" edited by %(fullname)s.'),
'details': _(u'Document "%(content_object)s" was edited on %(datetime)s by %(fullname)s.'),
'expressions': {
'fullname': 'user[0]["fields"]["username"] if isinstance(user, list) else user.get_full_name() if user.get_full_name() else user.username',
}
}

View File

@@ -2,7 +2,7 @@ from __future__ import absolute_import
from django.utils.translation import ugettext_lazy as _
from history.permissions import PERMISSION_HISTORY_VIEW
from events.permissions import PERMISSION_EVENTS_VIEW
from .permissions import (PERMISSION_DOCUMENT_PROPERTIES_EDIT,
PERMISSION_DOCUMENT_VIEW, PERMISSION_DOCUMENT_DELETE,
@@ -54,7 +54,7 @@ document_multiple_update_page_count = {'text': _(u'Reset page count'), 'view': '
document_clear_transformations = {'text': _(u'Clear transformations'), 'view': 'documents:document_clear_transformations', 'args': 'object.id', 'famfam': 'page_paintbrush', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]}
document_multiple_clear_transformations = {'text': _(u'Clear transformations'), 'view': 'documents:document_multiple_clear_transformations', 'famfam': 'page_paintbrush', 'permissions': [PERMISSION_DOCUMENT_TRANSFORM]}
document_print = {'text': _(u'Print'), 'view': 'documents:document_print', 'args': 'object.id', 'famfam': 'printer', 'permissions': [PERMISSION_DOCUMENT_VIEW]}
document_history_view = {'text': _(u'History'), 'view': 'history:history_for_object', 'args': ['"documents"', '"document"', 'object.id'], 'famfam': 'book_go', 'permissions': [PERMISSION_HISTORY_VIEW]}
document_events_view = {'text': _(u'Events'), 'view': 'events:events_for_object', 'args': ['"documents"', '"document"', 'object.id'], 'famfam': 'book_go', 'permissions': [PERMISSION_EVENTS_VIEW]}
# Tools
document_clear_image_cache = {'text': _(u'Clear the document image cache'), 'view': 'documents: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.')}

View File

@@ -237,7 +237,7 @@ def document_edit(request, document_id):
document.label = form.cleaned_data['document_type_available_filenames'].filename
document.save()
event_document_edited.commit(actor=request.user)
event_document_edited.commit(actor=request.user, target=document)
document.add_as_recent_document_for_user(request.user)
messages.success(request, _(u'Document "%s" edited successfully.') % document)
@@ -279,7 +279,7 @@ def document_document_type_edit(request, document_id=None, document_id_list=None
for document in documents:
document.set_document_type(form.cleaned_data['document_type'])
event_document_edited.commit(actor=request.user)
event_document_edited.commit(actor=request.user, target=document)
document.add_as_recent_document_for_user(request.user)
messages.success(request, _(u'Document type changed successfully.'))

View File

@@ -1 +1,8 @@
from __future__ import absolute_import, unicode_literals
from project_tools.api import register_tool
from .classes import Event # NOQA
from .links import events_list
register_tool(events_list)

View File

@@ -2,8 +2,9 @@ from django.contrib import admin
from .models import EventType
class EventTypeAdmin(admin.ModelAdmin):
readonly_fields = ('name', 'get_label')
readonly_fields = ('name', '__str__')
admin.site.register(EventType, EventTypeAdmin)

View File

@@ -1,22 +1,31 @@
from __future__ import absolute_import
from __future__ import absolute_import, unicode_literals
from django.core import serializers
from django.db import models
from django.utils.translation import ugettext as _
from actstream import action
class Event(object):
_labels = {}
@classmethod
def get_label(cls, name):
try:
return cls._labels[name]
except KeyError:
return _('Unknown or obsolete event type: {0}'.format(name))
def __init__(self, name, label):
self.name = name
self.label = label
self.event_type = None
self.__class__._labels[name] = label
def commit(self, actor=None, action_object=None, target=None):
model = models.get_model('events', 'EventType')
if not self.event_type:
self.event_type, created = model.objects.get_or_create(
label=self.label, name=self.name)
self.event_type, created = model.objects.get_or_create(name=self.name)
action.send(actor or target, actor=actor, verb=self.name, action_object=action_object, target=target)

View File

@@ -0,0 +1,5 @@
from __future__ import unicode_literals
from django.utils.translation import ugettext_lazy as _
events_list = {'text': _('Events'), 'view': 'events:events_list', 'famfam': 'book', 'icon': 'book.png'}

View File

@@ -1,23 +0,0 @@
from django.contrib.contenttypes.models import ContentType
from django.db import models
class EventTypeManager(models.Manager):
def create(self, *args, **kwargs):
label = kwargs.pop('label')
instance = super(EventTypeManager, self).create(*args, **kwargs)
self.model._labels[instance.name] = label
return instance
def get(self, *args, **kwargs):
instance = super(EventTypeManager, self).get(*args, **kwargs)
instance.label = self.model._labels[instance.name]
return instance
def get_or_create(self, *args, **kwargs):
label = kwargs.pop('label')
instance, boolean = super(EventTypeManager, self).get_or_create(*args, **kwargs)
self.model._labels[instance.name] = label
return instance, boolean

View File

@@ -4,30 +4,38 @@ from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext as _
from .managers import EventTypeManager
from actstream.models import Action
from common.utils import encapsulate
from navigation.api import register_model_list_columns
from .classes import Event
from .widgets import event_type_link
@python_2_unicode_compatible
class EventType(models.Model):
_labels = {}
name = models.CharField(max_length=64, unique=True, verbose_name=_('Name'))
objects = EventTypeManager()
def __str__(self):
return unicode(self.get_label())
def get_label(self):
try:
return self.__class__._labels[self.name]
except KeyError:
return _('Unknown or obsolete event type: {0}'.format(self.name))
#@models.permalink
#def get_absolute_url(self):
# return ('history_type_list', [self.pk])
return unicode(Event.get_label(self.name))
class Meta:
verbose_name = _('Event type')
verbose_name_plural = _('Event types')
register_model_list_columns(Action, [
{
'name': _('Timestamp'),
'attribute': 'timestamp'
},
{
'name': _('Actor'),
'attribute': 'actor',
},
{
'name': _(u'Verb'),
'attribute': encapsulate(lambda entry: event_type_link(entry))
},
])

View File

@@ -0,0 +1,8 @@
from __future__ import absolute_import, unicode_literals
from django.utils.translation import ugettext_lazy as _
from permissions.models import PermissionNamespace, Permission
events_namespace = PermissionNamespace('events', _('Events'))
PERMISSION_EVENTS_VIEW = Permission.objects.register(events_namespace, 'events_view', _('Access the events of an object'))

View File

@@ -0,0 +1,200 @@
# -*- coding: utf-8 -*-
import json
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
type_equivalence = {
'documents.document_created': 'documents_document_create',
'documents.document_edited': 'documents_document_edit',
'checkouts.document_checked_out': 'checkouts_document_check_out',
'checkouts.document_checked_in': 'checkouts_document_check_in',
'checkouts.document_auto_checked_in': 'checkouts_document_auto_check_in',
'checkouts.document_forefull_check_in': 'checkouts_document_forceful_check_in',
}
class Migration(DataMigration):
depends_on = (
('actstream', '0001_initial'),
('history', '0002_auto__chg_field_history_datetime'),
)
def forwards(self, orm):
"Write your forwards methods here."
# Note: Don't use "from appname.models import ModelName".
# Use orm.ModelName to refer to models in this application,
# and orm['appname.ModelName'] for models in other applications.
user_content_type = orm['contenttypes.contenttype'].objects.get(app_label='auth', model='user')
for history_event in orm['history.history'].objects.all():
user_pk = None
if history_event.dictionary:
loaded_dictionary = json.loads(history_event.dictionary)
if 'user' in loaded_dictionary:
user_pk = json.loads(loaded_dictionary['user']['value'])[0]['pk']
try:
orm['documents.document'].objects.get(pk=history_event.object_id)
except Exception:
pass
else:
if user_pk and history_event.object_id:
action = orm['actstream.action'](
timestamp=history_event.datetime,
actor_content_type=user_content_type,
actor_object_id=user_pk,
verb=type_equivalence['{0}.{1}'.format(history_event.history_type.namespace, history_event.history_type.name)],
target_content_type=history_event.content_type,
target_object_id=history_event.object_id
)
action.save()
def backwards(self, orm):
"Write your backwards methods here."
models = {
u'actstream.action': {
'Meta': {'ordering': "('-timestamp',)", 'object_name': 'Action'},
'action_object_content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'action_object'", 'null': 'True', 'to': u"orm['contenttypes.ContentType']"}),
'action_object_object_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'actor_content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actor'", 'to': u"orm['contenttypes.ContentType']"}),
'actor_object_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'target_content_type': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'target'", 'null': 'True', 'to': u"orm['contenttypes.ContentType']"}),
'target_object_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'timestamp': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'verb': ('django.db.models.fields.CharField', [], {'max_length': '255'})
},
u'actstream.follow': {
'Meta': {'unique_together': "(('user', 'content_type', 'object_id'),)", 'object_name': 'Follow'},
'actor_only': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'started': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
},
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'documents.document': {
'Meta': {'ordering': "['-date_added']", 'object_name': 'Document'},
'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'document_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'documents'", 'to': u"orm['documents.DocumentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'label': ('django.db.models.fields.CharField', [], {'default': "u'Uninitialized document'", 'max_length': '255', 'db_index': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'default': "u'eng'", 'max_length': '8'}),
'uuid': ('django.db.models.fields.CharField', [], {'default': "u'bbce0d8c-5707-4b0d-a996-4f4780787b53'", 'max_length': '48'})
},
u'documents.documentpage': {
'Meta': {'ordering': "['page_number']", 'object_name': 'DocumentPage'},
'content': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'document_version': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pages'", 'to': u"orm['documents.DocumentVersion']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'page_label': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
'page_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1', 'db_index': 'True'})
},
u'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': u"orm['documents.DocumentPage']"}),
u'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'})
},
u'documents.documenttype': {
'Meta': {'ordering': "['name']", 'object_name': 'DocumentType'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'}),
'ocr': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
u'documents.documenttypefilename': {
'Meta': {'ordering': "['filename']", 'unique_together': "(('document_type', 'filename'),)", 'object_name': 'DocumentTypeFilename'},
'document_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'filenames'", 'to': u"orm['documents.DocumentType']"}),
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'filename': ('django.db.models.fields.CharField', [], {'max_length': '128', 'db_index': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
u'documents.documentversion': {
'Meta': {'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', [], {'related_name': "'versions'", 'to': u"orm['documents.Document']"}),
'encoding': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mimetype': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
},
u'documents.recentdocument': {
'Meta': {'ordering': "('-datetime_accessed',)", 'object_name': 'RecentDocument'},
'datetime_accessed': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'db_index': 'True', 'blank': 'True'}),
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['documents.Document']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"})
},
u'events.eventtype': {
'Meta': {'object_name': 'EventType'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
},
u'history.history': {
'Meta': {'ordering': "('-datetime',)", 'object_name': 'History'},
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']", 'null': 'True', 'blank': 'True'}),
'datetime': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'dictionary': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'history_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['history.HistoryType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'object_id': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'})
},
u'history.historytype': {
'Meta': {'ordering': "('namespace', 'name')", 'unique_together': "(('namespace', 'name'),)", 'object_name': 'HistoryType'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
'namespace': ('django.db.models.fields.CharField', [], {'max_length': '64'})
}
}
complete_apps = ['history', 'auth', 'actstream', 'documents', 'events']
symmetrical = True

View File

@@ -0,0 +1,7 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('events.views',
url(r'^all/$', 'events_list', (), 'events_list'),
url(r'^for_object/(?P<app_label>[\w\-]+)/(?P<module_name>[\w\-]+)/(?P<object_id>\d+)/$', 'events_list', (), 'events_for_object'),
url(r'^by_verb/(?P<verb>[\w\-]+)/$', 'events_list', (), 'events_by_verb'),
)

View File

@@ -1,3 +1,88 @@
from django.shortcuts import render
from __future__ import absolute_import, unicode_literals
# Create your views here.
from django.core.exceptions import PermissionDenied
from django.db.models.loading import get_model
from django.http import Http404
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _
from actstream.models import Action, any_stream
from acls.models import AccessEntry
from common.utils import encapsulate
from permissions.models import Permission
from .classes import Event
from .permissions import PERMISSION_EVENTS_VIEW
from .widgets import event_object_link
def events_list(request, app_label=None, module_name=None, object_id=None, verb=None):
extra_columns = []
context = {
'extra_columns': extra_columns,
'hide_object': True,
}
if app_label and module_name and object_id:
model = get_model(app_label, module_name)
if not model:
raise Http404
content_object = get_object_or_404(model, pk=object_id)
try:
Permission.objects.check_permissions(request.user, [PERMISSION_EVENTS_VIEW])
except PermissionDenied:
AccessEntry.objects.check_access(PERMISSION_EVENTS_VIEW, request.user, content_object)
context.update({
'object_list': any_stream(content_object),
'title': _('Events for: %s') % content_object,
'object': content_object
})
elif verb:
pre_object_list = Action.objects.filter(verb=verb)
try:
Permission.objects.check_permissions(request.user, [PERMISSION_EVENTS_VIEW])
except PermissionDenied:
# If user doesn't have global permission, get a list of document
# for which he/she does hace access use it to filter the
# provided object_list
object_list = AccessEntry.objects.filter_objects_by_access(PERMISSION_EVENTS_VIEW, request.user, pre_object_list, related='content_object')
else:
object_list = pre_object_list
context.update({
'title': _('Events of type: %s') % Event.get_label(verb),
'object_list': object_list
})
else:
pre_object_list = Action.objects.all()
try:
Permission.objects.check_permissions(request.user, [PERMISSION_EVENTS_VIEW])
except PermissionDenied:
# If user doesn't have global permission, get a list of document
# for which he/she does hace access use it to filter the
# provided object_list
object_list = AccessEntry.objects.filter_objects_by_access(PERMISSION_EVENTS_VIEW, request.user, pre_object_list, related='content_object')
else:
object_list = pre_object_list
context.update({
'title': _('Events'),
'object_list': object_list
})
if not (app_label and module_name and object_id):
extra_columns.append(
{
'name': _('Target'),
'attribute': encapsulate(lambda entry: event_object_link(entry))
}
)
return render_to_response('main/generic_list.html', context,
context_instance=RequestContext(request))

View File

@@ -0,0 +1,20 @@
from __future__ import unicode_literals
from django.core.urlresolvers import reverse
from django.utils.safestring import mark_safe
from .classes import Event
def event_object_link(entry):
return mark_safe('<a href="%(url)s">%(label)s</a>' % {
'url': entry.target.get_absolute_url() if entry.target else '#',
'label': entry.target}
)
def event_type_link(entry):
return mark_safe('<a href="%(url)s">%(label)s</a>' % {
'url': reverse('events:events_by_verb', kwargs={'verb': entry.verb}),
'label': Event.get_label(entry.verb)}
)

View File

@@ -1,30 +1 @@
from __future__ import absolute_import
from django.utils.translation import ugettext_lazy as _
from project_tools.api import register_tool
from navigation.api import register_model_list_columns, register_links
from common.utils import encapsulate
from .models import History
from .widgets import history_entry_type_link
from .links import history_list, history_details
register_tool(history_list)
register_model_list_columns(History, [
{
'name': _(u'Date and time'),
'attribute': 'datetime'
},
{
'name': _(u'Type'),
'attribute': encapsulate(lambda entry: history_entry_type_link(entry))
},
{
'name': _(u'Summary'),
'attribute': encapsulate(lambda entry: unicode(entry.get_processed_summary()))
}
])
register_links(History, [history_details])

View File

@@ -1,11 +0,0 @@
from __future__ import absolute_import
from common.forms import DetailForm
from .models import History
class HistoryDetailForm(DetailForm):
class Meta:
model = History
exclude = ('datetime', 'content_type', 'object_id', 'history_type', 'dictionary')

View File

@@ -1,8 +0,0 @@
from __future__ import absolute_import
from django.utils.translation import ugettext_lazy as _
from .permissions import PERMISSION_HISTORY_VIEW
history_list = {'text': _(u'History'), 'view': 'history:history_list', 'famfam': 'book', 'icon': 'book.png'}
history_details = {'text': _(u'Details'), 'view': 'history:history_view', 'famfam': 'book_open', 'args': 'object.pk', 'permissions': [PERMISSION_HISTORY_VIEW]}

View File

@@ -1,9 +0,0 @@
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.db import models
class ObjectHistoryManager(models.Manager):
def get_url_for_object(self):
ct = ContentType.objects.get_for_model(self.instance)
return reverse('history_for_object', args=[ct, self.instance.pk])

View File

@@ -1,108 +1,3 @@
from __future__ import absolute_import
import json
import pickle
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.core import serializers
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
#from .runtime_data import history_types_dict
class HistoryType(models.Model):
namespace = models.CharField(max_length=64, verbose_name=_(u'Namespace'))
name = models.CharField(max_length=64, verbose_name=_(u'Name'))
def __unicode__(self):
return '{0}.{1}'.format(self.namespace, self.name)
# try:
# return unicode(history_types_dict[self.namespace][self.name]['label'])
# except KeyError:
# return u'Obsolete history type: %s - %s' % (self.namespace, self.name)
def get_absolute_url(self):
return reverse('history:history_type_list', args=[self.pk])
class Meta:
ordering = ('namespace', 'name')
unique_together = ('namespace', 'name')
verbose_name = _(u'History type')
verbose_name_plural = _(u'History types')
class History(models.Model):
datetime = models.DateTimeField(verbose_name=_(u'Date time'), auto_now_add=True)
content_type = models.ForeignKey(ContentType, blank=True, null=True)
object_id = models.PositiveIntegerField(blank=True, null=True)
content_object = generic.GenericForeignKey('content_type', 'object_id')
history_type = models.ForeignKey(HistoryType, verbose_name=_(u'History type'))
dictionary = models.TextField(verbose_name=_(u'Dictionary'), blank=True)
def __unicode__(self):
return u'%s - %s - %s' % (self.datetime, self.content_object, self.history_type)
def get_label(self):
return history_types_dict[self.history_type.namespace][self.history_type.name]['label']
def get_summary(self):
return history_types_dict[self.history_type.namespace][self.history_type.name].get('summary', u'')
def get_details(self):
return history_types_dict[self.history_type.namespace][self.history_type.name].get('details', u'')
def get_expressions(self):
return history_types_dict[self.history_type.namespace][self.history_type.name].get('expressions', {})
def get_processed_summary(self):
return _process_history_text(self, self.get_summary())
def get_processed_details(self):
return _process_history_text(self, self.get_details())
@models.permalink
def get_absolute_url(self):
return ('history_view', [self.pk])
class Meta:
ordering = ('-datetime',)
verbose_name = _(u'History')
verbose_name_plural = _(u'Histories')
def _process_history_text(history, text):
key_values = {
'content_object': history.content_object,
'datetime': history.datetime
}
loaded_dictionary = json.loads(history.dictionary)
new_dict = {}
for key, values in loaded_dictionary.items():
value_type = pickle.loads(str(values['type']))
if isinstance(value_type, models.base.ModelBase):
for deserialized in serializers.deserialize('json', values['value']):
new_dict[key] = deserialized.object
elif isinstance(value_type, models.query.QuerySet):
qs = []
for deserialized in serializers.deserialize('json', values['value']):
qs.append(deserialized.object)
new_dict[key] = qs
else:
new_dict[key] = json.loads(values['value'])
key_values.update(new_dict)
expressions_dict = {}
for key, value in history.get_expressions().items():
try:
expressions_dict[key] = eval(value, key_values.copy())
except Exception as exception:
expressions_dict[key] = exception
key_values.update(expressions_dict)
return text % key_values

View File

@@ -1,8 +0,0 @@
from __future__ import absolute_import
from django.utils.translation import ugettext_lazy as _
from permissions.models import PermissionNamespace, Permission
history_namespace = PermissionNamespace('history', _(u'History'))
PERMISSION_HISTORY_VIEW = Permission.objects.register(history_namespace, 'history_view', _(u'Access the history of an object'))

View File

@@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
depends_on = (
('events', '0002_migrate_history_data'),
)
def forwards(self, orm):
# Removing unique constraint on 'HistoryType', fields ['namespace', 'name']
db.delete_unique(u'history_historytype', ['namespace', 'name'])
# Deleting model 'History'
db.delete_table(u'history_history')
# Deleting model 'HistoryType'
db.delete_table(u'history_historytype')
def backwards(self, orm):
# Adding model 'History'
db.create_table(u'history_history', (
('history_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['history.HistoryType'])),
('dictionary', self.gf('django.db.models.fields.TextField')(blank=True)),
('object_id', self.gf('django.db.models.fields.PositiveIntegerField')(null=True, blank=True)),
('datetime', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'], null=True, blank=True)),
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
))
db.send_create_signal(u'history', ['History'])
# Adding model 'HistoryType'
db.create_table(u'history_historytype', (
('namespace', self.gf('django.db.models.fields.CharField')(max_length=64)),
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(max_length=64)),
))
db.send_create_signal(u'history', ['HistoryType'])
# Adding unique constraint on 'HistoryType', fields ['namespace', 'name']
db.create_unique(u'history_historytype', ['namespace', 'name'])
models = {
}
complete_apps = ['history']

View File

@@ -1,8 +0,0 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('history.views',
url(r'^list/$', 'history_list', (), 'history_list'),
url(r'^list/for_object/(?P<app_label>[\w\-]+)/(?P<module_name>[\w\-]+)/(?P<object_id>\d+)/$', 'history_for_object', (), 'history_for_object'),
url(r'^(?P<object_id>\d+)/$', 'history_view', (), 'history_view'),
url(r'^type/(?P<history_type_pk>\d+)/list/$', 'history_type_list', (), 'history_type_list'),
)

View File

@@ -1,105 +0,0 @@
from __future__ import absolute_import
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied
from django.db.models.loading import get_model
from django.http import Http404
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _
from acls.models import AccessEntry
from common.utils import encapsulate
from permissions.models import Permission
from .forms import HistoryDetailForm
from .models import History, HistoryType
from .permissions import PERMISSION_HISTORY_VIEW
from .widgets import history_entry_object_link
def history_list(request, object_list=None, title=None, extra_context=None):
pre_object_list = object_list if not (object_list is None) else History.objects.all()
try:
Permission.objects.check_permissions(request.user, [PERMISSION_HISTORY_VIEW])
except PermissionDenied:
# If user doesn't have global permission, get a list of document
# for which he/she does hace access use it to filter the
# provided object_list
final_object_list = AccessEntry.objects.filter_objects_by_access(PERMISSION_HISTORY_VIEW, request.user, pre_object_list, related='content_object')
else:
final_object_list = pre_object_list
context = {
'object_list': final_object_list,
'title': title if title else _(u'History events'),
'extra_columns': [
{
'name': _(u'Object link'),
'attribute': encapsulate(lambda x: history_entry_object_link(x))
},
],
'hide_object': True,
}
if extra_context:
context.update(extra_context)
return render_to_response('main/generic_list.html', context,
context_instance=RequestContext(request))
def history_for_object(request, app_label, module_name, object_id):
model = get_model(app_label, module_name)
if not model:
raise Http404
content_object = get_object_or_404(model, pk=object_id)
content_type = ContentType.objects.get_for_model(model)
try:
Permission.objects.check_permissions(request.user, [PERMISSION_HISTORY_VIEW])
except PermissionDenied:
AccessEntry.objects.check_access(PERMISSION_HISTORY_VIEW, request.user, content_object)
context = {
'object_list': History.objects.filter(content_type=content_type, object_id=object_id),
'title': _(u'History events for: %s') % content_object,
'object': content_object,
'hide_object': True,
}
return render_to_response('main/generic_list.html', context,
context_instance=RequestContext(request))
def history_view(request, object_id):
history = get_object_or_404(History, pk=object_id)
try:
Permission.objects.check_permissions(request.user, [PERMISSION_HISTORY_VIEW])
except PermissionDenied:
AccessEntry.objects.check_access(PERMISSION_HISTORY_VIEW, request.user, history.content_object)
form = HistoryDetailForm(instance=history, extra_fields=[
{'label': _(u'Date'), 'field': lambda x: x.datetime.date()},
{'label': _(u'Time'), 'field': lambda x: unicode(x.datetime.time()).split('.')[0]},
{'label': _(u'Object'), 'field': 'content_object'},
{'label': _(u'Event type'), 'field': lambda x: x.get_label()},
{'label': _(u'Additional details'), 'field': lambda x: x.get_processed_details() or _(u'None')},
])
return render_to_response('main/generic_detail.html', {
'title': _(u'Details for: %s') % history.get_processed_summary(),
'form': form,
}, context_instance=RequestContext(request))
def history_type_list(request, history_type_pk):
history_type = get_object_or_404(HistoryType, pk=history_type_pk)
return history_list(
request,
object_list=History.objects.filter(history_type=history_type),
title=_(u'History events of type: %s') % history_type,
)

View File

@@ -1,23 +0,0 @@
from django.utils.html import escape
from django.utils.safestring import mark_safe
def history_entry_object_link(entry):
return mark_safe(u'<a href="%(url)s">%(label)s</a>' % {
'url': entry.content_object.get_absolute_url() if entry.content_object else u'#',
'label': escape(unicode(entry.content_object)) if entry.content_object else u''}
)
def history_entry_summary(entry):
return mark_safe(u'<a href="%(url)s">%(label)s</a>' % {
'url': entry.get_absolute_url(),
'label': unicode(entry.get_processed_summary())}
)
def history_entry_type_link(entry):
return mark_safe(u'<a href="%(url)s">%(label)s</a>' % {
'url': entry.history_type.get_absolute_url(),
'label': unicode(entry.history_type)}
)

View File

@@ -2,7 +2,6 @@ from __future__ import absolute_import
from django.contrib.auth.models import User, Group
from actstream import registry
from navigation.api import register_links
from navigation.links import link_spacer
@@ -28,5 +27,4 @@ register_setup(group_setup)
APIEndPoint('users', app_name='user_management')
registry.register(User)
registry.register(Group)

View File

@@ -1,3 +1,7 @@
from django.db import models
from django.contrib.auth.models import User, Group
# Create your models here.
from actstream import registry
registry.register(User)
registry.register(Group)

View File

@@ -8,7 +8,6 @@ urlpatterns = patterns('',
url(r'^', include('common.urls', namespace='common')),
url(r'^', include('main.urls', namespace='main')),
url(r'^acls/', include('acls.urls', namespace='acls')),
url(r'^activity/', include('actstream.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'^api/', include('rest_api.urls')),
url(r'^checkouts/', include('checkouts.urls', namespace='checkouts')),
@@ -18,9 +17,9 @@ urlpatterns = patterns('',
url(r'^documents/', include('documents.urls', namespace='documents')),
url(r'^documents/signatures/', include('document_signatures.urls', namespace='signatures')),
url(r'^docs/', include('rest_framework_swagger.urls')),
url(r'^events/', include('events.urls', namespace='events')),
url(r'^folders/', include('folders.urls', namespace='folders')),
url(r'^gpg/', include('django_gpg.urls', namespace='django_gpg')),
url(r'^history/', include('history.urls', namespace='history')),
url(r'^installation/', include('installation.urls', namespace='installation')),
url(r'^linking/', include('linking.urls', namespace='linking')),
url(r'^mailer/', include('mailer.urls', namespace='mailer')),