Convert Metadata and Fee validators to use new JSON Schema-based system
This commit is contained in:
parent
3f22f39ce1
commit
d8d462f43c
4 changed files with 329 additions and 169 deletions
|
@ -1,116 +1,39 @@
|
||||||
import logging
|
import logging
|
||||||
|
import fee_schemas
|
||||||
|
|
||||||
from lbrynet.metadata.Validator import Validator, skip_validate
|
from lbrynet.metadata.StructuredDict import StructuredDict
|
||||||
from lbrynet.conf import CURRENCIES
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def verify_supported_currency(fee):
|
class FeeValidator(StructuredDict):
|
||||||
assert len(fee) == 1
|
|
||||||
for c in fee:
|
|
||||||
assert c in CURRENCIES
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def verify_amount(x):
|
|
||||||
return isinstance(x, float) or isinstance(x, int) and x > 0
|
|
||||||
|
|
||||||
|
|
||||||
class LBCFeeValidator(Validator):
|
|
||||||
FV001 = "0.0.1"
|
|
||||||
CURRENT_FEE_VERSION = FV001
|
|
||||||
|
|
||||||
FEE_REVISIONS = {}
|
|
||||||
|
|
||||||
FEE_REVISIONS[FV001] = [
|
|
||||||
(Validator.REQUIRE, 'amount', verify_amount),
|
|
||||||
(Validator.REQUIRE, 'address', skip_validate),
|
|
||||||
]
|
|
||||||
|
|
||||||
FEE_MIGRATIONS = []
|
|
||||||
|
|
||||||
current_version = CURRENT_FEE_VERSION
|
|
||||||
versions = FEE_REVISIONS
|
|
||||||
migrations = FEE_MIGRATIONS
|
|
||||||
|
|
||||||
def __init__(self, fee):
|
def __init__(self, fee):
|
||||||
Validator.__init__(self, fee)
|
self._versions = [
|
||||||
|
('0.0.1', fee_schemas.VER_001, None)
|
||||||
|
]
|
||||||
|
|
||||||
|
StructuredDict.__init__(self, fee, fee.get('ver', '0.0.1'))
|
||||||
|
|
||||||
class BTCFeeValidator(Validator):
|
|
||||||
FV001 = "0.0.1"
|
|
||||||
CURRENT_FEE_VERSION = FV001
|
|
||||||
|
|
||||||
FEE_REVISIONS = {}
|
|
||||||
|
|
||||||
FEE_REVISIONS[FV001] = [
|
|
||||||
(Validator.REQUIRE, 'amount',verify_amount),
|
|
||||||
(Validator.REQUIRE, 'address', skip_validate),
|
|
||||||
]
|
|
||||||
|
|
||||||
FEE_MIGRATIONS = []
|
|
||||||
|
|
||||||
current_version = CURRENT_FEE_VERSION
|
|
||||||
versions = FEE_REVISIONS
|
|
||||||
migrations = FEE_MIGRATIONS
|
|
||||||
|
|
||||||
def __init__(self, fee):
|
|
||||||
Validator.__init__(self, fee)
|
|
||||||
|
|
||||||
|
|
||||||
class USDFeeValidator(Validator):
|
|
||||||
FV001 = "0.0.1"
|
|
||||||
CURRENT_FEE_VERSION = FV001
|
|
||||||
|
|
||||||
FEE_REVISIONS = {}
|
|
||||||
|
|
||||||
FEE_REVISIONS[FV001] = [
|
|
||||||
(Validator.REQUIRE, 'amount',verify_amount),
|
|
||||||
(Validator.REQUIRE, 'address', skip_validate),
|
|
||||||
]
|
|
||||||
|
|
||||||
FEE_MIGRATIONS = []
|
|
||||||
|
|
||||||
current_version = CURRENT_FEE_VERSION
|
|
||||||
versions = FEE_REVISIONS
|
|
||||||
migrations = FEE_MIGRATIONS
|
|
||||||
|
|
||||||
def __init__(self, fee):
|
|
||||||
Validator.__init__(self, fee)
|
|
||||||
|
|
||||||
|
|
||||||
class FeeValidator(Validator):
|
|
||||||
CV001 = "0.0.1"
|
|
||||||
CURRENT_CURRENCY_VERSION = CV001
|
|
||||||
|
|
||||||
CURRENCY_REVISIONS = {}
|
|
||||||
|
|
||||||
CURRENCY_REVISIONS[CV001] = [
|
|
||||||
(Validator.OPTIONAL, 'BTC', BTCFeeValidator.validate),
|
|
||||||
(Validator.OPTIONAL, 'USD', USDFeeValidator.validate),
|
|
||||||
(Validator.OPTIONAL, 'LBC', LBCFeeValidator.validate),
|
|
||||||
]
|
|
||||||
|
|
||||||
CURRENCY_MIGRATIONS = []
|
|
||||||
|
|
||||||
current_version = CURRENT_CURRENCY_VERSION
|
|
||||||
versions = CURRENCY_REVISIONS
|
|
||||||
migrations = CURRENCY_MIGRATIONS
|
|
||||||
|
|
||||||
def __init__(self, fee_dict):
|
|
||||||
Validator.__init__(self, fee_dict)
|
|
||||||
self.currency_symbol = self.keys()[0]
|
self.currency_symbol = self.keys()[0]
|
||||||
self.amount = self._get_amount()
|
self.amount = self._get_amount()
|
||||||
self.address = self[self.currency_symbol]['address']
|
self.address = self[self.currency_symbol]['address']
|
||||||
|
|
||||||
def _get_amount(self):
|
def _get_amount(self):
|
||||||
amt = self[self.currency_symbol]['amount']
|
amt = self[self.currency_symbol]['amount']
|
||||||
if isinstance(amt, float):
|
try:
|
||||||
return amt
|
return float(amt)
|
||||||
else:
|
except TypeError:
|
||||||
try:
|
log.error('Failed to convert fee amount %s to float', amt)
|
||||||
return float(amt)
|
raise
|
||||||
except TypeError:
|
|
||||||
log.error('Failed to convert %s to float', amt)
|
|
||||||
raise
|
class LBCFeeValidator(StructuredDict):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class BTCFeeValidator(StructuredDict):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class USDFeeValidator(StructuredDict):
|
||||||
|
pass
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from lbrynet.metadata.Validator import Validator, skip_validate
|
from lbrynet.metadata.StructuredDict import StructuredDict
|
||||||
from lbrynet.metadata.Fee import FeeValidator, verify_supported_currency
|
|
||||||
from lbrynet.conf import SOURCE_TYPES
|
from lbrynet.conf import SOURCE_TYPES
|
||||||
|
import metadata_schemas
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
NAME_ALLOWED_CHARSET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0987654321-'
|
NAME_ALLOWED_CHARSET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0987654321-'
|
||||||
|
@ -14,73 +14,25 @@ def verify_name_characters(name):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def validate_sources(sources):
|
class Metadata(StructuredDict):
|
||||||
for source in sources:
|
def __init__(self, metadata, migrate=True, target_version=None):
|
||||||
assert source in SOURCE_TYPES, "Unknown source type: %s" % str(source)
|
self._versions = [
|
||||||
return True
|
('0.0.1', metadata_schemas.VER_001, None),
|
||||||
|
('0.0.2', metadata_schemas.VER_002, self._migrate_001_to_002),
|
||||||
|
('0.0.3', metadata_schemas.VER_003, self._migrate_002_to_003)
|
||||||
|
]
|
||||||
|
|
||||||
|
starting_version = metadata.get('ver', '0.0.1')
|
||||||
|
|
||||||
|
StructuredDict.__init__(self, metadata, starting_version, migrate, target_version)
|
||||||
|
|
||||||
|
|
||||||
class Metadata(Validator):
|
def _migrate_001_to_002(self):
|
||||||
MV001 = "0.0.1"
|
self['ver'] = '0.0.2'
|
||||||
MV002 = "0.0.2"
|
|
||||||
MV003 = "0.0.3"
|
|
||||||
CURRENT_METADATA_VERSION = MV003
|
|
||||||
|
|
||||||
METADATA_REVISIONS = {}
|
def _migrate_002_to_003(self):
|
||||||
|
self['ver'] = '0.0.3'
|
||||||
|
|
||||||
METADATA_REVISIONS[MV001] = [
|
if 'content-type' in self:
|
||||||
(Validator.REQUIRE, 'title', skip_validate),
|
self['content_type'] = self['content-type']
|
||||||
(Validator.REQUIRE, 'description', skip_validate),
|
del self['content-type']
|
||||||
(Validator.REQUIRE, 'author', skip_validate),
|
|
||||||
(Validator.REQUIRE, 'language', skip_validate),
|
|
||||||
(Validator.REQUIRE, 'license', skip_validate),
|
|
||||||
(Validator.REQUIRE, 'content-type', skip_validate),
|
|
||||||
(Validator.REQUIRE, 'sources', validate_sources),
|
|
||||||
(Validator.OPTIONAL, 'thumbnail', skip_validate),
|
|
||||||
(Validator.OPTIONAL, 'preview', skip_validate),
|
|
||||||
(Validator.OPTIONAL, 'fee', verify_supported_currency),
|
|
||||||
(Validator.OPTIONAL, 'contact', skip_validate),
|
|
||||||
(Validator.OPTIONAL, 'pubkey', skip_validate),
|
|
||||||
]
|
|
||||||
|
|
||||||
METADATA_REVISIONS[MV002] = [
|
|
||||||
(Validator.REQUIRE, 'nsfw', skip_validate),
|
|
||||||
(Validator.REQUIRE, 'ver', skip_validate),
|
|
||||||
(Validator.OPTIONAL, 'license_url', skip_validate),
|
|
||||||
]
|
|
||||||
|
|
||||||
METADATA_REVISIONS[MV003] = [
|
|
||||||
(Validator.REQUIRE, 'content_type', skip_validate),
|
|
||||||
(Validator.SKIP, 'content-type'),
|
|
||||||
(Validator.OPTIONAL, 'sig', skip_validate),
|
|
||||||
(Validator.IF_KEY, 'sig', (Validator.REQUIRE, 'pubkey', skip_validate), Validator.DO_NOTHING),
|
|
||||||
(Validator.IF_KEY, 'pubkey', (Validator.REQUIRE, 'sig', skip_validate), Validator.DO_NOTHING),
|
|
||||||
]
|
|
||||||
|
|
||||||
MIGRATE_MV001_TO_MV002 = [
|
|
||||||
(Validator.IF_KEY, 'nsfw', Validator.DO_NOTHING, (Validator.LOAD, 'nsfw', False)),
|
|
||||||
(Validator.IF_KEY, 'ver', Validator.DO_NOTHING, (Validator.LOAD, 'ver', MV002)),
|
|
||||||
]
|
|
||||||
|
|
||||||
MIGRATE_MV002_TO_MV003 = [
|
|
||||||
(Validator.IF_KEY, 'content-type', (Validator.UPDATE, 'content-type', 'content_type'), Validator.DO_NOTHING),
|
|
||||||
(Validator.IF_VAL, 'ver', MV002, (Validator.LOAD, 'ver', MV003), Validator.DO_NOTHING),
|
|
||||||
]
|
|
||||||
|
|
||||||
METADATA_MIGRATIONS = [
|
|
||||||
MIGRATE_MV001_TO_MV002,
|
|
||||||
MIGRATE_MV002_TO_MV003,
|
|
||||||
]
|
|
||||||
|
|
||||||
current_version = CURRENT_METADATA_VERSION
|
|
||||||
versions = METADATA_REVISIONS
|
|
||||||
migrations = METADATA_MIGRATIONS
|
|
||||||
|
|
||||||
def __init__(self, metadata, process_now=True):
|
|
||||||
Validator.__init__(self, metadata, process_now)
|
|
||||||
self.meta_version = self.get('ver', Metadata.MV001)
|
|
||||||
self._load_fee()
|
|
||||||
|
|
||||||
def _load_fee(self):
|
|
||||||
if 'fee' in self:
|
|
||||||
self.update({'fee': FeeValidator(self['fee'])})
|
|
16
lbrynet/metadata/fee_schemas.py
Normal file
16
lbrynet/metadata/fee_schemas.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
VER_001 = {
|
||||||
|
'$schema': 'http://json-schema.org/draft-04/schema#',
|
||||||
|
'title': 'LBRY fee schema 0.0.1',
|
||||||
|
'type': 'object',
|
||||||
|
|
||||||
|
'properties': {
|
||||||
|
'amount': {
|
||||||
|
'type': 'number',
|
||||||
|
'minimum': 0,
|
||||||
|
'exclusiveMinimum': True,
|
||||||
|
},
|
||||||
|
'address': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
269
lbrynet/metadata/metadata_schemas.py
Normal file
269
lbrynet/metadata/metadata_schemas.py
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
VER_001 = {
|
||||||
|
'$schema': 'http://json-schema.org/draft-04/schema#',
|
||||||
|
'title': 'LBRY metadata schema 0.0.1',
|
||||||
|
'definitions': {
|
||||||
|
'fee_info': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'amount': {
|
||||||
|
'type': 'number',
|
||||||
|
'minimum': 0,
|
||||||
|
'exclusiveMinimum': True,
|
||||||
|
},
|
||||||
|
'address': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'type': 'object',
|
||||||
|
|
||||||
|
'properties': {
|
||||||
|
'ver': {
|
||||||
|
'type': 'string',
|
||||||
|
'default': '0.0.1'
|
||||||
|
},
|
||||||
|
'title': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'description': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'author': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'language': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'license': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'content-type': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'sources': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'lbry_sd_hash': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'btih': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'url': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'additionalProperties': False
|
||||||
|
},
|
||||||
|
'thumbnail': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'preview': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'fee': {
|
||||||
|
'properties': {
|
||||||
|
'LBC': { '$ref': '#/definitions/fee_info' },
|
||||||
|
'BTC': { '$ref': '#/definitions/fee_info' },
|
||||||
|
'USD': { '$ref': '#/definitions/fee_info' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'contact': {
|
||||||
|
'type': 'number'
|
||||||
|
},
|
||||||
|
'pubkey': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'required': ['title', 'description', 'author', 'language', 'license', 'content-type', 'sources'],
|
||||||
|
'additionalProperties': False
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VER_002 = {
|
||||||
|
'$schema': 'http://json-schema.org/draft-04/schema#',
|
||||||
|
'title': 'LBRY metadata schema 0.0.2',
|
||||||
|
'definitions': {
|
||||||
|
'fee_info': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'amount': {
|
||||||
|
'type': 'number',
|
||||||
|
'minimum': 0,
|
||||||
|
'exclusiveMinimum': True,
|
||||||
|
},
|
||||||
|
'address': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'type': 'object',
|
||||||
|
|
||||||
|
'properties': {
|
||||||
|
'ver': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': ['0.0.2'],
|
||||||
|
},
|
||||||
|
'title': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'description': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'author': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'language': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'license': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'content-type': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'sources': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'lbry_sd_hash': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'btih': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'url': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'additionalProperties': False
|
||||||
|
},
|
||||||
|
'thumbnail': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'preview': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'fee': {
|
||||||
|
'properties': {
|
||||||
|
'LBC': { '$ref': '#/definitions/fee_info' },
|
||||||
|
'BTC': { '$ref': '#/definitions/fee_info' },
|
||||||
|
'USD': { '$ref': '#/definitions/fee_info' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'contact': {
|
||||||
|
'type': 'number'
|
||||||
|
},
|
||||||
|
'pubkey': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'license_url': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'nsfw': {
|
||||||
|
'type': 'boolean',
|
||||||
|
'default': False
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
'required': ['ver', 'title', 'description', 'author', 'language', 'license', 'content-type', 'sources', 'nsfw'],
|
||||||
|
'additionalProperties': False
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VER_003 = {
|
||||||
|
'$schema': 'http://json-schema.org/draft-04/schema#',
|
||||||
|
'title': 'LBRY metadata schema 0.0.3',
|
||||||
|
'definitions': {
|
||||||
|
'fee_info': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'amount': {
|
||||||
|
'type': 'number',
|
||||||
|
'minimum': 0,
|
||||||
|
'exclusiveMinimum': True,
|
||||||
|
},
|
||||||
|
'address': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'type': 'object',
|
||||||
|
|
||||||
|
'properties': {
|
||||||
|
'ver': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': ['0.0.3'],
|
||||||
|
},
|
||||||
|
'title': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'description': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'author': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'language': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'license': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'content_type': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'sources': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'lbry_sd_hash': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'btih': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'url': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'additionalProperties': False
|
||||||
|
},
|
||||||
|
'thumbnail': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'preview': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'fee': {
|
||||||
|
'properties': {
|
||||||
|
'LBC': { '$ref': '#/definitions/fee_info' },
|
||||||
|
'BTC': { '$ref': '#/definitions/fee_info' },
|
||||||
|
'USD': { '$ref': '#/definitions/fee_info' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'contact': {
|
||||||
|
'type': 'number'
|
||||||
|
},
|
||||||
|
'pubkey': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'license_url': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'nsfw': {
|
||||||
|
'type': 'boolean',
|
||||||
|
'default': False
|
||||||
|
},
|
||||||
|
'sig': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'required': ['ver', 'title', 'description', 'author', 'language', 'license', 'content_type', 'sources', 'nsfw'],
|
||||||
|
'additionalProperties': False,
|
||||||
|
'dependencies': {
|
||||||
|
'pubkey': ['sig'],
|
||||||
|
'sig': ['pubkey']
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue