Skip to content

Commit

Permalink
Merge pull request #3948 from mathesar-foundation/fix-500-commondata
Browse files Browse the repository at this point in the history
Fixes server errors when RPC exceptions are thrown while rendering common_data
  • Loading branch information
Anish9901 authored Oct 11, 2024
2 parents 72dacc9 + 5bec105 commit fe1e672
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 107 deletions.
12 changes: 5 additions & 7 deletions mathesar/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,16 @@
path('administration/users/', views.admin_home, name='admin_users_home'),
path('administration/users/<int:user_id>/', views.admin_home, name='admin_users_edit'),
path('administration/update/', views.admin_home, name='admin_update'),
path('shares/tables/<slug>/', views.shared_table, name='shared_table'),
path('shares/explorations/<slug>/', views.shared_query, name='shared_query'),
path('databases/', views.databases, name='databases'),
path('databases/', views.databases_list_route, name='databases_list_route'),
path('i18n/', include('django.conf.urls.i18n')),
re_path(
r'^db/(?P<database_id>\d+)/schemas/(?P<schema_id>\d+)/',
views.schemas_home,
name='schema_home'
views.schema_route,
name='schema_route'
),
re_path(
r'^db/(?P<database_id>\d+)/((schemas|settings)/)?',
views.schemas,
name='schemas'
views.database_route,
name='database_route'
),
]
149 changes: 53 additions & 96 deletions mathesar/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from functools import wraps

from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render, redirect
from modernrpc.views import RPCEntryPoint
from modernrpc.exceptions import RPCException
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
Expand All @@ -12,26 +15,43 @@
from mathesar.rpc.schemas import list_ as schemas_list
from mathesar.rpc.servers.configured import list_ as get_servers_list
from mathesar.rpc.tables import list_with_metadata as tables_list
from mathesar.api.serializers.tables import TableSerializer
from mathesar.api.serializers.queries import QuerySerializer
from mathesar.api.ui.serializers.users import UserSerializer
from mathesar.api.utils import is_valid_uuid_v4
from mathesar.models.shares import SharedTable, SharedQuery
from mathesar.state import reset_reflection
from mathesar import __version__


def get_database_list(request):
return databases_list(request=request)


def wrap_data_and_rpc_exceptions(f):
@wraps(f)
def safe_func(*args, **kwargs):
try:
return {
'state': 'success',
'data': f(*args, **kwargs)
}
except RPCException as exp:
return {
'state': 'failure',
'error': {
'code': exp.code,
'message': exp.message
}
}
return safe_func


@wrap_data_and_rpc_exceptions
def get_schema_list(request, database_id):
if database_id is not None:
return schemas_list(request=request, database_id=database_id)
else:
return []


def get_database_list(request):
return databases_list(request=request)


