prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Add events to track embeds usage
  
  Add events to track embeds usage
  
  
  </issue>
  <code>
  [start of redash/handlers/embed.py]
  1 import json
  2 
  3 from funcy import project
  4 from flask import render_template, request
  5 from flask_login import login_required, current_user
  6 from flask_restful import abort
  7 
  8 from redash import models, settings
  9 from redash import serializers
  10 from redash.utils import json_dumps
  11 from redash.handlers import routes
  12 from redash.handlers.base import org_scoped_rule
  13 from redash.permissions import require_access, view_only
  14 from authentication import current_org
  15 
  16 
  17 @routes.route(org_scoped_rule('/embed/query/<query_id>/visualization/<visualization_id>'), methods=['GET'])
  18 @login_required
  19 def embed(query_id, visualization_id, org_slug=None):
  20     # TODO: add event for embed access
  21     query = models.Query.get_by_id_and_org(query_id, current_org)
  22     require_access(query.groups, current_user, view_only)
  23     vis = query.visualizations.where(models.Visualization.id == visualization_id).first()
  24     qr = {}
  25 
  26     if vis is not None:
  27         vis = vis.to_dict()
  28         qr = query.latest_query_data
  29         if qr is None:
  30             abort(400, message="No Results for this query")
  31         else:
  32             qr = qr.to_dict()
  33     else:
  34         abort(404, message="Visualization not found.")
  35 
  36     client_config = {}
  37     client_config.update(settings.COMMON_CLIENT_CONFIG)
  38 
  39     qr = project(qr, ('data', 'id', 'retrieved_at'))
  40     vis = project(vis, ('description', 'name', 'id', 'options', 'query', 'type', 'updated_at'))
  41     vis['query'] = project(vis['query'], ('created_at', 'description', 'name', 'id', 'latest_query_data_id', 'name', 'updated_at'))
  42 
  43     return render_template("embed.html",
  44                            client_config=json_dumps(client_config),
  45                            visualization=json_dumps(vis),
  46                            query_result=json_dumps(qr))
  47 
  48 
  49 @routes.route(org_scoped_rule('/public/dashboards/<token>'), methods=['GET'])
  50 @login_required
  51 def public_dashboard(token, org_slug=None):
  52     # TODO: verify object is a dashboard?
  53     if not isinstance(current_user, models.ApiUser):
  54         api_key = models.ApiKey.get_by_api_key(token)
  55         dashboard = api_key.object
  56     else:
  57         dashboard = current_user.object
  58 
  59     user = {
  60         'permissions': [],
  61         'apiKey': current_user.id
  62     }
  63 
  64     headers = {
  65         'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate'
  66     }
  67 
  68     response = render_template("public.html",
  69                                headless='embed' in request.args,
  70                                user=json.dumps(user),
  71                                seed_data=json_dumps({
  72                                  'dashboard': serializers.public_dashboard(dashboard)
  73                                }),
  74                                client_config=json.dumps(settings.COMMON_CLIENT_CONFIG))
  75 
  76     return response, 200, headers
  77
  [end of redash/handlers/embed.py]
  [start of redash/handlers/base.py]
  1 import time
  2 from flask import request, Blueprint
  3 from flask_restful import Resource, abort
  4 from flask_login import current_user, login_required
  5 from peewee import DoesNotExist
  6 
  7 from redash import settings
  8 from redash.tasks import record_event
  9 from redash.models import ApiUser
  10 from redash.authentication import current_org
  11 
  12 routes = Blueprint('redash', __name__, template_folder=settings.fix_assets_path('templates'))
  13 
  14 
  15 class BaseResource(Resource):
  16     decorators = [login_required]
  17 
  18     def __init__(self, *args, **kwargs):
  19         super(BaseResource, self).__init__(*args, **kwargs)
  20         self._user = None
  21 
  22     def dispatch_request(self, *args, **kwargs):
  23         kwargs.pop('org_slug', None)
  24 
  25         return super(BaseResource, self).dispatch_request(*args, **kwargs)
  26 
  27     @property
  28     def current_user(self):
  29         return current_user._get_current_object()
  30 
  31     @property
  32     def current_org(self):
  33         return current_org._get_current_object()
  34 
  35     def record_event(self, options):
  36         if isinstance(self.current_user, ApiUser):
  37             options.update({
  38                 'api_key': self.current_user.name,
  39                 'org_id': self.current_org.id
  40             })
  41         else:
  42             options.update({
  43                 'user_id': self.current_user.id,
  44                 'org_id': self.current_org.id
  45             })
  46 
  47         options.update({
  48             'user_agent': request.user_agent.string,
  49             'ip': request.remote_addr
  50         })
  51 
  52         if 'timestamp' not in options:
  53             options['timestamp'] = int(time.time())
  54 
  55         record_event.delay(options)
  56 
  57 
  58 def require_fields(req, fields):
  59     for f in fields:
  60         if f not in req:
  61             abort(400)
  62 
  63 
  64 def get_object_or_404(fn, *args, **kwargs):
  65     try:
  66         return fn(*args, **kwargs)
  67     except DoesNotExist:
  68         abort(404)
  69 
  70 
  71 def org_scoped_rule(rule):
  72     if settings.MULTI_ORG:
  73         return "/<org_slug:org_slug>{}".format(rule)
  74 
  75     return rule
  76
  [end of redash/handlers/base.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/redash/handlers/base.py b/redash/handlers/base.py
  --- a/redash/handlers/base.py
  +++ b/redash/handlers/base.py
  @@ -5,7 +5,7 @@
   from peewee import DoesNotExist
   
   from redash import settings
  -from redash.tasks import record_event
  +from redash.tasks import record_event as record_event_task
   from redash.models import ApiUser
   from redash.authentication import current_org
   
  @@ -33,26 +33,30 @@
           return current_org._get_current_object()
   
       def record_event(self, options):
  -        if isinstance(self.current_user, ApiUser):
  -            options.update({
  -                'api_key': self.current_user.name,
  -                'org_id': self.current_org.id
  -            })
  -        else:
  -            options.update({
  -                'user_id': self.current_user.id,
  -                'org_id': self.current_org.id
  -            })
  +        record_event(self.current_org, self.current_user, options)
   
  +
  +def record_event(org, user, options):
  +    if isinstance(user, ApiUser):
  +        options.update({
  +            'api_key': user.name,
  +            'org_id': org.id
  +        })
  +    else:
           options.update({
  -            'user_agent': request.user_agent.string,
  -            'ip': request.remote_addr
  +            'user_id': user.id,
  +            'org_id': org.id
           })
   
  -        if 'timestamp' not in options:
  -            options['timestamp'] = int(time.time())
  +    options.update({
  +        'user_agent': request.user_agent.string,
  +        'ip': request.remote_addr
  +    })
  +
  +    if 'timestamp' not in options:
  +        options['timestamp'] = int(time.time())
   
  -        record_event.delay(options)
  +    record_event_task.delay(options)
   
   
   def require_fields(req, fields):
  diff --git a/redash/handlers/embed.py b/redash/handlers/embed.py
  --- a/redash/handlers/embed.py
  +++ b/redash/handlers/embed.py
  @@ -9,7 +9,7 @@
   from redash import serializers
   from redash.utils import json_dumps
   from redash.handlers import routes
  -from redash.handlers.base import org_scoped_rule
  +from redash.handlers.base import org_scoped_rule, record_event
   from redash.permissions import require_access, view_only
   from authentication import current_org
   
  @@ -17,7 +17,6 @@
   @routes.route(org_scoped_rule('/embed/query/<query_id>/visualization/<visualization_id>'), methods=['GET'])
   @login_required
   def embed(query_id, visualization_id, org_slug=None):
  -    # TODO: add event for embed access
       query = models.Query.get_by_id_and_org(query_id, current_org)
       require_access(query.groups, current_user, view_only)
       vis = query.visualizations.where(models.Visualization.id == visualization_id).first()
  @@ -33,6 +32,15 @@
       else:
           abort(404, message="Visualization not found.")
   
  +    record_event(current_org, current_user, {
  +        'action': 'view',
  +        'object_id': visualization_id,
  +        'object_type': 'visualization',
  +        'query_id': query_id,
  +        'embed': True,
  +        'referer': request.headers.get('Referer')
  +    })
  +
       client_config = {}
       client_config.update(settings.COMMON_CLIENT_CONFIG)
   
  @@ -65,6 +73,15 @@
           'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate'
       }
   
  +    record_event(current_org, current_user, {
  +        'action': 'view',
  +        'object_id': dashboard.id,
  +        'object_type': 'dashboard',
  +        'public': True,
  +        'headless': 'embed' in request.args,
  +        'referer': request.headers.get('Referer')
  +    })
  +
       response = render_template("public.html",
                                  headless='embed' in request.args,
                                  user=json.dumps(user),
  
verification_info: {"golden_diff": "diff --git a/redash/handlers/base.py b/redash/handlers/base.py\n--- a/redash/handlers/base.py\n+++ b/redash/handlers/base.py\n@@ -5,7 +5,7 @@\n from peewee import DoesNotExist\n \n from redash import settings\n-from redash.tasks import record_event\n+from redash.tasks import record_event as record_event_task\n from redash.models import ApiUser\n from redash.authentication import current_org\n \n@@ -33,26 +33,30 @@\n         return current_org._get_current_object()\n \n     def record_event(self, options):\n-        if isinstance(self.current_user, ApiUser):\n-            options.update({\n-                'api_key': self.current_user.name,\n-                'org_id': self.current_org.id\n-            })\n-        else:\n-            options.update({\n-                'user_id': self.current_user.id,\n-                'org_id': self.current_org.id\n-            })\n+        record_event(self.current_org, self.current_user, options)\n \n+\n+def record_event(org, user, options):\n+    if isinstance(user, ApiUser):\n+        options.update({\n+            'api_key': user.name,\n+            'org_id': org.id\n+        })\n+    else:\n         options.update({\n-            'user_agent': request.user_agent.string,\n-            'ip': request.remote_addr\n+            'user_id': user.id,\n+            'org_id': org.id\n         })\n \n-        if 'timestamp' not in options:\n-            options['timestamp'] = int(time.time())\n+    options.update({\n+        'user_agent': request.user_agent.string,\n+        'ip': request.remote_addr\n+    })\n+\n+    if 'timestamp' not in options:\n+        options['timestamp'] = int(time.time())\n \n-        record_event.delay(options)\n+    record_event_task.delay(options)\n \n \n def require_fields(req, fields):\ndiff --git a/redash/handlers/embed.py b/redash/handlers/embed.py\n--- a/redash/handlers/embed.py\n+++ b/redash/handlers/embed.py\n@@ -9,7 +9,7 @@\n from redash import serializers\n from redash.utils import json_dumps\n from redash.handlers import routes\n-from redash.handlers.base import org_scoped_rule\n+from redash.handlers.base import org_scoped_rule, record_event\n from redash.permissions import require_access, view_only\n from authentication import current_org\n \n@@ -17,7 +17,6 @@\n @routes.route(org_scoped_rule('/embed/query/<query_id>/visualization/<visualization_id>'), methods=['GET'])\n @login_required\n def embed(query_id, visualization_id, org_slug=None):\n-    # TODO: add event for embed access\n     query = models.Query.get_by_id_and_org(query_id, current_org)\n     require_access(query.groups, current_user, view_only)\n     vis = query.visualizations.where(models.Visualization.id == visualization_id).first()\n@@ -33,6 +32,15 @@\n     else:\n         abort(404, message=\"Visualization not found.\")\n \n+    record_event(current_org, current_user, {\n+        'action': 'view',\n+        'object_id': visualization_id,\n+        'object_type': 'visualization',\n+        'query_id': query_id,\n+        'embed': True,\n+        'referer': request.headers.get('Referer')\n+    })\n+\n     client_config = {}\n     client_config.update(settings.COMMON_CLIENT_CONFIG)\n \n@@ -65,6 +73,15 @@\n         'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate'\n     }\n \n+    record_event(current_org, current_user, {\n+        'action': 'view',\n+        'object_id': dashboard.id,\n+        'object_type': 'dashboard',\n+        'public': True,\n+        'headless': 'embed' in request.args,\n+        'referer': request.headers.get('Referer')\n+    })\n+\n     response = render_template(\"public.html\",\n                                headless='embed' in request.args,\n                                user=json.dumps(user),\n", "issue": "Add events to track embeds usage\n\nAdd events to track embeds usage\n\n", "before_files": [{"content": "import json\n\nfrom funcy import project\nfrom flask import render_template, request\nfrom flask_login import login_required, current_user\nfrom flask_restful import abort\n\nfrom redash import models, settings\nfrom redash import serializers\nfrom redash.utils import json_dumps\nfrom redash.handlers import routes\nfrom redash.handlers.base import org_scoped_rule\nfrom redash.permissions import require_access, view_only\nfrom authentication import current_org\n\n\n@routes.route(org_scoped_rule('/embed/query/<query_id>/visualization/<visualization_id>'), methods=['GET'])\n@login_required\ndef embed(query_id, visualization_id, org_slug=None):\n    # TODO: add event for embed access\n    query = models.Query.get_by_id_and_org(query_id, current_org)\n    require_access(query.groups, current_user, view_only)\n    vis = query.visualizations.where(models.Visualization.id == visualization_id).first()\n    qr = {}\n\n    if vis is not None:\n        vis = vis.to_dict()\n        qr = query.latest_query_data\n        if qr is None:\n            abort(400, message=\"No Results for this query\")\n        else:\n            qr = qr.to_dict()\n    else:\n        abort(404, message=\"Visualization not found.\")\n\n    client_config = {}\n    client_config.update(settings.COMMON_CLIENT_CONFIG)\n\n    qr = project(qr, ('data', 'id', 'retrieved_at'))\n    vis = project(vis, ('description', 'name', 'id', 'options', 'query', 'type', 'updated_at'))\n    vis['query'] = project(vis['query'], ('created_at', 'description', 'name', 'id', 'latest_query_data_id', 'name', 'updated_at'))\n\n    return render_template(\"embed.html\",\n                           client_config=json_dumps(client_config),\n                           visualization=json_dumps(vis),\n                           query_result=json_dumps(qr))\n\n\n@routes.route(org_scoped_rule('/public/dashboards/<token>'), methods=['GET'])\n@login_required\ndef public_dashboard(token, org_slug=None):\n    # TODO: verify object is a dashboard?\n    if not isinstance(current_user, models.ApiUser):\n        api_key = models.ApiKey.get_by_api_key(token)\n        dashboard = api_key.object\n    else:\n        dashboard = current_user.object\n\n    user = {\n        'permissions': [],\n        'apiKey': current_user.id\n    }\n\n    headers = {\n        'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate'\n    }\n\n    response = render_template(\"public.html\",\n                               headless='embed' in request.args,\n                               user=json.dumps(user),\n                               seed_data=json_dumps({\n                                 'dashboard': serializers.public_dashboard(dashboard)\n                               }),\n                               client_config=json.dumps(settings.COMMON_CLIENT_CONFIG))\n\n    return response, 200, headers\n", "path": "redash/handlers/embed.py"}, {"content": "import time\nfrom flask import request, Blueprint\nfrom flask_restful import Resource, abort\nfrom flask_login import current_user, login_required\nfrom peewee import DoesNotExist\n\nfrom redash import settings\nfrom redash.tasks import record_event\nfrom redash.models import ApiUser\nfrom redash.authentication import current_org\n\nroutes = Blueprint('redash', __name__, template_folder=settings.fix_assets_path('templates'))\n\n\nclass BaseResource(Resource):\n    decorators = [login_required]\n\n    def __init__(self, *args, **kwargs):\n        super(BaseResource, self).__init__(*args, **kwargs)\n        self._user = None\n\n    def dispatch_request(self, *args, **kwargs):\n        kwargs.pop('org_slug', None)\n\n        return super(BaseResource, self).dispatch_request(*args, **kwargs)\n\n    @property\n    def current_user(self):\n        return current_user._get_current_object()\n\n    @property\n    def current_org(self):\n        return current_org._get_current_object()\n\n    def record_event(self, options):\n        if isinstance(self.current_user, ApiUser):\n            options.update({\n                'api_key': self.current_user.name,\n                'org_id': self.current_org.id\n            })\n        else:\n            options.update({\n                'user_id': self.current_user.id,\n                'org_id': self.current_org.id\n            })\n\n        options.update({\n            'user_agent': request.user_agent.string,\n            'ip': request.remote_addr\n        })\n\n        if 'timestamp' not in options:\n            options['timestamp'] = int(time.time())\n\n        record_event.delay(options)\n\n\ndef require_fields(req, fields):\n    for f in fields:\n        if f not in req:\n            abort(400)\n\n\ndef get_object_or_404(fn, *args, **kwargs):\n    try:\n        return fn(*args, **kwargs)\n    except DoesNotExist:\n        abort(404)\n\n\ndef org_scoped_rule(rule):\n    if settings.MULTI_ORG:\n        return \"/<org_slug:org_slug>{}\".format(rule)\n\n    return rule\n", "path": "redash/handlers/base.py"}]}