WhatsApp
@@ -610,15 +612,21 @@
const phonenumberVerifiedText = document.getElementById("api-settings-card-description-verified");
const phonenumberUnverifiedText = document.getElementById("api-settings-card-description-unverified");
- let preExistingPhoneNumber = "{{ phone_number }}";
+ const preExistingPhoneNumber = "{{ phone_number }}";
let isPhoneNumberVerified = "{{ is_phone_number_verified }}";
let isTwilioEnabled = "{{ is_twilio_enabled }}";
+ isPhoneNumberVerified = isPhoneNumberVerified.toLowerCase();
+ isTwilioEnabled = isTwilioEnabled.toLowerCase();
- if (preExistingPhoneNumber != "None" && (isPhoneNumberVerified == "True" || isPhoneNumberVerified == "true")) {
+ if (isTwilioEnabled !== "true" ) {
+ const phoneNumberVerificationCard = document.getElementById("phone-number-input-card");
+ phoneNumberVerificationCard.style.display = "none";
+ }
+ if (preExistingPhoneNumber != "None" && isPhoneNumberVerified === "true") {
phonenumberVerifyButton.style.display = "none";
phonenumberRemoveButton.style.display = "";
- } else if (preExistingPhoneNumber != "None" && (isPhoneNumberVerified == "False" || isPhoneNumberVerified == "false")) {
- if (isTwilioEnabled == "True" || isTwilioEnabled == "true") {
+ } else if (preExistingPhoneNumber != "None" && isPhoneNumberVerified === "false") {
+ if (isTwilioEnabled == "true") {
phonenumberVerifyButton.style.display = "";
phonenumberRemoveButton.style.display = "none";
} else {
@@ -759,7 +767,5 @@
}, 5000);
});
})
-
-
{% endblock %}
diff --git a/src/khoj/main.py b/src/khoj/main.py
index b5421979..72036695 100644
--- a/src/khoj/main.py
+++ b/src/khoj/main.py
@@ -14,6 +14,8 @@ import threading
import warnings
from importlib.metadata import version
+from khoj.utils.helpers import in_debug_mode
+
# Ignore non-actionable warnings
warnings.filterwarnings("ignore", message=r"snapshot_download.py has been made private", category=FutureWarning)
warnings.filterwarnings("ignore", message=r"legacy way to download files from the HF hub,", category=FutureWarning)
@@ -45,7 +47,7 @@ with redirect_stdout(collectstatic_output):
call_command("collectstatic", "--noinput")
# Initialize the Application Server
-if os.getenv("KHOJ_DEBUG", "false").lower() == "true":
+if in_debug_mode():
app = FastAPI(debug=True)
else:
app = FastAPI(docs_url=None) # Disable Swagger UI in production
diff --git a/src/khoj/routers/api_config.py b/src/khoj/routers/api_config.py
index 12f53abb..26729f41 100644
--- a/src/khoj/routers/api_config.py
+++ b/src/khoj/routers/api_config.py
@@ -22,7 +22,6 @@ from khoj.database.models import (
NotionConfig,
)
from khoj.routers.helpers import CommonQueryParams, update_telemetry_state
-from khoj.routers.twilio import create_otp, is_twilio_enabled, verify_otp
from khoj.utils import constants, state
from khoj.utils.rawconfig import (
FullConfig,
@@ -279,77 +278,6 @@ async def update_search_model(
return {"status": "ok"}
-@api_config.post("/phone", status_code=200)
-@requires(["authenticated"])
-async def update_phone_number(
- request: Request,
- phone_number: str,
- client: Optional[str] = None,
-):
- user = request.user.object
-
- await adapters.aset_user_phone_number(user, phone_number)
-
- if is_twilio_enabled():
- create_otp(user)
- else:
- logger.warning("Phone verification is not enabled")
-
- update_telemetry_state(
- request=request,
- telemetry_type="api",
- api="set_phone_number",
- client=client,
- metadata={"phone_number": phone_number},
- )
-
- return {"status": "ok"}
-
-
-@api_config.delete("/phone", status_code=200)
-@requires(["authenticated"])
-async def delete_phone_number(
- request: Request,
- client: Optional[str] = None,
-):
- user = request.user.object
-
- await adapters.aremove_phone_number(user)
-
- update_telemetry_state(
- request=request,
- telemetry_type="api",
- api="delete_phone_number",
- client=client,
- )
-
- return {"status": "ok"}
-
-
-@api_config.post("/phone/verify", status_code=200)
-@requires(["authenticated"])
-async def verify_mobile_otp(
- request: Request,
- code: str,
- client: Optional[str] = None,
-):
- user: KhojUser = request.user.object
-
- update_telemetry_state(
- request=request,
- telemetry_type="api",
- api="verify_phone_number",
- client=client,
- )
-
- if is_twilio_enabled() and not verify_otp(user, code):
- raise HTTPException(status_code=400, detail="Invalid OTP")
-
- user.verified_phone_number = True
- await user.asave()
- return {"status": "ok"}
-
-
@api_config.get("/index/size", response_model=Dict[str, int])
@requires(["authenticated"])
async def get_indexed_data_size(request: Request, common: CommonQueryParams):
diff --git a/src/khoj/routers/api_phone.py b/src/khoj/routers/api_phone.py
new file mode 100644
index 00000000..84c9a5d2
--- /dev/null
+++ b/src/khoj/routers/api_phone.py
@@ -0,0 +1,86 @@
+import logging
+from typing import Optional
+
+from fastapi import APIRouter, Depends, HTTPException, Request
+from starlette.authentication import requires
+
+from khoj.database import adapters
+from khoj.database.models import KhojUser
+from khoj.routers.helpers import ApiUserRateLimiter, update_telemetry_state
+from khoj.routers.twilio import create_otp, verify_otp
+
+api_phone = APIRouter()
+logger = logging.getLogger(__name__)
+
+
+@api_phone.post("", status_code=200)
+@requires(["authenticated"])
+async def update_phone_number(
+ request: Request,
+ phone_number: str,
+ client: Optional[str] = None,
+ rate_limiter_per_day=Depends(
+ ApiUserRateLimiter(requests=5, subscribed_requests=5, window=60 * 60 * 24, slug="update_phone")
+ ),
+):
+ user = request.user.object
+
+ await adapters.aset_user_phone_number(user, phone_number)
+ create_otp(user)
+
+ update_telemetry_state(
+ request=request,
+ telemetry_type="api",
+ api="set_phone_number",
+ client=client,
+ metadata={"phone_number": phone_number},
+ )
+
+ return {"status": "ok"}
+
+
+@api_phone.delete("", status_code=200)
+@requires(["authenticated"])
+async def delete_phone_number(
+ request: Request,
+ client: Optional[str] = None,
+):
+ user = request.user.object
+
+ await adapters.aremove_phone_number(user)
+
+ update_telemetry_state(
+ request=request,
+ telemetry_type="api",
+ api="delete_phone_number",
+ client=client,
+ )
+
+ return {"status": "ok"}
+
+
+@api_phone.post("/verify", status_code=200)
+@requires(["authenticated"])
+async def verify_mobile_otp(
+ request: Request,
+ code: str,
+ client: Optional[str] = None,
+ rate_limiter_per_day=Depends(
+ ApiUserRateLimiter(requests=5, subscribed_requests=5, window=60 * 60 * 24, slug="verify_phone")
+ ),
+):
+ user: KhojUser = request.user.object
+
+ update_telemetry_state(
+ request=request,
+ telemetry_type="api",
+ api="verify_phone_number",
+ client=client,
+ )
+
+ if not verify_otp(user, code):
+ raise HTTPException(status_code=400, detail="Invalid OTP")
+
+ user.verified_phone_number = True
+ await user.asave()
+ return {"status": "ok"}
diff --git a/src/khoj/routers/helpers.py b/src/khoj/routers/helpers.py
index b0d8c348..6bfdc9b9 100644
--- a/src/khoj/routers/helpers.py
+++ b/src/khoj/routers/helpers.py
@@ -360,6 +360,11 @@ class ApiUserRateLimiter:
if subscribed and count_requests >= self.subscribed_requests:
raise HTTPException(status_code=429, detail="Slow down! Too Many Requests")
if not subscribed and count_requests >= self.requests:
+ if self.subscribed_requests == self.requests:
+ raise HTTPException(
+ status_code=429,
+ detail="Slow down! Too Many Requests",
+ )
raise HTTPException(
status_code=429,
detail="We're glad you're enjoying Khoj! You've exceeded your usage limit for today. Come back tomorrow or subscribe to increase your rate limit via [your settings](https://app.khoj.dev/config).",
diff --git a/src/khoj/utils/cli.py b/src/khoj/utils/cli.py
index 968232e6..efbb596e 100644
--- a/src/khoj/utils/cli.py
+++ b/src/khoj/utils/cli.py
@@ -16,7 +16,7 @@ from khoj.migrations.migrate_processor_config_openai import (
)
from khoj.migrations.migrate_server_pg import migrate_server_pg
from khoj.migrations.migrate_version import migrate_config_to_version
-from khoj.utils.helpers import resolve_absolute_path
+from khoj.utils.helpers import in_debug_mode, resolve_absolute_path
from khoj.utils.yaml import parse_config_from_file
@@ -73,7 +73,7 @@ def cli(args=None):
else:
args = run_migrations(args)
args.config = parse_config_from_file(args.config_file)
- if os.environ.get("KHOJ_DEBUG"):
+ if in_debug_mode():
args.config.app.should_log_telemetry = False
return args
diff --git a/src/khoj/utils/helpers.py b/src/khoj/utils/helpers.py
index df2a3cd0..503ede14 100644
--- a/src/khoj/utils/helpers.py
+++ b/src/khoj/utils/helpers.py
@@ -317,3 +317,9 @@ def batcher(iterable, max_n):
if not chunk:
return
yield (x for x in chunk if x is not None)
+
+
+def in_debug_mode():
+ """Check if Khoj is running in debug mode.
+ Set KHOJ_DEBUG environment variable to true to enable debug mode."""
+ return os.getenv("KHOJ_DEBUG", "false").lower() == "true"
diff --git a/src/khoj/utils/models.py b/src/khoj/utils/models.py
index b76d369a..f848d4e4 100644
--- a/src/khoj/utils/models.py
+++ b/src/khoj/utils/models.py
@@ -5,8 +5,6 @@ import openai
import torch
from tqdm import trange
-from khoj.utils import state
-
class BaseEncoder(ABC):
@abstractmethod