| OLD | NEW | 
|    1 # This file is part of the Adblock Plus web scripts, |    1 # This file is part of the Adblock Plus web scripts, | 
|    2 # Copyright (C) 2006-2016 Eyeo GmbH |    2 # Copyright (C) 2006-2016 Eyeo GmbH | 
|    3 # |    3 # | 
|    4 # Adblock Plus is free software: you can redistribute it and/or modify |    4 # Adblock Plus is free software: you can redistribute it and/or modify | 
|    5 # it under the terms of the GNU General Public License version 3 as |    5 # it under the terms of the GNU General Public License version 3 as | 
|    6 # published by the Free Software Foundation. |    6 # published by the Free Software Foundation. | 
|    7 # |    7 # | 
|    8 # Adblock Plus is distributed in the hope that it will be useful, |    8 # Adblock Plus is distributed in the hope that it will be useful, | 
|    9 # but WITHOUT ANY WARRANTY; without even the implied warranty of |    9 # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|   10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |   10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|   11 # GNU General Public License for more details. |   11 # GNU General Public License for more details. | 
|   12 # |   12 # | 
|   13 # You should have received a copy of the GNU General Public License |   13 # You should have received a copy of the GNU General Public License | 
|   14 # along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. |   14 # along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
|   15  |   15  | 
|   16 import copy |   16 import copy | 
|   17 import json |   17 import json | 
|   18 import random |   18 import random | 
|   19 import time |   19 import time | 
|   20 import urlparse |   20 import urlparse | 
|   21  |   21  | 
|   22 from sitescripts.notifications.parser import load_notifications |   22 from sitescripts.notifications.parser import load_notifications | 
|   23 from sitescripts.web import url_handler |   23 from sitescripts.web import url_handler | 
|   24  |   24  | 
|   25  |   25  | 
|   26 def _determine_groups(version, notifications): |   26 def _determine_groups(version, notifications): | 
|   27     version_groups = dict(x.split("/") for x in version.split("-")[1:] |   27     version_groups = dict(x.split('/') for x in version.split('-')[1:] | 
|   28                           if x.count("/") == 1) |   28                           if x.count('/') == 1) | 
|   29     groups = [] |   29     groups = [] | 
|   30     for notification in notifications: |   30     for notification in notifications: | 
|   31         group_id = notification["id"] |   31         group_id = notification['id'] | 
|   32         if group_id in version_groups: |   32         if group_id in version_groups: | 
|   33             groups.append({"id": group_id, "variant": int(version_groups[group_i
     d])}) |   33             groups.append({'id': group_id, 'variant': int(version_groups[group_i
     d])}) | 
|   34     return groups |   34     return groups | 
|   35  |   35  | 
|   36  |   36  | 
|   37 def _assign_groups(notifications): |   37 def _assign_groups(notifications): | 
|   38     groups = [] |   38     groups = [] | 
|   39     selection = random.random() |   39     selection = random.random() | 
|   40     start = 0 |   40     start = 0 | 
|   41     for notification in notifications: |   41     for notification in notifications: | 
|   42         if "variants" not in notification: |   42         if 'variants' not in notification: | 
|   43             continue |   43             continue | 
|   44         group = {"id": notification["id"], "variant": 0} |   44         group = {'id': notification['id'], 'variant': 0} | 
|   45         groups.append(group) |   45         groups.append(group) | 
|   46         for i, variant in enumerate(notification["variants"]): |   46         for i, variant in enumerate(notification['variants']): | 
|   47             sample_size = variant["sample"] |   47             sample_size = variant['sample'] | 
|   48             end = start + sample_size |   48             end = start + sample_size | 
|   49             selected = sample_size > 0 and start <= selection <= end |   49             selected = sample_size > 0 and start <= selection <= end | 
|   50             start = end |   50             start = end | 
|   51             if selected: |   51             if selected: | 
|   52                 group["variant"] = i + 1 |   52                 group['variant'] = i + 1 | 
|   53                 break |   53                 break | 
|   54     return groups |   54     return groups | 
|   55  |   55  | 
|   56  |   56  | 
|   57 def _get_active_variant(notifications, groups): |   57 def _get_active_variant(notifications, groups): | 
|   58     for group in groups: |   58     for group in groups: | 
|   59         group_id = group["id"] |   59         group_id = group['id'] | 
|   60         variant = group["variant"] |   60         variant = group['variant'] | 
|   61         if variant == 0: |   61         if variant == 0: | 
|   62             continue |   62             continue | 
|   63         notification = next((x for x in notifications if x["id"] == group_id), N
     one) |   63         notification = next((x for x in notifications if x['id'] == group_id), N
     one) | 
