From cf4291738e1087dd010a1828261ad9fb4e1bba39 Mon Sep 17 00:00:00 2001 From: DerGrumpf Date: Tue, 16 Sep 2025 16:03:19 +0200 Subject: [PATCH] Finished: Now its a Personal Project --- jupyterhub/Dockerfile | 3 -- jupyterhub/compose.yml | 3 -- jupyterhub/jupyterhub_config.py | 35 -------------------- jupyterhub/nbgrader/nbgrader_config.py | 30 ----------------- jupyterhub/nbgrader_config.py | 44 ------------------------- jupyterhub/templates/logo.png | Bin 11257 -> 573 bytes 6 files changed, 115 deletions(-) delete mode 100644 jupyterhub/nbgrader/nbgrader_config.py delete mode 100644 jupyterhub/nbgrader_config.py diff --git a/jupyterhub/Dockerfile b/jupyterhub/Dockerfile index ead7e15..5a37f23 100644 --- a/jupyterhub/Dockerfile +++ b/jupyterhub/Dockerfile @@ -23,9 +23,6 @@ RUN pip install --no-cache-dir \ dockerspawner \ jupyterhub-nativeauthenticator \ jupyterhub-dummyauthenticator \ - nbgrader \ - ngshare \ - ngshare-exchange \ psycopg2-binary RUN mkdir -p /srv/nbgrader \ diff --git a/jupyterhub/compose.yml b/jupyterhub/compose.yml index 015d6c6..0427655 100644 --- a/jupyterhub/compose.yml +++ b/jupyterhub/compose.yml @@ -11,9 +11,6 @@ services: - /var/run/docker.sock:/var/run/docker.sock - ./templates:/srv/jupyterhub/templates:ro - ./jupyterhub_config.py:/srv/jupyterhub/jupyterhub_config.py - - ./nbgrader_config.py:/srv/jupyterhub/nbgrader/nbgrader_config.py:ro - - ../nbgrader/exchange:/srv/nbgrader/exchange - - ../nbgrader/courses:/srv/nbgrader/courses # Just the Hacky way to pull images at startup # It just pulls the image but they wont startup diff --git a/jupyterhub/jupyterhub_config.py b/jupyterhub/jupyterhub_config.py index c14bfc6..323002a 100644 --- a/jupyterhub/jupyterhub_config.py +++ b/jupyterhub/jupyterhub_config.py @@ -156,38 +156,3 @@ c.JupyterHub.concurrent_spawn_limit = 10 # Allow named servers c.JupyterHub.allow_named_servers = True c.JupyterHub.named_server_limit_per_user = 3 - -# ngshare service configuration -c.JupyterHub.services.append( - { - "name": "ngshare", - "url": "http://127.0.0.1:10101", - "command": [ - "python3", - "-m", - "ngshare", - "--admins", - "admin", - "--debug" if ds_debug else "", - ], - "environment": { - "JUPYTERHUB_SERVICE_URL": "http://127.0.0.1:10101", - "JUPYTERHUB_SERVICE_REDIRECT_URL": f"{base_url}services/ngshare/", - "JUPYTERHUB_BASE_URL": base_url, - }, - } -) - -# Additional ngshare configuration -c.JupyterHub.load_roles = [ - { - "name": "ngshare", - "scopes": [ - "admin:servers", - "access:services", - "list:users", - "read:users:activity", - ], - "services": ["ngshare"], - } -] diff --git a/jupyterhub/nbgrader/nbgrader_config.py b/jupyterhub/nbgrader/nbgrader_config.py deleted file mode 100644 index 0e8e798..0000000 --- a/jupyterhub/nbgrader/nbgrader_config.py +++ /dev/null @@ -1,30 +0,0 @@ -# /srv/nbgrader/nbgrader_config.py -c = get_config() - -# 1. Course Configuration -c.CourseDirectory.course_id = "intro-to-python" # Change to your course name -c.CourseDirectory.root = '/srv/nbgrader/courses' - -# 2. Exchange Directory (for submitting/collecting assignments) -c.Exchange.root = '/srv/nbgrader/exchange' -c.Exchange.path_includes_course = True - -# 3. JupyterHub Integration -#c.NbGrader.hub_url = 'http://jupyterhub:8081/hub/api' -#c.NbGrader.hubapi_token = 'your-hub-token' # Generate with: openssl rand -hex 32 - -# 4. Database Configuration -c.StudentAssignmentNotebook.database_url = 'sqlite:////srv/nbgrader/nbgrader.sqlite' - -# 5. Assignment Policies -c.ExecutePreprocessor.timeout = 300 # 5 minutes timeout per cell -c.ClearSolutions.code_stub = "# YOUR CODE HERE" -c.ClearSolutions.text_stub = "YOUR ANSWER HERE" - -# 6. Formgrader UI Settings -c.FormgradeApp.port = 9999 -c.FormgradeApp.authenticator_class = 'nbgrader.auth.hubauth.HubAuth' -c.FormgradeApp.ip = '0.0.0.0' - -# 7. Permissions -c.CourseDirectory.groupshared = True diff --git a/jupyterhub/nbgrader_config.py b/jupyterhub/nbgrader_config.py deleted file mode 100644 index 9ba770b..0000000 --- a/jupyterhub/nbgrader_config.py +++ /dev/null @@ -1,44 +0,0 @@ -import os - -c = get_config() - -# Database configuration - use the same PostgreSQL as JupyterHub -p_user = os.environ.get("POSTGRES_USER", "") -p_pass = os.environ.get("POSTGRES_PASSWORD", "") -p_host = os.environ.get("POSTGRES_HOST", "postgres") -p_db = os.environ.get("POSTGRES_DB", "jupyterhub") - -# NBgrader database URL -c.CourseDirectory.db_url = f"postgresql://{p_user}:{p_pass}@{p_host}:5432/{p_db}" - -# Course configuration -course_id = os.environ.get("NBGRADER_COURSE_ID", "default_course") -c.CourseDirectory.course_id = course_id -c.CourseDirectory.root = "/srv/nbgrader" - -# Exchange directory configuration -exchange_dir = os.environ.get("NBGRADER_EXCHANGE_DIRECTORY", "/srv/nbgrader/exchange") -c.Exchange.root = exchange_dir -c.CourseDirectory.course_id = course_id - -# Authentication -c.FormgradeApp.authenticator_plugin_class = "nbgrader.auth.JupyterHubAuthPlugin" - -# Logging -c.Application.log_level = "INFO" - -# Formgrader settings -c.FormgradeApp.ip = "0.0.0.0" -c.FormgradeApp.port = 9999 -c.FormgradeApp.base_url = "/jupyter/services/nbgrader-formgrader/" - -# Enable tornado debug mode for development -c.FormgradeApp.tornado_settings = {"debug": True} - -# Assignment settings -c.AssignmentListApp.assignment_dir = "/home/jovyan/assignments" -c.AssignmentListApp.exchange_directory = exchange_dir - -# Grader settings -c.AutogradeApp.force = True -c.GenerateAssignmentApp.force = True diff --git a/jupyterhub/templates/logo.png b/jupyterhub/templates/logo.png index 5d90a034d39f5cbededfa16018c1cb83c1cbb35a..670b7cb73f9ef2faa6d23e156018f08f160fbc84 100644 GIT binary patch literal 573 zcmV-D0>b@?P))I$%2f)wn* zUaNw(s7cjSTQx1s$2`W` z3spRj9FGL24Z%rBSHq?mpT@W3$eUQKcS#3>(xtDqgWhgbHZi-I_ceGIB2vQ0-v8ij z-5(l;rrVVdoMzipM^Mh zrQohANUqUXBJhG`fXiY|pX+($%QXDIC935RJRf{oJHTCF=mctMRikHRByy z29PNk`wt*v9yCudiQ~BESzL#W4+-YaZPhEdlm4*MuQ4siHd zCF&K40cx{^qc;l8^<)`Z18`Rf)ft8J-Q-zXs{xsUvCIKPhM!W&=`#Cox#Y-arvP%- zqglEC08~Z=1HHp(A0c{%)6RHa!GMv(+)EmTX?zNoN+w1pbH>;o&KUuYp)*^J00000 LNkvXXu0mjf2I~MK literal 11257 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 V8C}yFJeUkXT3kV_T;yxO{{kMwH244j