Esempio n. 1
0
    def create(self, validated_data, **kwargs):
        if "view" not in self.context or not self.context["view"].kwargs.get(
                "invite_id"):
            raise serializers.ValidationError(
                "Please provide an invite ID to continue.")

        user: Optional[User] = None
        is_new_user: bool = False

        if self.context["request"].user.is_authenticated:
            user = cast(User, self.context["request"].user)

        invite_id = self.context["view"].kwargs.get("invite_id")

        try:
            invite: OrganizationInvite = OrganizationInvite.objects.select_related(
                "organization").get(id=invite_id)
        except (OrganizationInvite.DoesNotExist):
            raise serializers.ValidationError(
                "The provided invite ID is not valid.")

        with transaction.atomic():
            if not user:
                is_new_user = True
                user = User.objects.create_user(
                    invite.target_email,
                    validated_data.pop("password"),
                    validated_data.pop("first_name"),
                    **validated_data,
                )

            try:
                invite.use(user)
            except ValueError as e:
                raise serializers.ValidationError(str(e))

        if is_new_user:
            login(
                self.context["request"],
                user,
                backend="django.contrib.auth.backends.ModelBackend",
            )

            report_user_signed_up(
                user.distinct_id,
                is_instance_first_user=False,
                is_organization_first_user=False,
                new_onboarding_enabled=(
                    not invite.organization.setup_section_2_completed),
                backend_processor="OrganizationInviteSignupSerializer",
            )

        else:
            report_user_joined_organization(organization=invite.organization,
                                            current_user=user)

        # Update user props
        user_identify.identify_task.delay(user_id=user.id)

        return user
Esempio n. 2
0
    def create(self, validated_data, **kwargs):
        if settings.DEMO:
            return self.enter_demo(validated_data)

        is_instance_first_user: bool = not User.objects.exists()

        organization_name = validated_data.pop("organization_name", validated_data["first_name"])

        self._organization, self._team, self._user = User.objects.bootstrap(
            organization_name=organization_name,
            create_team=self.create_team,
            **validated_data,
            is_staff=is_instance_first_user,
        )
        user = self._user

        login(
            self.context["request"], user, backend="django.contrib.auth.backends.ModelBackend",
        )

        report_user_signed_up(
            user,
            is_instance_first_user=is_instance_first_user,
            is_organization_first_user=True,
            new_onboarding_enabled=(not self._organization.setup_section_2_completed),
            backend_processor="OrganizationSignupSerializer",
            user_analytics_metadata=user.get_analytics_metadata(),
            org_analytics_metadata=user.organization.get_analytics_metadata() if user.organization else None,
        )

        return user
Esempio n. 3
0
    def create(self, validated_data, **kwargs):
        is_instance_first_user: bool = not User.objects.exists()

        organization_name = validated_data.pop("organization_name",
                                               validated_data["first_name"])

        self._organization, self._team, self._user = User.objects.bootstrap(
            organization_name=organization_name,
            create_team=self.create_team,
            **validated_data,
        )
        user = self._user

        # Temp (due to FF-release [`new-onboarding-2822`]): Activate the setup/onboarding process if applicable
        if self.enable_new_onboarding(user):
            self._organization.setup_section_2_completed = False
            self._organization.save()

        login(
            self.context["request"],
            user,
            backend="django.contrib.auth.backends.ModelBackend",
        )

        report_user_signed_up(
            user.distinct_id,
            is_instance_first_user=is_instance_first_user,
            is_organization_first_user=True,
            new_onboarding_enabled=(
                not self._organization.setup_section_2_completed),
            backend_processor="OrganizationSignupSerializer",
        )

        return user
Esempio n. 4
0
def signup_to_organization_view(request, invite_id):
    """
    TODO: DEPRECATED in favor of posthog.api.organization.OrganizationInviteSignupSerializer
    """
    if not invite_id:
        return redirect("/")
    if not User.objects.exists():
        return redirect("/preflight")
    try:
        invite: Union[
            OrganizationInvite,
            TeamInviteSurrogate] = OrganizationInvite.objects.select_related(
                "organization").get(id=invite_id)
    except (OrganizationInvite.DoesNotExist, ValidationError):
        try:
            invite = TeamInviteSurrogate(invite_id)
        except Team.DoesNotExist:
            return redirect("/")

    organization = cast(Organization, invite.organization)
    user = request.user
    if request.method == "POST":
        if request.user.is_authenticated:
            user = cast(User, request.user)
            try:
                invite.use(user)
            except ValueError as e:
                return render_template(
                    "signup_to_organization.html",
                    request=request,
                    context={
                        "user": user,
                        "custom_error": str(e),
                        "organization": organization,
                        "invite_id": invite_id,
                    },
                )
            else:
                posthoganalytics.capture(
                    user.distinct_id,
                    "user joined from invite",
                    properties={"organization_id": organization.id},
                )
                return redirect("/")
        else:
            email = request.POST["email"]
            password = request.POST["password"]
            first_name = request.POST.get("name")
            email_opt_in = request.POST.get("emailOptIn") == "on"
            valid_inputs = (is_input_valid("name", first_name)
                            and is_input_valid("email", email)
                            and is_input_valid("password", password))
            already_exists = User.objects.filter(email=email).exists()
            custom_error = None
            try:
                invite.validate(user=None, email=email)
            except ValueError as e:
                custom_error = str(e)
            if already_exists or not valid_inputs or custom_error:
                return render_template(
                    "signup_to_organization.html",
                    request=request,
                    context={
                        "email": email,
                        "name": first_name,
                        "already_exists": already_exists,
                        "custom_error": custom_error,
                        "invalid_input": not valid_inputs,
                        "organization": organization,
                        "invite_id": invite_id,
                    },
                )
            user = User.objects.create_user(email,
                                            password,
                                            first_name=first_name,
                                            email_opt_in=email_opt_in)
            invite.use(user, prevalidated=True)
            login(request,
                  user,
                  backend="django.contrib.auth.backends.ModelBackend")

            report_user_signed_up(
                user.distinct_id,
                is_instance_first_user=False,
                is_organization_first_user=False,
                new_onboarding_enabled=(
                    not organization.setup_section_2_completed),
                backend_processor="signup_to_organization_view",
            )

            return redirect("/")
    return render_template(
        "signup_to_organization.html",
        request,
        context={
            "organization": organization,
            "user": user,
            "invite_id": invite_id
        },
    )
Esempio n. 5
0
def social_create_user(strategy: DjangoStrategy,
                       details,
                       backend,
                       request,
                       user=None,
                       *args,
                       **kwargs):
    if user:
        return {"is_new": False}
    user_email = details["email"][0] if isinstance(
        details["email"], (list, tuple)) else details["email"]
    user_name = details["fullname"]
    strategy.session_set("user_name", user_name)
    strategy.session_set("backend", backend.name)
    from_invite = False
    invite_id = strategy.session_get("invite_id")
    if not invite_id:
        organization_name = strategy.session_get("organization_name", None)
        email_opt_in = strategy.session_get("email_opt_in", None)
        if not organization_name or email_opt_in is None:
            return redirect(finish_social_signup)

        serializer = OrganizationSignupSerializer(
            data={
                "organization_name": organization_name,
                "email_opt_in": email_opt_in,
                "first_name": user_name,
                "email": user_email,
                "password": None,
            },
            context={"request": request},
        )

        serializer.is_valid(raise_exception=True)
        user = serializer.save()
    else:
        from_invite = True
        try:
            invite: Union[
                OrganizationInvite,
                TeamInviteSurrogate] = OrganizationInvite.objects.select_related(
                    "organization", ).get(id=invite_id)
        except (OrganizationInvite.DoesNotExist, ValidationError):
            try:
                invite = TeamInviteSurrogate(invite_id)
            except Team.DoesNotExist:
                return redirect(
                    f"/signup/{invite_id}?error_code=invalid_invite&source=social_create_user"
                )

        try:
            invite.validate(user=None, email=user_email)
        except exceptions.ValidationError as e:
            return redirect(
                f"/signup/{invite_id}?error_code={e.get_codes()[0]}&error_detail={e.args[0]}&source=social_create_user"
            )

        try:
            user = strategy.create_user(email=user_email,
                                        first_name=user_name,
                                        password=None)
        except Exception as e:
            capture_exception(e)
            message = "Account unable to be created. This account may already exist. Please try again"
            " or use different credentials."
            return redirect(
                f"/signup/{invite_id}?error_code=unknown&error_detail={message}&source=social_create_user"
            )

        invite.use(user, prevalidated=True)

    report_user_signed_up(
        distinct_id=user.distinct_id,
        is_instance_first_user=User.objects.count() == 1,
        is_organization_first_user=not from_invite,
        new_onboarding_enabled=False,
        backend_processor="social_create_user",
        social_provider=backend.name,
    )

    return {"is_new": True, "user": user}
Esempio n. 6
0
def social_create_user(strategy: DjangoStrategy, details, backend, request, user=None, *args, **kwargs):
    if user:
        return {"is_new": False}
    backend_processor = "social_create_user"
    user_email = details["email"][0] if isinstance(details["email"], (list, tuple)) else details["email"]
    user_name = (
        details["fullname"]
        or f"{details['first_name'] or ''} {details['last_name'] or ''}".strip()
        or details["username"]
    )
    strategy.session_set("user_name", user_name)
    strategy.session_set("backend", backend.name)
    from_invite = False
    invite_id = strategy.session_get("invite_id")

    if not user_email or not user_name:
        missing_attr = "email" if not user_email else "name"
        raise ValidationError(
            {missing_attr: "This field is required and was not provided by the IdP."}, code="required"
        )

    if invite_id:
        from_invite = True
        user = process_social_invite_signup(strategy, invite_id, user_email, user_name)

    else:
        # Domain whitelist?
        user = process_social_domain_whitelist_signup(user_email, user_name)
        if user:
            backend_processor = "domain_whitelist"

        # SAML
        if not user:
            user = process_social_saml_signup(backend, user_email, user_name)
            if user:
                backend_processor = "saml"

        if not user:
            organization_name = strategy.session_get("organization_name", None)
            email_opt_in = strategy.session_get("email_opt_in", None)
            if not organization_name or email_opt_in is None:
                return redirect(finish_social_signup)

            serializer = SignupSerializer(
                data={
                    "organization_name": organization_name,
                    "email_opt_in": email_opt_in,
                    "first_name": user_name,
                    "email": user_email,
                    "password": None,
                },
                context={"request": request},
            )

            serializer.is_valid(raise_exception=True)
            user = serializer.save()

    report_user_signed_up(
        user,
        is_instance_first_user=User.objects.count() == 1,
        is_organization_first_user=not from_invite,
        new_onboarding_enabled=False,
        backend_processor=backend_processor,
        social_provider=backend.name,
        user_analytics_metadata=user.get_analytics_metadata(),
        org_analytics_metadata=user.organization.get_analytics_metadata() if user.organization else None,
    )

    return {"is_new": True, "user": user}
Esempio n. 7
0
def social_create_user(strategy: DjangoStrategy,
                       details,
                       backend,
                       request,
                       user=None,
                       *args,
                       **kwargs):
    if user:
        return {"is_new": False}
    user_email = details["email"][0] if isinstance(
        details["email"], (list, tuple)) else details["email"]
    user_name = details["fullname"]
    strategy.session_set("user_name", user_name)
    strategy.session_set("backend", backend.name)
    from_invite = False
    invite_id = strategy.session_get("invite_id")
    if not invite_id:
        company_name = strategy.session_get("company_name", None)
        email_opt_in = strategy.session_get("email_opt_in", None)
        if not company_name or email_opt_in is None:
            return redirect(finish_social_signup)

        serializer = OrganizationSignupSerializer(
            data=dict(
                company_name=company_name,
                email_opt_in=email_opt_in,
                first_name=user_name,
                email=user_email,
                password=None,
            ),
            context={"request": request},
        )

        serializer.is_valid(raise_exception=True)
        user = serializer.save()
    else:
        from_invite = True
        try:
            invite: Union[
                OrganizationInvite,
                TeamInviteSurrogate] = OrganizationInvite.objects.select_related(
                    "organization", ).get(id=invite_id)
        except (OrganizationInvite.DoesNotExist, ValidationError):
            try:
                invite = TeamInviteSurrogate(invite_id)
            except Team.DoesNotExist:
                processed = render_to_string(
                    "auth_error.html",
                    {"message": "Invalid invite link!"},
                )
                return HttpResponse(processed, status=401)

        try:
            invite.validate(user=None, email=user_email)
        except ValueError as e:
            processed = render_to_string(
                "auth_error.html",
                {"message": str(e)},
            )
            return HttpResponse(processed, status=401)

        try:
            user = strategy.create_user(email=user_email,
                                        first_name=user_name,
                                        password=None)
        except Exception as e:
            capture_exception(e)
            processed = render_to_string(
                "auth_error.html",
                {
                    "message":
                    "Account unable to be created. This account may already exist. Please try again or use different credentials!"
                },
            )
            return HttpResponse(processed, status=401)
        invite.use(user, prevalidated=True)

    report_user_signed_up(
        distinct_id=user.distinct_id,
        is_instance_first_user=User.objects.count() == 1,
        is_organization_first_user=not from_invite,
        new_onboarding_enabled=False,
        backend_processor="social_create_user",
        social_provider=backend.name,
    )

    return {"is_new": True, "user": user}
