Repository: getredash/redash

Issue:
Shared queries don't work
<!--

We use GitHub only for bug reports 🐛

Anything else should be a discussion: https://github.com/getredash/redash/discussions/ 👫

🚨For support, help & questions use https://github.com/getredash/redash/discussions/categories/q-a
💡For feature requests & ideas use https://github.com/getredash/redash/discussions/categories/ideas

**Found a security vulnerability?** Please email security@redash.io to report any security vulnerabilities. We will acknowledge receipt of your vulnerability and strive to send you regular updates about our progress. If you're curious about the status of your disclosure please feel free to email us again. If you want to encrypt your disclosure email, you can use this PGP key.

-->

### Issue Summary

Embedded query shows an error.

### Steps to Reproduce

1. Create query
2. Click on `Emded elsewhere` -> `Public URL`
3. Open that URL 
4. See `Error: Internal Server Error`

```
[2023-10-03 10:24:37,182][PID:10][ERROR][redash.app] Exception on /api/queries/1696/results [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/flask_login/utils.py", line 277, in decorated_view
    return current_app.ensure_sync(func)(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/flask/views.py", line 109, in view
    return current_app.ensure_sync(self.dispatch_request)(**kwargs)
  File "/app/redash/handlers/base.py", line 31, in dispatch_request
    return super(BaseResource, self).dispatch_request(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/flask_restful/__init__.py", line 604, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/app/redash/permissions.py", line 71, in decorated
    return fn(*args, **kwargs)
  File "/app/redash/handlers/query_results.py", line 270, in post
    return run_query(
  File "/app/redash/handlers/query_results.py", line 109, in run_query
    "Username": current_user.get_actual_user(),
AttributeError: 'ApiUser' object has no attribute 'get_actual_user'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1484, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1469, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/usr/local/lib/python3.8/site-packages/flask_restful/__init__.py", line 489, in wrapper
    resp = resource(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/flask_login/utils.py", line 279, in decorated_view
    return func(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/flask/views.py", line 109, in view
    return current_app.ensure_sync(self.dispatch_request)(**kwargs)
  File "/app/redash/handlers/base.py", line 31, in dispatch_request
    return super(BaseResource, self).dispatch_request(*args, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/flask_restful/__init__.py", line 604, in dispatch_request
    resp = meth(*args, **kwargs)
  File "/app/redash/permissions.py", line 71, in decorated
    return fn(*args, **kwargs)
  File "/app/redash/handlers/query_results.py", line 270, in post
    return run_query(
  File "/app/redash/handlers/query_results.py", line 109, in run_query
    "Username": current_user.get_actual_user(),
AttributeError: 'ApiUser' object has no attribute 'get_actual_user'
```

### Technical details:

* Redash Version: master branch
* How did you install Redash: helm



Discussion:

Resolving patch:
diff --git a/redash/models/users.py b/redash/models/users.py
--- a/redash/models/users.py
+++ b/redash/models/users.py
@@ -5,8 +5,7 @@
 from functools import reduce
 from operator import or_
 
-from flask import current_app as app
-from flask import request_started, url_for
+from flask import current_app, request_started, url_for
 from flask_login import AnonymousUserMixin, UserMixin, current_user
 from passlib.apps import custom_app_context as pwd_context
 from sqlalchemy.dialects import postgresql
@@ -129,7 +128,7 @@ def regenerate_api_key(self):
     def to_dict(self, with_api_key=False):
         profile_image_url = self.profile_image_url
         if self.is_disabled:
-            assets = app.extensions["webpack"]["assets"] or {}
+            assets = current_app.extensions["webpack"]["assets"] or {}
             path = "images/avatar.svg"
             profile_image_url = url_for("static", filename=assets.get(path, path))
 
@@ -158,7 +157,8 @@ def to_dict(self, with_api_key=False):
 
         return d
 
-    def is_api_user(self):
+    @staticmethod
+    def is_api_user():
         return False
 
     @property
@@ -377,7 +377,8 @@ class AnonymousUser(AnonymousUserMixin, PermissionsCheckMixin):
     def permissions(self):
         return []
 
-    def is_api_user(self):
+    @staticmethod
+    def is_api_user():
         return False
 
 
@@ -397,7 +398,8 @@ def __init__(self, api_key, org, groups, name=None):
     def __repr__(self):
         return "<{}>".format(self.name)
 
-    def is_api_user(self):
+    @staticmethod
+    def is_api_user():
         return True
 
     @property
@@ -410,5 +412,9 @@ def org_id(self):
     def permissions(self):
         return ["view_query"]
 
-    def has_access(self, obj, access_type):
+    @staticmethod
+    def has_access(obj, access_type):
         return False
+
+    def get_actual_user(self):
+        return repr(self)


Test patch:
diff --git a/tests/models/test_users.py b/tests/models/test_users.py
--- a/tests/models/test_users.py
+++ b/tests/models/test_users.py
@@ -1,5 +1,5 @@
 from redash import redis_connection
-from redash.models import User, db
+from redash.models import ApiUser, User, db
 from redash.models.users import LAST_ACTIVE_KEY, sync_last_active_at
 from redash.utils import dt_from_timestamp
 from tests import BaseTestCase, authenticated_user
@@ -103,3 +103,16 @@ def test_sync(self):
             user_reloaded = User.query.filter(User.id == user.id).first()
             self.assertIn("active_at", user_reloaded.details)
             self.assertEqual(user_reloaded.active_at, timestamp)
+
+
+class TestUserGetActualUser(BaseTestCase):
+    def test_default_user(self):
+        user_email = "test@example.com"
+        user = self.factory.create_user(email=user_email)
+        self.assertEqual(user.get_actual_user(), user_email)
+
+    def test_api_user(self):
+        user_email = "test@example.com"
+        user = self.factory.create_user(email=user_email)
+        api_user = ApiUser(user.api_key, user.org, user.group_ids)
+        self.assertEqual(api_user.get_actual_user(), repr(api_user))