Beispiel #1
0
feedparser.RESOLVE_RELATIVE_URIS = False
feedparser.SANITIZE_HTML = False

UTC = datetime.timezone.utc

# TODO: maybe remove in the future
# On the date story ident change to v2 format
STORY_INDENT_V2_DATE = datetime.datetime(2020, 9, 1, 0, 0, 0, tzinfo=UTC)

RawFeedSchema = T.dict(
    version=T.str,
    title=T.str,
    url=T.str,
    home_url=T.str.optional,
    icon_url=T.str.optional,
    description=T.str.optional,
    dt_updated=T.datetime.object.optional,
    author_name=T.str.optional,
    author_url=T.str.optional,
    author_avatar_url=T.str.optional,
)

_MAX_CONTENT_LENGTH = 1000 * 1024
_MAX_SUMMARY_LENGTH = 10 * 1024

RawStorySchema = T.dict(
    ident=T.str,
    title=T.str,
    url=T.str.optional,
    content=T.str.maxlen(_MAX_CONTENT_LENGTH).optional,
    summary=T.str.maxlen(_MAX_SUMMARY_LENGTH).optional,
Beispiel #2
0
from rssant_common.validator import compiler
from .response import FeedResponse

LOG = logging.getLogger(__name__)

feedparser.RESOLVE_RELATIVE_URIS = False
feedparser.SANITIZE_HTML = False

UTC = datetime.timezone.utc

RawFeedSchema = T.dict(
    version=T.str,
    title=T.str,
    url=T.str,
    home_url=T.str.optional,
    icon_url=T.str.optional,
    description=T.str.optional,
    dt_updated=T.datetime.object.optional,
    author_name=T.str.optional,
    author_url=T.str.optional,
    author_avatar_url=T.str.optional,
)

RawStorySchema = T.dict(
    ident=T.str,
    title=T.str,
    url=T.str.optional,
    content=T.str.optional,
    summary=T.str.optional,
    image_url=T.str.optional,
    dt_published=T.datetime.object.optional,
    dt_updated=T.datetime.object.optional,
Beispiel #3
0
import time
import base64
import json
import hmac
import brotli
from validr import T, Invalid
from rssant_common.validator import compiler

validate_image_token = compiler.compile(
    T.dict(
        timestamp=T.int,
        referrer=T.url.optional,
    ))


class ImageTokenEncodeError(Exception):
    """ImageTokenEncodeError"""


class ImageTokenDecodeError(Exception):
    """ImageTokenDecodeError"""


class ImageTokenExpiredError(ImageTokenDecodeError):
    """ImageTokenExpiredError"""


class ImageToken:
    def __init__(self, *, referrer: str = None, timestamp: int = None):
        self.referrer = (referrer or '')[:255]
        self.timestamp = timestamp or int(time.time())
Beispiel #4
0
def do_sync_local_ask(ctx: ActorContext) -> T.dict(message=T.str):
    LOG.info(ctx.message)
    r = dict(message='local_ask OK')
    LOG.info(r)
    return r
Beispiel #5
0
from rssant_api.helper import shorten
from .processor import (
    story_html_to_text, story_html_clean, story_extract_attach,
    story_has_mathjax, process_story_links, normalize_url, validate_url,
)


LOG = logging.getLogger(__name__)


FeedSchema = T.dict(
    version=T.str.maxlen(200),
    title=T.str.maxlen(200),
    url=T.url,
    home_url=T.url.invalid_to_default.optional,
    icon_url=T.url.invalid_to_default.optional,
    description=T.str.maxlen(300).optional,
    dt_updated=T.datetime.object.optional,
    author_name=T.str.maxlen(100).optional,
    author_url=T.url.invalid_to_default.optional,
    author_avatar_url=T.url.invalid_to_default.optional,
)

_MAX_CONTENT_LENGTH = 300 * 1024
_MAX_SUMMARY_LENGTH = 300
_MAX_STORYS = 300

StorySchema = T.dict(
    ident=T.str.maxlen(200),
    title=T.str.maxlen(200),
    url=T.url.optional,
    content=T.str.maxlen(_MAX_CONTENT_LENGTH).optional,
Beispiel #6
0
from validr import Compiler, T

from ..helper import expect_position
from . import case


class User:
    def __init__(self, userid):
        self.userid = userid


@case({
    T.dict(userid=T.int): [
        ({
            'userid': 1
        }, {
            'userid': 1
        }),
        (User(1), {
            'userid': 1
        }),
        ({
            'userid': 1,
            'extra': 'xxx'
        }, {
            'userid': 1
        }),
    ],
    T.dict(userid=T.int).optional: {
        'valid': [
            None,
Beispiel #7
0
def test_schema():
    assert T(MyModel) == T.dict(id=T.int.min(0))
    assert T(User) == T.dict(id=T.int.min(100).default(100), name=T.str)
Beispiel #8
0
         None,
         [],
     ],
     'invalid': [
         123,
     ]
 },
 T.list(T.int).unique: {
     'valid': [
         [1, 2, 3],
     ],
     'invalid': [
         [1, 2, '2'],
     ]
 },
 T.list(T.dict(key=T.int)).unique: {
     'valid': [
         [{
             'key': 1
         }, {
             'key': 2
         }],
     ],
     'invalid': [
         [{
             'key': 1
         }, {
             'key': 1
         }],
     ]
 },
Beispiel #9
0
>>> encoded = encode_image_url(url, referer)
>>> decoded = decode_image_url(encoded)
>>> decoded['url'] == url
True
>>> decoded['referer'] == referer
True
"""
import base64
import json
import brotli
from validr import T, Invalid
from rssant_common.validator import compiler

validate_image_url = compiler.compile(
    T.dict(
        url=T.url,
        referer=T.url.optional,
    ))


class ImageUrlEncodeError(Exception):
    """ImageUrlEncodeError"""


class ImageUrlDecodeError(Exception):
    """ImageUrlDecodeError"""


def encode_image_url(url, referer=None):
    try:
        text = json.dumps(validate_image_url(dict(url=url, referer=referer)))
        data = brotli.compress(text.encode('utf-8'))
Beispiel #10
0
from validr import T
from cached_property import cached_property

from .actor import Actor
from .network_helper import LOCAL_NODE_NAME
from .helper import generate_message_id
from .message import ActorMessage


LOG = logging.getLogger(__name__)


NodeSpecSchema = T.dict(
    name=T.str,
    modules=T.list(T.str),
    networks=T.list(T.dict(
        name=T.str,
        url=T.str.optional,
    ))
)


class NodeInfo:
    def __init__(self, name: str, modules: set, networks: list):
        self.name = name
        self.modules = modules
        self._networks = networks

    def __repr__(self):
        return '<{} #{} {}>'.format(type(self).__name__, self.id, self.name)

    @cached_property
Beispiel #11
0
import os.path
import re

from dotenv import load_dotenv
from validr import T, modelclass, fields, Invalid

from rssant_common.validator import compiler
from actorlib.network_helper import LOCAL_NODE_NAME

validate_extra_networks = compiler.compile(
    T.list(T.dict(
        name=T.str,
        url=T.url.relaxed,
    )))


@modelclass(compiler=compiler)
class ConfigModel:
    pass


class EnvConfig(ConfigModel):
    debug: bool = T.bool.default(False).desc('debug')
    profiler_enable: bool = T.bool.default(False).desc(
        'enable profiler or not')
    debug_toolbar_enable: bool = T.bool.default(False).desc(
        'enable debug toolbar or not')
    log_level: str = T.enum('DEBUG,INFO,WARNING,ERROR').default('INFO')
    root_url: str = T.url.relaxed.default('http://localhost:6789')
    scheduler_network: str = T.str.default('localhost')
    scheduler_url: str = T.url.relaxed.default(
Beispiel #12
0
    content_hash_base64=T.str,
    link=T.str.optional,
    author=T.str.optional,
    icon=T.str.optional,
    description=T.str.optional,
    version=T.str.optional,
    dt_updated=T.datetime.object.optional,
    encoding=T.str.optional,
    etag=T.str.optional,
    last_modified=T.str.optional,
)

FeedOutputSchemaFields = FeedSchemaFields.copy()
FeedOutputSchemaFields.update(dt_updated=T.datetime.optional, )

StorySchema = T.dict(**StorySchemaFields)
FeedSchema = T.dict(
    **FeedSchemaFields,
    storys=T.list(StorySchema),
)

StoryOutputSchema = T.dict(**StoryOutputSchemaFields)
FeedOutputSchema = T.dict(
    **FeedOutputSchemaFields,
    storys=T.list(StoryOutputSchema),
)

validate_feed_output = compiler.compile(FeedOutputSchema)


@actor('harbor_rss.update_feed_creation_status')
Beispiel #13
0
 async def do_echo(self, text: T.str) -> T.dict(text=T.str):
     return dict(text=text)
Beispiel #14
0
    with pytest.raises(Invalid):
        assert _(T.int.optional)('')
    with pytest.raises(Invalid):
        assert _(T.dict(key=T.int).optional)('')

    with pytest.raises(Invalid):
        assert _(T.int)(None)
    with pytest.raises(Invalid):
        assert _(T.str)(None)
    with pytest.raises(Invalid):
        assert _(T.dict(key=T.int))(None)
    with pytest.raises(Invalid):
        assert _(T.list(T.int))(None)


def test_default():
    assert _(T.int.default(0))(None) == 0
    assert _(T.str.default('x'))(None) == 'x'
    assert _(T.int.optional.default(0))(None) == 0
    assert _(T.str.optional.default('x'))(None) == 'x'


@schema_error_position(
    (T.unknown, ''),
    (T.str.unknown, ''),
    (T.dict(key=T.list(T.dict(key=T.unknown))), 'key[].key'),
)
def test_schema_error_position():
    pass
Beispiel #15
0
REFERER_DENY_LIST = """
qpic.cn
qlogo.cn
qq.com
"""
is_referer_deny_url = compile_url_blacklist(REFERER_DENY_LIST)

StorySchema = T.dict(
    unique_id=T.str,
    title=T.str,
    content_hash_base64=T.str,
    author=T.str.optional,
    link=T.url.optional,
    image_url=T.url.optional,
    iframe_url=T.url.optional,
    audio_url=T.url.optional,
    has_mathjax=T.bool.optional,
    dt_published=T.datetime.optional,
    dt_updated=T.datetime.optional,
    summary=T.str.optional,
    content=T.str.optional,
)

FeedSchema = T.dict(
    url=T.url,
    use_proxy=T.bool.default(False),
    title=T.str,
    content_length=T.int,
    content_hash_base64=T.str,
    link=T.url.optional,
Beispiel #16
0
def test_compiled_items():
    compiler = Compiler()
    value = compiler.compile(T.int.min(0))
    assert repr(T.dict(key=value)) == 'T.dict({key})'
    assert repr(T.list(value)) == 'T.list(int)'
Beispiel #17
0

REFERER_DENY_LIST = """
qpic.cn
qlogo.cn
qq.com
"""
is_referer_deny_url = compile_url_blacklist(REFERER_DENY_LIST)


StorySchema = T.dict(
    unique_id=T.str,
    title=T.str,
    content_hash_base64=T.str,
    author=T.str.optional,
    link=T.url.optional,
    has_mathjax=T.bool.optional,
    dt_published=T.datetime.optional,
    dt_updated=T.datetime.optional,
    summary=T.str.optional,
    content=T.str.optional,
)

FeedSchema = T.dict(
    url=T.url,
    title=T.str,
    content_length=T.int,
    content_hash_base64=T.str,
    link=T.url.optional,
    author=T.str.optional,
    icon=T.str.optional,
    description=T.str.optional,
Beispiel #18
0
 async def do_echo(self, text: T.str.default("")) -> T.dict(text=T.str):
     """A echo method"""
     if text == "error":
         raise EchoError("I echo an error")
     return {"text": text * self.echo_times}
Beispiel #19
0
def test_dict_error_position():
    validate = compiler.compile(T.dict(key=T.list(T.dict(key=T.int))))
    validate({'key': [{'key': 'x'}]})
Beispiel #20
0
 async def get_echo(self) -> T.dict(text=T.str):
     text = self.request.query.get("text") or ""
     return {"text": text * self.echo_times}
Beispiel #21
0
    icon=T.str.optional,
    description=T.str.optional,
    version=T.str.optional,
    dt_updated=T.datetime.object.optional,
    encoding=T.str.optional,
    etag=T.str.optional,
    last_modified=T.str.optional,
    response_status=T.int.optional,
    checksum_data=T.bytes.maxlen(4096).optional,
    warnings=T.str.optional,
)

FeedOutputSchemaFields = FeedSchemaFields.copy()
FeedOutputSchemaFields.update(dt_updated=T.datetime.optional, )

StorySchema = T.dict(**StorySchemaFields)
FeedSchema = T.dict(
    **FeedSchemaFields,
    storys=T.list(StorySchema),
)

FeedInfoSchemaFieldNames = [
    'response_status',
    'warnings',
]
FeedInfoSchemaFields = {
    k: FeedSchemaFields[k]
    for k in FeedInfoSchemaFieldNames
}
FeedInfoSchema = T.dict(
    **FeedInfoSchemaFields,
Beispiel #22
0
async def do_async_local_ask(ctx: ActorContext) -> T.dict(message=T.str):
    LOG.info(ctx.message)
    r = await ctx.ask('worker.sync_local_ask')
    LOG.info(r)
    return r