From 3621b7aa00c2d9c8416c5da6fd4d6cc2cb186cc4 Mon Sep 17 00:00:00 2001 From: "yohei.naruse" Date: Thu, 25 Aug 2016 17:56:07 +0900 Subject: [PATCH 1/4] add query fork to models.py --- models.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/models.py b/models.py index 4dd77eacb8..b95f02a304 100644 --- a/models.py +++ b/models.py @@ -837,6 +837,31 @@ def recent(cls, groups, user_id=None, limit=20): return query + @classmethod + def fork(cls, id, user, org): + query = cls.get_by_id_and_org(id, org) + forked_query = Query() + forked_query.name = 'Copy of (#{}) {}'.format(id, query.name) + forked_query.user = user + forked_list = ['org', 'data_source', 'latest_query_data', 'description', 'query', 'query_hash'] + for a in forked_list: + setattr(forked_query, a, getattr(query, a)) + forked_query.save() + + forked_visualizations = [] + for v in query.visualizations: + if v.type == 'TABLE': + continue + forked_v = v.to_dict() + forked_v['options'] = v.options + forked_v['query'] = forked_query + forked_v.pop('id') + forked_visualizations.append(forked_v) + + with db.database.atomic(): + Visualization.insert_many(forked_visualizations).execute() + return forked_query + def pre_save(self, created): super(Query, self).pre_save(created) self.query_hash = utils.gen_query_hash(self.query) From f49292bb170025e1ec6bc967abde53ee1d045aa3 Mon Sep 17 00:00:00 2001 From: "yohei.naruse" Date: Wed, 22 Jun 2016 23:49:10 +0900 Subject: [PATCH 2/4] add query fork api --- handlers/api.py | 3 ++- handlers/queries.py | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/handlers/api.py b/handlers/api.py index 7658e2687e..2db4f63c71 100644 --- a/handlers/api.py +++ b/handlers/api.py @@ -9,7 +9,7 @@ from redash.handlers.dashboards import DashboardListResource, RecentDashboardsResource, DashboardResource, DashboardShareResource from redash.handlers.data_sources import DataSourceTypeListResource, DataSourceListResource, DataSourceSchemaResource, DataSourceResource, DataSourcePauseResource, DataSourceTestResource from redash.handlers.events import EventResource -from redash.handlers.queries import QueryRefreshResource, QueryListResource, QueryRecentResource, QuerySearchResource, QueryResource, MyQueriesResource +from redash.handlers.queries import QueryForkResource, QueryRefreshResource, QueryListResource, QueryRecentResource, QuerySearchResource, QueryResource, MyQueriesResource from redash.handlers.query_results import QueryResultListResource, QueryResultResource, JobResource from redash.handlers.users import UserResource, UserListResource, UserInviteResource, UserResetPasswordResource from redash.handlers.visualizations import VisualizationListResource @@ -71,6 +71,7 @@ def json_representation(data, code, headers=None): api.add_org_resource(MyQueriesResource, '/api/queries/my', endpoint='my_queries') api.add_org_resource(QueryRefreshResource, '/api/queries//refresh', endpoint='query_refresh') api.add_org_resource(QueryResource, '/api/queries/', endpoint='query') +api.add_org_resource(QueryForkResource, '/api/queries//fork', endpoint='query_fork') api.add_org_resource(ObjectPermissionsListResource, '/api///acl', endpoint='object_permissions') api.add_org_resource(CheckPermissionResource, '/api///acl/', endpoint='check_permissions') diff --git a/handlers/queries.py b/handlers/queries.py index 4879e63f0b..049ada5bb9 100644 --- a/handlers/queries.py +++ b/handlers/queries.py @@ -138,6 +138,13 @@ def delete(self, query_id): query.archive(self.current_user) +class QueryForkResource(BaseResource): + @require_permission('edit_query') + def post(self, query_id): + query = get_object_or_404(models.Query.fork, query_id, self.current_user, self.current_org) + return query.to_dict(with_visualizations=True) + + class QueryRefreshResource(BaseResource): def post(self, query_id): query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) From bd36487ede6e20ba461c33d5c95fd836503bc01d Mon Sep 17 00:00:00 2001 From: "yohei.naruse" Date: Thu, 25 Aug 2016 20:19:24 +0900 Subject: [PATCH 3/4] fix bugs --- models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/models.py b/models.py index b95f02a304..14f435b2be 100644 --- a/models.py +++ b/models.py @@ -857,9 +857,10 @@ def fork(cls, id, user, org): forked_v['query'] = forked_query forked_v.pop('id') forked_visualizations.append(forked_v) - - with db.database.atomic(): - Visualization.insert_many(forked_visualizations).execute() + + if len(forked_visualizations) > 0: + with db.database.atomic(): + Visualization.insert_many(forked_visualizations).execute() return forked_query def pre_save(self, created): From 4de6df4f8ffa4e2633ccedd4794ad44e6200af9e Mon Sep 17 00:00:00 2001 From: "yohei.naruse" Date: Mon, 3 Oct 2016 02:07:20 +0900 Subject: [PATCH 4/4] apply review. --- handlers/queries.py | 5 +++-- models.py | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/handlers/queries.py b/handlers/queries.py index 049ada5bb9..5dae9cc9e5 100644 --- a/handlers/queries.py +++ b/handlers/queries.py @@ -141,8 +141,9 @@ def delete(self, query_id): class QueryForkResource(BaseResource): @require_permission('edit_query') def post(self, query_id): - query = get_object_or_404(models.Query.fork, query_id, self.current_user, self.current_org) - return query.to_dict(with_visualizations=True) + query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org) + forked_query = query.fork(self.current_user) + return forked_query.to_dict(with_visualizations=True) class QueryRefreshResource(BaseResource): diff --git a/models.py b/models.py index 14f435b2be..7a4aa43e0d 100644 --- a/models.py +++ b/models.py @@ -837,11 +837,10 @@ def recent(cls, groups, user_id=None, limit=20): return query - @classmethod - def fork(cls, id, user, org): - query = cls.get_by_id_and_org(id, org) + def fork(self, user): + query = self forked_query = Query() - forked_query.name = 'Copy of (#{}) {}'.format(id, query.name) + forked_query.name = 'Copy of (#{}) {}'.format(query.id, query.name) forked_query.user = user forked_list = ['org', 'data_source', 'latest_query_data', 'description', 'query', 'query_hash'] for a in forked_list: