Projet

Général

Profil

0001-try-parent-path-if-theme-retrieval-fails-for-current.patch

Benjamin Dauvergne, 04 octobre 2016 00:10

Télécharger (6,43 ko)

Voir les différences:

Subject: [PATCH] try parent path if theme retrieval fails for current path
 (fixes #13385)

 hobo/context_processors.py      | 66 ++++++++++++++++++++++++++++++-----------
 tests/test_context_processor.py | 38 ++++++++++++++++++++++++
 tox.ini                         |  1 +
 3 files changed, 87 insertions(+), 18 deletions(-)
 create mode 100644 tests/test_context_processor.py
hobo/context_processors.py
30 30
    template_vars.update({'statics_hash': statics_hash.hexdigest()})
31 31
    return template_vars
32 32

  
33

  
33 34
class RemoteTemplate(object):
34 35
    def __init__(self, source):
35
        self.source = source
36
        self.source = urlparse.urlunparse(urlparse.urlparse(source)[:3] + ('', '', ''))
37
        self.disable_recurse = False
36 38

  
37 39
    @property
38 40
    def cache_key(self):
39
         return hashlib.md5(urlparse.urlunparse(
40
             urlparse.urlparse(self.source)[:3] + ('', '', ''))).hexdigest()
41
        return hashlib.md5(self.source).hexdigest()
41 42

  
42 43
    def get_template(self):
44
        template_body = self.get_template_body()
45
        if template_body is None:
46
            logger.error('failed to retrieve theme')
47
            raise Exception('failed to retrieve theme')
48
        return Template(template_body)
49

  
50
    def get_template_body(self):
43 51
        item = cache.get(self.cache_key)
44 52
        if item is None:
45
            template_body = self.update_content()
46
            if template_body is None:
47
                raise Exception('Failed to retrieve theme')
53
            template_body = self.request_template_body()
48 54
        else:
49 55
            template_body, expiry_time = item
50 56
            if expiry_time < datetime.datetime.now():
51 57
                # stale value, put it back into the cache for other consumers and
52 58
                # update the content in a different thread
53 59
                self.cache(template_body)
54
                threading.Thread(target=self.update_content).start()
55
        return Template(template_body)
60
                # for background refresh we do not care about retrieval miss
61
                self.disable_recurse = True
62
                threading.Thread(target=self.request_template_body).start()
63
        return template_body
56 64

  
57
    def update_content(self):
58
        r = requests.get(settings.THEME_SKELETON_URL, params={'source': self.source})
59
        if r.status_code != 200:
60
            logger.error('failed to retrieve theme')
65
    def get_template_body_recurse(self):
66
        '''We were unable to retrieve a base template for this source URL, look for one level up.'''
67
        if self.disable_recurse:
61 68
            return None
62
        self.cache(r.text)
63
        return r.text
69
        parsed = urlparse.urlparse(self.source)
70
        if not parsed.path or parsed.path == '/':
71
            return None
72
        if parsed.path.endswith('/'):  # cd ..
73
            new_path = urlparse.urljoin(parsed.path, '..')
74
        else:
75
            new_path = urlparse.urljoin(parsed.path, '.')
76
        old_source = self.source
77
        self.source = urlparse.urlunparse(parsed[:2] + (new_path, '', '', ''))
78
        template_body = self.get_template_body()
79
        self.source = old_source
80
        return template_body
64 81

  
65
    def cache(self, template_body):
82
    def request_template_body(self):
83
        try:
84
            r = requests.get(settings.THEME_SKELETON_URL, params={'source': self.source})
85
        except requests.RequestException:
86
            template_body = self.get_template_body_recurse()
87
        else:
88
            if r.status_code != 200:
89
                template_body = self.get_template_body_recurse()
90
            else:
91
                template_body = r.text
92
        self.cache_template_body(template_body)
93
        return template_body
94

  
95
    def cache_template_body(self, template_body):
66 96
        expiry_time = datetime.datetime.now() + datetime.timedelta(seconds=CACHE_REFRESH_TIMEOUT)
67
        cache.set(self.cache_key,
68
                (template_body, expiry_time),
69
                2592000) # bypass cache level expiration time
97
        cache.set(self.cache_key, (template_body, expiry_time),
98
                  2592000)  # bypass cache level expiration time
99

  
70 100

  
71 101
def theme_base(request):
72 102
    # this context processor adds two variables to context:
tests/test_context_processor.py
1
from hobo.context_processors import theme_base
2
from httmock import urlmatch, HTTMock
3

  
4
from django.core.cache import cache
5

  
6

  
7
def test_theme_base(settings, rf):
8
    settings.THEME_SKELETON_URL = 'http://combo.example.com/_skeleton_/'
9
    seen_urls = []
10
    TEMPLATE = 'Feeling lucky, punk?'
11

  
12
    @urlmatch(netloc=r'combo.example.com$')
13
    def combo_mock(url, request):
14
        seen_urls.append(url)
15
        if 'page1' in url.query:
16
            return {'status_code': 500, 'content': 'No template sorry'}
17
        return TEMPLATE
18

  
19
    cache.clear()
20
    with HTTMock(combo_mock):
21
        context = theme_base(rf.get('/'))
22
        assert context['theme_base']().origin.source == TEMPLATE
23
        assert len(seen_urls) == 1
24
        seen_urls = []
25
        context = theme_base(rf.get('/'))
26
        assert context['theme_base']().origin.source == TEMPLATE
27
        assert len(seen_urls) == 0
28
        seen_urls = []
29
        context = theme_base(rf.get('/page1/page2/'))
30
        assert context['theme_base']().origin.source == TEMPLATE
31
        assert len(seen_urls) == 2
32
        seen_urls = []
33
        context = theme_base(rf.get('/page1/'))
34
        assert context['theme_base']().origin.source == TEMPLATE
35
        assert len(seen_urls) == 0
36
        context = theme_base(rf.get('/page1/page2/'))
37
        assert context['theme_base']().origin.source == TEMPLATE
38
        assert len(seen_urls) == 0
tox.ini
43 43
	passerelle: suds
44 44
	passerelle: python-memcached
45 45
	http://git.entrouvert.org/debian/django-tenant-schemas.git/snapshot/django-tenant-schemas-master.tar.gz
46
	httmock
46 47
commands =
47 48
	./getlasso.sh
48 49
	hobo: py.test {env:COVERAGE:} {env:NOMIGRATIONS:} {posargs:tests/}
49
-