fix: disabled web app access control if systemFeatures.webapp_auth.enabled is false

pull/19898/head
NFish 1 year ago
parent 2ec5007ba2
commit d6652beb62

@ -34,6 +34,7 @@ import { AppTypeIcon } from '@/app/components/app/type-selector'
import Tooltip from '@/app/components/base/tooltip' import Tooltip from '@/app/components/base/tooltip'
import AccessControl from '@/app/components/app/app-access-control' import AccessControl from '@/app/components/app/app-access-control'
import { AccessMode } from '@/models/access-control' import { AccessMode } from '@/models/access-control'
import { useGlobalPublicStore } from '@/context/global-public-context'
export type AppCardProps = { export type AppCardProps = {
app: App app: App
@ -43,6 +44,7 @@ export type AppCardProps = {
const AppCard = ({ app, onRefresh }: AppCardProps) => { const AppCard = ({ app, onRefresh }: AppCardProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const { notify } = useContext(ToastContext) const { notify } = useContext(ToastContext)
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
const { isCurrentWorkspaceEditor } = useAppContext() const { isCurrentWorkspaceEditor } = useAppContext()
const { onPlanInfoChanged } = useProviderContext() const { onPlanInfoChanged } = useProviderContext()
const { push } = useRouter() const { push } = useRouter()
@ -208,13 +210,13 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
e.preventDefault() e.preventDefault()
exportCheck() exportCheck()
} }
const onClickSwitch = async (e: React.MouseEvent<HTMLDivElement>) => { const onClickSwitch = async (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation() e.stopPropagation()
props.onClick?.() props.onClick?.()
e.preventDefault() e.preventDefault()
setShowSwitchModal(true) setShowSwitchModal(true)
} }
const onClickDelete = async (e: React.MouseEvent<HTMLDivElement>) => { const onClickDelete = async (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation() e.stopPropagation()
props.onClick?.() props.onClick?.()
e.preventDefault() e.preventDefault()
@ -242,49 +244,49 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
} }
} }
return ( return (
<div className="relative w-full py-1" onMouseLeave={onMouseLeave}> <div className="relative flex w-full flex-col py-1" onMouseLeave={onMouseLeave}>
<button className='mx-1 flex h-8 w-[calc(100%_-_8px)] cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-base-hover' onClick={onClickSettings}> <button className='mx-1 flex h-8 cursor-pointer items-center gap-2 rounded-lg px-3 hover:bg-state-base-hover' onClick={onClickSettings}>
<span className='system-sm-regular text-text-secondary'>{t('app.editApp')}</span> <span className='system-sm-regular text-text-secondary'>{t('app.editApp')}</span>
</button> </button>
<Divider className="!my-1" /> <Divider className="my-1" />
<button className='mx-1 flex h-8 w-[calc(100%_-_8px)] cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-base-hover' onClick={onClickDuplicate}> <button className='mx-1 flex h-8 cursor-pointer items-center gap-2 rounded-lg px-3 hover:bg-state-base-hover' onClick={onClickDuplicate}>
<span className='system-sm-regular text-text-secondary'>{t('app.duplicate')}</span> <span className='system-sm-regular text-text-secondary'>{t('app.duplicate')}</span>
</button> </button>
<button className='mx-1 flex h-8 w-[calc(100%_-_8px)] cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-base-hover' onClick={onClickExport}> <button className='mx-1 flex h-8 cursor-pointer items-center gap-2 rounded-lg px-3 hover:bg-state-base-hover' onClick={onClickExport}>
<span className='system-sm-regular text-text-secondary'>{t('app.export')}</span> <span className='system-sm-regular text-text-secondary'>{t('app.export')}</span>
</button> </button>
{(app.mode === 'completion' || app.mode === 'chat') && ( {(app.mode === 'completion' || app.mode === 'chat') && (
<> <>
<Divider className="!my-1" /> <Divider className="my-1" />
<div <button
className='mx-1 flex h-9 cursor-pointer items-center rounded-lg px-3 py-2 hover:bg-state-base-hover' className='mx-1 flex h-8 cursor-pointer items-center rounded-lg px-3 hover:bg-state-base-hover'
onClick={onClickSwitch} onClick={onClickSwitch}
> >
<span className='text-sm leading-5 text-text-secondary'>{t('app.switch')}</span> <span className='text-sm leading-5 text-text-secondary'>{t('app.switch')}</span>
</div> </button>
</> </>
)} )}
<Divider className="!my-1" /> <Divider className="my-1" />
<button className='mx-1 flex h-8 w-[calc(100%_-_8px)] cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-base-hover' onClick={onClickInstalledApp}> <button className='mx-1 flex h-8 cursor-pointer items-center gap-2 rounded-lg px-3 hover:bg-state-base-hover' onClick={onClickInstalledApp}>
<span className='system-sm-regular text-text-secondary'>{t('app.openInExplore')}</span> <span className='system-sm-regular text-text-secondary'>{t('app.openInExplore')}</span>
</button> </button>
<Divider className="!my-1" /> <Divider className="my-1" />
{ {
isCurrentWorkspaceEditor && <> systemFeatures.webapp_auth.enabled && isCurrentWorkspaceEditor && <>
<button className='mx-1 flex h-9 cursor-pointer items-center rounded-lg px-3 py-2 hover:bg-state-base-hover' onClick={onClickAccessControl}> <button className='mx-1 flex h-8 cursor-pointer items-center rounded-lg px-3 hover:bg-state-base-hover' onClick={onClickAccessControl}>
<span className='text-sm leading-5 text-text-secondary'>{t('app.accessControl')}</span> <span className='text-sm leading-5 text-text-secondary'>{t('app.accessControl')}</span>
</button> </button>
<Divider /> <Divider className='my-1' />
</> </>
} }
<div <button
className='group mx-1 flex h-8 w-[calc(100%_-_8px)] cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-destructive-hover' className='group mx-1 flex h-8 cursor-pointer items-center gap-2 rounded-lg px-3 py-[6px] hover:bg-state-destructive-hover'
onClick={onClickDelete} onClick={onClickDelete}
> >
<span className='system-sm-regular text-text-secondary group-hover:text-text-destructive'> <span className='system-sm-regular text-text-secondary group-hover:text-text-destructive'>
{t('common.operation.delete')} {t('common.operation.delete')}
</span> </span>
</div> </button>
</div> </div>
) )
} }