|   64         if not notification: |   64         if not notification: | 
|   65             continue |   65             continue | 
|   66         notification = copy.deepcopy(notification) |   66         notification = copy.deepcopy(notification) | 
|   67         notification.update(notification["variants"][variant - 1]) |   67         notification.update(notification['variants'][variant - 1]) | 
|   68         for key_to_remove in ("sample", "variants"): |   68         for key_to_remove in ('sample', 'variants'): | 
|   69             notification.pop(key_to_remove, None) |   69             notification.pop(key_to_remove, None) | 
|   70         return notification |   70         return notification | 
|   71  |   71  | 
|   72  |   72  | 
|   73 def _can_be_shown(notification): |   73 def _can_be_shown(notification): | 
|   74     return notification.get("title", None) and notification.get("message", None) |   74     return notification.get('title', None) and notification.get('message', None) | 
|   75  |   75  | 
|   76  |   76  | 
|   77 def _generate_version(groups): |   77 def _generate_version(groups): | 
|   78     version = time.strftime("%Y%m%d%H%M", time.gmtime()) |   78     version = time.strftime('%Y%m%d%H%M', time.gmtime()) | 
|   79     for group in groups: |   79     for group in groups: | 
|   80         version += "-%s/%s" % (group["id"], group["variant"]) |   80         version += '-%s/%s' % (group['id'], group['variant']) | 
|   81     return version |   81     return version | 
|   82  |   82  | 
|   83  |   83  | 
|   84 def _get_notifications_to_send(notifications, groups): |   84 def _get_notifications_to_send(notifications, groups): | 
|   85     active_variant = _get_active_variant(notifications, groups) |   85     active_variant = _get_active_variant(notifications, groups) | 
|   86     if active_variant: |   86     if active_variant: | 
|   87         return [active_variant] if _can_be_shown(active_variant) else [] |   87         return [active_variant] if _can_be_shown(active_variant) else [] | 
|   88  |   88  | 
|   89     notifications_to_send = [] |   89     notifications_to_send = [] | 
|   90     for notification in notifications: |   90     for notification in notifications: | 
|   91         if not _can_be_shown(notification): |   91         if not _can_be_shown(notification): | 
|   92             continue |   92             continue | 
|   93         if "variants" in notification: |   93         if 'variants' in notification: | 
|   94             notification = copy.deepcopy(notification) |   94             notification = copy.deepcopy(notification) | 
|   95             del notification["variants"] |   95             del notification['variants'] | 
|   96         notifications_to_send.append(notification) |   96         notifications_to_send.append(notification) | 
|   97     return notifications_to_send |   97     return notifications_to_send | 
|   98  |   98  | 
|   99  |   99  | 
|  100 def _create_response(notifications, groups): |  100 def _create_response(notifications, groups): | 
|  101     return { |  101     return { | 
|  102         "version": _generate_version(groups), |  102         'version': _generate_version(groups), | 
|  103         "notifications": _get_notifications_to_send(notifications, groups) |  103         'notifications': _get_notifications_to_send(notifications, groups) | 
|  104     } |  104     } | 
|  105  |  105  | 
|  106  |  106  | 
|  107 @url_handler("/notification.json") |  107 @url_handler('/notification.json') | 
|  108 def notification(environ, start_response): |  108 def notification(environ, start_response): | 
|  109     params = urlparse.parse_qs(environ.get("QUERY_STRING", "")) |  109     params = urlparse.parse_qs(environ.get('QUERY_STRING', '')) | 
|  110     version = params.get("lastVersion", [""])[0] |  110     version = params.get('lastVersion', [''])[0] | 
|  111     notifications = load_notifications() |  111     notifications = load_notifications() | 
|  112     groups = _determine_groups(version, notifications) |  112     groups = _determine_groups(version, notifications) | 
|  113     notifications = [x for x in notifications if not x.get("inactive", False)] |  113     notifications = [x for x in notifications if not x.get('inactive', False)] | 
|  114     if not groups: |  114     if not groups: | 
|  115         groups = _assign_groups(notifications) |  115         groups = _assign_groups(notifications) | 
|  116     response = _create_response(notifications, groups) |  116     response = _create_response(notifications, groups) | 
|  117     response_headers = [("Content-Type", "application/json; charset=utf-8"), |  117     response_headers = [('Content-Type', 'application/json; charset=utf-8'), | 
|  118                         ("ABP-Notification-Version", response["version"])] |  118                         ('ABP-Notification-Version', response['version'])] | 
|  119     response_body = json.dumps(response, ensure_ascii=False, indent=2, |  119     response_body = json.dumps(response, ensure_ascii=False, indent=2, | 
|  120                                separators=(",", ": "), |  120                                separators=(',', ': '), | 
|  121                                sort_keys=True).encode("utf-8") |  121                                sort_keys=True).encode('utf-8') | 
|  122     start_response("200 OK", response_headers) |  122     start_response('200 OK', response_headers) | 
|  123     return response_body |  123     return response_body | 
| OLD | NEW |