settings_handler.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. """Tornado handlers for frontend config storage."""
  2. # Copyright (c) Jupyter Development Team.
  3. # Distributed under the terms of the Modified BSD License.
  4. from __future__ import annotations
  5. import json
  6. from typing import Any
  7. from jsonschema import ValidationError
  8. from jupyter_server.extension.handler import ExtensionHandlerJinjaMixin, ExtensionHandlerMixin
  9. from tornado import web
  10. from .settings_utils import SchemaHandler, get_settings, save_settings
  11. from .translation_utils import translator
  12. class SettingsHandler(ExtensionHandlerMixin, ExtensionHandlerJinjaMixin, SchemaHandler):
  13. """A settings API handler."""
  14. def initialize( # type:ignore[override]
  15. self,
  16. name: str,
  17. app_settings_dir: str,
  18. schemas_dir: str,
  19. settings_dir: str,
  20. labextensions_path: list[str],
  21. overrides: dict[str, Any] | None = None,
  22. **kwargs: Any, # noqa: ARG002
  23. ) -> None:
  24. """Initialize the handler."""
  25. SchemaHandler.initialize(
  26. self, app_settings_dir, schemas_dir, settings_dir, labextensions_path, overrides
  27. )
  28. ExtensionHandlerMixin.initialize(self, name)
  29. @web.authenticated
  30. def get(self, schema_name: str = "") -> Any:
  31. """
  32. Get setting(s)
  33. Parameters
  34. ----------
  35. schema_name: str
  36. The id of a unique schema to send, added to the URL
  37. ## NOTES:
  38. An optional argument `ids_only=true` can be provided in the URL to get only the
  39. ids of the schemas instead of the content.
  40. """
  41. # Need to be update here as translator locale is not change when a new locale is put
  42. # from frontend
  43. locale = self.get_current_locale()
  44. translator.set_locale(locale)
  45. ids_only = self.get_argument("ids_only", "") == "true"
  46. result, warnings = get_settings(
  47. self.app_settings_dir,
  48. self.schemas_dir,
  49. self.settings_dir,
  50. labextensions_path=self.labextensions_path,
  51. schema_name=schema_name,
  52. overrides=self.overrides,
  53. translator=translator.translate_schema,
  54. ids_only=ids_only,
  55. )
  56. # Print all warnings.
  57. for w in warnings:
  58. if w:
  59. self.log.warning(w)
  60. return self.finish(json.dumps(result))
  61. @web.authenticated
  62. def put(self, schema_name: str) -> None:
  63. """Update a setting"""
  64. overrides = self.overrides
  65. schemas_dir = self.schemas_dir
  66. settings_dir = self.settings_dir
  67. settings_error = "No current settings directory"
  68. invalid_json_error = "Failed parsing JSON payload: %s"
  69. invalid_payload_format_error = (
  70. "Invalid format for JSON payload. Must be in the form {'raw': ...}"
  71. )
  72. validation_error = "Failed validating input: %s"
  73. if not settings_dir:
  74. raise web.HTTPError(500, settings_error)
  75. raw_payload = self.request.body.strip().decode("utf-8")
  76. try:
  77. raw_settings = json.loads(raw_payload)["raw"]
  78. save_settings(
  79. schemas_dir,
  80. settings_dir,
  81. schema_name,
  82. raw_settings,
  83. overrides,
  84. self.labextensions_path,
  85. )
  86. except json.decoder.JSONDecodeError as e:
  87. raise web.HTTPError(400, invalid_json_error % str(e)) from None
  88. except (KeyError, TypeError):
  89. raise web.HTTPError(400, invalid_payload_format_error) from None
  90. except ValidationError as e:
  91. raise web.HTTPError(400, validation_error % str(e)) from None
  92. self.set_status(204)