VBV-102: refactor server urls
This commit is contained in:
parent
db01be1726
commit
d5f4b37cfe
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<!-- workaround for vitejs bundling -> reference https:// -->
|
||||
<link href="https://vbv-lernwelt.control.iterativ.ch/static/fonts/BuenosAires/stylesheet.css" rel="stylesheet">
|
||||
<script defer src="/learnpath/icons/"></script>
|
||||
<script defer src="/server/core/icons/"></script>
|
||||
<!-- end workaround -->
|
||||
|
||||
<title>myVBV</title>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ def main():
|
|||
client.get('http://localhost:8000/')
|
||||
|
||||
client.post(
|
||||
'http://localhost:8000/core/login/',
|
||||
'http://localhost:8000/api/core/login/',
|
||||
json={
|
||||
'username': 'admin',
|
||||
'password': 'test',
|
||||
|
|
@ -16,7 +16,7 @@ def main():
|
|||
)
|
||||
|
||||
response = client.get(
|
||||
'http://localhost:8000/learnpath/api/page/unit-test-lernpfad/',
|
||||
'http://localhost:8000/api/learnpath/page/unit-test-lernpfad/',
|
||||
)
|
||||
print(response.status_code)
|
||||
print(response.json())
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@ export const useLearningPathStore = defineStore({
|
|||
if (this.learningPath && !reload) {
|
||||
return this.learningPath;
|
||||
}
|
||||
const learningPathData = await itGet(`/learnpath/api/page/${slug}/`);
|
||||
const learningPathData = await itGet(`/api/learnpath/page/${slug}/`);
|
||||
const completionData = await itGet(`/api/completion/learning_path/${learningPathData.translation_key}/`);
|
||||
|
||||
if (!learningPathData) {
|
||||
throw `No learning path found with: ${slug}`;
|
||||
}
|
||||
|
||||
|
||||
this.learningPath = LearningPath.fromJson(learningPathData, completionData);
|
||||
return this.learningPath;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import * as log from 'loglevel';
|
||||
import * as log from "loglevel";
|
||||
|
||||
import {defineStore} from 'pinia'
|
||||
import {itGet, itPost} from '@/fetchHelpers';
|
||||
import {useAppStore} from '@/stores/app';
|
||||
import { defineStore } from "pinia";
|
||||
import { itGet, itPost } from "@/fetchHelpers";
|
||||
import { useAppStore } from "@/stores/app";
|
||||
// typed state https://stackoverflow.com/questions/71012513/when-using-pinia-and-typescript-how-do-you-use-an-action-to-set-the-state
|
||||
|
||||
export type UserState = {
|
||||
|
|
@ -34,7 +34,7 @@ export const useUserStore = defineStore({
|
|||
actions: {
|
||||
handleLogin(username: string, password: string, next='/') {
|
||||
if (username && password) {
|
||||
itPost('/core/login/', {
|
||||
itPost('/api/core/login/', {
|
||||
username,
|
||||
password,
|
||||
}).then((data) => {
|
||||
|
|
@ -49,7 +49,7 @@ export const useUserStore = defineStore({
|
|||
}
|
||||
},
|
||||
handleLogout() {
|
||||
itPost('/core/logout/', {})
|
||||
itPost('/api/core/logout/', {})
|
||||
.then(data => {
|
||||
Object.assign(this, initialUserState);
|
||||
window.location.href = '/';
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ function log(data: any) {
|
|||
<it-icon-message class="w-16 h-16 text-orange-500"/>
|
||||
</div>
|
||||
|
||||
<div class="inline-flex flex-col text-green-500">
|
||||
<div class="inline-flex flex-col text-blue-400">
|
||||
ls-network big
|
||||
<it-icon-ls-network class="w-16 h-16"/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export const login = (username, password) => {
|
||||
cy.request({
|
||||
method: 'POST',
|
||||
url: '/core/login/',
|
||||
url: '/api/core/login/',
|
||||
body: { username, password },
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
from django.conf import settings
|
||||
from rest_framework.routers import DefaultRouter, SimpleRouter
|
||||
|
||||
if settings.DEBUG:
|
||||
router = DefaultRouter()
|
||||
else:
|
||||
router = SimpleRouter()
|
||||
|
||||
|
||||
app_name = "api"
|
||||
urlpatterns = router.urls
|
||||
|
|
@ -78,7 +78,6 @@ THIRD_PARTY_APPS = [
|
|||
"rest_framework.authtoken",
|
||||
"corsheaders",
|
||||
"drf_spectacular",
|
||||
"django_htmx",
|
||||
|
||||
'wagtail.contrib.forms',
|
||||
'wagtail.contrib.redirects',
|
||||
|
|
@ -288,7 +287,7 @@ EMAIL_TIMEOUT = 5
|
|||
# ADMIN
|
||||
# ------------------------------------------------------------------------------
|
||||
# Django Admin URL.
|
||||
ADMIN_URL = "admin/"
|
||||
ADMIN_URL = "server/admin/"
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#admins
|
||||
ADMINS = [("""Daniel Egger""", "info@iterativ.ch")]
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#managers
|
||||
|
|
@ -454,7 +453,17 @@ REST_FRAMEWORK = {
|
|||
CORS_URLS_REGEX = r"^/api/.*$"
|
||||
|
||||
# django-csp
|
||||
CSP_DEFAULT_SRC = ("'self'", "'unsafe-inline'", 'ws://localhost:5173', 'localhost:8000', 'blob:', 'data:', 'http://*')
|
||||
CSP_DEFAULT_SRC = [
|
||||
"'self'",
|
||||
"'unsafe-inline'",
|
||||
'ws://localhost:5173',
|
||||
'ws://127.0.0.1:5173',
|
||||
'localhost:8000',
|
||||
'localhost:8001',
|
||||
'blob:',
|
||||
'data:',
|
||||
'http://*'
|
||||
]
|
||||
CSP_FRAME_ANCESTORS = ("'self'",)
|
||||
|
||||
# By Default swagger ui is available only to admin user. You can change permission classs to change that
|
||||
|
|
|
|||
|
|
@ -5,19 +5,19 @@ from django.contrib.auth.decorators import user_passes_test
|
|||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
from django.urls import include, path, re_path
|
||||
from django.views import defaults as default_views
|
||||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
||||
from ratelimit.exceptions import Ratelimited
|
||||
from rest_framework.authtoken.views import obtain_auth_token
|
||||
from wagtail import urls as wagtail_urls
|
||||
from wagtail.admin import urls as wagtailadmin_urls
|
||||
from wagtail.documents import urls as wagtaildocs_urls
|
||||
|
||||
from vbv_lernwelt.completion.views import request_learning_path_completion, request_circle_completion, \
|
||||
mark_circle_completion
|
||||
from vbv_lernwelt.core.middleware.auth import django_view_authentication_exempt
|
||||
from vbv_lernwelt.core.views import (
|
||||
rate_limit_exceeded_view,
|
||||
permission_denied_view,
|
||||
check_rate_limit, cypress_reset_view, vue_home, vue_login, me_user_view, vue_logout, )
|
||||
from .wagtail_api import wagtail_api_router
|
||||
check_rate_limit, cypress_reset_view, vue_home, vue_login, me_user_view, vue_logout, generate_web_component_icons, )
|
||||
from vbv_lernwelt.learnpath.views import page_api_view
|
||||
|
||||
|
||||
def raise_example_error(request):
|
||||
|
|
@ -31,39 +31,43 @@ def raise_example_error(request):
|
|||
|
||||
# fmt: off
|
||||
urlpatterns = [
|
||||
path('admin/raise_error/', user_passes_test(lambda u: u.is_superuser, login_url='/login/')(raise_example_error), ),
|
||||
path(settings.ADMIN_URL, admin.site.urls),
|
||||
path("checkratelimit/", check_rate_limit),
|
||||
|
||||
# wagtail urls
|
||||
path('server/cms/', include(wagtailadmin_urls)),
|
||||
path('server/documents/', include(wagtaildocs_urls)),
|
||||
path('server/pages/', include(wagtail_urls)),
|
||||
|
||||
# user management
|
||||
path("sso/", include("vbv_lernwelt.sso.urls")),
|
||||
path('cms/', include(wagtailadmin_urls)),
|
||||
path('documents/', include(wagtaildocs_urls)),
|
||||
path('pages/', include(wagtail_urls)),
|
||||
path('learnpath/', include("vbv_lernwelt.learnpath.urls")),
|
||||
path('api/completion/', include("vbv_lernwelt.completion.urls")),
|
||||
re_path(r'api/core/me/$', me_user_view, name='me_user_view'),
|
||||
re_path(r'core/login/$', django_view_authentication_exempt(vue_login), name='vue_login'),
|
||||
re_path(r'core/logout/$', vue_logout, name='vue_logout'),
|
||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
re_path(r'api/core/login/$', django_view_authentication_exempt(vue_login), name='vue_login'),
|
||||
re_path(r'api/core/logout/$', vue_logout, name='vue_logout'),
|
||||
|
||||
# core
|
||||
re_path(r"server/core/icons/$", generate_web_component_icons, name="generate_web_component_icons"),
|
||||
|
||||
# learnpath
|
||||
path(r"api/learnpath/page/<slug:slug>/", page_api_view, name="page_api_view"),
|
||||
|
||||
# completion
|
||||
path(r"api/completion/circle/<uuid:circle_key>/", request_circle_completion, name="request_circle_completion"),
|
||||
path(r"api/completion/learning_path/<uuid:learning_path_key>/", request_learning_path_completion, name="request_learning_path_completion"),
|
||||
path(r"api/completion/circle/mark/", mark_circle_completion, name="mark_circle_completion"),
|
||||
|
||||
# testing and debug
|
||||
path('server/raise_error/', user_passes_test(lambda u: u.is_superuser, login_url='/login/')(raise_example_error), ),
|
||||
path("server/checkratelimit/", check_rate_limit),
|
||||
]
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
|
||||
if settings.DEBUG:
|
||||
# Static file serving when using Gunicorn + Uvicorn for local web socket development
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
|
||||
# API URLS
|
||||
urlpatterns += [
|
||||
# API base url
|
||||
path("api/", include("config.api_router")),
|
||||
path('wagtailapi/v2/', wagtail_api_router.urls),
|
||||
|
||||
# DRF auth token
|
||||
path("auth-token/", obtain_auth_token),
|
||||
path("api/schema/", SpectacularAPIView.as_view(), name="api-schema"),
|
||||
path("api/docs/", SpectacularSwaggerView.as_view(url_name="api-schema"), name="api-docs",),
|
||||
]
|
||||
|
||||
if settings.APP_ENVIRONMENT != 'production':
|
||||
urlpatterns += [
|
||||
re_path(r'core/cypressreset/$', cypress_reset_view, name='cypress_reset_view'),
|
||||
re_path(r'api/core/cypressreset/$', cypress_reset_view, name='cypress_reset_view'),
|
||||
]
|
||||
# fmt: on
|
||||
|
||||
|
|
@ -107,4 +111,4 @@ if settings.DEBUG:
|
|||
|
||||
|
||||
# serve everything else via the vue app
|
||||
urlpatterns += [re_path(r'^.*$', vue_home, name='home')]
|
||||
urlpatterns += [re_path(r'^(?!.*(server/|api/|sso/)).*$', vue_home, name='home')]
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
from wagtail.api.v2.router import WagtailAPIRouter
|
||||
from wagtail.api.v2.views import PagesAPIViewSet
|
||||
from wagtail.documents.api.v2.views import DocumentsAPIViewSet
|
||||
from wagtail.images.api.v2.views import ImagesAPIViewSet
|
||||
|
||||
# Create the router. "wagtailapi" is the URL namespace
|
||||
wagtail_api_router = WagtailAPIRouter('wagtailapi')
|
||||
|
||||
# Add the three endpoints using the "register_endpoint" method.
|
||||
# The first parameter is the name of the endpoint (eg. pages, images). This
|
||||
# is used in the URL of the endpoint
|
||||
# The second parameter is the endpoint class that handles the requests
|
||||
wagtail_api_router.register_endpoint('pages', PagesAPIViewSet)
|
||||
wagtail_api_router.register_endpoint('images', ImagesAPIViewSet)
|
||||
wagtail_api_router.register_endpoint('documents', DocumentsAPIViewSet)
|
||||
|
|
@ -3,7 +3,7 @@ from django.test import TestCase, override_settings
|
|||
|
||||
class RateLimitTest(TestCase):
|
||||
def setUp(self):
|
||||
self.url = "/checkratelimit/"
|
||||
self.url = "/server/checkratelimit/"
|
||||
|
||||
@override_settings(RATELIMIT_ENABLE=True)
|
||||
def test_checkView_rateLimitAfter5Requests(self):
|
||||
|
|
|
|||
|
|
@ -113,8 +113,6 @@ django-extensions==3.1.5
|
|||
# via -r requirements-dev.in
|
||||
django-filter==21.1
|
||||
# via wagtail
|
||||
django-htmx==1.9.0
|
||||
# via -r requirements.in
|
||||
django-ipware==4.0.2
|
||||
# via -r requirements.in
|
||||
django-model-utils==4.2.0
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ djangorestframework # https://github.com/encode/django-rest-framework
|
|||
django-cors-headers # https://github.com/adamchainz/django-cors-headers
|
||||
# DRF-spectacular for api documentation
|
||||
drf-spectacular
|
||||
django-htmx
|
||||
dj-database-url
|
||||
django-click
|
||||
django-ratelimit
|
||||
|
|
|
|||
|
|
@ -71,8 +71,6 @@ django-csp==3.7
|
|||
# via -r requirements.in
|
||||
django-filter==21.1
|
||||
# via wagtail
|
||||
django-htmx==1.9.0
|
||||
# via -r requirements.in
|
||||
django-ipware==4.0.2
|
||||
# via -r requirements.in
|
||||
django-model-utils==4.2.0
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
from django.urls import path
|
||||
|
||||
from vbv_lernwelt.completion.views import request_circle_completion, mark_circle_completion, \
|
||||
request_learning_path_completion
|
||||
|
||||
urlpatterns = [
|
||||
path(r"circle/<uuid:circle_key>/", request_circle_completion, name="request_circle_completion"),
|
||||
path(r"learning_path/<uuid:learning_path_key>/", request_learning_path_completion, name="request_learning_path_completion"),
|
||||
path(r"circle/mark/", mark_circle_completion, name="mark_circle_completion"),
|
||||
]
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
# Create your views here.
|
||||
import glob
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
import structlog
|
||||
|
|
@ -23,9 +25,7 @@ logger = structlog.get_logger(__name__)
|
|||
|
||||
@django_view_authentication_exempt
|
||||
@ensure_csrf_cookie
|
||||
|
||||
|
||||
def vue_home(request):
|
||||
def vue_home(request, *args):
|
||||
if settings.IT_SERVE_VUE:
|
||||
try:
|
||||
res = requests.get(f'{settings.IT_SERVE_VUE_URL}{request.get_full_path()}')
|
||||
|
|
@ -114,3 +114,24 @@ def cypress_reset_view(request):
|
|||
call_command('cypress_reset')
|
||||
|
||||
return HttpResponseRedirect('/admin/')
|
||||
|
||||
|
||||
@django_view_authentication_exempt
|
||||
def generate_web_component_icons(request):
|
||||
svg_files = []
|
||||
for filepath in glob.iglob(f'{settings.APPS_DIR}/static/icons/*.svg'):
|
||||
with open(filepath, 'r') as f:
|
||||
filename = Path(filepath).stem
|
||||
elementname = 'it-' + filename
|
||||
svg_files.append({
|
||||
'filepath': filepath,
|
||||
'content': f.read(),
|
||||
'filename': filename,
|
||||
'elementname': elementname,
|
||||
'classname': filename.replace('-', '_'),
|
||||
})
|
||||
return render(
|
||||
request, "core/icons.html",
|
||||
context={'svg_files': svg_files},
|
||||
content_type="application/javascript"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class TestRetrieveLearingPathContents(APITestCase):
|
|||
|
||||
def test_get_learnpathPage(self):
|
||||
learning_path = LearningPath.objects.get(slug='unit-test-lernpfad')
|
||||
response = self.client.get('/learnpath/api/page/unit-test-lernpfad/')
|
||||
response = self.client.get('/api/learnpath/page/unit-test-lernpfad/')
|
||||
print(response)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
data = response.json()
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
from django.urls import path, re_path
|
||||
|
||||
from .views import generate_web_component_icons, page_api_view
|
||||
|
||||
urlpatterns = [
|
||||
path(r"api/page/<slug:slug>/", page_api_view, name="page_api_view"),
|
||||
re_path(r"icons/$", generate_web_component_icons, name="generate_web_component_icons"),
|
||||
]
|
||||
|
|
@ -1,17 +1,11 @@
|
|||
# Create your views here.
|
||||
import glob
|
||||
from pathlib import Path
|
||||
|
||||
import structlog
|
||||
from django.conf import settings
|
||||
from django.shortcuts import render
|
||||
from django.views.decorators.cache import cache_page
|
||||
from rest_framework.decorators import api_view
|
||||
from rest_framework.response import Response
|
||||
from wagtail.models import Page
|
||||
|
||||
from vbv_lernwelt.core.middleware.auth import django_view_authentication_exempt
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
|
||||
|
|
@ -27,22 +21,3 @@ def page_api_view(request, slug):
|
|||
return Response({"error": str(e)}, status=404)
|
||||
|
||||
|
||||
@django_view_authentication_exempt
|
||||
def generate_web_component_icons(request):
|
||||
svg_files = []
|
||||
for filepath in glob.iglob(f'{settings.APPS_DIR}/static/icons/*.svg'):
|
||||
with open(filepath, 'r') as f:
|
||||
filename = Path(filepath).stem
|
||||
elementname = 'it-' + filename
|
||||
svg_files.append({
|
||||
'filepath': filepath,
|
||||
'content': f.read(),
|
||||
'filename': filename,
|
||||
'elementname': elementname,
|
||||
'classname': filename.replace('-', '_'),
|
||||
})
|
||||
return render(
|
||||
request, "learnpath/icons.html",
|
||||
context={'svg_files': svg_files},
|
||||
content_type="application/javascript"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@
|
|||
<!-- Le javascript
|
||||
================================================== -->
|
||||
{# Placed at the top of the document so pages load faster with defer #}
|
||||
<script defer src="https://unpkg.com/htmx.org@1.6.1"></script>
|
||||
<script defer src="/learnpath/icons/"></script>
|
||||
<script defer src="/server/core/icons/"></script>
|
||||
|
||||
{% block javascript %}
|
||||
<!-- Your stuff: Third-party javascript libraries go here -->
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
</style>
|
||||
|
||||
<script defer src="/learnpath/icons/"></script>
|
||||
<script defer src="/server/core/icons/"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
if (document.location.href.endsWith('/')) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue