Co-authored-by: Joel <iamjoel007@gmail.com>tags/0.5.3
| @@ -19,5 +19,3 @@ from .explore import audio, completion, conversation, installed_app, message, pa | |||
| from .workspace import account, members, model_providers, models, tool_providers, workspace | |||
| # Import billing controllers | |||
| from .billing import billing | |||
| # Import operation controllers | |||
| from .operation import operation | |||
| @@ -3,10 +3,12 @@ from flask_restful import Resource | |||
| from services.feature_service import FeatureService | |||
| from . import api | |||
| from .wraps import cloud_utm_record | |||
| class FeatureApi(Resource): | |||
| @cloud_utm_record | |||
| def get(self): | |||
| return FeatureService.get_features(current_user.current_tenant_id).dict() | |||
| @@ -1,30 +0,0 @@ | |||
| from flask_login import current_user | |||
| from flask_restful import Resource, reqparse | |||
| from controllers.console import api | |||
| from controllers.console.setup import setup_required | |||
| from controllers.console.wraps import account_initialization_required, only_edition_cloud | |||
| from libs.login import login_required | |||
| from services.operation_service import OperationService | |||
| class TenantUtm(Resource): | |||
| @setup_required | |||
| @login_required | |||
| @account_initialization_required | |||
| @only_edition_cloud | |||
| def post(self): | |||
| parser = reqparse.RequestParser() | |||
| parser.add_argument('utm_source', type=str, required=True) | |||
| parser.add_argument('utm_medium', type=str, required=True) | |||
| parser.add_argument('utm_campaign', type=str, required=False, default='') | |||
| parser.add_argument('utm_content', type=str, required=False, default='') | |||
| parser.add_argument('utm_term', type=str, required=False, default='') | |||
| args = parser.parse_args() | |||
| return OperationService.record_utm(current_user.current_tenant_id, args) | |||
| api.add_resource(TenantUtm, '/operation/utm') | |||
| @@ -1,10 +1,13 @@ | |||
| # -*- coding:utf-8 -*- | |||
| import json | |||
| from functools import wraps | |||
| from flask import request | |||
| from controllers.console.workspace.error import AccountNotInitializedError | |||
| from flask import abort, current_app | |||
| from flask_login import current_user | |||
| from services.feature_service import FeatureService | |||
| from services.operation_service import OperationService | |||
| def account_initialization_required(view): | |||
| @@ -73,3 +76,20 @@ def cloud_edition_billing_resource_check(resource: str, | |||
| return decorated | |||
| return interceptor | |||
| def cloud_utm_record(view): | |||
| @wraps(view) | |||
| def decorated(*args, **kwargs): | |||
| try: | |||
| features = FeatureService.get_features(current_user.current_tenant_id) | |||
| if features.billing.enabled: | |||
| utm_info = request.cookies.get('utm_info') | |||
| if utm_info: | |||
| utm_info = json.loads(utm_info) | |||
| OperationService.record_utm(current_user.current_tenant_id, utm_info) | |||
| except Exception as e: | |||
| pass | |||
| return view(*args, **kwargs) | |||
| return decorated | |||
| @@ -20,13 +20,13 @@ class OperationService: | |||
| return response.json() | |||
| @classmethod | |||
| def record_utm(cls, tenant_id, args): | |||
| def record_utm(cls, tenant_id: str, utm_info: dict): | |||
| params = { | |||
| 'tenant_id': tenant_id, | |||
| 'utm_source': args['utm_source'], | |||
| 'utm_medium': args['utm_medium'], | |||
| 'utm_campaign': args['utm_campaign'], | |||
| 'utm_content': args['utm_content'], | |||
| 'utm_term': args['utm_term'] | |||
| 'utm_source': utm_info.get('utm_source', ''), | |||
| 'utm_medium': utm_info.get('utm_medium', ''), | |||
| 'utm_campaign': utm_info.get('utm_campaign', ''), | |||
| 'utm_content': utm_info.get('utm_content', ''), | |||
| 'utm_term': utm_info.get('utm_term', '') | |||
| } | |||
| return cls._send_request('POST', '/tenant_utms', params=params) | |||
| @@ -15,14 +15,6 @@ const SwrInitor = ({ | |||
| const searchParams = useSearchParams() | |||
| const consoleToken = searchParams.get('console_token') | |||
| const consoleTokenFromLocalStorage = localStorage?.getItem('console_token') | |||
| const utm = { | |||
| utm_source: searchParams.get('utm_source') || '', | |||
| utm_medium: searchParams.get('utm_medium') || '', | |||
| utm_campaign: searchParams.get('utm_campaign') || '', | |||
| utm_content: searchParams.get('utm_content') || '', | |||
| utm_term: searchParams.get('utm_term') || '', | |||
| } | |||
| localStorage?.setItem('utm', JSON.stringify(utm)) | |||
| const [init, setInit] = useState(false) | |||
| useEffect(() => { | |||
| @@ -7,7 +7,6 @@ import { | |||
| fetchModelList, | |||
| fetchModelProviders, | |||
| fetchSupportRetrievalMethods, | |||
| operationUtm, | |||
| } from '@/service/common' | |||
| import { | |||
| ModelFeatureEnum, | |||
| @@ -100,23 +99,7 @@ export const ProviderContextProvider = ({ | |||
| const [isFetchedPlan, setIsFetchedPlan] = useState(false) | |||
| const [enableBilling, setEnableBilling] = useState(true) | |||
| const [enableReplaceWebAppLogo, setEnableReplaceWebAppLogo] = useState(false) | |||
| const handleOperateUtm = () => { | |||
| let utm | |||
| try { | |||
| utm = JSON.parse(localStorage?.getItem('utm') || '{}') | |||
| } | |||
| catch (e) { | |||
| utm = { | |||
| utm_source: '', | |||
| utm_medium: '', | |||
| utm_campaign: '', | |||
| utm_content: '', | |||
| utm_term: '', | |||
| } | |||
| } | |||
| if (utm.utm_source || utm.utm_medium || utm.utm_campaign || utm.utm_content || utm.utm_term) | |||
| operationUtm({ url: '/operation/utm', body: utm }) | |||
| } | |||
| const fetchPlan = async () => { | |||
| const data = await fetchCurrentPlanInfo() | |||
| const enabled = data.billing.enabled | |||
| @@ -124,7 +107,6 @@ export const ProviderContextProvider = ({ | |||
| setEnableReplaceWebAppLogo(data.can_replace_logo) | |||
| if (enabled) { | |||
| setPlan(parseCurrentPlan(data)) | |||
| handleOperateUtm() | |||
| setIsFetchedPlan(true) | |||
| } | |||
| } | |||
| @@ -251,11 +251,3 @@ export type ModerationService = ( | |||
| text: string | |||
| } | |||
| ) => Promise<ModerateResponse> | |||
| export type Utm = { | |||
| utm_source?: string | |||
| utm_medium?: string | |||
| utm_campaign?: string | |||
| utm_term?: string | |||
| utm_content?: string | |||
| } | |||
| @@ -20,7 +20,6 @@ import type { | |||
| ProviderAzureToken, | |||
| SetupStatusResponse, | |||
| UserProfileOriginResponse, | |||
| Utm, | |||
| } from '@/models/common' | |||
| import type { | |||
| UpdateOpenAIKeyResponse, | |||
| @@ -263,7 +262,3 @@ type RetrievalMethodsRes = { | |||
| export const fetchSupportRetrievalMethods: Fetcher<RetrievalMethodsRes, string> = (url) => { | |||
| return get<RetrievalMethodsRes>(url) | |||
| } | |||
| export const operationUtm: Fetcher<CommonResponse, { url: string; body: Utm }> = ({ url, body }) => { | |||
| return post(url, { body }) as Promise<CommonResponse> | |||
| } | |||