artifacts: refactor metadata code
- fix type conversions - split some code so we can re-use it - add specific validations of duplicates and wrong types
This commit is contained in:
parent
1d91e6557d
commit
fcdef0dd05
2 changed files with 64 additions and 13 deletions
|
|
@ -157,3 +157,15 @@ class VCSServerUnavailable(HTTPBadGateway):
|
|||
if message:
|
||||
self.explanation += ': ' + message
|
||||
super(VCSServerUnavailable, self).__init__()
|
||||
|
||||
|
||||
class ArtifactMetadataDuplicate(ValueError):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.err_section = kwargs.pop('err_section', None)
|
||||
self.err_key = kwargs.pop('err_key', None)
|
||||
super(ArtifactMetadataDuplicate, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class ArtifactMetadataBadValueType(ValueError):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ from rhodecode.lib.ext_json import json
|
|||
from rhodecode.lib.caching_query import FromCache
|
||||
from rhodecode.lib.encrypt import AESCipher, validate_and_get_enc_data
|
||||
from rhodecode.lib.encrypt2 import Encryptor
|
||||
from rhodecode.lib.exceptions import (
|
||||
ArtifactMetadataDuplicate, ArtifactMetadataBadValueType)
|
||||
from rhodecode.model.meta import Base, Session
|
||||
|
||||
URL_SEP = '/'
|
||||
|
|
@ -5145,6 +5147,10 @@ class FileStore(Base, BaseModel):
|
|||
nullable=True, unique=None, default=None)
|
||||
repo_group = relationship('RepoGroup', lazy='joined')
|
||||
|
||||
@classmethod
|
||||
def get_by_store_uid(cls, file_store_uid):
|
||||
return FileStore.query().filter(FileStore.file_uid == file_store_uid).scalar()
|
||||
|
||||
@classmethod
|
||||
def create(cls, file_uid, filename, file_hash, file_size, file_display_name='',
|
||||
file_description='', enabled=True, hidden=False, check_acl=True,
|
||||
|
|
@ -5176,6 +5182,19 @@ class FileStore(Base, BaseModel):
|
|||
return
|
||||
|
||||
for section, key, value, value_type in args:
|
||||
has_key = FileStoreMetadata().query() \
|
||||
.filter(FileStoreMetadata.file_store_id == file_store.file_store_id) \
|
||||
.filter(FileStoreMetadata.file_store_meta_section == section) \
|
||||
.filter(FileStoreMetadata.file_store_meta_key == key) \
|
||||
.scalar()
|
||||
if has_key:
|
||||
msg = 'key `{}` already defined under section `{}` for this file.'\
|
||||
.format(key, section)
|
||||
raise ArtifactMetadataDuplicate(msg, err_section=section, err_key=key)
|
||||
|
||||
# NOTE(marcink): raises ArtifactMetadataBadValueType
|
||||
FileStoreMetadata.valid_value_type(value_type)
|
||||
|
||||
meta_entry = FileStoreMetadata()
|
||||
meta_entry.file_store = file_store
|
||||
meta_entry.file_store_meta_section = section
|
||||
|
|
@ -5185,8 +5204,12 @@ class FileStore(Base, BaseModel):
|
|||
|
||||
Session().add(meta_entry)
|
||||
|
||||
if commit:
|
||||
Session().commit()
|
||||
try:
|
||||
if commit:
|
||||
Session().commit()
|
||||
except IntegrityError:
|
||||
Session().rollback()
|
||||
raise ArtifactMetadataDuplicate('Duplicate section/key found for this file.')
|
||||
|
||||
@classmethod
|
||||
def bump_access_counter(cls, file_uid, commit=True):
|
||||
|
|
@ -5239,20 +5262,28 @@ class FileStoreMetadata(Base, BaseModel):
|
|||
|
||||
file_store = relationship('FileStore', lazy='joined')
|
||||
|
||||
@classmethod
|
||||
def valid_value_type(cls, value):
|
||||
if value.split('.')[0] not in cls.SETTINGS_TYPES:
|
||||
raise ArtifactMetadataBadValueType(
|
||||
'value_type must be one of %s got %s' % (cls.SETTINGS_TYPES.keys(), value))
|
||||
|
||||
@hybrid_property
|
||||
def file_store_meta_value(self):
|
||||
v = self._file_store_meta_value
|
||||
_type = self._file_store_meta_value
|
||||
if _type:
|
||||
val = self._file_store_meta_value
|
||||
|
||||
if self._file_store_meta_value_type:
|
||||
# e.g unicode.encrypted == unicode
|
||||
_type = self._file_store_meta_value.split('.')[0]
|
||||
# decode the encrypted value
|
||||
_type = self._file_store_meta_value_type.split('.')[0]
|
||||
# decode the encrypted value if it's encrypted field type
|
||||
if '.encrypted' in self._file_store_meta_value_type:
|
||||
cipher = EncryptedTextValue()
|
||||
v = safe_unicode(cipher.process_result_value(v, None))
|
||||
val = safe_unicode(cipher.process_result_value(val, None))
|
||||
# do final type conversion
|
||||
converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode']
|
||||
val = converter(val)
|
||||
|
||||
converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode']
|
||||
return converter(v)
|
||||
return val
|
||||
|
||||
@file_store_meta_value.setter
|
||||
def file_store_meta_value(self, val):
|
||||
|
|
@ -5270,11 +5301,19 @@ class FileStoreMetadata(Base, BaseModel):
|
|||
@file_store_meta_value_type.setter
|
||||
def file_store_meta_value_type(self, val):
|
||||
# e.g unicode.encrypted
|
||||
if val.split('.')[0] not in self.SETTINGS_TYPES:
|
||||
raise Exception('type must be one of %s got %s'
|
||||
% (self.SETTINGS_TYPES.keys(), val))
|
||||
self.valid_value_type(val)
|
||||
self._file_store_meta_value_type = val
|
||||
|
||||
def __json__(self):
|
||||
data = {
|
||||
'artifact': self.file_store.file_uid,
|
||||
'section': self.file_store_meta_section,
|
||||
'key': self.file_store_meta_key,
|
||||
'value': self.file_store_meta_value,
|
||||
}
|
||||
|
||||
return data
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s[%s]%s=>%s]>' % (self.__class__.__name__, self.file_store_meta_section,
|
||||
self.file_store_meta_key, self.file_store_meta_value)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue