Merge branch 'feature/graphql-api' into develop
# Conflicts: # server/config/settings/base.py # server/config/urls.py # server/example.env # server/requirements/requirements-dev.txt # server/requirements/requirements.txt
|
|
@ -249,7 +249,8 @@ bh_unicode_properties.cache
|
|||
# Sublime-github package stores a github token in this file
|
||||
# https://packagecontrol.io/packages/sublime-github
|
||||
GitHub.sublime-settings
|
||||
|
||||
.direnv
|
||||
.idea
|
||||
|
||||
### Vim template
|
||||
# Swap
|
||||
|
|
|
|||
|
|
@ -56,3 +56,7 @@ npm run dev
|
|||
* In the .idea/vbv_lernwelt.iml file change the module type to "PYTHON_MODULE".
|
||||
* Add django facet in "Project Structure".
|
||||
* Run configuration with "Python -> server.py" to have async debugging support.
|
||||
### Optional
|
||||
* Install the EnvFile Plugin
|
||||
* Install the tailwind css Plugin from Jetbrains
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
encrypted: env_secrets/caprover.env
|
||||
encrypted: env_secrets/production.env
|
||||
encrypted: env_secrets/local_lorenz.env
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
#!/bin/bash
|
||||
|
||||
#export DATABASE_HOST=postgres
|
||||
#export DATABASE_PORT=5432
|
||||
#export DATABASE_URL=postgres://$DATABASE_USER:$PG_PASSWORD@$DATABASE_HOST:$DATABASE_PORT/$DATABASE_NAME
|
||||
#
|
||||
#echo $DATABASE_URL
|
||||
#DJANGO_SETTINGS_MODULE=config.settings.base
|
||||
#DATABASE_NAME=vbv_lernwelt
|
||||
SKIP_SETUP=false
|
||||
##
|
||||
|
||||
echo "Setting up VBV Project for Local usage"
|
||||
if [ "$SKIP_SETUP" = false ]; then
|
||||
if [ -z "$PG_PORT" ]; then # if the port is set in the env, use iterg
|
||||
DB_PORT="";
|
||||
else
|
||||
DB_PORT="-p $PG_PORT";
|
||||
fi
|
||||
if [ -z "$PG_USER" ]; then # if the user is set in the env, use it
|
||||
DB_USER="";
|
||||
else
|
||||
DB_USER="-U $PG_USER";
|
||||
fi
|
||||
echo "psql -h localhost --port=$DB_PORT --username=$DB_USER -c 'drop database if exists' $DATABASE_NAME;"
|
||||
|
||||
echo "Drop all connections to the database"
|
||||
psql -h localhost --port=$DB_PORT --username=$DB_USER -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '$DATABASE_NAME' AND pid <> pg_backend_pid();"
|
||||
|
||||
echo "Drop database: $DATABASE_NAME"
|
||||
psql -h localhost --port=$DB_PORT --username=$DB_USER -c "drop database if exists $DATABASE_NAME;"
|
||||
|
||||
echo "Create database: $DATABASE_NAME"
|
||||
psql -h localhost --port=$DB_PORT --username=$DB_USER -c "create database $DATABASE_NAME;"
|
||||
|
||||
# reset data
|
||||
python3 server/manage.py createcachetable --settings="$DJANGO_SETTINGS_MODULE"
|
||||
python3 server/manage.py migrate --settings="$DJANGO_SETTINGS_MODULE"
|
||||
python3 server/manage.py create_default_users --settings="$DJANGO_SETTINGS_MODULE"
|
||||
python3 server/manage.py create_default_learningpath --settings="$DJANGO_SETTINGS_MODULE"
|
||||
#
|
||||
# # make django translations
|
||||
(cd server && python3 manage.py compilemessages --settings="$DJANGO_SETTINGS_MODULE")
|
||||
fi
|
||||
|
||||
|
|
@ -10,5 +10,8 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"cypress": "^9.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"tailwindcss": "^3.0.24"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ DJANGO_SETTINGS_MODULE=config.settings.test_cypress
|
|||
CYPRESS_DB=vbv_lernwelt_cypress
|
||||
|
||||
if [ "$SKIP_SETUP" = false ]; then
|
||||
if [ -z "$PG_PORT" ]; then # if the port is set in the env, use it
|
||||
if [ -z "$PG_PORT" ]; then # if the port is set in the env, use iterg
|
||||
DB_PORT="";
|
||||
else
|
||||
DB_PORT="-p $PG_PORT";
|
||||
|
|
@ -66,12 +66,7 @@ if [ "$SKIP_SETUP" = false ]; then
|
|||
# make django translations
|
||||
(cd server && python3 manage.py compilemessages --settings="$DJANGO_SETTINGS_MODULE")
|
||||
|
||||
# python3 src/manage.py constance --settings="$DJANGO_SETTINGS_MODULE" set API_WFM_BACKEND_ENABLED true
|
||||
# python3 src/manage.py constance --settings="$DJANGO_SETTINGS_MODULE" set TIBCO_SOAP_CUSTOMER_INTERACTION_CLIENT_ENABLED true
|
||||
# python3 src/manage.py constance --settings="$DJANGO_SETTINGS_MODULE" set API_EMAIL_MESSAGING_ENABLED true
|
||||
# python3 src/manage.py constance --settings="$DJANGO_SETTINGS_MODULE" set C4_NOTIFICATIONS_ENABLED true
|
||||
# python3 src/manage.py constance --settings="$DJANGO_SETTINGS_MODULE" set SFTP_POSTFINANCE_ENABLED true
|
||||
# python3 src/manage.py constance --settings="$DJANGO_SETTINGS_MODULE" set EASY_INSURANCE_AGENT_CAN_CREATE true
|
||||
|
||||
else
|
||||
echo "else"
|
||||
# python3 src/manage.py recreate_customer_data_for_integration_tests --settings="$DJANGO_SETTINGS_MODULE"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ DEBUG = env.bool("VBV_DJANGO_DEBUG", False)
|
|||
# In Windows, this must be set to your system time zone.
|
||||
TIME_ZONE = "Europe/Zurich"
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#language-code
|
||||
LANGUAGE_CODE = "en-us"
|
||||
LANGUAGE_CODE = "de-CH"
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#site-id
|
||||
SITE_ID = 1
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#use-i18n
|
||||
|
|
@ -83,13 +83,32 @@ THIRD_PARTY_APPS = [
|
|||
"corsheaders",
|
||||
"drf_spectacular",
|
||||
"django_htmx",
|
||||
|
||||
"grapple",
|
||||
"graphene_django",
|
||||
|
||||
'wagtail.contrib.forms',
|
||||
'wagtail.contrib.redirects',
|
||||
'wagtail.embeds',
|
||||
'wagtail.sites',
|
||||
'wagtail.users',
|
||||
'wagtail.snippets',
|
||||
'wagtail.documents',
|
||||
'wagtail.images',
|
||||
'wagtail.search',
|
||||
'wagtail.admin',
|
||||
'wagtail.core',
|
||||
'wagtail.locales',
|
||||
|
||||
'modelcluster',
|
||||
'taggit',
|
||||
]
|
||||
|
||||
LOCAL_APPS = [
|
||||
"vbv_lernwelt.core",
|
||||
"vbv_lernwelt.simpletodo",
|
||||
"vbv_lernwelt.sso",
|
||||
# Your stuff: custom apps go here
|
||||
"vbv_lernwelt.learnpath",
|
||||
]
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
|
||||
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
|
||||
|
|
@ -153,6 +172,7 @@ MIDDLEWARE = [
|
|||
"django_htmx.middleware.HtmxMiddleware",
|
||||
"vbv_lernwelt.core.middleware.auth.AuthenticationRequiredMiddleware",
|
||||
"vbv_lernwelt.core.middleware.security.SecurityRequestResponseLoggingMiddleware",
|
||||
"wagtail.contrib.redirects.middleware.RedirectMiddleware",
|
||||
"vbv_lernwelt.core.middleware.auth.UserLoggedInCookieMiddleWare",
|
||||
]
|
||||
|
||||
|
|
@ -177,6 +197,41 @@ MEDIA_ROOT = str(APPS_DIR / "media")
|
|||
# https://docs.djangoproject.com/en/dev/ref/settings/#media-url
|
||||
MEDIA_URL = "/media/"
|
||||
|
||||
|
||||
# WAGTAIL
|
||||
# ------------------------------------------------------------------------------
|
||||
WAGTAIL_SITE_NAME = 'VBV Lernwelt'
|
||||
WAGTAIL_I18N_ENABLED = True
|
||||
|
||||
LANGUAGES = [
|
||||
('en-US', "English (American)"),
|
||||
('fr-CH', "Swiss French"),
|
||||
('de-CH', "Swiss German"),
|
||||
('it-CH', "Swiss Italian")
|
||||
]
|
||||
|
||||
|
||||
WAGTAIL_CONTENT_LANGUAGES = [
|
||||
('fr-CH', "Swiss French"),
|
||||
('de-CH', "Swiss German"),
|
||||
('it-CH', "Swiss Italian")
|
||||
]
|
||||
|
||||
WAGTAILSEARCH_BACKENDS = {
|
||||
'default': {
|
||||
'BACKEND': 'wagtail.search.backends.database',
|
||||
}
|
||||
}
|
||||
|
||||
# Wagtails Grapple Config:
|
||||
GRAPHENE = {"SCHEMA": "grapple.schema.schema"}
|
||||
GRAPPLE = {
|
||||
"APPS": ["learnpath"],
|
||||
"EXPOSE_GRAPHIQL" : True
|
||||
|
||||
}
|
||||
|
||||
|
||||
# TEMPLATES
|
||||
# ------------------------------------------------------------------------------
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#templates
|
||||
|
|
@ -476,14 +531,14 @@ if DJANGO_DEV_MODE == "development":
|
|||
# django-debug-toolbar
|
||||
# ------------------------------------------------------------------------------
|
||||
# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#prerequisites
|
||||
INSTALLED_APPS += ["debug_toolbar"] # noqa F405
|
||||
#INSTALLED_APPS += ["debug_toolbar"] # noqa F405
|
||||
# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#middleware
|
||||
MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] # noqa F405
|
||||
# MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] # noqa F405
|
||||
# https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html#debug-toolbar-config
|
||||
DEBUG_TOOLBAR_CONFIG = {
|
||||
"DISABLE_PANELS": ["debug_toolbar.panels.redirects.RedirectsPanel"],
|
||||
"SHOW_TEMPLATE_CONTEXT": True,
|
||||
}
|
||||
# DEBUG_TOOLBAR_CONFIG = {
|
||||
# "DISABLE_PANELS": ["debug_toolbar.panels.redirects.RedirectsPanel"],
|
||||
# "SHOW_TEMPLATE_CONTEXT": True,
|
||||
# }
|
||||
# https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#internal-ips
|
||||
INTERNAL_IPS = ["127.0.0.1", "10.0.2.2"]
|
||||
if env.bool("VBV_DJANGO_LOCAL_DOCKER", False):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
# pylint: disable=unused-wildcard-import,wildcard-import,wrong-import-position
|
||||
import getpass
|
||||
import os
|
||||
|
||||
from .base import * # noqa
|
||||
from .base import env
|
||||
|
||||
# GENERAL
|
||||
# ------------------------------------------------------------------------------
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
||||
SECRET_KEY = env(
|
||||
"VBV_DJANGO_SECRET_KEY",
|
||||
default="1NpUCSvAKLpDZL9e3tqDaUesdfsadfasdfasdfMD3UjB72ZS",
|
||||
)
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#test-runner
|
||||
TEST_RUNNER = "django.test.runner.DiscoverRunner"
|
||||
|
||||
# PASSWORDS
|
||||
# ------------------------------------------------------------------------------
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#password-hashers
|
||||
PASSWORD_HASHERS = ["django.contrib.auth.hashers.MD5PasswordHasher"]
|
||||
|
||||
# EMAIL
|
||||
# ------------------------------------------------------------------------------
|
||||
# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
|
||||
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
||||
|
||||
|
||||
class DisableMigrations(dict):
|
||||
def __contains__(self, item):
|
||||
return True
|
||||
|
||||
def __getitem__(self, item):
|
||||
return None
|
||||
|
||||
#MIGRATION_MODULES = DisableMigrations()
|
||||
|
||||
|
||||
|
||||
|
||||
# Your stuff...
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
@ -39,7 +39,7 @@ MIGRATION_MODULES = DisableMigrations()
|
|||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.postgresql_psycopg2",
|
||||
"NAME": "vbv_lernwelt",
|
||||
"NAME": "vbv_lernwelt_test",
|
||||
"USER": os.environ.get("PG_USER", getpass.getuser()),
|
||||
"PASSWORD": os.environ.get("PG_PASSWORD"),
|
||||
"HOST": "localhost",
|
||||
|
|
@ -47,5 +47,6 @@ DATABASES = {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
# Your stuff...
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
from django.contrib import admin
|
||||
|
|
@ -10,13 +11,16 @@ from django.views.generic import TemplateView
|
|||
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
|
||||
from ratelimit.exceptions import Ratelimited
|
||||
from rest_framework.authtoken.views import obtain_auth_token
|
||||
|
||||
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,
|
||||
)
|
||||
from wagtail.admin import urls as wagtailadmin_urls
|
||||
from wagtail.core import urls as wagtail_urls
|
||||
from wagtail.documents import urls as wagtaildocs_urls
|
||||
from grapple import urls as grapple_urls
|
||||
|
||||
|
||||
def raise_example_error(request):
|
||||
|
|
@ -36,6 +40,9 @@ urlpatterns = [
|
|||
path("checkratelimit/", check_rate_limit),
|
||||
path("todo/", include("vbv_lernwelt.simpletodo.urls")),
|
||||
path("sso/", include("vbv_lernwelt.sso.urls")),
|
||||
path('cms/', include(wagtailadmin_urls)),
|
||||
path('documents/', include(wagtaildocs_urls)),
|
||||
path('pages/', include(wagtail_urls)),
|
||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
if settings.DEBUG:
|
||||
# Static file serving when using Gunicorn + Uvicorn for local web socket development
|
||||
|
|
@ -54,6 +61,7 @@ urlpatterns += [
|
|||
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",),
|
||||
path("", include(grapple_urls)),
|
||||
]
|
||||
# fmt: on
|
||||
|
||||
|
|
|
|||
|
|
@ -32,3 +32,9 @@ sentry-sdk
|
|||
structlog
|
||||
python-json-logger
|
||||
concurrent-log-handler
|
||||
|
||||
wagtail<3
|
||||
wagtail-factories
|
||||
wagtail-grapple==0.14.1
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
python manage.py migrate
|
||||
python manage.py createcachetable
|
||||
python manage.py create_default_users
|
||||
#python manage.py create_default_learingpath
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
from django.contrib.auth.hashers import make_password
|
||||
from django.contrib.auth.models import Group
|
||||
|
||||
from vbv_lernwelt.core.models import User
|
||||
|
||||
|
||||
def create_default_users(user_model=User, group_model=Group):
|
||||
admin_group, created = group_model.objects.get_or_create(name='admin_group')
|
||||
content_creator_grop, created = group_model.objects.get_or_create(name='content_creator_grop')
|
||||
student_group, created = group_model.objects.get_or_create(name='student_group')
|
||||
|
||||
admin_user, created = _get_or_create_user(user_model=user_model,
|
||||
username='admin',
|
||||
password='admin')
|
||||
admin_user.is_superuser=True
|
||||
admin_user.groups.add(admin_group)
|
||||
|
||||
admin_user.save()
|
||||
student_user, created = _get_or_create_user(user_model=user_model, username='student', password='student')
|
||||
student_user.groups.add(student_group)
|
||||
student_user.save()
|
||||
|
||||
|
||||
def _get_or_create_user(user_model, *args, **kwargs):
|
||||
username = kwargs.get('username', None)
|
||||
password = kwargs.get('password', None)
|
||||
created = False
|
||||
|
||||
user = user_model.objects.filter(username=username).first()
|
||||
|
||||
if not user:
|
||||
user = user_model.objects.create(username=username, password=make_password(password))
|
||||
created = True
|
||||
return user, created
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
from vbv_lernwelt.core.create_default_users import create_default_users
|
||||
|
||||
|
||||
import djclick as click
|
||||
|
||||
|
||||
@click.command()
|
||||
def command():
|
||||
print("Creating default users.")
|
||||
create_default_users()
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import djclick as click
|
||||
from django.conf import settings
|
||||
from wagtail.core.models import Locale
|
||||
|
||||
|
||||
@click.command()
|
||||
def command():
|
||||
for language in settings.WAGTAIL_CONTENT_LANGUAGES:
|
||||
Locale.objects.create(language_code=language[0])
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
from django.test import TestCase
|
||||
|
||||
from vbv_lernwelt.core.models import User
|
||||
from vbv_lernwelt.core.tests.factories import UserFactory
|
||||
from vbv_lernwelt.simpletodo.models import SimpleList
|
||||
|
||||
|
||||
class TestUserCreation(TestCase):
|
||||
def test_create_user(self):
|
||||
User(last_name='Sepp').save()
|
||||
|
||||
def test_simple(self):
|
||||
# create_default_learning_path()
|
||||
self.user = UserFactory()
|
||||
SimpleList.objects.get_or_create(title='Default', user=self.user)
|
||||
self.assertTrue(True)
|
||||
|
|
@ -4,7 +4,7 @@ import structlog
|
|||
from django.conf import settings
|
||||
from rest_framework.throttling import UserRateThrottle
|
||||
from structlog.types import EventDict
|
||||
|
||||
#from .models import User
|
||||
|
||||
def structlog_add_app_info(
|
||||
logger: logging.Logger, method_name: str, event_dict: EventDict
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class LearnpathConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'vbv_lernwelt.learnpath'
|
||||
|
||||
def ready(self):
|
||||
try:
|
||||
# pylint: disable=unused-import,import-outside-toplevel
|
||||
import vbv_lernwelt.learnpath.signals # noqa F401
|
||||
except ImportError:
|
||||
pass
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Iterativ GmbH
|
||||
# http://www.iterativ.ch/
|
||||
#
|
||||
# Copyright (c) 2015 Iterativ GmbH. All rights reserved.
|
||||
#
|
||||
# Created on 2022-03-31
|
||||
# @author: lorenz.padberg@iterativ.ch
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# pylint: disable=import-outside-toplevel
|
||||
|
||||
import djclick as click
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from vbv_lernwelt.learnpath.tests.create_default_learning_path import create_default_learning_path
|
||||
|
||||
|
||||
@click.command()
|
||||
def command():
|
||||
create_default_learning_path()
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# pylint: disable=import-outside-toplevel
|
||||
|
||||
import djclick as click
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from vbv_lernwelt.learnpath.tests.create_default_learning_path import create_default_learning_path, \
|
||||
delete_default_learning_path
|
||||
|
||||
import djclick as click
|
||||
|
||||
|
||||
@click.command()
|
||||
def command():
|
||||
delete_default_learning_path()
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
# Generated by Django 3.2.12 on 2022-05-04 15:52
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import modelcluster.fields
|
||||
import wagtail.core.blocks
|
||||
import wagtail.core.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0066_collection_management_permissions'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Circle',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
|
||||
('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
|
||||
('description', models.TextField(blank=True, default='')),
|
||||
('goals', models.TextField(blank=True, default='')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Circle',
|
||||
},
|
||||
bases=('wagtailcore.page', models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Competence',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
|
||||
('category_short', models.CharField(default='', max_length=3)),
|
||||
('name', models.CharField(max_length=2048)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Competence',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='CompetencePage',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Learning Path',
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='LearningPath',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Learning Path',
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='LearningSequence',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
|
||||
('title', models.CharField(default='', max_length=256)),
|
||||
('category', models.CharField(choices=[('INCIRCLE', 'In Circle'), ('START', 'Start'), ('END', 'End')], default='INCIRCLE', max_length=16)),
|
||||
('circle', modelcluster.fields.ParentalKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='learning_sequences', to='learnpath.circle')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Learning Sequence',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Topic',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
|
||||
('title', models.TextField(default='')),
|
||||
('is_visible', models.BooleanField(default=True)),
|
||||
('learning_path', modelcluster.fields.ParentalKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='topics', to='learnpath.learningpath')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Topic',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='LearningUnit',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
|
||||
('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
|
||||
('contents', wagtail.core.fields.StreamField([('web_based_training', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())])), ('video', wagtail.core.blocks.StructBlock([('url', wagtail.core.blocks.URLBlock())]))], blank=True, null=True)),
|
||||
('learning_sequence', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='learning_units', to='learnpath.learningsequence')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Learning Unit',
|
||||
},
|
||||
bases=('wagtailcore.page', models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FullfillmentCriteria',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=2048)),
|
||||
('competence', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='learnpath.competence')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Fullfillment Criteria',
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='competence',
|
||||
name='competence_page',
|
||||
field=modelcluster.fields.ParentalKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='competences', to='learnpath.competencepage'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='circle',
|
||||
name='topic',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='circles', to='learnpath.topic'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.12 on 2022-05-04 16:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('learnpath', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='fullfillmentcriteria',
|
||||
name='sort_order',
|
||||
field=models.IntegerField(blank=True, editable=False, null=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# Generated by Django 3.2.12 on 2022-05-12 12:56
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('learnpath', '0002_fullfillmentcriteria_sort_order'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='learningunit',
|
||||
name='learning_sequence',
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='LearningPackage',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('sort_order', models.IntegerField(blank=True, editable=False, null=True)),
|
||||
('title', models.CharField(default='', max_length=256)),
|
||||
('learning_sequence', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='learning_packages', to='learnpath.learningsequence')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['sort_order'],
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='learningunit',
|
||||
name='learning_package',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='learning_units', to='learnpath.learningpackage'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 3.2.12 on 2022-05-12 12:56
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('learnpath', '0003_auto_20220512_1456'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='learningpackage',
|
||||
name='learning_sequence',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='learning_packages', to='learnpath.learningsequence'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 3.2.12 on 2022-05-12 12:56
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('learnpath', '0004_alter_learningpackage_learning_sequence'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='learningunit',
|
||||
name='learning_package',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='learning_units', to='learnpath.learningpackage'),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
# Create your models here.
|
||||
|
||||
from django.utils.text import slugify
|
||||
from wagtail.core.blocks import StreamBlock
|
||||
from wagtail.core.fields import StreamField
|
||||
from wagtail.core.models import Page, Orderable
|
||||
|
||||
from vbv_lernwelt.learnpath.models_competences import *
|
||||
from vbv_lernwelt.learnpath.models_learning_unit_content import WebBasedTrainingBlock, VideoBlock
|
||||
from grapple.helpers import register_query_field
|
||||
import graphene
|
||||
|
||||
from grapple.models import (
|
||||
GraphQLString, GraphQLPage,
|
||||
GraphQLStreamfield, GraphQLBoolean, GraphQLInt, GraphQLForeignKey, GraphQLField
|
||||
)
|
||||
|
||||
|
||||
@register_query_field("learning_path")
|
||||
class LearningPath(Page):
|
||||
# PageChooserPanel('related_page', 'demo.PublisherPage'),
|
||||
|
||||
content_panels = Page.content_panels + [
|
||||
InlinePanel('topics', label="Topics"),
|
||||
]
|
||||
|
||||
subpage_types = ['learnpath.Circle']
|
||||
|
||||
graphql_fields = [
|
||||
GraphQLString("title", required=True),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Learning Path"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title}"
|
||||
|
||||
|
||||
class Topic(Orderable):
|
||||
title = models.TextField(default='')
|
||||
is_visible = models.BooleanField(default=True)
|
||||
|
||||
learning_path = ParentalKey('learnpath.LearningPath',
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='topics',
|
||||
)
|
||||
|
||||
panels = [FieldPanel('title'),
|
||||
FieldPanel('is_visible'),
|
||||
]
|
||||
|
||||
graphql_fields = [
|
||||
GraphQLString("title"),
|
||||
GraphQLBoolean("is_visible"),
|
||||
]
|
||||
|
||||
# content_panels = Page.content_panels + [
|
||||
# FieldPanel('is_visible', classname="full"),
|
||||
# PageChooserPanel('learning_path', 'learnpath.LearningPath'),
|
||||
# ]
|
||||
|
||||
# parent_page_types = ['learnpath.LearningPath']
|
||||
# subpage_types = ['learnpath.Circle']
|
||||
def full_clean(self, *args, **kwargs):
|
||||
self.slug = find_available_slug(Topic, slugify(self.title, allow_unicode=True))
|
||||
super(Topic, self).full_clean(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Topic"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title}"
|
||||
|
||||
|
||||
class Circle(Page, Orderable):
|
||||
description = models.TextField(default="", blank=True)
|
||||
goals = models.TextField(default="", blank=True)
|
||||
topic = models.ForeignKey(
|
||||
'learnpath.Topic',
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='circles'
|
||||
)
|
||||
|
||||
parent_page_types = ['learnpath.Learningpath']
|
||||
subpage_types = ['learnpath.LearningUnit']
|
||||
|
||||
content_panels = Page.content_panels + [
|
||||
FieldPanel('description'),
|
||||
FieldPanel('topic'),
|
||||
FieldPanel('goals'),
|
||||
InlinePanel('learning_sequences', label="Learning Sequences"),
|
||||
]
|
||||
#
|
||||
graphql_fields = [
|
||||
GraphQLString("title", required=True),
|
||||
GraphQLString("description"),
|
||||
GraphQLString("goals"),
|
||||
]
|
||||
|
||||
|
||||
def full_clean(self, *args, **kwargs):
|
||||
self.slug = find_available_slug(Circle, slugify(self.title, allow_unicode=True))
|
||||
super(Circle, self).full_clean(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Circle"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title}"
|
||||
|
||||
|
||||
IN_CIRCLE = 'INCIRCLE'
|
||||
START = 'START'
|
||||
END = 'END'
|
||||
|
||||
LEARNING_SEQUENCE_CATEGORIES = [
|
||||
(IN_CIRCLE, 'In Circle'),
|
||||
(START, 'Start'),
|
||||
(END, 'End')
|
||||
]
|
||||
|
||||
|
||||
class LearningSequence(Orderable):
|
||||
# TODO: How to do a icon choice field?
|
||||
title = models.CharField(max_length=256, default='')
|
||||
category = models.CharField(max_length=16, choices=LEARNING_SEQUENCE_CATEGORIES, default=IN_CIRCLE)
|
||||
|
||||
circle = ParentalKey(
|
||||
'learnpath.Circle',
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='learning_sequences',
|
||||
)
|
||||
|
||||
panels = [FieldPanel('title'), FieldPanel('category'), FieldPanel('circle')]
|
||||
|
||||
|
||||
|
||||
graphql_fields = [
|
||||
GraphQLString("title", required=True),
|
||||
GraphQLBoolean("category"),
|
||||
]
|
||||
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Learning Sequence"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title}"
|
||||
|
||||
def full_clean(self, *args, **kwargs):
|
||||
self.slug = find_available_slug(LearningSequence, slugify(self.title, allow_unicode=True))
|
||||
super(LearningSequence, self).full_clean(*args, **kwargs)
|
||||
|
||||
|
||||
|
||||
class LearningPackage(Orderable):
|
||||
title = models.CharField(max_length=256, default='')
|
||||
|
||||
learning_sequence = models.ForeignKey(
|
||||
'learnpath.LearningSequence',
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='learning_packages',
|
||||
)
|
||||
panels = [FieldPanel('title')]
|
||||
|
||||
graphql_fields = [
|
||||
GraphQLString("title", required=False),
|
||||
]
|
||||
|
||||
|
||||
def full_clean(self, *args, **kwargs):
|
||||
self.slug = find_available_slug(LearningPackage, slugify(self.title, allow_unicode=True))
|
||||
super(LearningPackage, self).full_clean(*args, **kwargs)
|
||||
|
||||
|
||||
class LearningUnit(Page, Orderable):
|
||||
"""
|
||||
This is a group of contents, with the übung and test it is one unit. ... more of a structural charactacter.
|
||||
|
||||
"""
|
||||
# TODO: Review model architecture, is the stream field the right thing here?
|
||||
parent_page_types = ['learnpath.Circle']
|
||||
learning_package = models.ForeignKey(
|
||||
'learnpath.LearningPackage',
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='learning_units',
|
||||
)
|
||||
|
||||
content_blocks = [
|
||||
('web_based_training', WebBasedTrainingBlock()),
|
||||
('video', VideoBlock()),
|
||||
]
|
||||
|
||||
contents = StreamField(StreamBlock(content_blocks),
|
||||
null=True, blank=True, min_num=1, max_num=1)
|
||||
|
||||
content_panels = [
|
||||
FieldPanel('title', classname="full title"),
|
||||
FieldPanel('learning_package'),
|
||||
StreamFieldPanel('contents'),
|
||||
]
|
||||
|
||||
graphql_fields = [
|
||||
GraphQLString("title", required=True),
|
||||
GraphQLStreamfield('contents')
|
||||
]
|
||||
|
||||
subpage_types = []
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Learning Unit"
|
||||
|
||||
def full_clean(self, *args, **kwargs):
|
||||
self.slug = find_available_slug(LearningUnit, slugify(self.title, allow_unicode=True))
|
||||
super(LearningUnit, self).full_clean(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title}"
|
||||
|
||||
|
||||
|
||||
def find_available_slug(model, requested_slug, ignore_page_id=None):
|
||||
"""
|
||||
Finds an available slug within the specified parent.
|
||||
|
||||
If the requested slug is not available, this adds a number on the end, for example:
|
||||
|
||||
- 'requested-slug'
|
||||
- 'requested-slug-1'
|
||||
- 'requested-slug-2'
|
||||
|
||||
And so on, until an available slug is found.
|
||||
|
||||
The `ignore_page_id` keyword argument is useful for when you are updating a page,
|
||||
you can pass the page being updated here so the page's current slug is not
|
||||
treated as in use by another page.
|
||||
"""
|
||||
|
||||
# TODO: In comparison ot wagtails own function, I look for the same model instead of the parent
|
||||
pages = model.objects.filter(slug__startswith=requested_slug)
|
||||
|
||||
if ignore_page_id:
|
||||
pages = pages.exclude(id=ignore_page_id)
|
||||
|
||||
existing_slugs = set(pages.values_list("slug", flat=True))
|
||||
slug = requested_slug
|
||||
number = 1
|
||||
|
||||
while slug in existing_slugs:
|
||||
slug = requested_slug + "-" + str(number)
|
||||
number += 1
|
||||
|
||||
return slug
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
from django.db import models
|
||||
from wagtail.core.models import Page, Orderable
|
||||
from modelcluster.fields import ParentalKey
|
||||
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel, InlinePanel
|
||||
|
||||
|
||||
class CompetencePage(Page):
|
||||
"""This is the page where the competences and Fullfillment criterias are manged
|
||||
For one Learning Path"""
|
||||
|
||||
|
||||
content_panels = Page.content_panels + [
|
||||
InlinePanel('competences', label="Competences"),
|
||||
]
|
||||
|
||||
subpage_types = ['learnpath.Circle']
|
||||
|
||||
parent_page_types = ['learnpath.LearningPath']
|
||||
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Learning Path"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title}"
|
||||
|
||||
|
||||
class Competence(Orderable):
|
||||
""" In VBV Terms this is a "Handlungskompetenz"""
|
||||
category_short = models.CharField(max_length=3, default='')
|
||||
name = models.CharField(max_length=2048)
|
||||
|
||||
|
||||
competence_page = ParentalKey('learnpath.CompetencePage',
|
||||
null=True,
|
||||
blank=True,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='competences',
|
||||
)
|
||||
|
||||
|
||||
|
||||
def get_short_info(self):
|
||||
return f"{self.category_short}{self.sort_order}"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.get_short_info()}: {self.name}"
|
||||
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Competence"
|
||||
|
||||
|
||||
class FullfillmentCriteria(Orderable):
|
||||
""" VBV Term Leistungskriterium"""
|
||||
name = models.CharField(max_length=2048)
|
||||
competence = models.ForeignKey(Competence, on_delete=models.CASCADE, null=True)
|
||||
|
||||
def get_short_info(self):
|
||||
return f"{self.competence.get_short_info()}.{self.sort_order}"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.get_short_info()}: {self.name}"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Fullfillment Criteria"
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
from django.db import models
|
||||
from wagtail.core import blocks
|
||||
|
||||
|
||||
# 'video_block'
|
||||
class VideoBlock(blocks.StructBlock):
|
||||
# TODO: Possible video Types for the user, upload file, add URL
|
||||
title = models.CharField(max_length=128, default="")
|
||||
description = models.TextField(default="")
|
||||
url = blocks.URLBlock()
|
||||
|
||||
class Meta:
|
||||
icon = 'media'
|
||||
|
||||
|
||||
|
||||
# 'Web based training Block'
|
||||
class WebBasedTrainingBlock(blocks.StructBlock):
|
||||
RISE = 'rise'
|
||||
|
||||
WBT_TYPE_CHOICES = (
|
||||
(RISE, 'Rise'),
|
||||
)
|
||||
|
||||
url = blocks.URLBlock()
|
||||
type = models.CharField(
|
||||
max_length=100,
|
||||
choices=WBT_TYPE_CHOICES,
|
||||
default=RISE
|
||||
)
|
||||
|
||||
class Meta:
|
||||
icon = 'media'
|
||||
|
||||
# 'Transver Task'
|
||||
class TranverTaskBlock(blocks.StructBlock):
|
||||
title = models.CharField(max_length=128, default="")
|
||||
description = models.TextField(default="")
|
||||
|
||||
class Meta:
|
||||
icon = 'media'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Iterativ GmbH
|
||||
# http://www.iterativ.ch/
|
||||
#
|
||||
# Copyright (c) 2015 Iterativ GmbH. All rights reserved.
|
||||
#
|
||||
# Created on 2022-03-29
|
||||
# @author: lorenz.padberg@iterativ.ch
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
{
|
||||
"competences": [
|
||||
{
|
||||
"name": "Weiterempfehlung für Neukunden generieren",
|
||||
"category_short": "A",
|
||||
"fullfillment_criteria": [
|
||||
{
|
||||
"name": "bestehende Kunden so zu beraten, dass sie von diesen weiterempfohlen werden"
|
||||
},
|
||||
{
|
||||
"name": "geeignete Personen wie z.B. Garagisten, Architekten, Treuhänder auf die Vermittlung/Zusammenarbeit anzusprechen"
|
||||
},
|
||||
{
|
||||
"name": "verschiedene Datenquellen wie Internet, Telefonbuch, Handelszeitung, Baugesuche etc. gezielt für die Gewinnung von Neukunden zu benützen"
|
||||
},
|
||||
{
|
||||
"name": "ein beliebiges Gespräch resp. einen bestehenden Kontakt in die Richtung «Versicherung» zu lenken"
|
||||
},
|
||||
{
|
||||
"name": "das Thema Risiko und Sicherheit in einem Gespräch gezielt und auf die Situation des jeweiligen Gesprächspartners bezogen einfliessen zu lassen"
|
||||
},
|
||||
{
|
||||
"name": "im täglichen Kontakt potentielle Kundinnen und Kunden zu erkennen"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Kundengespräche vereinbaren",
|
||||
"category_short": "A",
|
||||
"fullfillment_criteria": [
|
||||
{
|
||||
"name": "je nach (Neu-) Kunde Form und Ort für das Gespräch festzulegen"
|
||||
},
|
||||
{
|
||||
"name": "sich intern und extern die nötigen Informationen über den (Neu-) Kunde zu beschaffen"
|
||||
},
|
||||
{
|
||||
"name": "die Terminierung auf ein bestimmtes Thema wie z.B. Rechtsschutz, Vorsorge, Krankenversicherung etc. auszurichten"
|
||||
},
|
||||
{
|
||||
"name": "für das zu führende Gespräch eine Agenda zu erstellen"
|
||||
},
|
||||
{
|
||||
"name": "für das zu führende Gespräch geeignete Hilfsmittel und Unterlagen zusammenzustellen"
|
||||
}, {
|
||||
"name": "eine Kaltakquise durchzuführen und auf mögliche Einwände reagieren zu können"
|
||||
}
|
||||
]
|
||||
|
||||
},
|
||||
{
|
||||
"name": "Auftritt in den sozialen Medien zeitgemäss halten",
|
||||
"category_short": "A",
|
||||
"fullfillment_criteria": [ {
|
||||
"name": "in Zusammenarbeit mit den IT-Spezialisten und der Marketingabteilung die Inhalte für den zu realisierenden Medienauftritt zielgruppengerecht festzulegen"
|
||||
},
|
||||
{
|
||||
"name": "für die verschiedenen Kundensegmente die passenden sozialen Medien zu definieren"
|
||||
},
|
||||
{
|
||||
"name": "die Inhalte compliant zu halten"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Kundendaten erfassen",
|
||||
"category_short": "A",
|
||||
"fullfillment_criteria": []
|
||||
},
|
||||
{
|
||||
"name": "Wünsche, Ziele und Bedürfnisse der Kunden im Gespräch ermitteln",
|
||||
"category_short": "B",
|
||||
"fullfillment_criteria": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import factory
|
||||
import wagtail_factories
|
||||
|
||||
from vbv_lernwelt.learnpath.models_competences import Competence, FullfillmentCriteria, CompetencePage
|
||||
from vbv_lernwelt.learnpath.tests.learningpath_factories import LearningPathFactory
|
||||
|
||||
|
||||
class CompetencePageFactory(wagtail_factories.PageFactory):
|
||||
# learning_path = factory.SubFactory(LearningPathFactory)
|
||||
|
||||
class Meta:
|
||||
model = CompetencePage
|
||||
|
||||
|
||||
class CompetenceFactory(factory.django.DjangoModelFactory):
|
||||
category_short = 'A'
|
||||
name = "Weiterempfehung für neukunden generieren"
|
||||
competence_page = factory.SubFactory(CompetencePageFactory)
|
||||
|
||||
class Meta:
|
||||
model = Competence
|
||||
|
||||
|
||||
class FullfilmentCriteriaFactory(factory.django.DjangoModelFactory):
|
||||
name = 'Bestehende Kunden so zu beraten, dass sie von diesen weiterempfohlen werden'
|
||||
competence = factory.SubFactory(CompetenceFactory)
|
||||
|
||||
class Meta:
|
||||
model = FullfillmentCriteria
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import json
|
||||
|
||||
|
||||
import os.path
|
||||
|
||||
from vbv_lernwelt.learnpath.tests.competences_factories import CompetenceFactory, FullfilmentCriteriaFactory
|
||||
|
||||
competences_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'competences.json')
|
||||
|
||||
|
||||
def create_default_competences(competences_json=competences_file):
|
||||
with open(competences_json) as f:
|
||||
competences_json = json.load(f)
|
||||
|
||||
for index, compentence in enumerate(competences_json['competences']):
|
||||
|
||||
competence_model = CompetenceFactory(name=compentence['name'], category_short=compentence['category_short'], sort_order=index)
|
||||
print(competence_model)
|
||||
|
||||
for criteria_index, criteria in enumerate(compentence['fullfillment_criteria']):
|
||||
criteria_model = FullfilmentCriteriaFactory(name=criteria['name'], competence=competence_model, sort_order=criteria_index)
|
||||
print(criteria_model)
|
||||
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
import wagtail_factories
|
||||
from wagtail.core.models import Site
|
||||
|
||||
from vbv_lernwelt.learnpath.models import LearningPath, Topic, Circle, LearningSequence, LearningUnit
|
||||
from vbv_lernwelt.learnpath.tests.create_default_competences import create_default_competences
|
||||
from vbv_lernwelt.learnpath.tests.learningpath_factories import LearningPathFactory, TopicFactory, CircleFactory, \
|
||||
LearningSequenceFactory, LearningUnitFactory, VideoBlockFactory, WebBasedTrainingBlockFactory, LearningPackageFactory
|
||||
|
||||
|
||||
def create_default_learning_path():
|
||||
site = Site.objects.filter(is_default_site=True).first()
|
||||
|
||||
if not site:
|
||||
site = wagtail_factories.SiteFactory(is_default_site=True)
|
||||
|
||||
create_default_competences()
|
||||
|
||||
lp = LearningPathFactory(title="Versicherungsvermittler/in", parent=site.root_page)
|
||||
|
||||
tp = TopicFactory(title="Basis", is_visible=False, learning_path=lp)
|
||||
|
||||
circle_1 = CircleFactory(title="Basis", parent=lp, topic=tp, description="""In diesem Circle erklären wir dir, wie der Lehrgang
|
||||
Versicherungsvermittler / in " aufgebaut ist. Zudem vermitteln wir dir die wichtigsten Grundlagen,
|
||||
damit erfolgreich mit deinem Lernpfad starten kannst.""")
|
||||
|
||||
ls_1 = LearningSequenceFactory(title='Einleitung', circle=circle_1)
|
||||
|
||||
lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=ls_1)
|
||||
|
||||
lu_1 = LearningUnitFactory(title="Herzlich Willkommmen", parent=circle_1, learning_package=lpck_1)
|
||||
lu_1 = LearningUnitFactory(title="Herzlich Willkommmen 1", parent=circle_1, learning_package=lpck_1)
|
||||
lu_1 = LearningUnitFactory(title="Herzlich Willkommmen 2", parent=circle_1, learning_package=lpck_1)
|
||||
|
||||
ls_2 = LearningSequenceFactory(title='Grundlagen', circle=circle_1)
|
||||
lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=ls_2)
|
||||
|
||||
lu_1 = LearningUnitFactory(title="Aber jetzt, Butter bei die Fische", parent=circle_1, learning_package=lpck_1)
|
||||
|
||||
tp = TopicFactory(title="Gewinnen von Kunden", learning_path=lp)
|
||||
|
||||
circle_2 = CircleFactory(title="Gewinnen", parent=lp, description="""Versicherungsvermittlerinnen und -vermittler verfügen über
|
||||
ein starkes Netzwerk, das sie gezielt pflegen und ausbauen. Sie beraten und betreuen ihre bestehenden Kundinnen und Kunden professionell und gewinnen so ihr Vertrauen. Dadurch schaffen sie die Basis für das Gewinnen
|
||||
von neuen Kundinnen und Kunden. Versicherungsvermittlerinnen und -vermittler sprechen ihre bestehenden Kundinnen
|
||||
und Kunden auf Weiterempfehlung an. So nutzen sie ihre
|
||||
bestehenden Kontakte geschickt für das Anwerben von
|
||||
Neukundinnen und -kunden.
|
||||
""", goals="""— Bestehende Kunden so zu beraten, dass
|
||||
sie von diesen weiterempfohlen werden
|
||||
— Geeignete Personen wie z.B. Garagisten, Architekten, Treuhänder auf die
|
||||
Vermittlung/Zusammenarbeit anzusprechen
|
||||
— Verschiedene Datenquellen wie Internet, Telefonbuch, Handelszeitung, Baugesuche etc. Gezielt für die Gewinnung
|
||||
von Neukunden zu benützen
|
||||
— Ein beliebiges Gespräch resp. Einen bestehenden Kontakt in die Richtung
|
||||
«Versicherung» zu lenken
|
||||
— Das Thema Risiko und Sicherheit in einem Gespräch gezielt und auf die Situation des jeweiligen Gesprächspartners bezogen einfliessen zu lassen
|
||||
— Im täglichen Kontakt potenzielle Kundinnen und Kunden zu erkennen""")
|
||||
|
||||
tp = TopicFactory(title="Beraten der Kunden", learning_path=lp)
|
||||
circle_3 = CircleFactory(title="Einstieg", parent=lp, topic=tp)
|
||||
circle_4 = CircleFactory(title="Analyse", parent=lp, topic=tp,
|
||||
description="""Nach dem Gespräch werten sie die Analyse aus und erstellen mit den
|
||||
zur Verfügung stehenden Systemen formal korrekte Lösungsvorschläge bzw.
|
||||
Ausschreibungen. Je nach Komplexität der Situation ziehen sie die nötigen
|
||||
Fachspezialisten bei.""",
|
||||
goals="""
|
||||
— Aus dem IST-Zustand (aus der durchgeführten Analyse) individuelle, risikogewichtete und finanzierbare Lösungsvorschläge zu erarbeiten
|
||||
— Eine Unterversicherung, eine Doppeloder Überversicherung oder einen fehlenden Versicherungsschutz festzustellen
|
||||
— Mögliches Optimierungspotential unter Berücksichtigung der finanziellen
|
||||
Situation des Kunden zu erkennen
|
||||
— Lösungsvorschläge zu skizzieren und
|
||||
zu visualisieren""")
|
||||
|
||||
sequence_1 = LearningSequenceFactory(title="Starten", circle=circle_4)
|
||||
lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_1)
|
||||
|
||||
learning_unit = LearningUnitFactory(title='Einleitung Circle "Anlayse"', parent=circle_4, learning_package=lpck_1)
|
||||
learning_unit = LearningUnitFactory.create(title='** Einstieg Video"', parent=circle_4, learning_package=lpck_1)
|
||||
video_url = "https://www.vbv.ch/fileadmin/vbv/Videos/Statements_Externe/Janos_M/Testimonial_Janos_Mischler_PositiveEffekte.mp4"
|
||||
video_title = "Ausbildung ist pflicht"
|
||||
video_description = "Erfahren Sie, was für Janos Mischler die positiven Aspekte von ständiger Weiterbildung sind – aus fachlicher und aus persönlicher Sicht."
|
||||
video_block = VideoBlockFactory(type="video", url=video_url, title=video_title, description=video_description)
|
||||
learning_unit.contents.append(('video', video_block))
|
||||
learning_unit.save()
|
||||
|
||||
learning_unit = LearningUnitFactory.create(title='** Web Based Training"', parent=circle_4, learning_package=lpck_1)
|
||||
wbt_url = "web_based_trainings/rise_cmi5_test_export/scormcontent/index.html"
|
||||
wbt_block = WebBasedTrainingBlockFactory(type="web_based_training", url=wbt_url)
|
||||
learning_unit.contents.append(('web_based_training', wbt_block))
|
||||
learning_unit.save()
|
||||
|
||||
learning_unit = LearningUnitFactory.create(title="Selbsteinschätzung", parent=circle_4, learning_package=lpck_1)
|
||||
|
||||
sequence_2 = LearningSequenceFactory.create(title="Beobachten", circle=circle_4)
|
||||
lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_2)
|
||||
|
||||
learning_unit = LearningUnitFactory.create(title="Mein Motorfahrzeug kaufen", parent=circle_4, learning_package=lpck_1)
|
||||
learning_unit = LearningUnitFactory.create(title="Sich selbständig machen", parent=circle_4, learning_package=lpck_1)
|
||||
|
||||
sequence_3 = LearningSequenceFactory.create(title="Anwenden", circle=circle_4)
|
||||
lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_3)
|
||||
|
||||
learning_unit = LearningUnitFactory.create(title="Nora kauft sich ein neues Auto", parent=circle_4, learning_package=lpck_1)
|
||||
learning_unit = LearningUnitFactory.create(title="Manuel träumt von einem neuen Tesla", parent=circle_4, learning_package=lpck_1)
|
||||
|
||||
lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_3)
|
||||
|
||||
learning_unit = LearningUnitFactory.create(title="Deine Erkenntnisse und Learnings", parent=circle_4, learning_package=lpck_1)
|
||||
|
||||
sequence_4 = LearningSequenceFactory.create(title="Üben", circle=circle_4)
|
||||
|
||||
lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_4)
|
||||
learning_unit = LearningUnitFactory.create(title="Ermittlung des Kundenbedarfs", parent=circle_4, learning_package=lpck_1)
|
||||
learning_unit = LearningUnitFactory.create(title="Aktives Zuhören", parent=circle_4, learning_package=lpck_1)
|
||||
learning_unit = LearningUnitFactory.create(title="In Bildern Sprechen", parent=circle_4, learning_package=lpck_1)
|
||||
|
||||
lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_4)
|
||||
learning_unit = LearningUnitFactory.create(title="Priorisieren des Bedarfs", parent=circle_4, learning_package=lpck_1)
|
||||
learning_unit = LearningUnitFactory.create(title="Zusammenfassung des Bedarfs", parent=circle_4, learning_package=lpck_1)
|
||||
|
||||
sequence_5 = LearningSequenceFactory.create(title="Testen", circle=circle_4)
|
||||
lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_5)
|
||||
|
||||
learning_unit = LearningUnitFactory.create(title="Bedarfsfragen", parent=circle_4, learning_package=lpck_1)
|
||||
learning_unit = LearningUnitFactory.create(title="Andwendung der Fragetechniken", parent=circle_4, learning_package=lpck_1)
|
||||
|
||||
sequence_5 = LearningSequenceFactory.create(title="Vernetzen", circle=circle_4)
|
||||
lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_5)
|
||||
|
||||
learning_unit = LearningUnitFactory.create(title="Online Training", parent=circle_4, learning_package=lpck_1)
|
||||
|
||||
sequence_6 = LearningSequenceFactory.create(title="Beenden", circle=circle_4)
|
||||
lpck_1 = LearningPackageFactory(title="Wunderbar !", learning_sequence=sequence_6)
|
||||
|
||||
learning_unit = LearningUnitFactory.create(title="Selbsteinschätzung", parent=circle_4, learning_package=lpck_1)
|
||||
|
||||
circle_5 = CircleFactory.create(title="Lösung",
|
||||
parent=lp,
|
||||
topic=tp,
|
||||
goals="""— Die Daten des Kunden korrekt in die notwendigen Systeme einzutragen
|
||||
— Fachspezialisten beizuziehen, falls dies angezeigt ist
|
||||
— Mit den zur Verfügung stehenden Systemen korrekte Lösungsvorschläge
|
||||
(z.B. Offerten oder Ausschreibungen) zu verfassen
|
||||
— Falls nötig die Lösungsvorschläge dem Underwriting weiterzuleiten und
|
||||
Unklarheiten zu bereinigen """)
|
||||
|
||||
circle_6 = CircleFactory.create(title="Abschluss",
|
||||
parent=lp,
|
||||
topic=tp,
|
||||
goals="""— Je nach Komplexität der Lösungsvorschläge (z.B. Offerten oder Offertvergleich) einen Fachspezialisten aufzubieten
|
||||
— Sich kundenorientiert auf das Gespräch vorzubereiten und sich passend zu präsentieren""")
|
||||
|
||||
tp = TopicFactory.create(title="Betreuen und Ausbauen des Kundenstamms", learning_path=lp)
|
||||
circle_7 = CircleFactory.create(title="Betreuen", parent=lp, topic=tp)
|
||||
|
||||
tp = TopicFactory.create(title="Prüfung", is_visible=False, learning_path=lp)
|
||||
circle_7 = CircleFactory.create(title="Prüfungsvorbereitung", parent=lp, topic=tp)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def delete_default_learning_path():
|
||||
LearningUnit.objects.all().delete()
|
||||
LearningSequence.objects.all().delete()
|
||||
Circle.objects.all().delete()
|
||||
Topic.objects.all().delete()
|
||||
LearningPath.objects.all().delete()
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
GET http://localhost:8000/graphql/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
{
|
||||
page(id: 8) {
|
||||
|
||||
children {
|
||||
__typename
|
||||
id
|
||||
title
|
||||
children {
|
||||
__typename
|
||||
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
page(id: 8) {
|
||||
|
||||
children {
|
||||
__typename
|
||||
id
|
||||
title
|
||||
children {
|
||||
__typename
|
||||
|
||||
id
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import wagtail_factories
|
||||
import factory
|
||||
from vbv_lernwelt.learnpath.models import LearningPath, Topic, Circle, LearningSequence, LearningUnit, LearningPackage
|
||||
from vbv_lernwelt.learnpath.models_learning_unit_content import VideoBlock, WebBasedTrainingBlock
|
||||
|
||||
|
||||
class LearningPathFactory(wagtail_factories.PageFactory):
|
||||
title = "Versicherungsvermittler/in"
|
||||
|
||||
class Meta:
|
||||
model = LearningPath
|
||||
|
||||
|
||||
class TopicFactory(factory.django.DjangoModelFactory):
|
||||
title = "Gewinnen von Kunden"
|
||||
is_visible = True
|
||||
|
||||
class Meta:
|
||||
model = Topic
|
||||
|
||||
|
||||
class CircleFactory(wagtail_factories.PageFactory):
|
||||
title = "Gewinnen"
|
||||
|
||||
class Meta:
|
||||
model = Circle
|
||||
|
||||
|
||||
class LearningSequenceFactory(factory.django.DjangoModelFactory):
|
||||
title = "Grundlagen"
|
||||
|
||||
class Meta:
|
||||
model = LearningSequence
|
||||
|
||||
class LearningPackageFactory(factory.django.DjangoModelFactory):
|
||||
title = "Whatever"
|
||||
|
||||
class Meta:
|
||||
model = LearningPackage
|
||||
|
||||
|
||||
class LearningUnitFactory(wagtail_factories.PageFactory):
|
||||
title = "Herzlich Willkommen"
|
||||
|
||||
class Meta:
|
||||
model = LearningUnit
|
||||
|
||||
|
||||
class VideoBlockFactory(wagtail_factories.StructBlockFactory):
|
||||
title = "Ausbildung ist Pflicht"
|
||||
url = "https://www.vbv.ch/fileadmin/vbv/Videos/Statements_Externe/Janos_M/Testimonial_Janos_Mischler_PositiveEffekte.mp4"
|
||||
|
||||
class Meta:
|
||||
model = VideoBlock
|
||||
|
||||
class WebBasedTrainingBlockFactory(wagtail_factories.StructBlockFactory):
|
||||
title = "Beispiel Rise Modul"
|
||||
url = "https://docs.wagtail.org/en/stable/topics/streamfield.html"
|
||||
|
||||
class Meta:
|
||||
model = WebBasedTrainingBlock
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
from django.test import TestCase
|
||||
|
||||
from vbv_lernwelt.learnpath.models_competences import Competence, FullfillmentCriteria
|
||||
from vbv_lernwelt.learnpath.tests.competences_factories import CompetencePageFactory, CompetenceFactory, \
|
||||
FullfilmentCriteriaFactory
|
||||
|
||||
|
||||
class TestCompetencesFactories(TestCase):
|
||||
def test_create_competences_page(self):
|
||||
CompetencePageFactory()
|
||||
|
||||
def test_create_competence(self):
|
||||
CompetenceFactory(name='Boogie Woogie')
|
||||
self.assertEqual(Competence.objects.filter(name='Boogie Woogie').count(), 1)
|
||||
|
||||
def test_create_fullfillment_criteria(self):
|
||||
FullfilmentCriteriaFactory(name='shuffle like ...')
|
||||
self.assertEqual(FullfillmentCriteria.objects.filter(name='shuffle like ...').count(), 1)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from wagtail.core.models import Locale
|
||||
|
||||
from vbv_lernwelt.learnpath.models import LearningPath
|
||||
from vbv_lernwelt.learnpath.tests.create_default_competences import create_default_competences
|
||||
from vbv_lernwelt.learnpath.tests.create_default_learning_path import create_default_learning_path
|
||||
|
||||
|
||||
class TestCreateDefaultCompetences(TestCase):
|
||||
def test_create_default_competeneces(self):
|
||||
create_default_competences()
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from wagtail.core.models import Locale
|
||||
|
||||
from vbv_lernwelt.learnpath.models import LearningPath
|
||||
from vbv_lernwelt.learnpath.tests.create_default_learning_path import create_default_learning_path
|
||||
|
||||
|
||||
class TestCreateDefaultLearningPaths(TestCase):
|
||||
def setUp(self) -> None:
|
||||
create_locales_for_wagtail()
|
||||
|
||||
def test_create_learning_path(self):
|
||||
create_default_learning_path()
|
||||
qs = LearningPath.objects.filter(title="Versicherungsvermittler/in")
|
||||
self.assertTrue(qs.exists())
|
||||
|
||||
|
||||
def create_locales_for_wagtail():
|
||||
for language in settings.WAGTAIL_CONTENT_LANGUAGES:
|
||||
Locale.objects.get_or_create(language_code=language[0])
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Iterativ GmbH
|
||||
# http://www.iterativ.ch/
|
||||
#
|
||||
# Copyright (c) 2015 Iterativ GmbH. All rights reserved.
|
||||
#
|
||||
# Created on 2022-03-29
|
||||
# @author: lorenz.padberg@iterativ.ch
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<courseStructure xmlns="https://w3id.org/xapi/profiles/cmi5/v1/CourseStructure.xsd">
|
||||
<course id="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/course">
|
||||
<title>
|
||||
<langstring lang="en-US">Export - Testmodul</langstring>
|
||||
</title>
|
||||
<description>
|
||||
<langstring lang="en-US"><strong><span style="color: rgb(0, 0, 0);">Herzlich willkommen!&nbsp;</span></strong><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 0);">In dieser Lernsequenz zeigt dir ein Fachexperte anhand von Kundensituationen, wie du erfolgreich den <strong>Kundenbedarf&nbsp;</strong><strong>ermitteln</strong>, <strong>analysieren, priorisieren&nbsp;</strong>und anschliessend<strong>&nbsp;zusammenfassen&nbsp;</strong>kannst.&nbsp;</span><br><span style="color: rgb(0, 0, 0);">Zudem erh&auml;ltst du wertvolle <strong>Werkzeuge&nbsp;</strong>und<strong>&nbsp;Hilfsmittel</strong>, die du im Gespr&auml;ch einsetzen kannst.&nbsp;</span><br><span style="color: rgb(0, 0, 0);">In den einzelnen Lektionen findest du ferner Hinweise und Empfehlungen, welches <strong>Versicherungsfachwissen&nbsp;</strong>du in diesen<strong>&nbsp;Kundensituationen</strong> ben&ouml;tigst.</span><br><span style="color: rgb(0, 0, 0);">Die Bearbeitungszeit dieser Lernsequenz dauert&nbsp;</span><span style="color: rgb(228, 79, 59);">xy&nbsp;</span><span style="color: rgb(0, 0, 0);">min.&nbsp;</span><br><span style="color: rgb(0, 0, 0);">Die Lektionen k&ouml;nnen auch einzelnen bearbeitet werden.</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 0);"><strong>Viel Erfolg!</strong></span><span style="color: rgb(228, 79, 59);"><strong>&nbsp;</strong></span><br></langstring>
|
||||
</description>
|
||||
</course>
|
||||
<objectives>
|
||||
<objective id="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/objective/zCsrPmg8-DHqvtr02ko_vaZAHxl9PZaN">
|
||||
<title>
|
||||
<langstring lang="en-US">
|
||||
Einstieg
|
||||
</langstring>
|
||||
</title>
|
||||
<description>
|
||||
<langstring lang="en-US">
|
||||
|
||||
</langstring>
|
||||
</description>
|
||||
</objective>
|
||||
<objective id="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/objective/rqh87qZLmckYDhxDILEC2FK_Jd8WnC2D">
|
||||
<title>
|
||||
<langstring lang="en-US">
|
||||
Bei Kunden auf Besuch
|
||||
</langstring>
|
||||
</title>
|
||||
<description>
|
||||
<langstring lang="en-US">
|
||||
|
||||
</langstring>
|
||||
</description>
|
||||
</objective>
|
||||
<objective id="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/objective/kkW2rZVsRdRxeM7Nb5bVLv-_caw7Lcrz">
|
||||
<title>
|
||||
<langstring lang="en-US">
|
||||
Bedarfsbogen einsetzen
|
||||
</langstring>
|
||||
</title>
|
||||
<description>
|
||||
<langstring lang="en-US">
|
||||
|
||||
</langstring>
|
||||
</description>
|
||||
</objective>
|
||||
<objective id="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/objective/CKY2_VgqHGm8_JQxds-QitJbfh-T8Pe6">
|
||||
<title>
|
||||
<langstring lang="en-US">
|
||||
Bedarfsbogen auswerten
|
||||
</langstring>
|
||||
</title>
|
||||
<description>
|
||||
<langstring lang="en-US">
|
||||
|
||||
</langstring>
|
||||
</description>
|
||||
</objective>
|
||||
<objective id="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/objective/StyvsD3zqY2mzlrtnv3NF_PCXJo6_JOg">
|
||||
<title>
|
||||
<langstring lang="en-US">
|
||||
Deine Erkenntnisse und Learnings
|
||||
</langstring>
|
||||
</title>
|
||||
<description>
|
||||
<langstring lang="en-US">
|
||||
|
||||
</langstring>
|
||||
</description>
|
||||
</objective>
|
||||
<objective id="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/objective/_PsT4xluII9_2SZFjWh-MkdVwqWF-Tj-">
|
||||
<title>
|
||||
<langstring lang="en-US">
|
||||
Quizz - zum Testen
|
||||
</langstring>
|
||||
</title>
|
||||
<description>
|
||||
<langstring lang="en-US">
|
||||
Hallo ,dies ist nur ein kurzer Test zum ausprobieren.
|
||||
</langstring>
|
||||
</description>
|
||||
</objective>
|
||||
</objectives>
|
||||
|
||||
<au id="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/activity" launchMethod="OwnWindow" moveOn="Passed" >
|
||||
<title>
|
||||
<langstring lang="en">
|
||||
Export - Testmodul
|
||||
</langstring>
|
||||
</title>
|
||||
<description>
|
||||
<langstring lang="en">
|
||||
<strong><span style="color: rgb(0, 0, 0);">Herzlich willkommen!&nbsp;</span></strong><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 0);">In dieser Lernsequenz zeigt dir ein Fachexperte anhand von Kundensituationen, wie du erfolgreich den <strong>Kundenbedarf&nbsp;</strong><strong>ermitteln</strong>, <strong>analysieren, priorisieren&nbsp;</strong>und anschliessend<strong>&nbsp;zusammenfassen&nbsp;</strong>kannst.&nbsp;</span><br><span style="color: rgb(0, 0, 0);">Zudem erh&auml;ltst du wertvolle <strong>Werkzeuge&nbsp;</strong>und<strong>&nbsp;Hilfsmittel</strong>, die du im Gespr&auml;ch einsetzen kannst.&nbsp;</span><br><span style="color: rgb(0, 0, 0);">In den einzelnen Lektionen findest du ferner Hinweise und Empfehlungen, welches <strong>Versicherungsfachwissen&nbsp;</strong>du in diesen<strong>&nbsp;Kundensituationen</strong> ben&ouml;tigst.</span><br><span style="color: rgb(0, 0, 0);">Die Bearbeitungszeit dieser Lernsequenz dauert&nbsp;</span><span style="color: rgb(228, 79, 59);">xy&nbsp;</span><span style="color: rgb(0, 0, 0);">min.&nbsp;</span><br><span style="color: rgb(0, 0, 0);">Die Lektionen k&ouml;nnen auch einzelnen bearbeitet werden.</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 0, 0);"><strong>Viel Erfolg!</strong></span><span style="color: rgb(228, 79, 59);"><strong>&nbsp;</strong></span><br>
|
||||
</langstring>
|
||||
</description>
|
||||
<objectives>
|
||||
<objective idref="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/objective/zCsrPmg8-DHqvtr02ko_vaZAHxl9PZaN" />
|
||||
<objective idref="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/objective/rqh87qZLmckYDhxDILEC2FK_Jd8WnC2D" />
|
||||
<objective idref="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/objective/kkW2rZVsRdRxeM7Nb5bVLv-_caw7Lcrz" />
|
||||
<objective idref="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/objective/CKY2_VgqHGm8_JQxds-QitJbfh-T8Pe6" />
|
||||
<objective idref="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/objective/StyvsD3zqY2mzlrtnv3NF_PCXJo6_JOg" />
|
||||
<objective idref="http://W5gboDeZ-uE5O0B683j1lB9eMrngLG2d_rise/objective/_PsT4xluII9_2SZFjWh-MkdVwqWF-Tj-" />
|
||||
</objectives>
|
||||
<url>scormdriver/indexAPI.html</url>
|
||||
<launchParameters>eyJjcHYiOiJndktDa0RlayIsInJsZCI6ZmFsc2V9</launchParameters>
|
||||
</au>
|
||||
</courseStructure>
|
||||
|
After Width: | Height: | Size: 195 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 356 KiB |
|
After Width: | Height: | Size: 326 KiB |
|
After Width: | Height: | Size: 488 KiB |
|
After Width: | Height: | Size: 942 B |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 280 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 165 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 367 KiB |
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 245 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
|
@ -0,0 +1,14 @@
|
|||
function SetBookmark() {
|
||||
var SD = window.parent,
|
||||
loc = window.location.href
|
||||
;
|
||||
|
||||
SD.SetBookmark(
|
||||
loc.substring(loc.toLowerCase().lastIndexOf("/scormcontent/") + 14, loc.length),
|
||||
document.title
|
||||
);
|
||||
SD.CommitData();
|
||||
}
|
||||
|
||||
//Automatically set a bookmark for this page.
|
||||
SetBookmark();
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
function SetSCOComplete()
|
||||
{
|
||||
var SD = window.parent;
|
||||
|
||||
//This is the last page so set it complete
|
||||
SD.SetReachedEnd();
|
||||
SD.CommitData();
|
||||
}
|
||||
|
||||
//Automatically set the SCO complete.
|
||||
SetSCOComplete();
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
function niExit()
|
||||
{
|
||||
var SD = window.parent;
|
||||
|
||||
var answer = confirm("Are You Sure You Wish To Exit This Course?");
|
||||
|
||||
if(answer)
|
||||
{
|
||||
SD.ConcedeControl();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<html>
|
||||
<!--/* Copyright © 2003-2013 Rustici Software, LLC All Rights Reserved. www.scorm.com */-->
|
||||
<head>
|
||||
<script>
|
||||
window.document.onkeypress = CheckForDebugCommand;
|
||||
|
||||
var intQuestionCounter = 0;
|
||||
var ASCII_QUESTION = 63;
|
||||
|
||||
function CheckForDebugCommand(e) {
|
||||
|
||||
|
||||
var intKeyCode = 0;
|
||||
if (window.event) {
|
||||
e = window.event;
|
||||
intKeyCode = e.keyCode;
|
||||
} else {
|
||||
intKeyCode = e.which;
|
||||
}
|
||||
|
||||
if (intKeyCode == ASCII_QUESTION) {
|
||||
intQuestionCounter++;
|
||||
if (intQuestionCounter == 3) {
|
||||
intQuestionCounter = 0;
|
||||
|
||||
parent.ShowDebugWindow();
|
||||
}
|
||||
} else if (intKeyCode != 0) { //in FireFox, the shift key comes through as a keypress with code of 0...we want to ignore this
|
||||
intQuestionCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--
|
||||
If the course does not load and is stuck on this page:
|
||||
-Click in the middle of the page
|
||||
-Press the question mark key (?) three times
|
||||
-A window should pop up containing debug information, send this information to technical support for further assistance
|
||||
-If no information appears, try again 1 or 2 more times, sometimes that just does the trick
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
|
||||
//<!--
|
||||
// Ultimate client-side JavaScript client sniff. Version 3.03
|
||||
// (C) Netscape Communications 1999-2001. Permission granted to reuse and distribute.
|
||||
// Revised 17 May 99 to add is_nav5up and is_ie5up (see below).
|
||||
// Revised 20 Dec 00 to add is_gecko and change is_nav5up to is_nav6up
|
||||
// also added support for IE5.5 Opera4&5 HotJava3 AOLTV
|
||||
// Revised 22 Feb 01 to correct Javascript Detection for IE 5.x, Opera 4,
|
||||
// correct Opera 5 detection
|
||||
// add support for winME and win2k
|
||||
// synch with browser-type-oo.js
|
||||
// Revised 26 Mar 01 to correct Opera detection
|
||||
// Revised 02 Oct 01 to add IE6 detection
|
||||
// Revised 16 Oct 03 to add explict NS 6 detection vs NS 7 - Mike Rustici
|
||||
|
||||
// Everything you always wanted to know about your JavaScript client
|
||||
// but were afraid to ask. Creates "is_" variables indicating:
|
||||
// (1) browser vendor:
|
||||
// is_nav, is_ie, is_opera, is_hotjava, is_webtv, is_TVNavigator, is_AOLTV
|
||||
// (2) browser version number:
|
||||
// is_major (integer indicating major version number: 2, 3, 4 ...)
|
||||
// is_minor (float indicating full version number: 2.02, 3.01, 4.04 ...)
|
||||
// (3) browser vendor AND major version number
|
||||
// is_nav2, is_nav3, is_nav4, is_nav4up, is_nav6, is_nav6up, is_gecko, is_ie3,
|
||||
// is_ie4, is_ie4up, is_ie5, is_ie5up, is_ie5_5, is_ie5_5up, is_ie6, is_ie6up, is_hotjava3, is_hotjava3up,
|
||||
// is_opera2, is_opera3, is_opera4, is_opera5, is_opera5up
|
||||
// (4) JavaScript version number:
|
||||
// is_js (float indicating full JavaScript version number: 1, 1.1, 1.2 ...)
|
||||
// (5) OS platform and version:
|
||||
// is_win, is_win16, is_win32, is_win31, is_win95, is_winnt, is_win98, is_winme, is_win2k
|
||||
// is_os2
|
||||
// is_mac, is_mac68k, is_macppc
|
||||
// is_unix
|
||||
// is_sun, is_sun4, is_sun5, is_suni86
|
||||
// is_irix, is_irix5, is_irix6
|
||||
// is_hpux, is_hpux9, is_hpux10
|
||||
// is_aix, is_aix1, is_aix2, is_aix3, is_aix4
|
||||
// is_linux, is_sco, is_unixware, is_mpras, is_reliant
|
||||
// is_dec, is_sinix, is_freebsd, is_bsd
|
||||
// is_vms
|
||||
//
|
||||
// See http://www.it97.de/JavaScript/JS_tutorial/bstat/navobj.html and
|
||||
// http://www.it97.de/JavaScript/JS_tutorial/bstat/Browseraol.html
|
||||
// for detailed lists of userAgent strings.
|
||||
//
|
||||
// Note: you don't want your Nav4 or IE4 code to "turn off" or
|
||||
// stop working when new versions of browsers are released, so
|
||||
// in conditional code forks, use is_ie5up ("IE 5.0 or greater")
|
||||
// is_opera5up ("Opera 5.0 or greater") instead of is_ie5 or is_opera5
|
||||
// to check version in code which you want to work on future
|
||||
// versions.
|
||||
|
||||
// convert all characters to lowercase to simplify testing
|
||||
var agt=navigator.userAgent.toLowerCase();
|
||||
|
||||
// *** BROWSER VERSION ***
|
||||
// Note: On IE5, these return 4, so use is_ie5up to detect IE5.
|
||||
var is_major = parseInt(navigator.appVersion);
|
||||
var is_minor = parseFloat(navigator.appVersion);
|
||||
|
||||
// Note: Opera and WebTV spoof Navigator. We do strict client detection.
|
||||
// If you want to allow spoofing, take out the tests for opera and webtv.
|
||||
var is_nav = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
|
||||
&& (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
|
||||
&& (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1));
|
||||
var is_nav2 = (is_nav && (is_major == 2));
|
||||
var is_nav3 = (is_nav && (is_major == 3));
|
||||
var is_nav4 = (is_nav && (is_major == 4));
|
||||
var is_nav4up = (is_nav && (is_major >= 4));
|
||||
var is_navonly = (is_nav && ((agt.indexOf(";nav") != -1) ||
|
||||
(agt.indexOf("; nav") != -1)) );
|
||||
var is_nav6 = (is_nav && (is_major == 5) && (agt.indexOf('rv:0') > -1));
|
||||
var is_nav6up = (is_nav && (is_major >= 5));
|
||||
var is_gecko = (agt.indexOf('gecko') != -1);
|
||||
|
||||
|
||||
var is_ie = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
|
||||
var is_ie3 = (is_ie && (is_major < 4));
|
||||
var is_ie4 = (is_ie && (is_major == 4) && (agt.indexOf("msie 4")!=-1) );
|
||||
var is_ie4up = (is_ie && (is_major >= 4));
|
||||
var is_ie5 = (is_ie && (is_major == 4) && (agt.indexOf("msie 5.0")!=-1) );
|
||||
var is_ie5_5 = (is_ie && (is_major == 4) && (agt.indexOf("msie 5.5") !=-1));
|
||||
var is_ie5up = (is_ie && !is_ie3 && !is_ie4);
|
||||
var is_ie5_5up =(is_ie && !is_ie3 && !is_ie4 && !is_ie5);
|
||||
var is_ie6 = (is_ie && (is_major == 4) && (agt.indexOf("msie 6.")!=-1) );
|
||||
var is_ie6up = (is_ie && !is_ie3 && !is_ie4 && !is_ie5 && !is_ie5_5);
|
||||
|
||||
// KNOWN BUG: On AOL4, returns false if IE3 is embedded browser
|
||||
// or if this is the first browser window opened. Thus the
|
||||
// variables is_aol, is_aol3, and is_aol4 aren't 100% reliable.
|
||||
var is_aol = (agt.indexOf("aol") != -1);
|
||||
var is_aol3 = (is_aol && is_ie3);
|
||||
var is_aol4 = (is_aol && is_ie4);
|
||||
var is_aol5 = (agt.indexOf("aol 5") != -1);
|
||||
var is_aol6 = (agt.indexOf("aol 6") != -1);
|
||||
|
||||
var is_opera = (agt.indexOf("opera") != -1);
|
||||
var is_opera2 = (agt.indexOf("opera 2") != -1 || agt.indexOf("opera/2") != -1);
|
||||
var is_opera3 = (agt.indexOf("opera 3") != -1 || agt.indexOf("opera/3") != -1);
|
||||
var is_opera4 = (agt.indexOf("opera 4") != -1 || agt.indexOf("opera/4") != -1);
|
||||
var is_opera5 = (agt.indexOf("opera 5") != -1 || agt.indexOf("opera/5") != -1);
|
||||
var is_opera5up = (is_opera && !is_opera2 && !is_opera3 && !is_opera4);
|
||||
|
||||
var is_webtv = (agt.indexOf("webtv") != -1);
|
||||
|
||||
var is_TVNavigator = ((agt.indexOf("navio") != -1) || (agt.indexOf("navio_aoltv") != -1));
|
||||
var is_AOLTV = is_TVNavigator;
|
||||
|
||||
var is_hotjava = (agt.indexOf("hotjava") != -1);
|
||||
var is_hotjava3 = (is_hotjava && (is_major == 3));
|
||||
var is_hotjava3up = (is_hotjava && (is_major >= 3));
|
||||
|
||||
// *** JAVASCRIPT VERSION CHECK ***
|
||||
var is_js;
|
||||
if (is_nav2 || is_ie3) is_js = 1.0;
|
||||
else if (is_nav3) is_js = 1.1;
|
||||
else if (is_opera5up) is_js = 1.3;
|
||||
else if (is_opera) is_js = 1.1;
|
||||
else if ((is_nav4 && (is_minor <= 4.05)) || is_ie4) is_js = 1.2;
|
||||
else if ((is_nav4 && (is_minor > 4.05)) || is_ie5) is_js = 1.3;
|
||||
else if (is_hotjava3up) is_js = 1.4;
|
||||
else if (is_nav6 || is_gecko) is_js = 1.5;
|
||||
// NOTE: In the future, update this code when newer versions of JS
|
||||
// are released. For now, we try to provide some upward compatibility
|
||||
// so that future versions of Nav and IE will show they are at
|
||||
// *least* JS 1.x capable. Always check for JS version compatibility
|
||||
// with > or >=.
|
||||
else if (is_nav6up) is_js = 1.5;
|
||||
// NOTE: ie5up on mac is 1.4
|
||||
else if (is_ie5up) is_js = 1.3
|
||||
|
||||
// HACK: no idea for other browsers; always check for JS version with > or >=
|
||||
else is_js = 0.0;
|
||||
|
||||
// *** PLATFORM ***
|
||||
var is_win = ( (agt.indexOf("win")!=-1) || (agt.indexOf("16bit")!=-1) );
|
||||
// NOTE: On Opera 3.0, the userAgent string includes "Windows 95/NT4" on all
|
||||
// Win32, so you can't distinguish between Win95 and WinNT.
|
||||
var is_win95 = ((agt.indexOf("win95")!=-1) || (agt.indexOf("windows 95")!=-1));
|
||||
|
||||
// is this a 16 bit compiled version?
|
||||
var is_win16 = ((agt.indexOf("win16")!=-1) ||
|
||||
(agt.indexOf("16bit")!=-1) || (agt.indexOf("windows 3.1")!=-1) ||
|
||||
(agt.indexOf("windows 16-bit")!=-1) );
|
||||
|
||||
var is_win31 = ((agt.indexOf("windows 3.1")!=-1) || (agt.indexOf("win16")!=-1) ||
|
||||
(agt.indexOf("windows 16-bit")!=-1));
|
||||
|
||||
var is_winme = ((agt.indexOf("win 9x 4.90")!=-1));
|
||||
var is_win2k = ((agt.indexOf("windows nt 5.0")!=-1));
|
||||
|
||||
// NOTE: Reliable detection of Win98 may not be possible. It appears that:
|
||||
// - On Nav 4.x and before you'll get plain "Windows" in userAgent.
|
||||
// - On Mercury client, the 32-bit version will return "Win98", but
|
||||
// the 16-bit version running on Win98 will still return "Win95".
|
||||
var is_win98 = ((agt.indexOf("win98")!=-1) || (agt.indexOf("windows 98")!=-1));
|
||||
var is_winnt = ((agt.indexOf("winnt")!=-1) || (agt.indexOf("windows nt")!=-1));
|
||||
var is_win32 = (is_win95 || is_winnt || is_win98 ||
|
||||
((is_major >= 4) && (navigator.platform == "Win32")) ||
|
||||
(agt.indexOf("win32")!=-1) || (agt.indexOf("32bit")!=-1));
|
||||
|
||||
var is_os2 = ((agt.indexOf("os/2")!=-1) ||
|
||||
(navigator.appVersion.indexOf("OS/2")!=-1) ||
|
||||
(agt.indexOf("ibm-webexplorer")!=-1));
|
||||
|
||||
var is_mac = (agt.indexOf("mac")!=-1);
|
||||
// hack ie5 js version for mac
|
||||
if (is_mac && is_ie5up) is_js = 1.4;
|
||||
var is_mac68k = (is_mac && ((agt.indexOf("68k")!=-1) ||
|
||||
(agt.indexOf("68000")!=-1)));
|
||||
var is_macppc = (is_mac && ((agt.indexOf("ppc")!=-1) ||
|
||||
(agt.indexOf("powerpc")!=-1)));
|
||||
|
||||
var is_sun = (agt.indexOf("sunos")!=-1);
|
||||
var is_sun4 = (agt.indexOf("sunos 4")!=-1);
|
||||
var is_sun5 = (agt.indexOf("sunos 5")!=-1);
|
||||
var is_suni86= (is_sun && (agt.indexOf("i86")!=-1));
|
||||
var is_irix = (agt.indexOf("irix") !=-1); // SGI
|
||||
var is_irix5 = (agt.indexOf("irix 5") !=-1);
|
||||
var is_irix6 = ((agt.indexOf("irix 6") !=-1) || (agt.indexOf("irix6") !=-1));
|
||||
var is_hpux = (agt.indexOf("hp-ux")!=-1);
|
||||
var is_hpux9 = (is_hpux && (agt.indexOf("09.")!=-1));
|
||||
var is_hpux10= (is_hpux && (agt.indexOf("10.")!=-1));
|
||||
var is_aix = (agt.indexOf("aix") !=-1); // IBM
|
||||
var is_aix1 = (agt.indexOf("aix 1") !=-1);
|
||||
var is_aix2 = (agt.indexOf("aix 2") !=-1);
|
||||
var is_aix3 = (agt.indexOf("aix 3") !=-1);
|
||||
var is_aix4 = (agt.indexOf("aix 4") !=-1);
|
||||
var is_linux = (agt.indexOf("inux")!=-1);
|
||||
var is_sco = (agt.indexOf("sco")!=-1) || (agt.indexOf("unix_sv")!=-1);
|
||||
var is_unixware = (agt.indexOf("unix_system_v")!=-1);
|
||||
var is_mpras = (agt.indexOf("ncr")!=-1);
|
||||
var is_reliant = (agt.indexOf("reliantunix")!=-1);
|
||||
var is_dec = ((agt.indexOf("dec")!=-1) || (agt.indexOf("osf1")!=-1) ||
|
||||
(agt.indexOf("dec_alpha")!=-1) || (agt.indexOf("alphaserver")!=-1) ||
|
||||
(agt.indexOf("ultrix")!=-1) || (agt.indexOf("alphastation")!=-1));
|
||||
var is_sinix = (agt.indexOf("sinix")!=-1);
|
||||
var is_freebsd = (agt.indexOf("freebsd")!=-1);
|
||||
var is_bsd = (agt.indexOf("bsd")!=-1);
|
||||
var is_unix = ((agt.indexOf("x11")!=-1) || is_sun || is_irix || is_hpux ||
|
||||
is_sco ||is_unixware || is_mpras || is_reliant ||
|
||||
is_dec || is_sinix || is_aix || is_linux || is_bsd || is_freebsd);
|
||||
|
||||
var is_vms = ((agt.indexOf("vax")!=-1) || (agt.indexOf("openvms")!=-1));
|
||||
|
||||
//--> end hide JavaScript
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
function loadDriverOptions (scope) {
|
||||
scope.APPID = "WQBM2ARBZR";
|
||||
scope.CLOUDURL = null;
|
||||
scope.USE_STRICT_SUSPEND_DATA_LIMITS = false;
|
||||
scope.FORCED_COMMIT_TIME = 60000;
|
||||
scope.strLMSStandard = "CMI5";
|
||||
scope.REVIEW_MODE_IS_READ_ONLY = true;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<html><body>
|
||||
<center>
|
||||
<br><br><br><br><br>
|
||||
Thank you for exiting the content. You may now navigate away from this content.
|
||||
</center>
|
||||
</body></html>
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--/* Copyright © 2003-2013 Rustici Software, LLC All Rights Reserved. www.scorm.com */-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title></title>
|
||||
|
||||
<style type="text/css">
|
||||
body,
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#content {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#content-frame {
|
||||
width: 1px;
|
||||
min-width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Resize Hack -->
|
||||
<script type="text/javascript">
|
||||
window.resizeTo(screen.width, screen.height);
|
||||
</script>
|
||||
|
||||
<script language="JavaScript1.2" src="driverOptions.js"></script>
|
||||
<script language="JavaScript1.2" src="scormdriver.js"></script>
|
||||
<script language="JavaScript1.2" src="preloadIntegrity.js"></script>
|
||||
<script language="JavaScript1.2">
|
||||
strContentLocation = "../scormcontent/index.html#/preview"; //Put the link to the start of the content here.
|
||||
totaliframesloaded = 0;
|
||||
|
||||
function updateIframesLoadedCount() {
|
||||
totaliframesloaded++;
|
||||
|
||||
if (totaliframesloaded == window.frames.length) {
|
||||
window.Start();
|
||||
}
|
||||
}
|
||||
|
||||
function LoadContent(){
|
||||
verifySuspendDataVersion(3);
|
||||
|
||||
var isAicc = false;
|
||||
strTemp = GetQueryStringValue("AICC_URL", document.location.search);
|
||||
if(strTemp!=null && strTemp!=""){
|
||||
isAicc = true;
|
||||
}
|
||||
|
||||
if(IsLoaded() || !isAicc)
|
||||
{
|
||||
//check for bookmark
|
||||
var bookmark = GetBookmark();
|
||||
|
||||
if (bookmark != "") {
|
||||
//if there is a bookmark, then go to that page
|
||||
window.scormdriver_content.document.location.href = "../scormcontent/" + bookmark;
|
||||
}
|
||||
else {
|
||||
//if not, go to the start page
|
||||
window.scormdriver_content.document.location.href = strContentLocation;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setTimeout(LoadContent, 500);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="content">
|
||||
<iframe id="content-frame" name="scormdriver_content" width="100%" height="100%" scrolling="no" frameborder="0" src="blank.html" onload="updateIframesLoadedCount()" allowfullscreen></iframe>
|
||||
<iframe name="AICCComm" src="AICCComm.html" frameborder="0" onload="updateIframesLoadedCount()" style="display: none;"></iframe>
|
||||
<iframe name="rusticisoftware_aicc_results" src="blank.html" frameborder="0" onload="updateIframesLoadedCount()" style="display: none;"></iframe>
|
||||
<iframe name="NothingFrame" src="blank.html" frameborder="0" onload="updateIframesLoadedCount()" style="display: none;"></iframe>
|
||||
</div>
|
||||
|
||||
<!-- Set iframes to mimic frames -->
|
||||
<script type="text/javascript">
|
||||
window.scormdriver_content = window.frames['scormdriver_content'];
|
||||
window.AICCComm = window.frames['AICCComm'];
|
||||
window.rusticisoftware_aicc_results = window.frames['rusticisoftware_aicc_results'];
|
||||
window.NothingFrame = window.frames['NothingFrame'];
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
function isTrue(val) {
|
||||
return val && String(val).toLowerCase() === 'true';
|
||||
}
|
||||
|
||||
function verifySuspendDataVersion(maxAttempts) {
|
||||
var commitDataAndBook;
|
||||
var launchData;
|
||||
var manifestCPV;
|
||||
var resetFlag;
|
||||
var sentBookCheck;
|
||||
var sentDataCheck;
|
||||
var suspendData = GetDataChunk();
|
||||
var suspendDataCPV;
|
||||
|
||||
if (!suspendData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (maxAttempts === 0) {
|
||||
WriteToDebug('WARNING: ERROR WITH CLEARING SUSPEND OR BOOKMARKING DATA!');
|
||||
WriteToDebug('NO MORE ATTEMPTS LEFT. COURSE BEHAVIOR MAY BE NEGATIVELY IMPACTED.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
launchData = JSON.parse(atob(GetLaunchData()));
|
||||
} catch (e) {
|
||||
WriteToDebug('WARNING: Issue with obtaining manifest launch data. Version reset behavior disabled.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
suspendData = JSON.parse(suspendData);
|
||||
} catch (e) {
|
||||
WriteToDebug('WARNING: Unable to parse suspend data. Version reset behavior disabled.');
|
||||
return;
|
||||
}
|
||||
|
||||
manifestCPV = launchData.cpv;
|
||||
resetFlag = launchData.rld;
|
||||
suspendDataCPV = suspendData.cpv;
|
||||
|
||||
if (suspendDataCPV !== manifestCPV) {
|
||||
WriteToDebug('WARNING: Suspend data version mismatch against manifest version.');
|
||||
if (resetFlag) {
|
||||
|
||||
if (REVIEW_MODE_IS_READ_ONLY && GetLessonMode() === 3) {
|
||||
WriteToDebug('WARNING: Course is in review mode. Unable to clear suspend and bookmarking data!');
|
||||
WriteToDebug('Resetting of learner data will not occur. Course behavior may be negatively impacted.');
|
||||
return;
|
||||
}
|
||||
|
||||
WriteToDebug('Okay to clear data. Now clearing suspend and bookmarking data...');
|
||||
|
||||
sentDataCheck = SetDataChunk("");
|
||||
WriteToDebug('Suspend Data Cleared: ' + sentDataCheck );
|
||||
|
||||
sentBookCheck = SetBookmark("");
|
||||
WriteToDebug('Bookmark Data Cleared: ' + sentBookCheck );
|
||||
|
||||
commitDataAndBook = CommitData();
|
||||
WriteToDebug('Data Commited: ' + commitDataAndBook );
|
||||
|
||||
if (isTrue(sentDataCheck) && isTrue(sentBookCheck) && isTrue(commitDataAndBook)) {
|
||||
WriteToDebug('Verified that all bookmarking and suspend data have been cleared. Data commited successfully.');
|
||||
} else {
|
||||
WriteToDebug('WARNING: ERROR WITH CLEARING SUSPEND OR BOOKMARKING DATA! RETRY ATTEMPTS LEFT: ' + (maxAttempts-1));
|
||||
verifySuspendDataVersion(maxAttempts-1);
|
||||
}
|
||||
} else {
|
||||
WriteToDebug('WARNING: Course reset flag not turned on. Resetting of learner data will not occur.');
|
||||
WriteToDebug('Course behavior may be negatively impacted.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
<!-- Your stuff: Third-party CSS libraries go here -->
|
||||
<!-- This file stores project-specific CSS -->
|
||||
<link href="{% static 'css/project.min.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/tailwind-output.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/output.css' %}" rel="stylesheet">
|
||||
{% endblock %}
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
|
|
@ -27,6 +27,8 @@
|
|||
<!-- Your stuff: Third-party javascript libraries go here -->
|
||||
<!-- place project specific Javascript in this file -->
|
||||
<script defer src="{% static 'js/project.js' %}"></script>
|
||||
<script src="https://d3js.org/d3.v4.min.js"></script>
|
||||
|
||||
|
||||
{% endblock javascript %}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load wagtailcore_tags %}
|
||||
|
||||
{% block body_class %}template-cicle{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="w-full flex mt-6">
|
||||
<div class="bg-white flex flex-col w-1/3 m-5">
|
||||
<div><a href="{% pageurl page.get_parent.get_parent %}">Zurück zum Lernpfad</a></div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<svg width="500" height="500">
|
||||
<defs>
|
||||
<marker id="triangle"
|
||||
viewBox="0 0 10 10"
|
||||
refX="5"
|
||||
refY="5"
|
||||
markerUnits="strokeWidth"
|
||||
markerWidth="10" markerHeight="10"
|
||||
orient="auto" overflow="visible" fill='#99C7E7'>
|
||||
<path d="M -2 5 L 8 0 L 8 10 z"/>
|
||||
</marker>
|
||||
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<h1 class="font-bold text-5xl mt-6 mb-4">{{ page.title }}</h1>
|
||||
<div class="mt4">{{ page.description }}</div>
|
||||
<div class="mt-4">{{ page.goals }}</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-50 flex-col w-2/3">
|
||||
{% for learning_sequence in page.learning_sequences.all %}
|
||||
<div class="p-6 max-w-sm mx-auto bg-white shadow-lg m-4">
|
||||
<h2 class="font-bold">{{ learning_sequence.title }}</h2>
|
||||
{% for learning_unit in learning_sequence.learning_units.all %}
|
||||
<div>
|
||||
<a target="_blank" href="{% pageurl learning_unit %}">{{ learning_unit.title }}</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var data = [5, 5, 5, 5, 5];
|
||||
|
||||
var svg = d3.select("svg"),
|
||||
width = svg.attr("width"),
|
||||
height = svg.attr("height"),
|
||||
radius = Math.min(width, height) / 2.5,
|
||||
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
|
||||
|
||||
|
||||
var color = '#99C7E7';
|
||||
|
||||
// Generate the pie
|
||||
var pie = d3.pie();
|
||||
|
||||
// Generate the arcs
|
||||
var arc = d3.arc()
|
||||
.innerRadius(radius / 2.5)
|
||||
.padAngle(12 / 360)
|
||||
.outerRadius(radius);
|
||||
|
||||
// Generate the arrows
|
||||
var arrow = d3.arc()
|
||||
.innerRadius(radius * 1.15)
|
||||
.padAngle(30 / 360)
|
||||
.outerRadius(radius * 1.16);
|
||||
|
||||
|
||||
//Generate groups
|
||||
var arcs = g.selectAll("arc")
|
||||
.data(pie(data))
|
||||
.enter()
|
||||
.append("g")
|
||||
.attr("class", "arc")
|
||||
|
||||
|
||||
//Generate groups
|
||||
var arrows = g.selectAll("arrow")
|
||||
.data(pie(data))
|
||||
.enter()
|
||||
.append("g")
|
||||
.attr("class", "arrow")
|
||||
.attr("marker-start", "url(#triangle)")
|
||||
|
||||
var markers = g.selectAll("arrow").attr("transform", "translate(60, 60) rotate(30)")
|
||||
|
||||
//Draw arc paths
|
||||
arcs.append("path")
|
||||
.attr("fill", color)
|
||||
.attr("d", arc)
|
||||
|
||||
//Draw arrow paths
|
||||
arrows.append("path")
|
||||
.attr("fill", color)
|
||||
.attr("d", arrow)
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load wagtailcore_tags %}
|
||||
|
||||
{% block body_class %}template-learningpath{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="font-bold text-5xl">{{ page.title }}</h1>
|
||||
|
||||
<div class="intro">{{ page.intro|richtext }}</div>
|
||||
<div class="flex flex-row w-full h-max-80 bg-gray-50 m-4 divide-x-4">
|
||||
|
||||
{% for topic in page.topics.all %}
|
||||
<div class="bg-gray-50-600 m-4">
|
||||
<h2 class="font-bold">{{ topic.title }}</h2>
|
||||
<div class="flex flex-row">
|
||||
{% for circle in topic.circles.all %}
|
||||
<div class="h-36 w-36 bg-gray-400 m-5">
|
||||
<h2><a href="{% pageurl circle %}">{{ circle.title }}</a></h2>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% load wagtailcore_tags %}
|
||||
{% load static %}
|
||||
|
||||
{% block body_class %}template-learning_unit{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<learning_unit>
|
||||
{% if not page.contents %}
|
||||
<div> O0ps, in dieser Lerneinheit wurde kein Inhalt erfasst.</div>
|
||||
{% endif %}
|
||||
|
||||
{% for block in page.contents %}
|
||||
|
||||
{% if block.block_type == 'video' %}
|
||||
<h1>{{ block.block_type }}</h1>
|
||||
<div class="video">
|
||||
<h1>{{ block.value.title }}</h1>
|
||||
<div>{{ block.value.description }}</div>
|
||||
|
||||
<video width="50%" controls>
|
||||
<source src={{ block.value.url }} type="video/mp4">
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if block.block_type == 'web_based_training' %}
|
||||
<div> Loading web based training...</div>
|
||||
<a class="font-bold" href="javascript:open_web_based_training('{{ block.value.url }}');">Click me!</a>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
</learning_unit>
|
||||
|
||||
|
||||
<script>
|
||||
function open_web_based_training(url){
|
||||
var realUrl = {% get_media_prefix %} + url
|
||||
console.log("Loading wbt", realUrl)
|
||||
window.location.href = realUrl;
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||