@ -44,6 +44,7 @@ import type { PublishWorkflowParams } from '@/types/workflow'
import { useAppWhiteListSubjects, useGetUserCanAccessApp } from '@/service/access-control' import { useAppWhiteListSubjects, useGetUserCanAccessApp } from '@/service/access-control'
import { AccessMode } from '@/models/access-control' import { AccessMode } from '@/models/access-control'
import { fetchAppDetail } from '@/service/apps' import { fetchAppDetail } from '@/service/apps'
import { useGlobalPublicStore } from '@/context/global-public-context'
export type AppPublisherProps = { export type AppPublisherProps = {
disabled?: boolean disabled?: boolean
@ -85,17 +86,18 @@ const AppPublisher = ({
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const appDetail = useAppStore(state => state.appDetail) const appDetail = useAppStore(state => state.appDetail)
const setAppDetail = useAppStore(s => s.setAppDetail) const setAppDetail = useAppStore(s => s.setAppDetail)
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
const { app_base_url: appBaseURL = '', access_token: accessToken = '' } = appDetail?.site ?? {} const { app_base_url: appBaseURL = '', access_token: accessToken = '' } = appDetail?.site ?? {}
const appMode = (appDetail?.mode !== 'completion' && appDetail?.mode !== 'workflow') ? 'chat' : appDetail.mode const appMode = (appDetail?.mode !== 'completion' && appDetail?.mode !== 'workflow') ? 'chat' : appDetail.mode
const appURL = `${appBaseURL}${basePath}/${appMode}/${accessToken}` const appURL = `${appBaseURL}${basePath}/${appMode}/${accessToken}`
const isChatApp = ['chat', 'agent-chat', 'completion'].includes(appDetail?.mode || '') const isChatApp = ['chat', 'agent-chat', 'completion'].includes(appDetail?.mode || '')
const { data: userCanAccessApp, isLoading: isGettingUserCanAccessApp, refetch } = useGetUserCanAccessApp({ appId: appDetail?.id, enabled: false }) const { data: userCanAccessApp, isLoading: isGettingUserCanAccessApp, refetch } = useGetUserCanAccessApp({ appId: appDetail?.id, enabled: false })
const { data: appAccessSubjects, isLoading: isGettingAppWhiteListSubjects } = useAppWhiteListSubjects(appDetail?.id, open && appDetail?.access_mode === AccessMode.SPECIFIC_GROUPS_MEMBERS) const { data: appAccessSubjects, isLoading: isGettingAppWhiteListSubjects } = useAppWhiteListSubjects(appDetail?.id, open && systemFeatures.webapp_auth.enabled && appDetail?.access_mode === AccessMode.SPECIFIC_GROUPS_MEMBERS)
useEffect(() => { useEffect(() => {
if (open && appDetail) if (systemFeatures.webapp_auth.enabled && open && appDetail)
refetch() refetch()
}, [open, appDetail, refetch]) }, [open, appDetail, refetch, systemFeatures])
const [showAppAccessControl, setShowAppAccessControl] = useState(false) const [showAppAccessControl, setShowAppAccessControl] = useState(false)
const [isAppAccessSet, setIsAppAccessSet] = useState(true) const [isAppAccessSet, setIsAppAccessSet] = useState(true)

@ -44,6 +44,7 @@ import { InputVarType } from '@/app/components/workflow/types'
import { TransferMethod } from '@/types/app' import { TransferMethod } from '@/types/app'
import { noop } from 'lodash-es' import { noop } from 'lodash-es'
import { useGetAppAccessMode, useGetUserCanAccessApp } from '@/service/access-control' import { useGetAppAccessMode, useGetUserCanAccessApp } from '@/service/access-control'
import { useGlobalPublicStore } from '@/context/global-public-context'
function getFormattedChatList(messages: any[]) { function getFormattedChatList(messages: any[]) {
const newChatList: ChatItem[] = [] const newChatList: ChatItem[] = []
@ -73,9 +74,18 @@ function getFormattedChatList(messages: any[]) {
export const useChatWithHistory = (installedAppInfo?: InstalledApp) => { export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
const isInstalledApp = useMemo(() => !!installedAppInfo, [installedAppInfo]) const isInstalledApp = useMemo(() => !!installedAppInfo, [installedAppInfo])
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
const { data: appInfo, isLoading: appInfoLoading, error: appInfoError } = useSWR(installedAppInfo ? null : 'appInfo', fetchAppInfo) const { data: appInfo, isLoading: appInfoLoading, error: appInfoError } = useSWR(installedAppInfo ? null : 'appInfo', fetchAppInfo)
const { isPending: isGettingAccessMode, data: appAccessMode } = useGetAppAccessMode({ appId: installedAppInfo?.app.id || appInfo?.app_id, isInstalledApp }) const { isPending: isGettingAccessMode, data: appAccessMode } = useGetAppAccessMode({
const { isPending: isCheckingPermission, data: userCanAccessResult } = useGetUserCanAccessApp({ appId: installedAppInfo?.app.id || appInfo?.app_id, isInstalledApp }) appId: installedAppInfo?.app.id || appInfo?.app_id,
isInstalledApp,
enabled: systemFeatures.webapp_auth.enabled,
})
const { isPending: isCheckingPermission, data: userCanAccessResult } = useGetUserCanAccessApp({
appId: installedAppInfo?.app.id || appInfo?.app_id,
isInstalledApp,
enabled: systemFeatures.webapp_auth.enabled,
})
useAppFavicon({ useAppFavicon({
enable: !installedAppInfo, enable: !installedAppInfo,

@ -37,6 +37,7 @@ import { TransferMethod } from '@/types/app'
import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils' import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils'
import { noop } from 'lodash-es' import { noop } from 'lodash-es'
import { useGetAppAccessMode, useGetUserCanAccessApp } from '@/service/access-control' import { useGetAppAccessMode, useGetUserCanAccessApp } from '@/service/access-control'
import { useGlobalPublicStore } from '@/context/global-public-context'
function getFormattedChatList(messages: any[]) { function getFormattedChatList(messages: any[]) {
const newChatList: ChatItem[] = [] const newChatList: ChatItem[] = []
@ -66,9 +67,18 @@ function getFormattedChatList(messages: any[]) {
export const useEmbeddedChatbot = () => { export const useEmbeddedChatbot = () => {
const isInstalledApp = false const isInstalledApp = false
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
const { data: appInfo, isLoading: appInfoLoading, error: appInfoError } = useSWR('appInfo', fetchAppInfo) const { data: appInfo, isLoading: appInfoLoading, error: appInfoError } = useSWR('appInfo', fetchAppInfo)
const { isPending: isGettingAccessMode, data: appAccessMode } = useGetAppAccessMode({ appId: appInfo?.app_id, isInstalledApp }) const { isPending: isGettingAccessMode, data: appAccessMode } = useGetAppAccessMode({
const { isPending: isCheckingPermission, data: userCanAccessResult } = useGetUserCanAccessApp({ appId: appInfo?.app_id, isInstalledApp }) appId: appInfo?.app_id,
isInstalledApp,
enabled: systemFeatures.webapp_auth.enabled,
})
const { isPending: isCheckingPermission, data: userCanAccessResult } = useGetUserCanAccessApp({
appId: appInfo?.app_id,
isInstalledApp,
enabled: systemFeatures.webapp_auth.enabled,
})
const appData = useMemo(() => { const appData = useMemo(() => {
return appInfo return appInfo

@ -41,6 +41,7 @@ import LogoSite from '@/app/components/base/logo/logo-site'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import { useGetAppAccessMode, useGetUserCanAccessApp } from '@/service/access-control' import { useGetAppAccessMode, useGetUserCanAccessApp } from '@/service/access-control'
import { AccessMode } from '@/models/access-control' import { AccessMode } from '@/models/access-control'
import { useGlobalPublicStore } from '@/context/global-public-context'
const GROUP_SIZE = 5 // to avoid RPM(Request per minute) limit. The group task finished then the next group. const GROUP_SIZE = 5 // to avoid RPM(Request per minute) limit. The group task finished then the next group.
enum TaskStatus { enum TaskStatus {
@ -101,6 +102,7 @@ const TextGeneration: FC<IMainProps> = ({
doSetInputs(newInputs) doSetInputs(newInputs)
inputsRef.current = newInputs inputsRef.current = newInputs
}, []) }, [])
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
const [appId, setAppId] = useState<string>('') const [appId, setAppId] = useState<string>('')
const [siteInfo, setSiteInfo] = useState<SiteInfo | null>(null) const [siteInfo, setSiteInfo] = useState<SiteInfo | null>(null)
const [canReplaceLogo, setCanReplaceLogo] = useState<boolean>(false) const [canReplaceLogo, setCanReplaceLogo] = useState<boolean>(false)
@ -109,8 +111,16 @@ const TextGeneration: FC<IMainProps> = ({
const [moreLikeThisConfig, setMoreLikeThisConfig] = useState<MoreLikeThisConfig | null>(null) const [moreLikeThisConfig, setMoreLikeThisConfig] = useState<MoreLikeThisConfig | null>(null)
const [textToSpeechConfig, setTextToSpeechConfig] = useState<TextToSpeechConfig | null>(null) const [textToSpeechConfig, setTextToSpeechConfig] = useState<TextToSpeechConfig | null>(null)
const { isPending: isGettingAccessMode, data: appAccessMode } = useGetAppAccessMode({ appId, isInstalledApp }) const { isPending: isGettingAccessMode, data: appAccessMode } = useGetAppAccessMode({
const { isPending: isCheckingPermission, data: userCanAccessResult } = useGetUserCanAccessApp({ appId, isInstalledApp }) appId,
isInstalledApp,
enabled: systemFeatures.webapp_auth.enabled,
})
const { isPending: isCheckingPermission, data: userCanAccessResult } = useGetUserCanAccessApp({
appId,
isInstalledApp,
enabled: systemFeatures.webapp_auth.enabled,
})
// save message // save message
const [savedMessages, setSavedMessages] = useState<SavedMessage[]>([]) const [savedMessages, setSavedMessages] = useState<SavedMessage[]>([])

@ -69,17 +69,17 @@ export const useUpdateAccessMode = () => {
}) })
} }
export const useGetAppAccessMode = ({ appId, isInstalledApp = true }: { appId?: string; isInstalledApp?: boolean }) => { export const useGetAppAccessMode = ({ appId, isInstalledApp = true, enabled }: { appId?: string; isInstalledApp?: boolean; enabled: boolean }) => {
return useQuery({ return useQuery({
queryKey: [NAME_SPACE, 'app-access-mode', appId], queryKey: [NAME_SPACE, 'app-access-mode', appId],
queryFn: () => getAppAccessMode(appId!, isInstalledApp), queryFn: () => getAppAccessMode(appId!, isInstalledApp),
enabled: !!appId, enabled: !!appId && enabled,
staleTime: 0, staleTime: 0,
gcTime: 0, gcTime: 0,
}) })
} }
export const useGetUserCanAccessApp = ({ appId, isInstalledApp = true, enabled = true }: { appId?: string; isInstalledApp?: boolean; enabled?: boolean }) => { export const useGetUserCanAccessApp = ({ appId, isInstalledApp = true, enabled }: { appId?: string; isInstalledApp?: boolean; enabled: boolean }) => {
return useQuery({ return useQuery({
queryKey: [NAME_SPACE, 'user-can-access-app', appId], queryKey: [NAME_SPACE, 'user-can-access-app', appId],
queryFn: () => getUserCanAccess(appId!, isInstalledApp), queryFn: () => getUserCanAccess(appId!, isInstalledApp),

Loading…
Cancel
Save