Add docstrings for almost all models
Also adds docstring to some managers and model methods. Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
@@ -70,6 +70,9 @@ class AccessControlList(models.Model):
|
||||
)
|
||||
|
||||
def get_permission_titles(self):
|
||||
"""
|
||||
Returns the descriptibe labels for the permissions.
|
||||
"""
|
||||
result = ', '.join(
|
||||
[force_text(permission) for permission in self.permissions.all()]
|
||||
)
|
||||
|
||||
@@ -19,6 +19,12 @@ from .search import cabinet_search # NOQA
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Cabinet(MPTTModel):
|
||||
"""
|
||||
Model to store a hierarchical tree of document containers. Each container
|
||||
can store an unlimited number of documents using an M2M field. Only
|
||||
the top level container is can have an ACL. All child container's
|
||||
access is delegated to their corresponding root container.
|
||||
"""
|
||||
parent = TreeForeignKey(
|
||||
blank=True, db_index=True, null=True, on_delete=models.CASCADE,
|
||||
related_name='children', to='self'
|
||||
@@ -41,6 +47,10 @@ class Cabinet(MPTTModel):
|
||||
return self.get_full_path()
|
||||
|
||||
def add_document(self, document, user=None):
|
||||
"""
|
||||
Add a document to a container. This can be done without using this
|
||||
method but this method provides the event commit already coded.
|
||||
"""
|
||||
self.documents.add(document)
|
||||
event_cabinets_add_document.commit(
|
||||
action_object=self, actor=user, target=document
|
||||
@@ -50,14 +60,26 @@ class Cabinet(MPTTModel):
|
||||
return reverse('cabinets:cabinet_view', args=(self.pk,))
|
||||
|
||||
def get_document_count(self, user):
|
||||
"""
|
||||
Return numeric count of the total documents in a cabinet. The count
|
||||
is filtered by access.
|
||||
"""
|
||||
return self.get_documents_queryset(user=user).count()
|
||||
|
||||
def get_documents_queryset(self, user):
|
||||
"""
|
||||
Provide a queryset of the documents in a cabinet. The queryset is
|
||||
filtered by access.
|
||||
"""
|
||||
return AccessControlList.objects.filter_by_access(
|
||||
permission_document_view, user, queryset=self.documents
|
||||
)
|
||||
|
||||
def get_full_path(self):
|
||||
"""
|
||||
Returns a string that represents the path to the cabinet. The
|
||||
path string starts from the root cabinet.
|
||||
"""
|
||||
result = []
|
||||
for node in self.get_ancestors(include_self=True):
|
||||
result.append(node.label)
|
||||
@@ -65,17 +87,22 @@ class Cabinet(MPTTModel):
|
||||
return ' / '.join(result)
|
||||
|
||||
def remove_document(self, document, user=None):
|
||||
"""
|
||||
Remove a document from a cabinet. This method provides the
|
||||
corresponding event commit.
|
||||
"""
|
||||
self.documents.remove(document)
|
||||
event_cabinets_remove_document.commit(
|
||||
action_object=self, actor=user, target=document
|
||||
)
|
||||
|
||||
def validate_unique(self, exclude=None):
|
||||
# Explicit validation of uniqueness of parent+label as the provided
|
||||
# unique_together check in Meta is not working for all 100% cases
|
||||
# when there is a FK in the unique_together tuple
|
||||
# https://code.djangoproject.com/ticket/1751
|
||||
|
||||
"""
|
||||
Explicit validation of uniqueness of parent+label as the provided
|
||||
unique_together check in Meta is not working for all 100% cases
|
||||
when there is a FK in the unique_together tuple
|
||||
https://code.djangoproject.com/ticket/1751
|
||||
"""
|
||||
with transaction.atomic():
|
||||
if connection.vendor == 'oracle':
|
||||
queryset = Cabinet.objects.filter(parent=self.parent, label=self.label)
|
||||
@@ -102,6 +129,11 @@ class Cabinet(MPTTModel):
|
||||
|
||||
|
||||
class DocumentCabinet(Cabinet):
|
||||
"""
|
||||
Represent a document's cabinet. This Model is a proxy model from Cabinet
|
||||
and is used as an alias to map columns to it without having to map them
|
||||
to the base Cabinet model.
|
||||
"""
|
||||
class Meta:
|
||||
proxy = True
|
||||
verbose_name = _('Document cabinet')
|
||||
|
||||
@@ -22,7 +22,7 @@ logger = logging.getLogger(__name__)
|
||||
@python_2_unicode_compatible
|
||||
class DocumentCheckout(models.Model):
|
||||
"""
|
||||
Model to store the state and information of a document checkout
|
||||
Model to store the state and information of a document checkout.
|
||||
"""
|
||||
document = models.OneToOneField(
|
||||
on_delete=models.CASCADE, to=Document, verbose_name=_('Document')
|
||||
@@ -99,6 +99,9 @@ class DocumentCheckout(models.Model):
|
||||
|
||||
|
||||
class NewVersionBlock(models.Model):
|
||||
"""
|
||||
Model to keep track of which documents have new version upload restricted.
|
||||
"""
|
||||
document = models.ForeignKey(
|
||||
on_delete=models.CASCADE, to=Document, verbose_name=_('Document')
|
||||
)
|
||||
|
||||
@@ -20,6 +20,10 @@ def upload_to(instance, filename):
|
||||
|
||||
|
||||
class ErrorLogEntry(models.Model):
|
||||
"""
|
||||
Class to store an error log for any object. Uses generic foreign keys to
|
||||
reference the parent object.
|
||||
"""
|
||||
namespace = models.CharField(
|
||||
max_length=128, verbose_name=_('Namespace')
|
||||
)
|
||||
@@ -46,6 +50,10 @@ class ErrorLogEntry(models.Model):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class SharedUploadedFile(models.Model):
|
||||
"""
|
||||
Keep a database link to a stored file. Used to share files between code
|
||||
that runs out of process.
|
||||
"""
|
||||
file = models.FileField(
|
||||
storage=storage_sharedupload, upload_to=upload_to,
|
||||
verbose_name=_('File')
|
||||
@@ -76,6 +84,10 @@ class SharedUploadedFile(models.Model):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class UserLocaleProfile(models.Model):
|
||||
"""
|
||||
Stores the locale preferences of an user. Stores timezone and language
|
||||
at the moment.
|
||||
"""
|
||||
user = models.OneToOneField(
|
||||
on_delete=models.CASCADE, related_name='locale_profile',
|
||||
to=settings.AUTH_USER_MODEL, verbose_name=_('User')
|
||||
|
||||
@@ -65,6 +65,9 @@ class Key(models.Model):
|
||||
return '{} - {}'.format(self.key_id, self.user_id)
|
||||
|
||||
def clean(self):
|
||||
"""
|
||||
Validate the key before saving.
|
||||
"""
|
||||
import_results = gpg_backend.import_key(key_data=self.key_data)
|
||||
|
||||
if not import_results.count:
|
||||
@@ -78,6 +81,9 @@ class Key(models.Model):
|
||||
|
||||
@property
|
||||
def key_id(self):
|
||||
"""
|
||||
Short form key ID (using the first 8 characters).
|
||||
"""
|
||||
return self.fingerprint[-8:]
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
@@ -101,13 +107,15 @@ class Key(models.Model):
|
||||
super(Key, self).save(*args, **kwargs)
|
||||
|
||||
def sign_file(self, file_object, passphrase=None, clearsign=False, detached=False, binary=False, output=None):
|
||||
# WARNING: using clearsign=True and subsequent decryption corrupts the
|
||||
# file. Appears to be a problem in python-gnupg or gpg itself.
|
||||
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=55647
|
||||
# "The problems differ from run to run and file to
|
||||
# file, and appear to be due to random data being inserted in the
|
||||
# output data stream."
|
||||
|
||||
"""
|
||||
Digitally sign a file
|
||||
WARNING: using clearsign=True and subsequent decryption corrupts the
|
||||
file. Appears to be a problem in python-gnupg or gpg itself.
|
||||
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=55647
|
||||
"The problems differ from run to run and file to
|
||||
file, and appear to be due to random data being inserted in the
|
||||
output data stream."
|
||||
"""
|
||||
file_sign_results = gpg_backend.sign_file(
|
||||
file_object=file_object, key_data=self.key_data,
|
||||
passphrase=passphrase, clearsign=clearsign, detached=detached,
|
||||
|
||||
@@ -18,6 +18,9 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Comment(models.Model):
|
||||
"""
|
||||
Model to store one comment per document per user per date & time.
|
||||
"""
|
||||
document = models.ForeignKey(
|
||||
db_index=True, on_delete=models.CASCADE, related_name='comments',
|
||||
to=Document, verbose_name=_('Document')
|
||||
|
||||
@@ -77,6 +77,14 @@ class Index(models.Model):
|
||||
)
|
||||
|
||||
def index_document(self, document):
|
||||
"""
|
||||
Method to start the indexing process for a document. The entire process
|
||||
happens inside one transaction. The document is first removed from all
|
||||
the index nodes to which it already belongs. The different index
|
||||
templates that match this document's type are evaluated and for each
|
||||
result a node is fetched or created and the document is added to that
|
||||
node.
|
||||
"""
|
||||
logger.debug('Index; Indexing document: %s', document)
|
||||
|
||||
with transaction.atomic():
|
||||
@@ -131,10 +139,18 @@ class Index(models.Model):
|
||||
|
||||
@property
|
||||
def template_root(self):
|
||||
"""
|
||||
Return the root node for this index.
|
||||
"""
|
||||
return self.node_templates.get(parent=None)
|
||||
|
||||
|
||||
class IndexInstance(Index):
|
||||
"""
|
||||
Model that represents an evaluated index. This is an index whose nodes
|
||||
have been evaluated against a series of documents. If is a proxy model
|
||||
at the moment.
|
||||
"""
|
||||
class Meta:
|
||||
proxy = True
|
||||
verbose_name = _('Index instance')
|
||||
@@ -286,6 +302,12 @@ class IndexTemplateNode(MPTTModel):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class IndexInstanceNode(MPTTModel):
|
||||
"""
|
||||
This model represent one instance node from a index template node. That is
|
||||
a node template that has been evaluated against a document and the result
|
||||
from that evaluation is this node's stored values. Instances of this
|
||||
model also point to the original node template.
|
||||
"""
|
||||
parent = TreeForeignKey(
|
||||
blank=True, null=True, on_delete=models.CASCADE, to='self',
|
||||
)
|
||||
@@ -311,6 +333,9 @@ class IndexInstanceNode(MPTTModel):
|
||||
return self.value
|
||||
|
||||
def delete_empty(self):
|
||||
"""
|
||||
Method to delete all empty node instances in a recursive manner.
|
||||
"""
|
||||
# Prevent another process to delete this node.
|
||||
try:
|
||||
lock = locking_backend.acquire_lock(
|
||||
@@ -374,6 +399,9 @@ class IndexInstanceNode(MPTTModel):
|
||||
return 'indexing:index_instance_node_{}'.format(self.pk)
|
||||
|
||||
def index(self):
|
||||
"""
|
||||
Return's the index instance of this node instance.
|
||||
"""
|
||||
return IndexInstance.objects.get(pk=self.index_template_node.index.pk)
|
||||
|
||||
def remove_document(self, document):
|
||||
@@ -399,6 +427,11 @@ class IndexInstanceNode(MPTTModel):
|
||||
|
||||
|
||||
class DocumentIndexInstanceNode(IndexInstanceNode):
|
||||
"""
|
||||
Proxy model of node instance. It is used to represent the node instance
|
||||
in which a document is currently located. It is used to aid in column
|
||||
registration. The inherited methods of this model should not be used.
|
||||
"""
|
||||
objects = DocumentIndexInstanceNodeManager()
|
||||
|
||||
class Meta:
|
||||
|
||||
@@ -11,6 +11,9 @@ from .managers import DocumentPageContentManager, DocumentTypeSettingsManager
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DocumentPageContent(models.Model):
|
||||
"""
|
||||
This model store's the parsed content of a document page.
|
||||
"""
|
||||
document_page = models.OneToOneField(
|
||||
on_delete=models.CASCADE, related_name='content', to=DocumentPage,
|
||||
verbose_name=_('Document page')
|
||||
@@ -33,6 +36,9 @@ class DocumentPageContent(models.Model):
|
||||
|
||||
|
||||
class DocumentTypeSettings(models.Model):
|
||||
"""
|
||||
This model stores the parsing settings for a document type.
|
||||
"""
|
||||
document_type = models.OneToOneField(
|
||||
on_delete=models.CASCADE, related_name='parsing_settings',
|
||||
to=DocumentType, unique=True, verbose_name=_('Document type')
|
||||
@@ -56,6 +62,10 @@ class DocumentTypeSettings(models.Model):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DocumentVersionParseError(models.Model):
|
||||
"""
|
||||
This module stores the errors captures when attempting to parse a
|
||||
document version.
|
||||
"""
|
||||
document_version = models.ForeignKey(
|
||||
on_delete=models.CASCADE, related_name='parsing_errors',
|
||||
to=DocumentVersion, verbose_name=_('Document version')
|
||||
|
||||
@@ -17,6 +17,9 @@ from .managers import (
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class StoredEventType(models.Model):
|
||||
"""
|
||||
Model to mirror the real event classes as database objects.
|
||||
"""
|
||||
name = models.CharField(
|
||||
max_length=64, unique=True, verbose_name=_('Name')
|
||||
)
|
||||
@@ -42,6 +45,10 @@ class StoredEventType(models.Model):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class EventSubscription(models.Model):
|
||||
"""
|
||||
This model stores the event subscriptions of an user for the entire
|
||||
system.
|
||||
"""
|
||||
user = models.ForeignKey(
|
||||
db_index=True, on_delete=models.CASCADE,
|
||||
related_name='event_subscriptions', to=settings.AUTH_USER_MODEL,
|
||||
@@ -64,6 +71,11 @@ class EventSubscription(models.Model):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Notification(models.Model):
|
||||
"""
|
||||
This model keeps track of the notifications for an user. Notifications are
|
||||
created when an event to which this user has been subscribed, are
|
||||
commited elsewhere in the system.
|
||||
"""
|
||||
user = models.ForeignKey(
|
||||
db_index=True, on_delete=models.CASCADE,
|
||||
related_name='notifications', to=settings.AUTH_USER_MODEL,
|
||||
|
||||
@@ -16,6 +16,11 @@ from .managers import SmartLinkManager
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class SmartLink(models.Model):
|
||||
"""
|
||||
This model stores the basic fields for a smart link. Smart links allow
|
||||
linking documents using a programmatic method of conditions that mirror
|
||||
Django's database filter operations.
|
||||
"""
|
||||
label = models.CharField(
|
||||
db_index=True, max_length=96, verbose_name=_('Label')
|
||||
)
|
||||
@@ -43,6 +48,10 @@ class SmartLink(models.Model):
|
||||
return self.label
|
||||
|
||||
def get_dynamic_label(self, document):
|
||||
"""
|
||||
If the smart links was created using a template label instead of a
|
||||
static label, resolve the template and return the result.
|
||||
"""
|
||||
if self.dynamic_label:
|
||||
context = Context({'document': document})
|
||||
try:
|
||||
@@ -58,6 +67,10 @@ class SmartLink(models.Model):
|
||||
return None
|
||||
|
||||
def get_linked_document_for(self, document):
|
||||
"""
|
||||
Execute the corresponding smart links conditions for the document
|
||||
provided and return the resulting document queryset.
|
||||
"""
|
||||
if document.document_type.pk not in self.document_types.values_list('pk', flat=True):
|
||||
raise Exception(
|
||||
_(
|
||||
@@ -100,6 +113,10 @@ class SmartLink(models.Model):
|
||||
|
||||
|
||||
class ResolvedSmartLink(SmartLink):
|
||||
"""
|
||||
Proxy model to represent an already resolved smart link. Used for easier
|
||||
colums registration.
|
||||
"""
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
@@ -109,6 +126,10 @@ class ResolvedSmartLink(SmartLink):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class SmartLinkCondition(models.Model):
|
||||
"""
|
||||
This model stores a single smart link condition. A smart link is a
|
||||
collection of one of more smart link conditions.
|
||||
"""
|
||||
smart_link = models.ForeignKey(
|
||||
on_delete=models.CASCADE, related_name='conditions', to=SmartLink,
|
||||
verbose_name=_('Smart link')
|
||||
|
||||
@@ -14,6 +14,11 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class LockManager(models.Manager):
|
||||
def acquire_lock(self, name, timeout=None):
|
||||
"""
|
||||
Attempts to acquire a lock. Return a LockError is the lock is already
|
||||
held by someone else or if is not possible to acquire the lock due to
|
||||
database or operational errors.
|
||||
"""
|
||||
logger.debug('trying to acquire lock: %s', name)
|
||||
lock = self.model(name=name, timeout=timeout)
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ from .settings import setting_default_lock_timeout
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Lock(models.Model):
|
||||
"""
|
||||
Model to provide distributed resource locking using the database.
|
||||
"""
|
||||
creation_datetime = models.DateTimeField(
|
||||
auto_now_add=True, verbose_name=_('Creation datetime')
|
||||
)
|
||||
@@ -30,6 +33,9 @@ class Lock(models.Model):
|
||||
return self.name
|
||||
|
||||
def release(self):
|
||||
"""
|
||||
Release a previously held lock.
|
||||
"""
|
||||
try:
|
||||
lock = Lock.objects.get(
|
||||
name=self.name, creation_datetime=self.creation_datetime
|
||||
|
||||
@@ -33,6 +33,12 @@ class LogEntry(models.Model):
|
||||
|
||||
|
||||
class UserMailer(models.Model):
|
||||
"""
|
||||
This model is used to create mailing profiles that can be used from inside
|
||||
the system. These profiles differ from the system mailing profile in that
|
||||
they can be created at runtime and can be assigned ACLs to restrict
|
||||
their use.
|
||||
"""
|
||||
label = models.CharField(
|
||||
max_length=128, unique=True, verbose_name=_('Label')
|
||||
)
|
||||
@@ -122,6 +128,9 @@ class UserMailer(models.Model):
|
||||
self.error_log.all().delete()
|
||||
|
||||
def send_document(self, document, to, subject='', body='', as_attachment=False):
|
||||
"""
|
||||
Send a document using this user mailing profile.
|
||||
"""
|
||||
context_dictionary = {
|
||||
'link': 'http://%s%s' % (
|
||||
Site.objects.get_current().domain,
|
||||
@@ -153,6 +162,10 @@ class UserMailer(models.Model):
|
||||
)
|
||||
|
||||
def test(self, to):
|
||||
"""
|
||||
Send a test message to make sure the mailing profile settings are
|
||||
correct.
|
||||
"""
|
||||
self.send(subject=_('Test email from Mayan EDMS'), to=to)
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,9 @@ def parser_choices():
|
||||
@python_2_unicode_compatible
|
||||
class MetadataType(models.Model):
|
||||
"""
|
||||
Define a type of metadata
|
||||
Model to store a type of metadata. Metadata are user defined properties
|
||||
that can be assigned a value for each document. Metadata types need
|
||||
to be assigned to a document type before they can be used.
|
||||
"""
|
||||
name = models.CharField(
|
||||
max_length=48,
|
||||
@@ -127,6 +129,10 @@ class MetadataType(models.Model):
|
||||
return MetadataType.comma_splitter(template.render(context=context))
|
||||
|
||||
def get_required_for(self, document_type):
|
||||
"""
|
||||
Return a queryset of metadata types that are required for the
|
||||
specified document type.
|
||||
"""
|
||||
return document_type.metadata.filter(
|
||||
required=True, metadata_type=self
|
||||
).exists()
|
||||
@@ -183,8 +189,8 @@ class MetadataType(models.Model):
|
||||
@python_2_unicode_compatible
|
||||
class DocumentMetadata(models.Model):
|
||||
"""
|
||||
Link a document to a specific instance of a metadata type with it's
|
||||
current value
|
||||
Model used to link an instance of a metadata type with a value to a
|
||||
document.
|
||||
"""
|
||||
document = models.ForeignKey(
|
||||
on_delete=models.CASCADE, related_name='metadata', to=Document,
|
||||
@@ -218,9 +224,10 @@ class DocumentMetadata(models.Model):
|
||||
|
||||
def delete(self, enforce_required=True, *args, **kwargs):
|
||||
"""
|
||||
enforce_required prevents deletion of required metadata at the
|
||||
model level. It used set to False when deleting document metadata
|
||||
on document type change.
|
||||
Delete a metadata from a document. enforce_required which defaults
|
||||
to True, prevents deletion of required metadata at the model level.
|
||||
It used set to False when deleting document metadata on document
|
||||
type change.
|
||||
"""
|
||||
if enforce_required and self.metadata_type.pk in self.document.document_type.metadata.filter(required=True).values_list('metadata_type', flat=True):
|
||||
raise ValidationError(
|
||||
@@ -241,6 +248,10 @@ class DocumentMetadata(models.Model):
|
||||
|
||||
@property
|
||||
def is_required(self):
|
||||
"""
|
||||
Return a boolean value of True of this metadata instance's parent type
|
||||
is required for the stored document type.
|
||||
"""
|
||||
return self.metadata_type.get_required_for(
|
||||
document_type=self.document.document_type
|
||||
)
|
||||
@@ -272,6 +283,10 @@ class DocumentMetadata(models.Model):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DocumentTypeMetadataType(models.Model):
|
||||
"""
|
||||
Model used to store the relationship between a metadata type and a
|
||||
document type.
|
||||
"""
|
||||
document_type = models.ForeignKey(
|
||||
on_delete=models.CASCADE, related_name='metadata', to=DocumentType,
|
||||
verbose_name=_('Document type')
|
||||
|
||||
@@ -9,6 +9,10 @@ from .managers import MessageManager
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Message(models.Model):
|
||||
"""
|
||||
Model to store an information message that will be displayed at the login
|
||||
screen. Messages can have an activation and deactivation date.
|
||||
"""
|
||||
label = models.CharField(
|
||||
max_length=32, help_text=_('Short description of this message.'),
|
||||
verbose_name=_('Label')
|
||||
|
||||
@@ -13,7 +13,7 @@ from .managers import (
|
||||
|
||||
class DocumentTypeSettings(models.Model):
|
||||
"""
|
||||
Define for OCR for a specific document should behave
|
||||
Model to store the OCR settings for a document type.
|
||||
"""
|
||||
document_type = models.OneToOneField(
|
||||
on_delete=models.CASCADE, related_name='ocr_settings',
|
||||
@@ -37,6 +37,9 @@ class DocumentTypeSettings(models.Model):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DocumentPageOCRContent(models.Model):
|
||||
"""
|
||||
This model stores the OCR results for a document page.
|
||||
"""
|
||||
document_page = models.OneToOneField(
|
||||
on_delete=models.CASCADE, related_name='ocr_content',
|
||||
to=DocumentPage, verbose_name=_('Document page')
|
||||
@@ -59,6 +62,10 @@ class DocumentPageOCRContent(models.Model):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DocumentVersionOCRError(models.Model):
|
||||
"""
|
||||
This models keeps track of the errors captured during the OCR of a
|
||||
document version.
|
||||
"""
|
||||
document_version = models.ForeignKey(
|
||||
on_delete=models.CASCADE, related_name='ocr_errors',
|
||||
to=DocumentVersion, verbose_name=_('Document version')
|
||||
|
||||
@@ -16,6 +16,11 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class StoredPermission(models.Model):
|
||||
"""
|
||||
This model is the counterpart of the permissions.classes.Permission
|
||||
class. Allows storing a database counterpart of a permission class.
|
||||
It is used to store the permissions help by a role or in an ACL.
|
||||
"""
|
||||
namespace = models.CharField(max_length=64, verbose_name=_('Namespace'))
|
||||
name = models.CharField(max_length=64, verbose_name=_('Name'))
|
||||
|
||||
@@ -34,9 +39,17 @@ class StoredPermission(models.Model):
|
||||
return self.name
|
||||
|
||||
def get_volatile_permission_id(self):
|
||||
"""
|
||||
Return the identifier of the real permission class represented by
|
||||
this model instance.
|
||||
"""
|
||||
return '{}.{}'.format(self.namespace, self.name)
|
||||
|
||||
def get_volatile_permission(self):
|
||||
"""
|
||||
Returns the real class of the permission represented by this model
|
||||
instance.
|
||||
"""
|
||||
return Permission.get(
|
||||
pk=self.get_volatile_permission_id(), proxy_only=True
|
||||
)
|
||||
@@ -45,6 +58,12 @@ class StoredPermission(models.Model):
|
||||
return (self.namespace, self.name)
|
||||
|
||||
def requester_has_this(self, user):
|
||||
"""
|
||||
Helper method to check if an user has been granted this permission.
|
||||
The check is done sequentially over all of the user's groups and
|
||||
roles. The check is interrupted at the first positive result.
|
||||
The check always returns True for superusers or staff users.
|
||||
"""
|
||||
if user.is_superuser or user.is_staff:
|
||||
logger.debug(
|
||||
'Permission "%s" granted to user "%s" as superuser or staff',
|
||||
@@ -70,6 +89,13 @@ class StoredPermission(models.Model):
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Role(models.Model):
|
||||
"""
|
||||
This model represents a Role. Roles are permission units. They are the
|
||||
only object to which permissions can be granted. They are themselves
|
||||
containers too, containing Groups, which are organization units. Roles
|
||||
are the basic method to grant a permission to a group. Permissions granted
|
||||
to a group using a role, are granted for the entire system.
|
||||
"""
|
||||
label = models.CharField(
|
||||
max_length=64, unique=True, verbose_name=_('Label')
|
||||
)
|
||||
|
||||
@@ -19,6 +19,10 @@ from .widgets import widget_single_tag
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Tag(models.Model):
|
||||
"""
|
||||
This model represents a binary property that can be applied to a document.
|
||||
The tag can have a label and a color.
|
||||
"""
|
||||
label = models.CharField(
|
||||
db_index=True, help_text=_(
|
||||
'A short text used as the tag name.'
|
||||
@@ -41,6 +45,9 @@ class Tag(models.Model):
|
||||
return self.label
|
||||
|
||||
def attach_to(self, document, user=None):
|
||||
"""
|
||||
Attach a tag to a document and commit the corresponding event.
|
||||
"""
|
||||
self.documents.add(document)
|
||||
event_tag_attach.commit(
|
||||
action_object=self, actor=user, target=document
|
||||
@@ -50,6 +57,10 @@ class Tag(models.Model):
|
||||
return reverse('tags:tag_tagged_item_list', args=(str(self.pk),))
|
||||
|
||||
def get_document_count(self, user):
|
||||
"""
|
||||
Return the numeric count of documents that have this tag attached.
|
||||
The count if filtered by access.
|
||||
"""
|
||||
queryset = AccessControlList.objects.filter_by_access(
|
||||
permission_document_view, user, queryset=self.documents
|
||||
)
|
||||
@@ -61,6 +72,9 @@ class Tag(models.Model):
|
||||
get_preview_widget.short_description = _('Preview')
|
||||
|
||||
def remove_from(self, document, user=None):
|
||||
"""
|
||||
Remove a tag from a document and commit the corresponding event.
|
||||
"""
|
||||
self.documents.remove(document)
|
||||
event_tag_remove.commit(
|
||||
action_object=self, actor=user, target=document
|
||||
|
||||
@@ -8,6 +8,11 @@ from .managers import UserOptionsManager
|
||||
|
||||
|
||||
class UserOptions(models.Model):
|
||||
"""
|
||||
This model stores administrative configurations for an user accounts.
|
||||
At the moment it stores a boolean flag to restrict an user's
|
||||
ability to change their password.
|
||||
"""
|
||||
user = models.OneToOneField(
|
||||
on_delete=models.CASCADE, related_name='user_options',
|
||||
to=settings.AUTH_USER_MODEL, unique=True, verbose_name=_('User')
|
||||
|
||||
Reference in New Issue
Block a user