@wrap_data_and_rpc_exceptions
def get_table_list(request, database_id, schema_oid):
if database_id is not None and schema_oid is not None:
return tables_list(
Expand Down Expand Up @@ -76,74 +96,35 @@ def _get_internal_db_meta():
return {'type': 'sqlite'}


def _get_base_data_all_routes(request, database_id=None, schema_id=None):
def get_common_data(request, database_id=None, schema_oid=None):
databases = get_database_list(request)
database_id_int = int(database_id) if database_id else None
current_database = next((database for database in databases if database['id'] == database_id_int), None)
current_database_id = current_database['id'] if current_database else None

schemas = get_schema_list(request, current_database_id)
schema_oid_int = int(schema_oid) if schema_oid else None
schemas_data = schemas['data'] if 'data' in schemas else []
current_schema = next((schema for schema in schemas_data if schema['oid'] == schema_oid_int), None)
current_schema_oid = current_schema['oid'] if current_schema else None

return {
'current_database': int(database_id) if database_id else None,
'current_schema': int(schema_id) if schema_id else None,
'current_database': current_database_id,
'current_schema': current_schema_oid,
'current_release_tag_name': __version__,
'databases': get_database_list(request),
'servers': get_servers_list(),
'databases': databases,
'internal_db': _get_internal_db_meta(),
'is_authenticated': not request.user.is_anonymous,
'queries': [],
'schemas': get_schema_list(request, database_id),
'servers': get_servers_list(),
'schemas': schemas,
'supported_languages': dict(getattr(settings, 'LANGUAGES', [])),
'tables': [],
'user': get_user_data(request)
}


def get_common_data(request, database_id=None, schema_id=None):
return {
**_get_base_data_all_routes(request, database_id, schema_id),
'tables': get_table_list(request, database_id, schema_id),
'queries': get_queries_list(request, database_id, schema_id),
'tables': get_table_list(request, current_database_id, current_schema_oid),
'user': get_user_data(request),
'queries': get_queries_list(request, current_database_id, current_schema_oid),
'routing_context': 'normal',
}


def get_common_data_for_shared_entity(request, schema=None):
# TODO: Provide only authorized schemas & databases
# database = schema.database if schema else None
# schemas = [schema] if schema else []
# databases = [database] if database else []
return {
# **_get_base_data_all_routes(request, database, schema),
# 'schemas': serialized_schemas,
# 'databases': serialized_databases,
**_get_base_data_all_routes(request),
'routing_context': 'anonymous',
}


def get_common_data_for_shared_table(request, table):
tables = [table] if table else []
serialized_tables = TableSerializer(
tables,
many=True,
context={'request': request}
).data
schema = table.schema if table else None
return {
**get_common_data_for_shared_entity(request, schema),
'tables': serialized_tables,
}


def get_common_data_for_shared_query(request, query):
queries = [query] if query else []
serialized_queries = QuerySerializer(
queries,
many=True,
context={'request': request}
).data
schema = query.base_table.schema if query else None
return {
**get_common_data_for_shared_entity(request, schema),
'queries': serialized_queries,
}


class MathesarRPCEntryPoint(LoginRequiredMixin, RPCEntryPoint):
pass

Expand All @@ -160,18 +141,18 @@ def home(request):
database_list = get_database_list(request)
number_of_databases = len(database_list)
if number_of_databases > 1:
return redirect('databases')
return redirect('databases_list_route')
elif number_of_databases == 1:
db = database_list[0]
return redirect('schemas', database_id=db['id'])
return redirect('database_route', database_id=db['id'])
else:
return render(request, 'mathesar/index.html', {
'common_data': get_common_data(request)
})


@login_required
def databases(request):
def databases_list_route(request):
return render(request, 'mathesar/index.html', {
'common_data': get_common_data(request)
})
Expand All @@ -192,43 +173,19 @@ def admin_home(request, **kwargs):


@login_required
def schemas(request, database_id, **kwargs):
def database_route(request, database_id, **kwargs):
return render(request, 'mathesar/index.html', {
'common_data': get_common_data(request, database_id, None)
})


@login_required
def schemas_home(request, database_id, schema_id, **kwargs):
def schema_route(request, database_id, schema_id, **kwargs):
return render(request, 'mathesar/index.html', {
'common_data': get_common_data(request, database_id, schema_id)
})


def shared_table(request, slug):
shared_table_link = SharedTable.get_by_slug(slug) if is_valid_uuid_v4(slug) else None
table = shared_table_link.table if shared_table_link else None

return render(request, 'mathesar/index.html', {
'common_data': get_common_data_for_shared_table(request, table),
'route_specific_data': {
'shared_table': {'table_id': table.id if table else None}
}
})


def shared_query(request, slug):
shared_query_link = SharedQuery.get_by_slug(slug) if is_valid_uuid_v4(slug) else None
query = shared_query_link.query if shared_query_link else None

return render(request, 'mathesar/index.html', {
'common_data': get_common_data_for_shared_query(request, query),
'route_specific_data': {
'shared_query': {'query_id': query.id if query else None}
}
})


def page_not_found_view(request, exception):
return render(request, 'mathesar/index.html', {
'common_data': get_common_data(request),
Expand Down
13 changes: 12 additions & 1 deletion mathesar_ui/src/stores/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,18 @@ export const schemas = collapse(
const $schemasStore = get(schemasStore);
if ($schemasStore.databaseId !== $currentDatabase?.id) {
if (preload && commonData.current_database === $currentDatabase?.id) {
setSchemasInStore($currentDatabase, commonData.schemas);
if (commonData.schemas.state === 'success') {
setSchemasInStore($currentDatabase, commonData.schemas.data);
} else {
schemasStore.set({
databaseId: $currentDatabase.id,
requestStatus: {
state: 'failure',
errors: [getErrorMessage(commonData.schemas.error)],
},
data: new Map(),
});
}
} else {
void fetchSchemasForCurrentDatabase();
}
Expand Down
14 changes: 13 additions & 1 deletion mathesar_ui/src/stores/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,19 @@ export const currentTablesData = collapse(
commonData.current_schema === $currentSchema?.oid &&
commonData.current_database === $currentSchema?.database.id
) {
setTablesStore($currentSchema, commonData.tables);
if (commonData.tables.state === 'success') {
setTablesStore($currentSchema, commonData.tables.data);
} else {
tablesStore.set({
databaseId: $currentSchema.database.id,
schemaOid: $currentSchema.oid,
tablesMap: new Map(),
requestStatus: {
state: 'failure',
errors: [getErrorMessage(commonData.tables.error)],
},
});
}
} else {
void fetchTablesForCurrentSchema();
}
Expand Down
17 changes: 15 additions & 2 deletions mathesar_ui/src/utils/preloadData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,24 @@ import type { RawSchema } from '@mathesar/api/rpc/schemas';
import type { RawServer } from '@mathesar/api/rpc/servers';
import type { RawTableWithMetadata } from '@mathesar/api/rpc/tables';

type WithStatus<D> =
| {
state: 'success';
data: D;
}
| {
state: 'failure';
error: {
code: number;
message: string;
};
};

export interface CommonData {
databases: RawDatabase[];
servers: RawServer[];
schemas: RawSchema[];
tables: RawTableWithMetadata[];
schemas: WithStatus<RawSchema[]>;
tables: WithStatus<RawTableWithMetadata[]>;
queries: SavedExploration[];
current_database: RawDatabase['id'] | null;
internal_db: {
Expand Down

0 comments on commit fe1e672

Please sign in to comment.