diff --git a/src/khoj/interface/web/assets/icons/credit-card.png b/src/khoj/interface/web/assets/icons/credit-card.png new file mode 100644 index 00000000..487dba5c Binary files /dev/null and b/src/khoj/interface/web/assets/icons/credit-card.png differ diff --git a/src/khoj/interface/web/base_config.html b/src/khoj/interface/web/base_config.html index 619c34c0..001ebef8 100644 --- a/src/khoj/interface/web/base_config.html +++ b/src/khoj/interface/web/base_config.html @@ -229,7 +229,7 @@ text-align: right; } - button.card-button.happy { + .card-button.happy { color: var(--leaf); } diff --git a/src/khoj/interface/web/config.html b/src/khoj/interface/web/config.html index 5a2089ca..5269065d 100644 --- a/src/khoj/interface/web/config.html +++ b/src/khoj/interface/web/config.html @@ -157,6 +157,42 @@ + +
+

Billing

+
+
+
+ Credit Card +

+ Subscription + Configured +

+
+
+

Manage your subscription to Khoj Cloud

+
+ {% if not is_subscribed %} + + {% else %} +
+ +
+ {% endif %} +
+
@@ -222,6 +258,18 @@ }) }; + function unsubscribe() { + fetch('/api/subscription', { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + "email": "{{ username }}" + }) + }) + } + var configure = document.getElementById("configure"); configure.addEventListener("click", function(event) { event.preventDefault(); diff --git a/src/khoj/routers/web_client.py b/src/khoj/routers/web_client.py index 3e568bc7..b49404a2 100644 --- a/src/khoj/routers/web_client.py +++ b/src/khoj/routers/web_client.py @@ -1,4 +1,5 @@ # System Packages +from datetime import datetime import json import os @@ -8,6 +9,7 @@ from fastapi import Request from fastapi.responses import HTMLResponse, FileResponse, RedirectResponse from fastapi.templating import Jinja2Templates from starlette.authentication import requires +from database.models import KhojUser from khoj.utils.rawconfig import ( GithubContentConfig, GithubRepoConfig, @@ -16,7 +18,13 @@ from khoj.utils.rawconfig import ( # Internal Packages from khoj.utils import constants, state -from database.adapters import EntryAdapters, get_user_github_config, get_user_notion_config, ConversationAdapters +from database.adapters import ( + EntryAdapters, + get_user_github_config, + get_user_notion_config, + ConversationAdapters, + is_user_subscribed, +) # Initialize Router web_client = APIRouter() @@ -108,8 +116,10 @@ def login_page(request: Request): @web_client.get("/config", response_class=HTMLResponse) @requires(["authenticated"], redirect="login_page") def config_page(request: Request): - user = request.user.object + user: KhojUser = request.user.object user_picture = request.session.get("user", {}).get("picture") + user_is_subscribed = is_user_subscribed(user.email) + days_to_renewal = (user.subscription_renewal_date - datetime.now()).days if user.subscription_renewal_date else 0 enabled_content_source = set(EntryAdapters.get_unique_file_source(user).all()) successfully_configured = { @@ -131,10 +141,12 @@ def config_page(request: Request): "request": request, "current_model_state": successfully_configured, "anonymous_mode": state.anonymous_mode, - "username": user.username if user else None, + "username": user.username, "conversation_options": all_conversation_options, "selected_conversation_config": selected_conversation_config.id if selected_conversation_config else None, "user_photo": user_picture, + "is_subscribed": user_is_subscribed, + "days_to_renewal": days_to_renewal, }, )