artifacts: added metadata table to store various extra data for artifact

This commit is contained in:
Marcin Kuzminski 2019-10-15 14:05:20 +02:00
parent 13d27c391a
commit 9c4dbfeb4b
5 changed files with 5433 additions and 10 deletions

View file

@ -45,7 +45,7 @@ PYRAMID_SETTINGS = {}
EXTENSIONS = {}
__version__ = ('.'.join((str(each) for each in VERSION[:3])))
__dbversion__ = 100 # defines current db version for migrations
__dbversion__ = 101 # defines current db version for migrations
__platform__ = platform.system()
__license__ = 'AGPLv3, and Commercial License'
__author__ = 'RhodeCode GmbH'

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
import logging
from sqlalchemy import *
from rhodecode.model import meta
from rhodecode.lib.dbmigrate.versions import _reset_base, notify
log = logging.getLogger(__name__)
def upgrade(migrate_engine):
"""
Upgrade operations go here.
Don't create your own engine; bind migrate_engine to your metadata
"""
_reset_base(migrate_engine)
from rhodecode.lib.dbmigrate.schema import db_4_18_0_1 as db
db.FileStoreMetadata.__table__.create()
fixups(db, meta.Session)
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
def fixups(models, _SESSION):
pass

View file

@ -4996,8 +4996,7 @@ class _BaseBranchPerms(BaseModel):
class UserToRepoBranchPermission(Base, _BaseBranchPerms):
__tablename__ = 'user_to_repo_branch_permissions'
__table_args__ = (
{'extend_existing': True, 'mysql_engine': 'InnoDB',
'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
base_table_args
)
branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
@ -5023,8 +5022,7 @@ class UserToRepoBranchPermission(Base, _BaseBranchPerms):
class UserGroupToRepoBranchPermission(Base, _BaseBranchPerms):
__tablename__ = 'user_group_to_repo_branch_permissions'
__table_args__ = (
{'extend_existing': True, 'mysql_engine': 'InnoDB',
'mysql_charset': 'utf8', 'sqlite_autoincrement': True,}
base_table_args
)
branch_rule_id = Column('branch_rule_id', Integer(), primary_key=True)
@ -5121,6 +5119,8 @@ class FileStore(Base, BaseModel):
user_id = Column('user_id', Integer(), ForeignKey('users.user_id'), nullable=False)
upload_user = relationship('User', lazy='joined', primaryjoin='User.user_id==FileStore.user_id')
file_metadata = relationship('FileStoreMetadata', lazy='joined')
# scope limited to user, which requester have access to
scope_user_id = Column(
'scope_user_id', Integer(), ForeignKey('users.user_id'),
@ -5169,6 +5169,25 @@ class FileStore(Base, BaseModel):
return store_entry
@classmethod
def store_metadata(cls, file_store_id, args, commit=True):
file_store = FileStore.get(file_store_id)
if file_store is None:
return
for section, key, value, value_type in args:
meta_entry = FileStoreMetadata()
meta_entry.file_store = file_store
meta_entry.file_store_meta_section = section
meta_entry.file_store_meta_key = key
meta_entry.file_store_meta_value_type = value_type
meta_entry.file_store_meta_value = value
Session().add(meta_entry)
if commit:
Session().commit()
@classmethod
def bump_access_counter(cls, file_uid, commit=True):
FileStore().query()\
@ -5182,6 +5201,85 @@ class FileStore(Base, BaseModel):
return '<FileStore({})>'.format(self.file_store_id)
class FileStoreMetadata(Base, BaseModel):
__tablename__ = 'file_store_metadata'
__table_args__ = (
UniqueConstraint('file_store_meta_section', 'file_store_meta_key'),
Index('file_store_meta_section_idx', 'file_store_meta_section'),
Index('file_store_meta_key_idx', 'file_store_meta_key'),
base_table_args
)
SETTINGS_TYPES = {
'str': safe_str,
'int': safe_int,
'unicode': safe_unicode,
'bool': str2bool,
'list': functools.partial(aslist, sep=',')
}
file_store_meta_id = Column(
"file_store_meta_id", Integer(), nullable=False, unique=True, default=None,
primary_key=True)
file_store_meta_section = Column(
"file_store_meta_section", UnicodeText().with_variant(UnicodeText(1024), 'mysql'),
nullable=True, unique=None, default=None)
file_store_meta_key = Column(
"file_store_meta_key", UnicodeText().with_variant(UnicodeText(1024), 'mysql'),
nullable=True, unique=None, default=None)
_file_store_meta_value = Column(
"file_store_meta_value", UnicodeText().with_variant(UnicodeText(20480), 'mysql'),
nullable=True, unique=None, default=None)
_file_store_meta_value_type = Column(
"file_store_meta_value_type", String(255), nullable=True, unique=None,
default='unicode')
file_store_id = Column(
'file_store_id', Integer(), ForeignKey('file_store.file_store_id'),
nullable=True, unique=None, default=None)
file_store = relationship('FileStore', lazy='joined')
@hybrid_property
def file_store_meta_value(self):
v = self._file_store_meta_value
_type = self._file_store_meta_value
if _type:
# e.g unicode.encrypted == unicode
_type = self._file_store_meta_value.split('.')[0]
# decode the encrypted value
if '.encrypted' in self._file_store_meta_value_type:
cipher = EncryptedTextValue()
v = safe_unicode(cipher.process_result_value(v, None))
converter = self.SETTINGS_TYPES.get(_type) or self.SETTINGS_TYPES['unicode']
return converter(v)
@file_store_meta_value.setter
def file_store_meta_value(self, val):
val = safe_unicode(val)
# encode the encrypted value
if '.encrypted' in self.file_store_meta_value_type:
cipher = EncryptedTextValue()
val = safe_unicode(cipher.process_bind_param(val, None))
self._file_store_meta_value = val
@hybrid_property
def file_store_meta_value_type(self):
return self._file_store_meta_value_type
@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._file_store_meta_value_type = val
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)
class DbMigrateVersion(Base, BaseModel):
__tablename__ = 'db_migrate_version'
__table_args__ = (

View file

@ -383,15 +383,12 @@
## ARTIFACT RENDERERS
<%def name="repo_artifact_name(repo_name, file_uid, artifact_display_name)">
<a href="${h.route_path('repo_artifacts_get', repo_name=repo_name, uid=file_uid)}">
${artifact_display_name or 'EMPTY NAME'}
${artifact_display_name or '_EMPTY_NAME_'}
</a>
</%def>
<%def name="repo_artifact_uid(repo_name, file_uid)">
<code>${h.shorter(file_uid, size=12, prefix=True)}</code>
</%def>
<%def name="repo_artifact_uid_action(repo_name, file_uid)">
<code>${h.shorter(file_uid, size=24, prefix=True)}</code>
<i class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${h.route_url('repo_artifacts_get', repo_name=repo_name, uid=file_uid)}" title="${_('Copy the full url')}"></i>
</%def>