Skip to content

Commit

Permalink
trial landing page
Browse files Browse the repository at this point in the history
  • Loading branch information
goneri committed Jul 9, 2024
1 parent 4600f76 commit 800b39b
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 34 deletions.
4 changes: 3 additions & 1 deletion ansible_ai_connect/main/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
CurrentUserView,
HomeView,
TermsOfService,
TrialView,
UnauthorizedView,
)

Expand All @@ -75,7 +76,7 @@
path("check/", WisdomServiceLivenessProbeView.as_view(), name="liveness_probe"),
path(
"community-terms/",
TermsOfService.as_view(template_name="users/community-terms.html"),
TermsOfService.as_view(),
name="community_terms",
),
path("o/", include((base_urlpatterns, app_name), namespace="oauth2_provider")),
Expand All @@ -85,6 +86,7 @@
name="login",
),
path("logout/", LogoutView.as_view(), name="logout"),
path("trial/", TrialView.as_view(), name="trial"),
]

if settings.DEBUG or settings.DEPLOYMENT_MODE == "saas":
Expand Down
10 changes: 10 additions & 0 deletions ansible_ai_connect/users/templates/users/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,16 @@ <h1 class="pf-c-title pf-m-lg">{{ project_name }}</h1>
{% if user.rh_user_is_org_admin or user.rh_user_has_seat %}
<p>Role: {% if user.rh_user_is_org_admin %}administrator{% endif %}{% if user.rh_user_is_org_admin and user.rh_user_has_seat %}, {% endif %}{% if user.rh_user_has_seat %}licensed user{% endif %}</p>
{% endif %}

<!--
{% if not user.commercial_terms_accepted %}
<a href="{% url 'community_terms' %}">Please accept the Terms and Condition</a>.
{% else %}
<p>Term and condition: {{ user.commercial_terms_accepted }}
{% endif %}
#}
-->

</div>

<form id="logout-form" method="post" action="{% url 'logout' %}">
Expand Down
96 changes: 96 additions & 0 deletions ansible_ai_connect/users/templates/users/trial.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
{% extends "base.html" %}
{% load static %}

{% block content %}
<section class="pf-c-page__main-section pf-m-light">
<div class="pf-l-bullseye">
<div class="pf-l-bullseye__item">
<div class="pf-c-empty-state">
<div class="pf-c-empty-state__content">

<div class="pf-l-bullseye pf-u-p-xl ls_logo_home">
<img src="{% static 'users/lightspeed.png' %}" width="95px" alt="{{ project_name }} logo"/>
</div>


<h1 class="pf-c-title pf-m-lg">{{ project_name }}</h1>

{% if user.is_authenticated %}
<div class="ls_message_body">
<p>{% firstof user.external_username user.username %}</p>
{% if user.rh_user_is_org_admin or user.rh_user_has_seat %}
<p>Role: {% if user.rh_user_is_org_admin %}administrator{% endif %}{% if user.rh_user_is_org_admin and user.rh_user_has_seat %}, {% endif %}{% if user.rh_user_has_seat %}licensed user{% endif %}</p>
{% endif %}

</div>


{% if has_active_plan %}
<div class="ls_message_body">
You have an active <i>{{ has_active_plan.plan.name }}</i> that will end the {{ has_active_plan.expired_at }}
</div>


<div class="pf-v5-c-form__group pf-m-action">
<div class="pf-v5-c-form__actions">
<a href="vscode://">
<button class="pf-v5-c-button pf-m-primary pf-m-start" type="submit">
<span class="pf-v5-c-button__icon pf-m-start">
<i class="fas fa-pen" aria-hidden="true"></i>
</span>
Open VS Code
</button>
</a>
</div>
</div>

{% elif has_expired_plan %}
You have an expired ({{ has_active_plan.plan.name }}).
{% else %}
<form action={% url 'trial' %} method="post">{% csrf_token %}


<div class="ls_message_body">
<p>Start a [90] days free trial with our recommanded model, <a href="https://www.ibm.com/products/watsonx-code-assistant">IBM watsonx Code Assistant</a>.
<p>This will only apply to you and will not affect your organization.
</div>


<div class="ls_message_body">
{% if not user.commercial_terms_accepted %}
<input type="checkbox" name="accept_commercial_terms">
<a href="{% url 'community_terms' %}">Accept the Terms and Condition</a>.
{% else %}
<!-- Term and condition: accepted -->
{% endif %}
</div>

<div class="pf-c-empty-state__content">
<button class="pf-c-button pf-m-primary" type="submit" name="start_trial" value="True">
<span class="pf-c-button__icon"><i class="fa fa-check-circle"></i></span>
Start Ansible Lightspeed trial
</button>
</div>
</form>
{% endif %}

{% else %}
<div class="pf-c-empty-state__body">You are currently not logged in. Please log in using the button below.</div>
<a class="pf-c-button pf-m-primary" type="button" href="{% url 'login' %}">Log in</a>
{% endif %}

<div class="pf-l-level pf-m-gutter ls_bottom_menu">
<a class="pf-l-level__item" href="https://matrix.to/#/%23ansible-lightspeed:ansible.im" target="_blank"><span class="fas fa-solid fa-comments"></span> Chat</a>
<a class="pf-l-level__item" href="{{ documentation_url }}" target="_blank"><span class="fas fa-sharp fa-solid fa-external-link-alt"></span> Documentation</a>
<a class="pf-l-level__item" href="https://status.redhat.com/" target="_blank"><span class="fas fa-sharp fa-solid fa-check"></span> Status</a>

{% if deployment_mode == 'saas' and user.is_authenticated and user.rh_user_is_org_admin %}
<a class="pf-l-level__item" href="/console"><span class="fas fa-solid fa-cog"></span> Admin Portal</a>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</section>
{% endblock content %}
115 changes: 82 additions & 33 deletions ansible_ai_connect/users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@
from django.apps import apps
from django.conf import settings
from django.forms import Form
from django.http import HttpResponseBadRequest, HttpResponseForbidden
from django.http import (
HttpResponseBadRequest,
HttpResponseForbidden,
HttpResponseRedirect,
)
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.utils.timezone import now
from django.views.generic import TemplateView
from rest_framework.generics import RetrieveAPIView
from rest_framework.permissions import IsAuthenticated
Expand All @@ -32,6 +37,7 @@
)
from ansible_ai_connect.ai.api.aws.wca_secret_manager import Suffixes
from ansible_ai_connect.main.cache.cache_per_user import cache_per_user
from ansible_ai_connect.users.models import Plan

from .serializers import UserResponseSerializer

Expand All @@ -42,26 +48,45 @@
class HomeView(TemplateView):
template_name = "users/home.html"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["use_tech_preview"] = settings.ANSIBLE_AI_ENABLE_TECH_PREVIEW
context["deployment_mode"] = settings.DEPLOYMENT_MODE
context["project_name"] = settings.ANSIBLE_AI_PROJECT_NAME

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.secret_manager = None
try:
secret_manager = apps.get_app_config("ai").get_wca_secret_manager()
self.secret_manager = apps.get_app_config("ai").get_wca_secret_manager()
except WcaSecretManagerMissingCredentialsError:
return context
pass

def dispatch(self, request, *args, **kwargs):
self.org_has_api_key = None
if (
self.request.user.is_authenticated
self.secret_manager
and self.request.user.is_authenticated
and self.request.user.rh_org_has_subscription
and not self.request.user.is_aap_user()
):
org_has_api_key = secret_manager.secret_exists(
org_has_api_key = self.secret_manager.secret_exists(
self.request.user.organization.id, Suffixes.API_KEY
)
context["org_has_api_key"] = org_has_api_key
self.org_has_api_key = org_has_api_key

if (
self.request.user.is_authenticated
and self.request.user.is_oidc_user
and self.request.user.rh_org_has_subscription
and self.secret_manager.secret_exists(
self.request.user.organization.id, Suffixes.API_KEY
)
):
return HttpResponseRedirect(reverse("trial"))

return super().dispatch(request, *args, **kwargs)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["use_tech_preview"] = settings.ANSIBLE_AI_ENABLE_TECH_PREVIEW
context["deployment_mode"] = settings.DEPLOYMENT_MODE
context["project_name"] = settings.ANSIBLE_AI_PROJECT_NAME
context["org_has_api_key"] = self.org_has_api_key

if settings.ANSIBLE_AI_ENABLE_TECH_PREVIEW and not (
self.request.user.is_authenticated and self.request.user.rh_user_has_seat
Expand Down Expand Up @@ -109,37 +134,61 @@ def retrieve(self, request, *args, **kwargs):


class TermsOfService(TemplateView):
template_name = None # passed in via the urlpatterns
template_name = "users/community-terms.html"
extra_context = {
"form": Form(),
}

def get(self, request, *args, **kwargs):
partial_token = request.GET.get("partial_token")
self.extra_context["partial_token"] = partial_token
if partial_token is None:
logger.warning("GET TermsOfService was invoked without partial_token")
return HttpResponseForbidden()
return super().get(request, args, kwargs)

def post(self, request, *args, **kwargs):
form = Form(request.POST)
form.is_valid()
partial_token = form.data.get("partial_token")
if partial_token is None:
logger.warning("POST TermsOfService was invoked without partial_token")
return HttpResponseBadRequest()
accepted = request.POST.get("accepted") == "True"
request.user.commercial_terms_accepted = now()
request.user.save()

strategy = load_strategy()
partial = strategy.partial_load(partial_token)
if partial is None:
logger.error("strategy.partial_load(partial_token) returned None")
return HttpResponseBadRequest()
return HttpResponseRedirect(reverse("trial"))

accepted = request.POST.get("accepted") == "True"
request.session["terms_accepted"] = accepted
request.session.save()

backend = partial.backend
complete = reverse("social:complete", kwargs={"backend": backend})
return strategy.redirect(complete + f"?partial_token={partial.token}")
class TrialView(TemplateView):
template_name = "users/trial.html"

def get_context_data(self, **kwargs):
user = self.request.user
has_active_plan = None
has_expired_plan = None

for up in user.userplan_set.all():
if up.is_active:
has_active_plan = up
else:
has_expired_plan = up

context = super().get_context_data(**kwargs)
context["project_name"] = settings.ANSIBLE_AI_PROJECT_NAME
context["deployment_mode"] = settings.DEPLOYMENT_MODE
context["has_active_plan"] = has_active_plan
context["has_expired_plan"] = has_expired_plan

return context

def post(self, request, *args, **kwargs):
form = Form(request.POST)
form.is_valid()

accept_commercial_terms = request.POST.get("accept_commercial_terms") == "on"
start_trial = request.POST.get("start_trial") == "True"

if accept_commercial_terms:
request.user.commercial_terms_accepted = now()
request.user.save()

if start_trial and request.user.commercial_terms_accepted:
trial_plan, _ = Plan.objects.get_or_create(
name="trial of 90 days", expires_after="90 days"
)
request.user.plans.add(trial_plan)

return HttpResponseRedirect(reverse("trial"))

0 comments on commit 800b39b

Please sign in to comment.