Esempio n. 8
0
def social_create_user(strategy: DjangoStrategy,
                       details,
                       backend,
                       request,
                       user=None,
                       *args,
                       **kwargs):
    if user:
        return {"is_new": False}
    backend_processor = "social_create_user"
    user_email = details["email"][0] if isinstance(
        details["email"], (list, tuple)) else details["email"]
    user_name = details["fullname"] or details["username"]
    strategy.session_set("user_name", user_name)
    strategy.session_set("backend", backend.name)
    from_invite = False
    invite_id = strategy.session_get("invite_id")
    if not invite_id:

        domain_organization: Optional[Organization] = None

        # TODO: This feature is currently available only in self-hosted
        if not settings.MULTI_TENANCY:
            # Check if the user is on a whitelisted domain
            domain = user_email.split("@")[-1]
            # TODO: Handle multiple organizations with the same whitelisted domain
            domain_organization = Organization.objects.filter(
                domain_whitelist__contains=[domain]).first()

        if domain_organization:
            backend_processor = "domain_whitelist"
            user = User.objects.create_and_join(
                organization=domain_organization,
                email=user_email,
                password=None,
                first_name=user_name)

        else:
            organization_name = strategy.session_get("organization_name", None)
            email_opt_in = strategy.session_get("email_opt_in", None)
            if not organization_name or email_opt_in is None:
                return redirect(finish_social_signup)

            serializer = SignupSerializer(
                data={
                    "organization_name": organization_name,
                    "email_opt_in": email_opt_in,
                    "first_name": user_name,
                    "email": user_email,
                    "password": None,
                },
                context={"request": request},
            )

            serializer.is_valid(raise_exception=True)
            user = serializer.save()
    else:
        from_invite = True
        try:
            invite: Union[
                OrganizationInvite,
                TeamInviteSurrogate] = OrganizationInvite.objects.select_related(
                    "organization", ).get(id=invite_id)
        except (OrganizationInvite.DoesNotExist, ValidationError):
            try:
                invite = TeamInviteSurrogate(invite_id)
            except Team.DoesNotExist:
                return redirect(
                    f"/signup/{invite_id}?error_code=invalid_invite&source=social_create_user"
                )

        try:
            invite.validate(user=None, email=user_email)
        except exceptions.ValidationError as e:
            return redirect(
                f"/signup/{invite_id}?error_code={e.get_codes()[0]}&error_detail={e.args[0]}&source=social_create_user"
            )

        try:
            user = strategy.create_user(email=user_email,
                                        first_name=user_name,
                                        password=None)
        except Exception as e:
            capture_exception(e)
            message = "Account unable to be created. This account may already exist. Please try again"
            " or use different credentials."
            return redirect(
                f"/signup/{invite_id}?error_code=unknown&error_detail={message}&source=social_create_user"
            )

        invite.use(user, prevalidated=True)

    report_user_signed_up(
        distinct_id=user.distinct_id,
        is_instance_first_user=User.objects.count() == 1,
        is_organization_first_user=not from_invite,
        new_onboarding_enabled=False,
        backend_processor=backend_processor,
        social_provider=backend.name,
    )

    return {"is_new": True, "user": user}