memegen.routes._utils.route()   A
last analyzed

Complexity

Conditions 3

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
from urllib.parse import unquote
2
3
4
import log
5
import requests
6
import background
7
from flask import (Response, url_for, render_template, send_file,
8
                   current_app, request)
9
10
11
def samples(blank=False):
12
    """Generate dictionaries of sample image data for template rendering."""
13
    for template in sorted(current_app.template_service.all()):
14
        path = "_" if blank else template.sample_path
15
        url = route('image.get', key=template.key, path=path,
16
                    preview=True, watermark='none')
17
        yield {
18
            'key': template.key,
19
            'name': template.name,
20
            'url': url,
21
        }
22
23
24
def route(*args, **kwargs):
25
    """Unquoted version of Flask's `url_for`."""
26
    for key, value in sorted(kwargs.items()):
27
        if value is True:
28
            kwargs[key] = 'true'
29
30
    return _secure(unquote(url_for(*args, **kwargs)))
31
32
33
def display(title, path, share=False, raw=False, mimetype='image/jpeg'):
34
    """Render a webpage or raw image based on request."""
35
    img = _format_url(request, 'share')
36
    img_twitter = _format_url(
37
        request, 'share',
38
        width=current_app.config['TWITTER_IMAGE_WIDTH'],
39
        height=current_app.config['TWITTER_IMAGE_HEIGHT'],
40
    )
41
    img_facebook = _format_url(
42
        request, 'share',
43
        width=current_app.config['FACEBOOK_IMAGE_WIDTH'],
44
        height=current_app.config['FACEBOOK_IMAGE_HEIGHT'],
45
    )
46
    img_copy = _format_url(request, 'share', 'watermark')
47
    url = _format_url(request, 'width', 'height')
48
49
    if share:
50
        log.info("Sharing image on page: %s", img)
51
52
        html = render_template(
53
            'share.html',
54
            title=title,
55
            img=_secure(img),
56
            img_twitter=_secure(img_twitter),
57
            img_facebook=_secure(img_facebook),
58
            img_copy=_secure(img_copy),
59
            url=_secure(url),
60
            config=current_app.config,
61
        )
62
        return html if raw else Response(html)
63
64
    else:
65
        log.info("Sending image: %s", path)
66
        return send_file(path, mimetype=mimetype)
67
68
69
def track(title):
70
    """Log the requested content, server-side."""
71
    google_url = current_app.config['GOOGLE_ANALYTICS_URL']
72
    google_tid = current_app.config['GOOGLE_ANALYTICS_TID']
73
    google_data = dict(
74
        v=1,
75
        tid=google_tid,
76
        cid=request.remote_addr,
77
78
        t='pageview',
79
        dh='memegen.link',
80
        dp=request.full_path,
81
        dt=str(title),
82
83
        uip=request.remote_addr,
84
        ua=request.user_agent.string,
85
    )
86
87
    remote_url = current_app.config['REMOTE_TRACKING_URL']
88
    remote_data = dict(
89
        text=str(title),
90
        source='memegen.link',
91
        context=unquote(request.url),
92
    )
93
94
    @background.task
95
    def run():
96
        if google_tid != 'localhost':
97
            response = requests.post(google_url, data=google_data)
98
            params = _format_query(google_data, as_string=True)
99
            log.debug("Tracking POST: %s %s", response.url, params)
100
101
        if remote_url:
102
            response = requests.get(remote_url, params=remote_data)
103
            log.debug("Tracking GET: %s", response.url)
104
    run()
105
106
107
def _secure(url):
108
    """Ensure HTTPS is used in production."""
109
    if current_app.config['ENV'] == 'prod':
110
        if url.startswith('http:'):
111
            url = url.replace('http:', 'https:', 1)
112
    return url
113
114
115
def _format_url(req, *skip, **add):
116
    """Get a formatted URL with sanitized query parameters."""
117
    base = req.base_url
118
119
    options = {}
120
    for key, value in dict(req.args).items():
121
        if key in skip:
122
            continue
123
        if isinstance(value, str):
124
            options[key] = value
125
        else:
126
            options[key] = value[0]
127
128
    options.update(add)
129
130
    params = _format_query(options)
131
132
    if params:
133
        return base + "?{}".format("&".join(params))
134
    else:
135
        return base
136
137
138
def _format_query(options, *, as_string=False):
139
    pattern = "{}={!r}" if as_string else "{}={}"
140
    pairs = sorted(pattern.format(k, v) for k, v in options.items())
141
    if as_string:
142
        return ' '.join(pairs)
143
    return pairs
144