|
7 | 7 | import warnings
|
8 | 8 | from fnmatch import fnmatch
|
9 | 9 |
|
| 10 | +from jupyter_events import EventLogger |
10 | 11 | from nbformat import ValidationError, sign
|
11 | 12 | from nbformat import validate as validate_nb
|
12 | 13 | from nbformat.v4 import new_notebook
|
|
25 | 26 | )
|
26 | 27 | from traitlets.config.configurable import LoggingConfigurable
|
27 | 28 |
|
| 29 | +from jupyter_server import DEFAULT_EVENTS_SCHEMA_PATH, JUPYTER_SERVER_EVENTS_URI |
28 | 30 | from jupyter_server.transutils import _i18n
|
29 | 31 | from jupyter_server.utils import ensure_async, import_item
|
30 | 32 |
|
@@ -53,6 +55,24 @@ class ContentsManager(LoggingConfigurable):
|
53 | 55 |
|
54 | 56 | """
|
55 | 57 |
|
| 58 | + event_schema_id = JUPYTER_SERVER_EVENTS_URI + "/contents_service/v1" |
| 59 | + event_logger = Instance(EventLogger).tag(config=True) |
| 60 | + |
| 61 | + @default("event_logger") |
| 62 | + def _default_event_logger(self): |
| 63 | + if self.parent and hasattr(self.parent, "event_logger"): |
| 64 | + return self.parent.event_logger |
| 65 | + else: |
| 66 | + # If parent does not have an event logger, create one. |
| 67 | + logger = EventLogger() |
| 68 | + schema_path = DEFAULT_EVENTS_SCHEMA_PATH / "contents_service" / "v1.yaml" |
| 69 | + logger.register_event_schema(schema_path) |
| 70 | + return logger |
| 71 | + |
| 72 | + def emit(self, data): |
| 73 | + """Emit event using the core event schema from Jupyter Server's Contents Manager.""" |
| 74 | + self.event_logger.emit(schema_id=self.event_schema_id, data=data) |
| 75 | + |
56 | 76 | root_dir = Unicode("/", config=True)
|
57 | 77 |
|
58 | 78 | allow_hidden = Bool(False, config=True, help="Allow access to hidden files")
|
@@ -416,11 +436,13 @@ def delete(self, path):
|
416 | 436 | raise HTTPError(400, "Can't delete root")
|
417 | 437 | self.delete_file(path)
|
418 | 438 | self.checkpoints.delete_all_checkpoints(path)
|
| 439 | + self.emit(data={"action": "delete", "path": path}) |
419 | 440 |
|
420 | 441 | def rename(self, old_path, new_path):
|
421 | 442 | """Rename a file and any checkpoints associated with that file."""
|
422 | 443 | self.rename_file(old_path, new_path)
|
423 | 444 | self.checkpoints.rename_all_checkpoints(old_path, new_path)
|
| 445 | + self.emit(data={"action": "rename", "path": new_path, "source_path": old_path}) |
424 | 446 |
|
425 | 447 | def update(self, model, path):
|
426 | 448 | """Update the file's path
|
@@ -616,6 +638,7 @@ def copy(self, from_path, to_path=None):
|
616 | 638 | raise HTTPError(404, "No such directory: %s" % to_path)
|
617 | 639 |
|
618 | 640 | model = self.save(model, to_path)
|
| 641 | + self.emit(data={"action": "copy", "path": to_path, "source_path": from_path}) |
619 | 642 | return model
|
620 | 643 |
|
621 | 644 | def log_info(self):
|
@@ -819,11 +842,13 @@ async def delete(self, path):
|
819 | 842 |
|
820 | 843 | await self.delete_file(path)
|
821 | 844 | await self.checkpoints.delete_all_checkpoints(path)
|
| 845 | + self.emit(data={"action": "delete", "path": path}) |
822 | 846 |
|
823 | 847 | async def rename(self, old_path, new_path):
|
824 | 848 | """Rename a file and any checkpoints associated with that file."""
|
825 | 849 | await self.rename_file(old_path, new_path)
|
826 | 850 | await self.checkpoints.rename_all_checkpoints(old_path, new_path)
|
| 851 | + self.emit(data={"action": "rename", "path": new_path, "source_path": old_path}) |
827 | 852 |
|
828 | 853 | async def update(self, model, path):
|
829 | 854 | """Update the file's path
|
@@ -985,6 +1010,7 @@ async def copy(self, from_path, to_path=None):
|
985 | 1010 | raise HTTPError(404, "No such directory: %s" % to_path)
|
986 | 1011 |
|
987 | 1012 | model = await self.save(model, to_path)
|
| 1013 | + self.emit(data={"action": "copy", "path": to_path, "source_path": from_path}) |
988 | 1014 | return model
|
989 | 1015 |
|
990 | 1016 | async def trust_notebook(self, path):
|
|
0 commit comments