Add Jivosite live chat widget support

Resolves #3 — widget is loaded on every page via base.html when
JIVOSITE_WIDGET_ID env var is set. Centralized Jinja2Templates instance
in web/templates_env.py with jivosite_widget_id as a global.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
mguschin
2026-03-10 14:11:25 +03:00
parent 00b74b8aa9
commit 4d4d5b0118
11 changed files with 19 additions and 16 deletions

View File

@@ -10,6 +10,8 @@ class Settings(BaseSettings):
EVOTOR_APP_ID: str = "" EVOTOR_APP_ID: str = ""
EVOTOR_WEBHOOK_SECRET: str = "" EVOTOR_WEBHOOK_SECRET: str = ""
JIVOSITE_WIDGET_ID: str = ""
HEALTH_CHECK_INTERVAL_SECONDS: int = 600 HEALTH_CHECK_INTERVAL_SECONDS: int = 600
CATALOG_REFRESH_INTERVAL_SECONDS: int = 3600 CATALOG_REFRESH_INTERVAL_SECONDS: int = 3600

View File

@@ -2,7 +2,7 @@ import uuid
from fastapi import APIRouter, Request, Depends from fastapi import APIRouter, Request, Depends
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates from web.templates_env import templates
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from web.auth import hash_password, verify_password, get_current_user from web.auth import hash_password, verify_password, get_current_user
@@ -12,7 +12,6 @@ from web.models import User
from web.schemas import validate_registration, validate_login from web.schemas import validate_registration, validate_login
router = APIRouter() router = APIRouter()
templates = Jinja2Templates(directory="web/templates")
@router.get("/register") @router.get("/register")

View File

@@ -3,7 +3,7 @@ import io
from fastapi import APIRouter, Request, Depends from fastapi import APIRouter, Request, Depends
from fastapi.responses import RedirectResponse, StreamingResponse from fastapi.responses import RedirectResponse, StreamingResponse
from fastapi.templating import Jinja2Templates from web.templates_env import templates
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from web.auth import get_current_user from web.auth import get_current_user
@@ -12,7 +12,6 @@ from web.evotor_api import refresh_catalog_cache
from web.models import User, EvotorConnection, SyncConfig, SyncFilter, CachedStore, CachedGroup, CachedProduct from web.models import User, EvotorConnection, SyncConfig, SyncFilter, CachedStore, CachedGroup, CachedProduct
router = APIRouter(prefix="/catalog") router = APIRouter(prefix="/catalog")
templates = Jinja2Templates(directory="web/templates")
def _get_or_create_sync_config(db: Session, user_id: int) -> SyncConfig: def _get_or_create_sync_config(db: Session, user_id: int) -> SyncConfig:

View File

@@ -1,6 +1,6 @@
from fastapi import APIRouter, Request, Depends from fastapi import APIRouter, Request, Depends
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates from web.templates_env import templates
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from web.auth import get_current_user from web.auth import get_current_user
@@ -8,7 +8,6 @@ from web.database import get_db
from web.models import User, EvotorConnection, VkConnection from web.models import User, EvotorConnection, VkConnection
router = APIRouter() router = APIRouter()
templates = Jinja2Templates(directory="web/templates")
SERVICE_TYPES = [ SERVICE_TYPES = [
{ {

View File

@@ -4,7 +4,7 @@ import httpx
from datetime import datetime from datetime import datetime
from fastapi import APIRouter, Request, Depends, HTTPException from fastapi import APIRouter, Request, Depends, HTTPException
from fastapi.responses import RedirectResponse, JSONResponse from fastapi.responses import RedirectResponse, JSONResponse
from fastapi.templating import Jinja2Templates from web.templates_env import templates
from pydantic import BaseModel from pydantic import BaseModel
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@@ -16,7 +16,6 @@ from web.models import User, EvotorConnection
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
router = APIRouter(prefix="/evotor") router = APIRouter(prefix="/evotor")
templates = Jinja2Templates(directory="web/templates")
EVOTOR_APP_URL = "https://market.evotor.ru/store/apps/{app_id}" EVOTOR_APP_URL = "https://market.evotor.ru/store/apps/{app_id}"
EVOTOR_STORES_URL = "https://api.evotor.ru/stores" EVOTOR_STORES_URL = "https://api.evotor.ru/stores"

View File

@@ -1,6 +1,6 @@
from fastapi import APIRouter, Request, Depends from fastapi import APIRouter, Request, Depends
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates from web.templates_env import templates
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from web.auth import get_current_user, verify_password, hash_password from web.auth import get_current_user, verify_password, hash_password
@@ -9,7 +9,6 @@ from web.models import User
from web.schemas import validate_profile, validate_reset_password from web.schemas import validate_profile, validate_reset_password
router = APIRouter() router = APIRouter()
templates = Jinja2Templates(directory="web/templates")
# VIEW PROFILE # VIEW PROFILE

View File

@@ -3,7 +3,7 @@ from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, Request, Depends from fastapi import APIRouter, Request, Depends
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates from web.templates_env import templates
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from web.auth import hash_password from web.auth import hash_password
@@ -13,7 +13,6 @@ from web.models import User
from web.schemas import validate_reset_password from web.schemas import validate_reset_password
router = APIRouter() router = APIRouter()
templates = Jinja2Templates(directory="web/templates")
@router.get("/forgot-password") @router.get("/forgot-password")

View File

@@ -2,7 +2,7 @@ from datetime import datetime
from fastapi import APIRouter, Request, Depends from fastapi import APIRouter, Request, Depends
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates from web.templates_env import templates
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from web.auth import get_current_user from web.auth import get_current_user
@@ -10,7 +10,6 @@ from web.database import get_db
from web.models import User, EvotorConnection, VkConnection, SyncConfig, SyncFilter from web.models import User, EvotorConnection, VkConnection, SyncConfig, SyncFilter
router = APIRouter(prefix="/sync") router = APIRouter(prefix="/sync")
templates = Jinja2Templates(directory="web/templates")
def _get_or_create_sync_config(db: Session, user_id: int) -> SyncConfig: def _get_or_create_sync_config(db: Session, user_id: int) -> SyncConfig:

View File

@@ -5,7 +5,7 @@ import httpx
from fastapi import APIRouter, Request, Depends from fastapi import APIRouter, Request, Depends
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates from web.templates_env import templates
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from web.auth import get_current_user from web.auth import get_current_user
@@ -14,7 +14,6 @@ from web.database import get_db
from web.models import User, VkConnection from web.models import User, VkConnection
router = APIRouter(prefix="/vk") router = APIRouter(prefix="/vk")
templates = Jinja2Templates(directory="web/templates")
VK_AUTHORIZE_URL = "https://oauth.vk.com/authorize" VK_AUTHORIZE_URL = "https://oauth.vk.com/authorize"
VK_TOKEN_URL = "https://oauth.vk.com/access_token" VK_TOKEN_URL = "https://oauth.vk.com/access_token"

View File

@@ -64,6 +64,9 @@
{% block content %}{% endblock %} {% block content %}{% endblock %}
</main> </main>
{% if jivosite_widget_id %}
<script src="//code.jivosite.com/widget/{{ jivosite_widget_id }}" async></script>
{% endif %}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/inputmask@5.0.9/dist/inputmask.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/inputmask@5.0.9/dist/inputmask.min.js"></script>
<script> <script>

6
web/templates_env.py Normal file
View File

@@ -0,0 +1,6 @@
from fastapi.templating import Jinja2Templates
from web.config import settings
templates = Jinja2Templates(directory="web/templates")
templates.env.globals["jivosite_widget_id"] = settings.JIVOSITE_WIDGET_ID