chore: shop vv-it, vv-de, vv-fr
This commit is contained in:
parent
561f9e3c96
commit
b414e4cf93
|
|
@ -16,12 +16,7 @@ const user = useUserStore();
|
||||||
Der Lehrgang und die Prüfung zum Erwerb des Verbandszertifikats als
|
Der Lehrgang und die Prüfung zum Erwerb des Verbandszertifikats als
|
||||||
Versicherungs-vermittler/-in.
|
Versicherungs-vermittler/-in.
|
||||||
</p>
|
</p>
|
||||||
<router-link
|
<a href="/start/vv" class="btn-primary">Mehr erfahren</a>
|
||||||
:to="{ name: 'accountProfile', params: { courseType: 'vv' } }"
|
|
||||||
class="btn-primary"
|
|
||||||
>
|
|
||||||
Jetzt mit Lehrgang starten
|
|
||||||
</router-link>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,27 @@
|
||||||
<template>
|
<template>
|
||||||
<main class="bg-gray-200 lg:px-12 lg:py-12">
|
<main class="bg-gray-200 lg:px-12 lg:py-12">
|
||||||
<div class="container-medium">
|
<div class="container-medium">
|
||||||
<h2 class="mb-8 text-blue-900">{{ $t("a.Versicherungsvermittler/-in") }}</h2>
|
|
||||||
<router-link
|
<router-link
|
||||||
class="btn-primary"
|
class="btn-primary"
|
||||||
:to="{ name: 'accountCreate', params: { courseType: 'vv' } }"
|
:to="{ name: 'accountCreate', params: { courseType: 'vv-de' } }"
|
||||||
>
|
>
|
||||||
{{ $t("a.Jetzt mit Lehrgang starten") }}
|
VV in Deutsch
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
<div class="container-medium">
|
||||||
|
<router-link
|
||||||
|
class="btn-primary"
|
||||||
|
:to="{ name: 'accountCreate', params: { courseType: 'vv-fr' } }"
|
||||||
|
>
|
||||||
|
VV in Französisch
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
<div class="container-medium">
|
||||||
|
<router-link
|
||||||
|
class="btn-primary"
|
||||||
|
:to="{ name: 'accountCreate', params: { courseType: 'vv-it' } }"
|
||||||
|
>
|
||||||
|
VV in Italienisch
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ import WizardPage from "@/components/onboarding/WizardPage.vue";
|
||||||
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
|
||||||
import { computed, ref, watch } from "vue";
|
import { computed, ref, watch } from "vue";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
import AvatarImage from "@/components/ui/AvatarImage.vue";
|
|
||||||
import { useFileUpload } from "@/composables";
|
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { useTranslation } from "i18next-vue";
|
import { useTranslation } from "i18next-vue";
|
||||||
import { profileNextRoute, useEntities } from "@/services/onboarding";
|
import { profileNextRoute, useEntities } from "@/services/onboarding";
|
||||||
|
|
@ -38,6 +36,7 @@ const validOrganisation = computed(() => {
|
||||||
return selectedOrganisation.value.id !== 0;
|
return selectedOrganisation.value.id !== 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* TODO: We do this later (not in the first release)
|
||||||
const {
|
const {
|
||||||
upload: avatarUpload,
|
upload: avatarUpload,
|
||||||
loading: avatarLoading,
|
loading: avatarLoading,
|
||||||
|
|
@ -47,7 +46,7 @@ const {
|
||||||
|
|
||||||
watch(avatarFileInfo, (info) => {
|
watch(avatarFileInfo, (info) => {
|
||||||
console.log("fileInfo changed", info);
|
console.log("fileInfo changed", info);
|
||||||
});
|
})*/
|
||||||
|
|
||||||
watch(selectedOrganisation, async (organisation) => {
|
watch(selectedOrganisation, async (organisation) => {
|
||||||
await user.setUserOrganisation(organisation.id);
|
await user.setUserOrganisation(organisation.id);
|
||||||
|
|
@ -75,6 +74,7 @@ const nextRoute = computed(() => {
|
||||||
|
|
||||||
<ItDropdownSelect v-model="selectedOrganisation" :items="organisations" />
|
<ItDropdownSelect v-model="selectedOrganisation" :items="organisations" />
|
||||||
|
|
||||||
|
<!--- TODO: We do this later (not in the first release)
|
||||||
<div class="mt-16 flex flex-col justify-between gap-12 lg:flex-row lg:gap-24">
|
<div class="mt-16 flex flex-col justify-between gap-12 lg:flex-row lg:gap-24">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="mb-3">{{ $t("a.Profilbild") }}</h3>
|
<h3 class="mb-3">{{ $t("a.Profilbild") }}</h3>
|
||||||
|
|
@ -103,6 +103,7 @@ const nextRoute = computed(() => {
|
||||||
</div>
|
</div>
|
||||||
<AvatarImage :loading="avatarLoading" :image-url="user.avatar_url" />
|
<AvatarImage :loading="avatarLoading" :image-url="user.avatar_url" />
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,13 @@ const user = useUserStore();
|
||||||
|
|
||||||
<p class="mb-4 mt-12">{{ $t("a.Hast du schon ein Konto?") }}</p>
|
<p class="mb-4 mt-12">{{ $t("a.Hast du schon ein Konto?") }}</p>
|
||||||
<a
|
<a
|
||||||
:href="getLoginURL({ course: props.courseType, lang: user.language })"
|
:href="
|
||||||
|
getLoginURL({
|
||||||
|
course: props.courseType,
|
||||||
|
lang: user.language,
|
||||||
|
next: `/onboarding/${courseType}/account/confirm`,
|
||||||
|
})
|
||||||
|
"
|
||||||
class="btn-secondary"
|
class="btn-secondary"
|
||||||
>
|
>
|
||||||
{{ $t("a.Anmelden") }}
|
{{ $t("a.Anmelden") }}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
# Onboarding flow
|
|
||||||
|
|
||||||
## ÜK
|
|
||||||
|
|
||||||
### Guard
|
|
||||||
|
|
||||||
1. Call /me
|
|
||||||
|
|
||||||
- User logged in -> redirect to /
|
|
||||||
- Anonymous user -> Set to /onboarding/uk/step1
|
|
||||||
|
|
||||||
## VV
|
|
||||||
|
|
||||||
### Guard
|
|
||||||
|
|
||||||
1. Call /shop/vv/state
|
|
||||||
- User logged in
|
|
||||||
- If already bought -> redirect to /
|
|
||||||
- If not bought -> redirect to /onboarding/vv/step1?state="success"
|
|
||||||
- Anonymous user -> Set to /onboarding/vv/step1
|
|
||||||
|
|
@ -4,6 +4,8 @@ import { computed } from "vue";
|
||||||
import mood_uk from "@/assets/images/mood_uk.jpg";
|
import mood_uk from "@/assets/images/mood_uk.jpg";
|
||||||
import mood_vv from "@/assets/images/mood_vv.jpg";
|
import mood_vv from "@/assets/images/mood_vv.jpg";
|
||||||
import { useTranslation } from "i18next-vue";
|
import { useTranslation } from "i18next-vue";
|
||||||
|
import { startsWith } from "lodash";
|
||||||
|
import { getVVCourseName } from "@/pages/onboarding/vv/helpers";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
courseType: {
|
courseType: {
|
||||||
|
|
@ -21,17 +23,17 @@ const courseData = computed(() => {
|
||||||
imageUrl: mood_uk,
|
imageUrl: mood_uk,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (props.courseType === "vv") {
|
if (startsWith(props.courseType, "vv")) {
|
||||||
return {
|
return {
|
||||||
name: t("a.Versicherungsvermittler/-in"),
|
name: getVVCourseName(props.courseType),
|
||||||
imageUrl: mood_vv,
|
imageUrl: mood_vv,
|
||||||
};
|
};
|
||||||
}
|
} else {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: "",
|
name: "",
|
||||||
imageUrl: "",
|
imageUrl: "",
|
||||||
};
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import { useEntities } from "@/services/onboarding";
|
||||||
import { useDebounceFn, useFetch } from "@vueuse/core";
|
import { useDebounceFn, useFetch } from "@vueuse/core";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { useTranslation } from "i18next-vue";
|
import { useTranslation } from "i18next-vue";
|
||||||
|
import { getVVCourseName } from "./helpers";
|
||||||
|
|
||||||
type BillingAddressType = {
|
type BillingAddressType = {
|
||||||
first_name: string;
|
first_name: string;
|
||||||
|
|
@ -27,6 +28,13 @@ type BillingAddressType = {
|
||||||
company_country: string;
|
company_country: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
courseType: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const user = useUserStore();
|
const user = useUserStore();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { organisations } = useEntities();
|
const { organisations } = useEntities();
|
||||||
|
|
@ -193,7 +201,7 @@ const executePayment = () => {
|
||||||
itPost("/api/shop/vv/checkout/", {
|
itPost("/api/shop/vv/checkout/", {
|
||||||
redirect_url: fullHost,
|
redirect_url: fullHost,
|
||||||
address: address.value,
|
address: address.value,
|
||||||
product: `vv-${user.language}`,
|
product: props.courseType,
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
console.log("Going to next page", res.next_step_url);
|
console.log("Going to next page", res.next_step_url);
|
||||||
window.location.href = res.next_step_url;
|
window.location.href = res.next_step_url;
|
||||||
|
|
@ -210,7 +218,7 @@ const executePayment = () => {
|
||||||
:translation="$t('a.Der Preis für den Lehrgang {course} beträgt {price}.')"
|
:translation="$t('a.Der Preis für den Lehrgang {course} beträgt {price}.')"
|
||||||
>
|
>
|
||||||
<template #course>
|
<template #course>
|
||||||
<b>"{{ $t("a.Versicherungsvermittler/-in") }} ({{ user.languageName }})"</b>
|
<b>"{{ getVVCourseName(props.courseType) }}"</b>
|
||||||
</template>
|
</template>
|
||||||
<template #price>
|
<template #price>
|
||||||
<b class="whitespace-nowrap">300 CHF</b>
|
<b class="whitespace-nowrap">300 CHF</b>
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ const user = useUserStore();
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<template #course>
|
<template #course>
|
||||||
{{ $t("a.Versicherungsvermittler/-in") }} ({{ user.languageName }})
|
{{ $t("a.Versicherungsvermittler/-in") }}
|
||||||
</template>
|
</template>
|
||||||
</i18next>
|
</i18next>
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
export const getVVCourseName = (courseType: string) => {
|
||||||
|
if (!["vv-de", "vv-it", "vv-fr"].includes(courseType)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const lookup: { [key: string]: string } = {
|
||||||
|
"vv-de": i18next.t("a.Deutsch"),
|
||||||
|
"vv-fr": i18next.t("a.Franzosisch"),
|
||||||
|
"vv-it": i18next.t("a.Italienisch"),
|
||||||
|
};
|
||||||
|
|
||||||
|
const vv = i18next.t("a.Versicherungsvermittler/-in");
|
||||||
|
return `${vv} (${lookup[courseType]})`;
|
||||||
|
};
|
||||||
|
|
@ -280,6 +280,7 @@ const router = createRouter({
|
||||||
path: "checkout/address",
|
path: "checkout/address",
|
||||||
component: () => import("@/pages/onboarding/vv/CheckoutAddress.vue"),
|
component: () => import("@/pages/onboarding/vv/CheckoutAddress.vue"),
|
||||||
name: "checkoutAddress",
|
name: "checkoutAddress",
|
||||||
|
props: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "checkout/complete",
|
path: "checkout/complete",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { itGetCached } from "@/fetchHelpers";
|
import { itGetCached } from "@/fetchHelpers";
|
||||||
import { useUserStore } from "@/stores/user";
|
import { useUserStore } from "@/stores/user";
|
||||||
|
import { isString, startsWith } from "lodash";
|
||||||
import type { Ref } from "vue";
|
import type { Ref } from "vue";
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
|
|
||||||
|
|
@ -7,7 +8,8 @@ export function profileNextRoute(courseType: string | string[]) {
|
||||||
if (courseType === "uk") {
|
if (courseType === "uk") {
|
||||||
return "setupComplete";
|
return "setupComplete";
|
||||||
}
|
}
|
||||||
if (courseType === "vv") {
|
// vv- -> vv-de, vv-fr or vv-it
|
||||||
|
if (isString(courseType) && startsWith(courseType, "vv-")) {
|
||||||
return "checkoutAddress";
|
return "checkoutAddress";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
|
|
||||||
|
|
@ -559,12 +559,10 @@ else:
|
||||||
|
|
||||||
ALLOWED_HOSTS = env.list(
|
ALLOWED_HOSTS = env.list(
|
||||||
"IT_DJANGO_ALLOWED_HOSTS",
|
"IT_DJANGO_ALLOWED_HOSTS",
|
||||||
# FIXME @livioso: Remove ngrok -> Datatrans Testing (hope I don't commit this)
|
|
||||||
default=[
|
default=[
|
||||||
"localhost",
|
"localhost",
|
||||||
"0.0.0.0",
|
"0.0.0.0",
|
||||||
"127.0.0.1",
|
"127.0.0.1",
|
||||||
"2375-2a02-21b4-9679-d800-8151-6008-2b6c-7a32.ngrok-free.app",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,8 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
mock_init_transaction.assert_called_once_with(
|
mock_init_transaction.assert_called_once_with(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
amount_chf_centimes=300_00,
|
amount_chf_centimes=300_00,
|
||||||
redirect_url_success=f"{REDIRECT_URL}/onboarding/vv/checkout/complete",
|
redirect_url_success=f"{REDIRECT_URL}/onboarding/{VV_DE_PRODUCT_SKU}/checkout/complete",
|
||||||
redirect_url_error=f"{REDIRECT_URL}/onboarding/vv/checkout/address?error",
|
redirect_url_error=f"{REDIRECT_URL}/onboarding/{VV_DE_PRODUCT_SKU}/checkout/address?error",
|
||||||
redirect_url_cancel=f"{REDIRECT_URL}/",
|
redirect_url_cancel=f"{REDIRECT_URL}/",
|
||||||
webhook_url=f"{REDIRECT_URL}/api/shop/transaction/webhook/",
|
webhook_url=f"{REDIRECT_URL}/api/shop/transaction/webhook/",
|
||||||
)
|
)
|
||||||
|
|
@ -111,7 +111,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
expected = (
|
expected = (
|
||||||
f"{REDIRECT_URL}/onboarding/vv/checkout/address?error&"
|
f"{REDIRECT_URL}/onboarding/{VV_DE_PRODUCT_SKU}/checkout/address?error&"
|
||||||
f"message=vv-de_product_sku_does_not_exist_needs_to_be_created_first"
|
f"message=vv-de_product_sku_does_not_exist_needs_to_be_created_first"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -138,7 +138,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
# THEN
|
# THEN
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
f"{REDIRECT_URL}/onboarding/vv/checkout/address?error",
|
f"{REDIRECT_URL}/onboarding/{VV_DE_PRODUCT_SKU}/checkout/address?error",
|
||||||
response.json()["next_step_url"],
|
response.json()["next_step_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,7 @@ def checkout_vv(request):
|
||||||
return next_step_response(
|
return next_step_response(
|
||||||
url=checkout_error_url(
|
url=checkout_error_url(
|
||||||
base_url=base_redirect_url,
|
base_url=base_redirect_url,
|
||||||
|
product_sku=sku,
|
||||||
message=f"{sku}_product_sku_does_not_exist_needs_to_be_created_first",
|
message=f"{sku}_product_sku_does_not_exist_needs_to_be_created_first",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -153,8 +154,12 @@ def checkout_vv(request):
|
||||||
transaction_id = init_transaction(
|
transaction_id = init_transaction(
|
||||||
user=request.user,
|
user=request.user,
|
||||||
amount_chf_centimes=product.price,
|
amount_chf_centimes=product.price,
|
||||||
redirect_url_success=checkout_success_url(base_redirect_url),
|
redirect_url_success=checkout_success_url(
|
||||||
redirect_url_error=checkout_error_url(base_redirect_url),
|
base_url=base_redirect_url, product_sku=sku
|
||||||
|
),
|
||||||
|
redirect_url_error=checkout_error_url(
|
||||||
|
base_url=base_redirect_url, product_sku=sku
|
||||||
|
),
|
||||||
redirect_url_cancel=checkout_cancel_url(base_redirect_url),
|
redirect_url_cancel=checkout_cancel_url(base_redirect_url),
|
||||||
webhook_url=webhook_url(base_redirect_url),
|
webhook_url=webhook_url(base_redirect_url),
|
||||||
)
|
)
|
||||||
|
|
@ -164,6 +169,7 @@ def checkout_vv(request):
|
||||||
return next_step_response(
|
return next_step_response(
|
||||||
url=checkout_error_url(
|
url=checkout_error_url(
|
||||||
base_url=base_redirect_url,
|
base_url=base_redirect_url,
|
||||||
|
product_sku=sku,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -214,8 +220,10 @@ def webhook_url(base_url: str) -> str:
|
||||||
return f"{base_url}/api/shop/transaction/webhook/"
|
return f"{base_url}/api/shop/transaction/webhook/"
|
||||||
|
|
||||||
|
|
||||||
def checkout_error_url(base_url: str, message: str | None = None) -> str:
|
def checkout_error_url(
|
||||||
url = f"{base_url}/onboarding/vv/checkout/address?error"
|
base_url: str, product_sku: str, message: str | None = None
|
||||||
|
) -> str:
|
||||||
|
url = f"{base_url}/onboarding/{product_sku}/checkout/address?error"
|
||||||
|
|
||||||
if message:
|
if message:
|
||||||
url += f"&message={message}"
|
url += f"&message={message}"
|
||||||
|
|
@ -227,5 +235,5 @@ def checkout_cancel_url(base_url: str) -> str:
|
||||||
return f"{base_url}/"
|
return f"{base_url}/"
|
||||||
|
|
||||||
|
|
||||||
def checkout_success_url(base_url: str = "") -> str:
|
def checkout_success_url(product_sku: str, base_url: str = "") -> str:
|
||||||
return f"{base_url}/onboarding/vv/checkout/complete"
|
return f"{base_url}/onboarding/{product_sku}/checkout/complete"
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ class TestSignInAuthorizeSSO(TestCase):
|
||||||
}
|
}
|
||||||
|
|
||||||
state = base64.urlsafe_b64encode(
|
state = base64.urlsafe_b64encode(
|
||||||
json.dumps({"course": "vv", "next": "/shall-be-ignored"}).encode()
|
json.dumps({"course": "vv-de", "next": "/shall-be-ignored"}).encode()
|
||||||
).decode()
|
).decode()
|
||||||
|
|
||||||
# WHEN
|
# WHEN
|
||||||
|
|
@ -87,7 +87,7 @@ class TestSignInAuthorizeSSO(TestCase):
|
||||||
|
|
||||||
# THEN
|
# THEN
|
||||||
self.assertEqual(302, response.status_code)
|
self.assertEqual(302, response.status_code)
|
||||||
self.assertEqual("/onboarding/vv/account/create", response.url) # noqa
|
self.assertEqual("/onboarding/vv-de/account/create", response.url) # noqa
|
||||||
|
|
||||||
user = User.objects.get(email=email) # noqa
|
user = User.objects.get(email=email) # noqa
|
||||||
self.assertIsNotNone(user)
|
self.assertIsNotNone(user)
|
||||||
|
|
@ -206,7 +206,7 @@ class TestSignIn(TestCase):
|
||||||
@patch("vbv_lernwelt.sso.views.oauth")
|
@patch("vbv_lernwelt.sso.views.oauth")
|
||||||
def test_signin_with_course_param(self, mock_oauth):
|
def test_signin_with_course_param(self, mock_oauth):
|
||||||
# GIVEN
|
# GIVEN
|
||||||
course_param = "vv"
|
course_param = "vv-de"
|
||||||
|
|
||||||
expected_state = {"course": course_param, "next": None}
|
expected_state = {"course": course_param, "next": None}
|
||||||
expected_state_encoded = base64.urlsafe_b64encode(
|
expected_state_encoded = base64.urlsafe_b64encode(
|
||||||
|
|
@ -229,14 +229,14 @@ class TestSignIn(TestCase):
|
||||||
ANY,
|
ANY,
|
||||||
"/sso/callback",
|
"/sso/callback",
|
||||||
state=expected_state_encoded,
|
state=expected_state_encoded,
|
||||||
lang="de",
|
ui_locales="de",
|
||||||
)
|
)
|
||||||
|
|
||||||
@override_settings(OAUTH_SIGNIN_REDIRECT_URI="/sso/callback")
|
@override_settings(OAUTH_SIGNIN_REDIRECT_URI="/sso/callback")
|
||||||
@patch("vbv_lernwelt.sso.views.oauth")
|
@patch("vbv_lernwelt.sso.views.oauth")
|
||||||
def test_signin_with_state_param(self, mock_oauth):
|
def test_signin_with_state_param(self, mock_oauth):
|
||||||
# GIVEN
|
# GIVEN
|
||||||
state_param = "vv"
|
state_param = "vv-de"
|
||||||
|
|
||||||
expected_state = {"course": state_param, "next": None}
|
expected_state = {"course": state_param, "next": None}
|
||||||
expected_state_encoded = base64.urlsafe_b64encode(
|
expected_state_encoded = base64.urlsafe_b64encode(
|
||||||
|
|
@ -259,7 +259,7 @@ class TestSignIn(TestCase):
|
||||||
ANY,
|
ANY,
|
||||||
"/sso/callback",
|
"/sso/callback",
|
||||||
state=expected_state_encoded,
|
state=expected_state_encoded,
|
||||||
lang="de",
|
ui_locales="de",
|
||||||
)
|
)
|
||||||
|
|
||||||
@override_settings(OAUTH_SIGNIN_REDIRECT_URI="/sso/callback")
|
@override_settings(OAUTH_SIGNIN_REDIRECT_URI="/sso/callback")
|
||||||
|
|
@ -289,7 +289,7 @@ class TestSignIn(TestCase):
|
||||||
ANY,
|
ANY,
|
||||||
"/sso/callback",
|
"/sso/callback",
|
||||||
state=expected_state_encoded,
|
state=expected_state_encoded,
|
||||||
lang=ANY,
|
ui_locales=ANY,
|
||||||
)
|
)
|
||||||
|
|
||||||
@override_settings(OAUTH_SIGNIN_REDIRECT_URI="/sso/callback")
|
@override_settings(OAUTH_SIGNIN_REDIRECT_URI="/sso/callback")
|
||||||
|
|
@ -314,7 +314,7 @@ class TestSignIn(TestCase):
|
||||||
ANY,
|
ANY,
|
||||||
"/sso/callback",
|
"/sso/callback",
|
||||||
state=ANY,
|
state=ANY,
|
||||||
lang=language,
|
ui_locales=language,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -323,7 +323,7 @@ class TestSignUp(TestCase):
|
||||||
@patch("vbv_lernwelt.sso.views.oauth")
|
@patch("vbv_lernwelt.sso.views.oauth")
|
||||||
def test_signup_with_course_param(self, mock_oauth):
|
def test_signup_with_course_param(self, mock_oauth):
|
||||||
# GIVEN
|
# GIVEN
|
||||||
course_param = "vv"
|
course_param = "vv-de"
|
||||||
language = "fr"
|
language = "fr"
|
||||||
|
|
||||||
expected_state = {"course": course_param, "next": None}
|
expected_state = {"course": course_param, "next": None}
|
||||||
|
|
|
||||||
|
|
@ -43,14 +43,18 @@ def signin(request):
|
||||||
f"SSO Login (course={course_param}, next={next_param})",
|
f"SSO Login (course={course_param}, next={next_param})",
|
||||||
sso_login_redirect_uri=redirect_uri,
|
sso_login_redirect_uri=redirect_uri,
|
||||||
)
|
)
|
||||||
|
|
||||||
return oauth.signin.authorize_redirect(
|
return oauth.signin.authorize_redirect(
|
||||||
request, redirect_uri, state=state_encoded, lang=request.GET.get("lang", "de")
|
request,
|
||||||
|
redirect_uri,
|
||||||
|
state=state_encoded,
|
||||||
|
ui_locales=request.GET.get("lang", "de"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_redirect_uri(user: User, course: str, next_url: str):
|
def get_redirect_uri(user: User, course: str | None, next_url: str | None):
|
||||||
if course == "vv" and not has_course_session_user_vv(user):
|
if course and course.startswith("vv") and not has_course_session_user_vv(user):
|
||||||
return redirect("/onboarding/vv/account/create")
|
return redirect(f"/onboarding/{course}/account/create")
|
||||||
elif (
|
elif (
|
||||||
course == "uk"
|
course == "uk"
|
||||||
and not CourseSession.objects.filter(coursesessionuser__user=user).exists()
|
and not CourseSession.objects.filter(coursesessionuser__user=user).exists()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue