test_dashboards passes

This commit is contained in:
Allen Short 2016-11-29 14:58:04 -06:00
parent bb755b5c25
commit dff39a6849
4 changed files with 41 additions and 31 deletions

View File

@ -3,9 +3,10 @@ from itertools import chain
from flask import request, url_for
from flask_restful import abort
from funcy import distinct, project, take
from sqlalchemy.orm.exc import StaleDataError
from redash import models, serializers
from redash.handlers.base import BaseResource, get_object_or_404
from redash.models import ConflictDetectedError
from redash.permissions import (can_modify, require_admin_or_owner,
require_object_modify_permission,
require_permission)
@ -37,9 +38,10 @@ class DashboardListResource(BaseResource):
user=self.current_user,
is_draft=True,
layout='[]')
models.db.session.add(dashboard)
models.db.session.commit()
return dashboard.to_dict()
class DashboardResource(BaseResource):
@require_permission('list_dashboards')
def get(self, dashboard_slug=None):
@ -63,13 +65,23 @@ class DashboardResource(BaseResource):
require_object_modify_permission(dashboard, self.current_user)
updates = project(dashboard_properties, ('name', 'layout', 'version',
'is_draft'))
# SQLAlchemy handles the case where a concurrent transaction beats us
# to the update. But we still have to make sure that we're not starting
# out behind.
if 'version' in updates and updates['version'] != dashboard.version:
abort(409)
updates['changed_by'] = self.current_user
self.update_model(dashboard, updates)
models.db.session.add(dashboard)
try:
dashboard.update_instance(**updates)
except ConflictDetectedError:
models.db.session.commit()
except StaleDataError:
abort(409)
result = dashboard.to_dict(with_widgets=True, user=self.current_user)
@ -79,9 +91,11 @@ class DashboardResource(BaseResource):
def delete(self, dashboard_slug):
dashboard = models.Dashboard.get_by_slug_and_org(dashboard_slug, self.current_org)
dashboard.is_archived = True
dashboard.save(changed_by=self.current_user)
return dashboard.to_dict(with_widgets=True, user=self.current_user)
dashboard.record_changes(changed_by=self.current_user)
models.db.session.add(dashboard)
d = dashboard.to_dict(with_widgets=True, user=self.current_user)
models.db.session.commit()
return d
class PublicDashboardResource(BaseResource):
@ -100,6 +114,7 @@ class DashboardShareResource(BaseResource):
dashboard = models.Dashboard.get_by_id_and_org(dashboard_id, self.current_org)
require_admin_or_owner(dashboard.user_id)
api_key = models.ApiKey.create_for_object(dashboard, self.current_user)
models.db.session.flush()
public_url = url_for('redash.public_dashboard', token=api_key.api_key, org_slug=self.current_org.slug, _external=True)
self.record_event({
@ -117,10 +132,11 @@ class DashboardShareResource(BaseResource):
if api_key:
api_key.active = False
api_key.save()
models.db.session.add(api_key)
self.record_event({
'action': 'deactivate_api_key',
'object_id': dashboard.id,
'object_type': 'dashboard',
})
models.db.session.commit()

View File

@ -894,7 +894,7 @@ class AccessPermission(GFKBase, db.Model):
@classmethod
def find(cls, obj, access_type=None, grantee=None, grantor=None):
return cls._query(cls.select(cls), obj, access_type, grantee, grantor)
return cls._query(obj, access_type, grantee, grantor)
@classmethod
def exists(cls, obj, access_type, grantee):
@ -902,7 +902,8 @@ class AccessPermission(GFKBase, db.Model):
@classmethod
def _query(cls, obj, access_type=None, grantee=None, grantor=None):
q = cls.query.filter(cls.object_id==obj.id, cls.object_type==obj.__tablename__)
q = cls.query.filter(cls.object_id == obj.id,
cls.object_type == obj.__tablename__)
if access_type:
q.filter(AccessPermission.access_type == access_type)
@ -1076,18 +1077,14 @@ class Dashboard(ChangeTrackingMixin, TimestampMixin, BelongsToOrgMixin, db.Model
layout = json.loads(self.layout)
if with_widgets:
widget_list = Widget.select(Widget, Visualization, Query, User)\
.where(Widget.dashboard == self.id)\
.join(Visualization, join_type=peewee.JOIN_LEFT_OUTER)\
.join(Query, join_type=peewee.JOIN_LEFT_OUTER)\
.join(User, join_type=peewee.JOIN_LEFT_OUTER)
widget_list = Widget.query.filter(Widget.dashboard == self)
widgets = {}
for w in widget_list:
if w.visualization_id is None:
widgets[w.id] = w.to_dict()
elif user and has_access(w.visualization.query.groups, user, view_only):
elif user and has_access(w.visualization.query_rel.groups, user, view_only):
widgets[w.id] = w.to_dict()
else:
widgets[w.id] = project(w.to_dict(),
@ -1175,7 +1172,7 @@ class Dashboard(ChangeTrackingMixin, TimestampMixin, BelongsToOrgMixin, db.Model
@classmethod
def get_by_slug_and_org(cls, slug, org):
return cls.get(cls.slug == slug, cls.org==org)
return cls.query.filter(cls.slug == slug, cls.org==org).one()
def tracked_save(self, changing_user, old_object=None, *args, **kwargs):
self.version += 1
@ -1330,11 +1327,13 @@ class ApiKey(TimestampMixin, GFKBase, db.Model):
@classmethod
def get_by_object(cls, object):
return cls.select().where(cls.object_type==object._meta.db_table, cls.object_id==object.id, cls.active==True).first()
return cls.query.filter(cls.object_type==object.__class__.__tablename__, cls.object_id==object.id, cls.active==True).first()
@classmethod
def create_for_object(cls, object, user):
return cls.create(org=user.org, object=object, created_by=user)
k = cls(org=user.org, object=object, created_by=user)
db.session.add(k)
return k
class NotificationDestination(BelongsToOrgMixin, db.Model):

View File

@ -52,7 +52,7 @@ class TestInvitePost(BaseTestCase):
password = 'test1234'
response = self.post_request('/invite/{}'.format(token), data={'password': password}, org=self.factory.org)
self.assertEqual(response.status_code, 302)
user = User.get_by_id(self.factory.user.id)
user = User.query.get(self.factory.user.id)
self.assertTrue(user.verify_password(password))

View File

@ -1,6 +1,6 @@
import json
from tests import BaseTestCase
from redash.models import ApiKey, Dashboard, AccessPermission
from redash.models import ApiKey, Dashboard, AccessPermission, db
from redash.permissions import ACCESS_TYPE_MODIFY
@ -30,15 +30,14 @@ class TestDashboardResourceGet(BaseTestCase):
restricted_ds = self.factory.create_data_source(group=self.factory.create_group())
query = self.factory.create_query(data_source=restricted_ds)
vis = self.factory.create_visualization(query=query)
vis = self.factory.create_visualization(query_rel=query)
restricted_widget = self.factory.create_widget(visualization=vis, dashboard=dashboard)
widget = self.factory.create_widget(dashboard=dashboard)
dashboard.layout = '[[{}, {}]]'.format(widget.id, restricted_widget.id)
dashboard.save()
db.session.commit()
rv = self.make_request('get', '/api/dashboards/{0}'.format(dashboard.slug))
self.assertEquals(rv.status_code, 200)
self.assertTrue(rv.json['widgets'][0][1]['restricted'])
self.assertNotIn('restricted', rv.json['widgets'][0][0])
@ -59,8 +58,7 @@ class TestDashboardResourcePost(BaseTestCase):
def test_raises_error_in_case_of_conflict(self):
d = self.factory.create_dashboard()
d.name = 'Updated'
d.save()
db.session.commit()
new_name = 'New Name'
rv = self.make_request('post', '/api/dashboards/{0}'.format(d.id),
data={'name': new_name, 'layout': '[]', 'version': d.version - 1})
@ -70,7 +68,6 @@ class TestDashboardResourcePost(BaseTestCase):
def test_overrides_existing_if_no_version_specified(self):
d = self.factory.create_dashboard()
d.name = 'Updated'
d.save()
new_name = 'New Name'
rv = self.make_request('post', '/api/dashboards/{0}'.format(d.id),
@ -122,8 +119,7 @@ class TestDashboardShareResourcePost(BaseTestCase):
res = self.make_request('post', '/api/dashboards/{}/share'.format(dashboard.id), user=user)
self.assertEqual(res.status_code, 403)
user.groups.append(self.factory.org.admin_group.id)
user.save()
user.group_ids.append(self.factory.org.admin_group.id)
res = self.make_request('post', '/api/dashboards/{}/share'.format(dashboard.id), user=user)
self.assertEqual(res.status_code, 200)
@ -151,8 +147,7 @@ class TestDashboardShareResourceDelete(BaseTestCase):
res = self.make_request('delete', '/api/dashboards/{}/share'.format(dashboard.id), user=user)
self.assertEqual(res.status_code, 403)
user.groups.append(self.factory.org.admin_group.id)
user.save()
user.group_ids.append(self.factory.org.admin_group.id)
res = self.make_request('delete', '/api/dashboards/{}/share'.format(dashboard.id), user=user)
self.assertEqual(res.status_code, 200)