diff --git a/schemas/qwc-data-service.json b/schemas/qwc-data-service.json index 0e0ffae..2b09e60 100644 --- a/schemas/qwc-data-service.json +++ b/schemas/qwc-data-service.json @@ -24,6 +24,14 @@ "description": "Base dir where attachments are stored", "type": "string" }, + "attachments_namespace_dir": { + "description": "The namespace dir, below attachments_base_dir. You can use {tenant}, {map}, {dataset}. Default is '{tenant}/{map}.{dataset}'", + "type": "string" + }, + "attachment_store_pattern": { + "description": "The path pattern to use when saving attachments to disk. You can use {random}, {filename}, {ext} and {}, where field refers to the value of the field of the committed feature. Default is '{random}/{filename}'", + "type": "string" + }, "allowed_attachment_extensions": { "description": "Comma separated list of allowed attachment file extensions, i.e. '.png,.jpg'", "type": "string" @@ -75,10 +83,6 @@ "max_attachment_file_size_per_dataset": { "description": "Lookup of maximum attachment file size in bytes per dataset", "type": "object" - }, - "attachment_store_pattern": { - "description": "The path pattern to use when saving attachments to disk. You can use {random}, {filename}, {ext} and {}, where field refers to the respective field value of the committed feature. Default is '{random}/{filename}'", - "type": "string" } } }, diff --git a/src/attachments_service.py b/src/attachments_service.py index 7315784..17aade8 100644 --- a/src/attachments_service.py +++ b/src/attachments_service.py @@ -39,6 +39,7 @@ def __init__(self, tenant, logger): self.allowed_extensions_per_dataset = config.get( 'allowed_extensions_per_dataset', {} ) + self.attachments_namespace_dir = config.get('attachments_namespace_dir', "{tenant}/{map}.{dataset}") self.attachment_store_pattern = config.get('attachment_store_pattern', "{random}/{filename}") for dataset in self.allowed_extensions_per_dataset: self.allowed_extensions_per_dataset[dataset] = self.allowed_extensions_per_dataset[dataset].split(",") @@ -134,7 +135,11 @@ def save_attachment(self, dataset, file, fields): ext=os.path.splitext(file.filename)[1], **fields ) - target_path = os.path.join(self.attachments_base_dir, self.tenant, dataset, slug) + target_path = os.path.join( + self.attachments_base_dir, + self.namespace_dir(dataset), + slug + ) # create target dir target_dir = os.path.dirname(target_path) @@ -156,7 +161,9 @@ def remove_attachment(self, dataset, slug): :param slug: File slug (identifier) """ target_dir = os.path.join( - self.attachments_base_dir, self.tenant, dataset) + self.attachments_base_dir, + self.namespace_dir(dataset) + ) try: os.remove(os.path.join(target_dir, slug)) self.logger.info("Removed attachment: %s" % slug) @@ -175,7 +182,10 @@ def resolve_attachment(self, dataset, slug): """Resolve attachment slug to full path""" path = os.path.realpath( os.path.join( - self.attachments_base_dir, self.tenant, dataset, slug)) + self.attachments_base_dir, + self.namespace_dir(dataset), + slug) + ) if os.path.isfile(path) and path.startswith( self.attachments_base_dir): return path @@ -188,3 +198,11 @@ def generate_slug(self, length): """ chars = string.ascii_letters + string.digits return ''.join(random.choice(chars) for c in range(length)) + + def namespace_dir(self, dataset): + mapname, datasetname = dataset.split(".", 1) + return self.attachments_namespace_dir.format( + tenant=self.tenant, + map=mapname, + dataset=datasetname + )