summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRené 'Necoro' Neumann <necoro@necoro.net>2017-02-27 01:18:09 +0100
committerRené 'Necoro' Neumann <necoro@necoro.net>2017-02-27 01:18:09 +0100
commit6bd9dcdb814b2f03f053ff5f5bf9a20ffe092582 (patch)
tree5813bc7f73c637757662cece27d388547c1bea1d
parentef3cda14736df8b8a9f7ff4f022b9a8250713bd9 (diff)
downloadarchivist-6bd9dcdb814b2f03f053ff5f5bf9a20ffe092582.tar.gz
archivist-6bd9dcdb814b2f03f053ff5f5bf9a20ffe092582.tar.bz2
archivist-6bd9dcdb814b2f03f053ff5f5bf9a20ffe092582.zip
Inserting Documents
-rw-r--r--archivist/cli.py77
-rw-r--r--archivist/model.py19
-rw-r--r--archivist/peewee_ext.py10
-rw-r--r--archivist/prefixes.py1
4 files changed, 91 insertions, 16 deletions
diff --git a/archivist/cli.py b/archivist/cli.py
index 0b8abe1..8238a30 100644
--- a/archivist/cli.py
+++ b/archivist/cli.py
@@ -61,6 +61,12 @@ def list_prefixes():
for p in Prefix.select():
print(" * %s (builtin: %s; pseudo: %s)" % (p.name, p.builtin, p.pseudo))
+def prefix_tag_name(name, prefix=None):
+ if prefix:
+ return "%s:%s" % (prefix, name)
+ else:
+ return name
+
class PrefixTag:
def __init__(self, tag, prefix = None):
self.tag = tag
@@ -72,6 +78,16 @@ class PrefixTag:
else:
return self.tag
+ def __iter__(self):
+ yield self.prefix
+ yield self.tag
+
+ def prefixed_name(self):
+ return prefix_tag_name(self.tag, self.prefix)
+
+ def __str__(self):
+ return self.prefixed_name()
+
class PrefixTagType(click.ParamType):
name = 'prefixed tag'
@@ -87,12 +103,8 @@ class PrefixTagType(click.ParamType):
TAG = PrefixTagType()
-@tag.command('add')
-@click.argument('name', type = TAG)
-@click.argument('description', required = False)
-def add_tag(name, description):
+def create_tag(name, description=None):
from .model import Tag, Prefix, db
-
with db.atomic():
if name.prefix:
prefix, created = Prefix.get_or_create(name = name.prefix)
@@ -100,14 +112,20 @@ def add_tag(name, description):
if not created and prefix.pseudo:
raise click.UsageError("Prefix '%s' is not allowed to carry additional tags." % name.prefix)
- tag, created = Tag.create_or_get(name = name.tag, prefix = name.prefix, description = description)
- if not created:
- print("Tag already existed:", tag)
+ return Tag.create_or_get(name = name.tag, prefix = name.prefix, description = description)
+
+@tag.command('add')
+@click.argument('name', type = TAG)
+@click.argument('description', required = False)
+def add_tag(name, description):
+ created, tag = create_tag(name, description)
+ if not created:
+ print("Tag already existed:", tag)
@tag.command('edit')
-@click.option('--description')
@click.argument('name', type = TAG)
-def edit_tag(description, name):
+@click.option('--description')
+def edit_tag(name, description):
from .model import Tag, Prefix, db
try:
@@ -118,3 +136,42 @@ def edit_tag(description, name):
if description:
tag.description = description
tag.save()
+
+@cli.group()
+def doc():
+ """Document handling"""
+ pass
+
+@doc.command('add')
+@click.argument('file', type=click.File(mode = 'rb'))
+@click.argument('tags', type = TAG, nargs = -1)
+@click.option('--create-tags', '-c', is_flag = True)
+@click.option('--ignore-missing-tags', '-i', is_flag = True)
+def add_doc(file, tags, create_tags, ignore_missing_tags):
+ """Add a new document together with the given tags."""
+
+ from .model import Document, Tag, db, DocumentTag
+ from .peewee_ext import sqlite_tuple_in
+ import magic
+
+ with db.atomic():
+ if tags:
+ if create_tags:
+ tags = [create_tag(tag)[0] for tag in tags]
+ else:
+ fetched_tags = Tag.select().where(sqlite_tuple_in((Tag.prefix, Tag.name), tags)).execute()
+ if len(fetched_tags) < len(tags):
+ print("Some tags were not present:", ', '.join(set(map(str, tags)).difference(map(str, fetched_tags))))
+ if not ignore_missing_tags:
+ raise click.ClickException("Not all tags present")
+ tags = fetched_tags
+
+ mimetype = magic.from_file(file.name, mime=True)
+
+ doc = Document.create(content = file.read(),
+ file_type = mimetype,
+ original_path = file.name,
+ direction = Document.Direction.IN)
+
+ for t in tags:
+ DocumentTag.create(document = doc, tag = t)
diff --git a/archivist/model.py b/archivist/model.py
index fd1bec3..bee6200 100644
--- a/archivist/model.py
+++ b/archivist/model.py
@@ -1,5 +1,5 @@
from peewee import *
-from playhouse.fields import CompressedField
+from playhouse.fields import CompressedField as _CompressedField
from playhouse.hybrid import *
from playhouse.sqlite_ext import SqliteExtDatabase
@@ -31,6 +31,13 @@ class BaseModel(Model):
class Meta:
database = db
+class CompressedField(_CompressedField):
+ def db_value(self, value):
+ return value if value is None else self.compress(value)
+
+ def python_value(self, value):
+ return value if value is None else self.decompress(value)
+
@table
class Document(BaseModel):
@unique
@@ -39,10 +46,11 @@ class Document(BaseModel):
OUT = 1
content = CompressedField()
- created = DateField(default=datetime.datetime.now)
+ created = DateField(default=datetime.date.today)
inserted = DateTimeField(default=datetime.datetime.now)
description = CharField(null=True)
original_path = CharField(null=True)
+ file_type = CharField(null=True)
direction = EnumField(Direction, null=True)
@classmethod
@@ -87,6 +95,7 @@ class Tag(BaseModel):
(('name', 'prefix'), True)
]
+ @property
def prefixed_name(self):
if self.prefix_id:
return "%s:%s" % (self.prefix_id, self.name)
@@ -94,12 +103,10 @@ class Tag(BaseModel):
return self.name
def __str__(self):
- description = ' -- ' + self.description if self.description else ''
-
- return self.prefixed_name() + description
+ return self.prefixed_name
def __repr__(self):
- return "<%s (#%d) %s>" % (self.__class__.__name__, self.id, self.prefixed_name())
+ return "<%s (#%d) %s>" % (self.__class__.__name__, self.id, self.prefixed_name)
@table
class DocumentTag(BaseModel):
diff --git a/archivist/peewee_ext.py b/archivist/peewee_ext.py
index 9fda66e..80bb6f4 100644
--- a/archivist/peewee_ext.py
+++ b/archivist/peewee_ext.py
@@ -1,6 +1,16 @@
from playhouse.sqlite_ext import VirtualModel, VirtualIntegerField, VirtualCharField
from peewee import Field
+from itertools import starmap
+from functools import reduce
+import operator as op
+
+def sqlite_tuple_in(fields, values):
+ """SQLite does not support (foo, bar) IN ((1,2),(3,4)).
+ So we construct a '(foo = 1 AND bar = 2) OR (foo = 3 AND bar = 4)' monstrum."""
+ subqueries = (reduce(op.and_, starmap(op.eq, zip(fields, value_tuple))) for value_tuple in values)
+ return reduce(op.or_, subqueries)
+
class EnumField(Field):
db_field = 'enum'
diff --git a/archivist/prefixes.py b/archivist/prefixes.py
index 4e73ca7..a039485 100644
--- a/archivist/prefixes.py
+++ b/archivist/prefixes.py
@@ -20,6 +20,7 @@ def _create_prefixes():
FieldPseudoPrefix('direction', 'In- or outgoing', Document.direction)
FieldPseudoPrefix('date', 'Date of creation', Document.created)
+ FieldPseudoPrefix('mime', 'Mime Type', Document.file_type)
for part in ('day', 'month', 'year'):
FieldPartPseudoPrefix(part, part.capitalize() + ' of creation', Document.created, part)