From d14987bd8916e70c3b6db0fd901d74c7061050a9 Mon Sep 17 00:00:00 2001
From: Martin Weise <martin.weise@tuwien.ac.at>
Date: Fri, 13 Dec 2024 21:05:20 +0000
Subject: [PATCH] Hotfix/ui view

---
 .../at/tuwien/endpoints/ViewEndpoint.java     |  4 ++
 dbrepo-ui/components/view/ViewToolbar.vue     | 19 ++++++++
 .../[database_id]/view/[view_id]/data.vue     | 18 ++++---
 lib/python/dbrepo/RestClient.py               | 47 +++++--------------
 lib/python/dbrepo/api/dto.py                  | 21 ++++-----
 lib/python/tests/test_unit_license.py         |  4 +-
 lib/python/tests/test_unit_query.py           | 47 +++++++++----------
 lib/python/tests/test_unit_table.py           | 26 +++++-----
 lib/python/tests/test_unit_view.py            | 26 +++++-----
 9 files changed, 103 insertions(+), 109 deletions(-)

diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
index 001350246e..84b24b66c7 100644
--- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
+++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java
@@ -270,6 +270,10 @@ public class ViewEndpoint extends AbstractEndpoint {
         // TODO improve with a single operation that checks if user xyz has access to view abc
         final PrivilegedViewDto view = metadataServiceGateway.getViewById(databaseId, viewId);
         if (!view.getIsPublic()) {
+            if (principal == null) {
+                log.error("Failed to get data from view: unauthorized");
+                throw new NotAllowedException("Failed to get data from view: unauthorized");
+            }
             metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal));
         }
         try {
diff --git a/dbrepo-ui/components/view/ViewToolbar.vue b/dbrepo-ui/components/view/ViewToolbar.vue
index c43b730397..fdbb47fe92 100644
--- a/dbrepo-ui/components/view/ViewToolbar.vue
+++ b/dbrepo-ui/components/view/ViewToolbar.vue
@@ -34,6 +34,7 @@
           :text="$t('navigation.info')"
           :to="`/database/${$route.params.database_id}/view/${$route.params.view_id}/info`" />
         <v-tab
+          v-if="canReadData"
           :text="$t('navigation.data')"
           :to="`/database/${$route.params.database_id}/view/${$route.params.view_id}/data`" />
       </v-tabs>
@@ -96,6 +97,24 @@ export default {
     roles () {
       return this.userStore.getRoles
     },
+    hasReadAccess () {
+      if (!this.access) {
+        return false
+      }
+      return this.access.type === 'read' ||  this.access.type === 'write_own' ||  this.access.type === 'write_all'
+    },
+    canReadData () {
+      if (!this.view) {
+        return false
+      }
+      if (this.view.is_public) {
+        return true
+      }
+      if (!this.user) {
+        return false
+      }
+      return this.view.owner.id === this.user.id || this.hasReadAccess
+    },
     identifiers () {
       if (!this.view) {
         return []
diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue
index bc460da08b..b42972913e 100644
--- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue
+++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue
@@ -1,5 +1,6 @@
 <template>
-  <div>
+  <div
+    v-if="canReadData">
     <ViewToolbar
       v-if="view" />
     <v-toolbar
@@ -7,7 +8,6 @@
       :title="$t('toolbars.database.current')"
       flat>
       <v-btn
-        v-if="canDownload"
         :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-download' : null"
         variant="flat"
         :loading="downloadLoading"
@@ -85,18 +85,24 @@ export default {
     access () {
       return this.userStore.getAccess
     },
-    canDownload () {
+    hasReadAccess () {
+      if (!this.access) {
+        return false
+      }
+      return this.access.type === 'read' ||  this.access.type === 'write_own' ||  this.access.type === 'write_all'
+    },
+    canReadData () {
       if (!this.view) {
         return false
       }
       if (this.view.is_public) {
         return true
       }
-      if (!this.access) {
+      if (!this.user) {
         return false
       }
-      return this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all'
-    }
+      return this.view.owner.id === this.user.id || this.hasReadAccess
+    },
   },
   mounted () {
     this.reload()
diff --git a/lib/python/dbrepo/RestClient.py b/lib/python/dbrepo/RestClient.py
index b80daff7d0..16eb31a3e3 100644
--- a/lib/python/dbrepo/RestClient.py
+++ b/lib/python/dbrepo/RestClient.py
@@ -957,8 +957,7 @@ class RestClient:
         raise ResponseCodeError(f'Failed to delete view: response code: {response.status_code} is not '
                                 f'202 (ACCEPTED): {response.text}')
 
-    def get_view_data(self, database_id: int, view_id: int, page: int = 0, size: int = 10,
-                      df: bool = False) -> Result | DataFrame:
+    def get_view_data(self, database_id: int, view_id: int, page: int = 0, size: int = 10) -> DataFrame:
         """
         Get data of a view in a database with given database id and view id.
 
@@ -966,9 +965,8 @@ class RestClient:
         :param view_id: The view id.
         :param page: The result pagination number. Optional. Default: 0.
         :param size: The result pagination size. Optional. Default: 10.
-        :param df: If true, the result is returned as Pandas DataFrame. Optional. Default: False.
 
-        :returns: The result of the view query, if successful.
+        :returns: The view data, if successful.
 
         :raises MalformedError: If the payload is rejected by the service.
         :raises ForbiddenError: If something went wrong with the authorization.
@@ -984,11 +982,7 @@ class RestClient:
             params.append(('size', size))
         response = self._wrapper(method="get", url=url, params=params)
         if response.status_code == 200:
-            body = response.json()
-            res = Result.model_validate(body)
-            if df:
-                return DataFrame.from_records(res.result)
-            return res
+            return DataFrame.from_records(response.json())
         if response.status_code == 400:
             raise MalformedError(f'Failed to get view data: {response.text}')
         if response.status_code == 403:
@@ -1026,7 +1020,7 @@ class RestClient:
                                 f'200 (OK): {response.text}')
 
     def get_table_data(self, database_id: int, table_id: int, page: int = 0, size: int = 10,
-                       timestamp: datetime.datetime = None, df: bool = False) -> Result | DataFrame:
+                       timestamp: datetime.datetime = None) -> DataFrame:
         """
         Get data of a table in a database with given database id and table id.
 
@@ -1035,9 +1029,8 @@ class RestClient:
         :param page: The result pagination number. Optional. Default: 0.
         :param size: The result pagination size. Optional. Default: 10.
         :param timestamp: The query execution time. Optional.
-        :param df: If true, the result is returned as Pandas DataFrame. Optional. Default: False.
 
-        :returns: The result of the view query, if successful.
+        :returns: The table data, if successful.
 
         :raises MalformedError: If the payload is rejected by the service.
         :raises ForbiddenError: If something went wrong with the authorization.
@@ -1054,11 +1047,7 @@ class RestClient:
             params.append(('timestamp', timestamp))
         response = self._wrapper(method="get", url=url, params=params)
         if response.status_code == 200:
-            body = response.json()
-            res = Result.model_validate(body)
-            if df:
-                return DataFrame.from_records(res.result)
-            return res
+            return DataFrame.from_records(response.json())
         if response.status_code == 400:
             raise MalformedError(f'Failed to get table data: {response.text}')
         if response.status_code == 403:
@@ -1551,7 +1540,7 @@ class RestClient:
                                 f'201 (CREATED): {response.text}')
 
     def create_subset(self, database_id: int, query: str, page: int = 0, size: int = 10,
-                      timestamp: datetime.datetime = None, df: bool = False) -> Result | DataFrame:
+                      timestamp: datetime.datetime = None) -> DataFrame:
         """
         Executes a SQL query in a database where the current user has at least read access with given database id. The
         result set can be paginated with setting page and size (both). Historic data can be queried by setting
@@ -1562,7 +1551,6 @@ class RestClient:
         :param page: The result pagination number. Optional. Default: 0.
         :param size: The result pagination size. Optional. Default: 10.
         :param timestamp: The timestamp at which the data validity is set. Optional. Default: <current timestamp>.
-        :param df: If true, the result is returned as Pandas DataFrame. Optional. Default: False.
 
         :returns: The result set, if successful.
 
@@ -1585,11 +1573,8 @@ class RestClient:
         response = self._wrapper(method="post", url=url, headers={"Accept": "application/json"},
                                  payload=ExecuteQuery(statement=query))
         if response.status_code == 201:
-            body = response.json()
-            res = Result.model_validate(body)
-            if df:
-                return DataFrame.from_records(res.result)
-            return res
+            logging.info(f'Created subset with id: {response.headers["X-Id"]}')
+            return DataFrame.from_records(response.json())
         if response.status_code == 400:
             raise MalformedError(f'Failed to create subset: {response.text}')
         if response.status_code == 403:
@@ -1605,8 +1590,7 @@ class RestClient:
         raise ResponseCodeError(f'Failed to create subset: response code: {response.status_code} is not '
                                 f'201 (CREATED): {response.text}')
 
-    def get_subset_data(self, database_id: int, subset_id: int, page: int = 0, size: int = 10,
-                        df: bool = False) -> Result | DataFrame:
+    def get_subset_data(self, database_id: int, subset_id: int, page: int = 0, size: int = 10) -> DataFrame:
         """
         Re-executes a query in a database with given database id and query id.
 
@@ -1615,9 +1599,8 @@ class RestClient:
         :param page: The result pagination number. Optional. Default: 0.
         :param size: The result pagination size. Optional. Default: 10.
         :param size: The result pagination size. Optional. Default: 10.
-        :param df: If true, the result is returned as Pandas DataFrame. Optional. Default: False.
 
-        :returns: The result set, if successful.
+        :returns: The subset data, if successful.
 
         :raises MalformedError: If the payload is rejected by the service.
         :raises ForbiddenError: If something went wrong with the authorization.
@@ -1631,11 +1614,7 @@ class RestClient:
             url += f'?page={page}&size={size}'
         response = self._wrapper(method="get", url=url, headers=headers)
         if response.status_code == 200:
-            body = response.json()
-            res = Result.model_validate(body)
-            if df:
-                return DataFrame.from_records(res.result)
-            return res
+            return DataFrame.from_records(response.json())
         if response.status_code == 400:
             raise MalformedError(f'Failed to get query data: {response.text}')
         if response.status_code == 403:
@@ -1936,7 +1915,7 @@ class RestClient:
 
         :returns: List of licenses, if successful.
         """
-        url = f'/api/database/license'
+        url = f'/api/license'
         response = self._wrapper(method="get", url=url)
         if response.status_code == 200:
             body = response.json()
diff --git a/lib/python/dbrepo/api/dto.py b/lib/python/dbrepo/api/dto.py
index 4de986e870..e54d1eba16 100644
--- a/lib/python/dbrepo/api/dto.py
+++ b/lib/python/dbrepo/api/dto.py
@@ -1,10 +1,11 @@
 from __future__ import annotations
 
+import datetime
 from dataclasses import field
 from enum import Enum
-import datetime
-from typing import List, Optional, Any, Annotated
-from pydantic import BaseModel, ConfigDict, PlainSerializer, Field
+from typing import List, Optional, Annotated
+
+from pydantic import BaseModel, PlainSerializer, Field
 
 Timestamp = Annotated[
     datetime.datetime, PlainSerializer(lambda v: v.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z', return_type=str)
@@ -638,12 +639,6 @@ class CreateView(BaseModel):
     is_public: bool
 
 
-class Result(BaseModel):
-    result: Any
-    headers: Any
-    id: Optional[int] = None
-
-
 class ViewBrief(BaseModel):
     id: int
     database_id: int
@@ -874,8 +869,8 @@ class DataType(BaseModel):
     display_name: str
     value: str
     documentation: str
-    is_quoted:  bool
-    is_buildable:  bool
+    is_quoted: bool
+    is_buildable: bool
     size_min: Optional[int] = None
     size_max: Optional[int] = None
     size_default: Optional[int] = None
@@ -884,8 +879,8 @@ class DataType(BaseModel):
     d_max: Optional[int] = None
     d_default: Optional[int] = None
     d_required: Optional[bool] = None
-    data_hint:  Optional[str] = None
-    type_hint:  Optional[str] = None
+    data_hint: Optional[str] = None
+    type_hint: Optional[str] = None
 
 
 class Column(BaseModel):
diff --git a/lib/python/tests/test_unit_license.py b/lib/python/tests/test_unit_license.py
index 2efb613c42..7f2a52890e 100644
--- a/lib/python/tests/test_unit_license.py
+++ b/lib/python/tests/test_unit_license.py
@@ -12,7 +12,7 @@ class DatabaseUnitTest(unittest.TestCase):
     def test_get_licenses_empty_succeeds(self):
         with requests_mock.Mocker() as mock:
             # mock
-            mock.get('/api/database/license', json=[])
+            mock.get('/api/license', json=[])
             # test
             response = RestClient().get_licenses()
             self.assertEqual([], response)
@@ -22,7 +22,7 @@ class DatabaseUnitTest(unittest.TestCase):
             exp = [License(identifier='CC-BY-4.0', uri='https://creativecommons.org/licenses/by/4.0/',
                            description='The Creative Commons Attribution license allows re-distribution and re-use of a licensed work on the condition that the creator is appropriately credited.')]
             # mock
-            mock.get('/api/database/license', json=[exp[0].model_dump()])
+            mock.get('/api/license', json=[exp[0].model_dump()])
             # test
             response = RestClient().get_licenses()
             self.assertEqual(exp, response)
diff --git a/lib/python/tests/test_unit_query.py b/lib/python/tests/test_unit_query.py
index e1b326fa57..be0982d535 100644
--- a/lib/python/tests/test_unit_query.py
+++ b/lib/python/tests/test_unit_query.py
@@ -1,3 +1,4 @@
+import json
 import unittest
 
 import requests_mock
@@ -6,25 +7,23 @@ import datetime
 from dbrepo.RestClient import RestClient
 from pandas import DataFrame
 
-from dbrepo.api.dto import Result, Query, User, UserAttributes, QueryType
-from dbrepo.api.exceptions import MalformedError, NotExistsError, ForbiddenError, QueryStoreError, \
-    MetadataConsistencyError, AuthenticationError
+from dbrepo.api.dto import Query, User, UserAttributes, QueryType
+from dbrepo.api.exceptions import MalformedError, NotExistsError, ForbiddenError
 
 
 class QueryUnitTest(unittest.TestCase):
 
     def test_create_subset_succeeds(self):
         with requests_mock.Mocker() as mock:
-            exp = Result(result=[{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}],
-                         headers=[{'id': 0, 'username': 1}],
-                         id=None)
+            exp = [{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}]
+            df = DataFrame.from_records(json.dumps(exp))
             # mock
-            mock.post('/api/database/1/subset', json=exp.model_dump(), status_code=201)
+            mock.post('/api/database/1/subset', json=json.dumps(exp), headers={'X-Id': '1'}, status_code=201)
             # test
             client = RestClient(username="a", password="b")
             response = client.create_subset(database_id=1, page=0, size=10,
                                             query="SELECT id, username FROM some_table WHERE id IN (1,2)")
-            self.assertEqual(exp, response)
+            self.assertTrue(DataFrame.equals(df, response))
 
     def test_create_subset_malformed_fails(self):
         with requests_mock.Mocker() as mock:
@@ -64,17 +63,16 @@ class QueryUnitTest(unittest.TestCase):
 
     def test_create_subset_not_auth_succeeds(self):
         with requests_mock.Mocker() as mock:
-            exp = Result(result=[{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}],
-                         headers=[{'id': 0, 'username': 1}],
-                         id=None)
+            exp = [{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}]
+            df = DataFrame.from_records(json.dumps(exp))
             # mock
-            mock.post('/api/database/1/subset', json=exp.model_dump(), status_code=201)
+            mock.post('/api/database/1/subset', json=json.dumps(exp), headers={'X-Id': '1'}, status_code=201)
             # test
 
             client = RestClient()
             response = client.create_subset(database_id=1, page=0, size=10,
                                             query="SELECT id, username FROM some_table WHERE id IN (1,2)")
-            self.assertEqual(exp, response)
+            self.assertTrue(DataFrame.equals(df, response))
 
     def test_find_query_succeeds(self):
         with requests_mock.Mocker() as mock:
@@ -173,27 +171,24 @@ class QueryUnitTest(unittest.TestCase):
 
     def test_get_subset_data_succeeds(self):
         with requests_mock.Mocker() as mock:
-            exp = Result(result=[{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}],
-                         headers=[{'id': 0, 'username': 1}],
-                         id=6)
+            exp = [{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}]
+            df = DataFrame.from_records(json.dumps(exp))
             # mock
-            mock.get('/api/database/1/subset/6/data', json=exp.model_dump())
+            mock.get('/api/database/1/subset/6/data', json=json.dumps(exp))
             # test
             response = RestClient().get_subset_data(database_id=1, subset_id=6)
-            self.assertEqual(exp, response)
+            self.assertTrue(DataFrame.equals(df, response))
 
     def test_get_subset_data_dataframe_succeeds(self):
         with requests_mock.Mocker() as mock:
-            res = Result(result=[{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}],
-                         headers=[{'id': 0, 'username': 1}],
-                         id=6)
-            exp = DataFrame.from_records(res.model_dump()['result'])
+            exp = [{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}]
+            df = DataFrame.from_records(json.dumps(exp))
             # mock
-            mock.get('/api/database/1/subset/6/data', json=res.model_dump())
+            mock.get('/api/database/1/subset/6/data', json=json.dumps(exp))
             # test
-            response = RestClient().get_subset_data(database_id=1, subset_id=6, df=True)
-            self.assertEqual(exp.shape, response.shape)
-            self.assertTrue(DataFrame.equals(exp, response))
+            response = RestClient().get_subset_data(database_id=1, subset_id=6)
+            self.assertEqual(df.shape, response.shape)
+            self.assertTrue(DataFrame.equals(df, response))
 
     def test_get_subset_data_not_allowed_fails(self):
         with requests_mock.Mocker() as mock:
diff --git a/lib/python/tests/test_unit_table.py b/lib/python/tests/test_unit_table.py
index 0be3a4a9fb..b6b7eacafc 100644
--- a/lib/python/tests/test_unit_table.py
+++ b/lib/python/tests/test_unit_table.py
@@ -1,3 +1,4 @@
+import json
 import unittest
 from json import dumps
 
@@ -7,7 +8,7 @@ import datetime
 from dbrepo.RestClient import RestClient
 from pandas import DataFrame
 
-from dbrepo.api.dto import Table, CreateTableConstraints, UserAttributes, User, Column, Constraints, ColumnType, Result, \
+from dbrepo.api.dto import Table, CreateTableConstraints, UserAttributes, User, Column, Constraints, ColumnType, \
     Concept, Unit, TableStatistics, ColumnStatistic, PrimaryKey, TableMinimal, ColumnMinimal, TableBrief, UserBrief
 from dbrepo.api.exceptions import MalformedError, ForbiddenError, NotExistsError, NameExistsError, QueryStoreError, \
     AuthenticationError, ExternalSystemError
@@ -242,27 +243,24 @@ class TableUnitTest(unittest.TestCase):
 
     def test_get_table_data_succeeds(self):
         with requests_mock.Mocker() as mock:
-            exp = Result(result=[{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}],
-                         headers=[{'id': 0, 'username': 1}],
-                         id=None)
+            exp = [{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}]
+            df = DataFrame.from_records(json.dumps(exp))
             # mock
-            mock.get('/api/database/1/table/9/data', json=exp.model_dump())
+            mock.get('/api/database/1/table/9/data', json=json.dumps(exp))
             # test
             response = RestClient().get_table_data(database_id=1, table_id=9)
-            self.assertEqual(exp, response)
+            self.assertTrue(DataFrame.equals(df, response))
 
     def test_get_table_data_dataframe_succeeds(self):
         with requests_mock.Mocker() as mock:
-            res = Result(result=[{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}],
-                         headers=[{'id': 0, 'username': 1}],
-                         id=None)
-            exp = DataFrame.from_records(res.model_dump()['result'])
+            exp = [{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}]
+            df = DataFrame.from_records(json.dumps(exp))
             # mock
-            mock.get('/api/database/1/table/9/data', json=res.model_dump())
+            mock.get('/api/database/1/table/9/data', json=json.dumps(exp))
             # test
-            response = RestClient().get_table_data(database_id=1, table_id=9, df=True)
-            self.assertEqual(exp.shape, response.shape)
-            self.assertTrue(DataFrame.equals(exp, response))
+            response = RestClient().get_table_data(database_id=1, table_id=9)
+            self.assertEqual(df.shape, response.shape)
+            self.assertTrue(DataFrame.equals(df, response))
 
     def test_get_table_data_malformed_fails(self):
         with requests_mock.Mocker() as mock:
diff --git a/lib/python/tests/test_unit_view.py b/lib/python/tests/test_unit_view.py
index 19a88be85a..30fa1d0cc1 100644
--- a/lib/python/tests/test_unit_view.py
+++ b/lib/python/tests/test_unit_view.py
@@ -1,3 +1,4 @@
+import json
 import unittest
 from json import dumps
 
@@ -7,7 +8,7 @@ import datetime
 from dbrepo.RestClient import RestClient
 from pandas import DataFrame
 
-from dbrepo.api.dto import UserAttributes, User, View, Result, ViewColumn, ColumnType
+from dbrepo.api.dto import UserAttributes, User, View, ViewColumn, ColumnType
 from dbrepo.api.exceptions import ForbiddenError, NotExistsError, MalformedError, AuthenticationError
 
 
@@ -211,27 +212,24 @@ class ViewUnitTest(unittest.TestCase):
 
     def test_get_view_data_succeeds(self):
         with requests_mock.Mocker() as mock:
-            exp = Result(result=[{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}],
-                         headers=[{'id': 0, 'username': 1}],
-                         id=None)
+            exp = [{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}]
+            df = DataFrame.from_records(json.dumps(exp))
             # mock
-            mock.get('/api/database/1/view/3/data', json=exp.model_dump())
+            mock.get('/api/database/1/view/3/data', json=json.dumps(exp))
             # test
             response = RestClient().get_view_data(database_id=1, view_id=3)
-            self.assertEqual(exp, response)
+            self.assertTrue(DataFrame.equals(df, response))
 
     def test_get_view_data_dataframe_succeeds(self):
         with requests_mock.Mocker() as mock:
-            res = Result(result=[{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}],
-                         headers=[{'id': 0, 'username': 1}],
-                         id=None)
-            exp = DataFrame.from_records(res.model_dump()['result'])
+            exp = [{'id': 1, 'username': 'foo'}, {'id': 2, 'username': 'bar'}]
+            df = DataFrame.from_records(json.dumps(exp))
             # mock
-            mock.get('/api/database/1/view/3/data', json=res.model_dump())
+            mock.get('/api/database/1/view/3/data', json=json.dumps(exp))
             # test
-            response: DataFrame = RestClient().get_view_data(database_id=1, view_id=3, df=True)
-            self.assertEqual(exp.shape, response.shape)
-            self.assertTrue(DataFrame.equals(exp, response))
+            response: DataFrame = RestClient().get_view_data(database_id=1, view_id=3)
+            self.assertEqual(df.shape, response.shape)
+            self.assertTrue(DataFrame.equals(df, response))
 
     def test_get_view_data_malformed_fails(self):
         with requests_mock.Mocker() as mock:
-- 
GitLab