feat: enforce per-user module access in Makelore
This commit is contained in:
@@ -7,7 +7,7 @@ import moduleRobotImage from '@/assets/module-robot.jpg';
|
||||
import logoWordmarkSource from '@/assets/makelore-wordmark-source.png';
|
||||
import { UserProfileDialog } from '@/components/profile/UserProfileDialog';
|
||||
import { useCurrentUserProfile } from '@/hooks/use-current-user-profile';
|
||||
import { aiModules, type AiModuleId } from '@/lib/ai-modules';
|
||||
import { aiModules, isAiModuleAllowed, type AiModuleId } from '@/lib/ai-modules';
|
||||
import { getAuthUserDisplayName } from '@/lib/auth-user-display';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
@@ -23,6 +23,7 @@ const moduleSelectionContent: Record<AiModuleId, { label: string; image: string;
|
||||
export function ModuleSelection({ authRequired = true }: { authRequired?: boolean }) {
|
||||
const navigate = useNavigate();
|
||||
const authUser = useAuthStore((state) => state.user);
|
||||
const moduleAccess = useAuthStore((state) => state.moduleAccess);
|
||||
const authenticated = useAuthStore((state) => state.isAuthenticated());
|
||||
const {
|
||||
userProfile,
|
||||
@@ -37,8 +38,8 @@ export function ModuleSelection({ authRequired = true }: { authRequired?: boolea
|
||||
|| profileRequired
|
||||
|| Boolean(profileSyncError && dismissedSyncError !== profileSyncError);
|
||||
|
||||
const openModule = (route: string | null) => {
|
||||
if (!route) return;
|
||||
const openModule = (route: string | null, enabled: boolean) => {
|
||||
if (!route || !enabled) return;
|
||||
if (authRequired && !authenticated) {
|
||||
navigate('/login');
|
||||
return;
|
||||
@@ -71,17 +72,20 @@ export function ModuleSelection({ authRequired = true }: { authRequired?: boolea
|
||||
>
|
||||
{aiModules.map((module) => {
|
||||
const content = moduleSelectionContent[module.id];
|
||||
const enabledByPolicy = isAiModuleAllowed(module.id, moduleAccess);
|
||||
const enabled = module.enabled && enabledByPolicy;
|
||||
return (
|
||||
<button
|
||||
key={module.id}
|
||||
type="button"
|
||||
data-testid={`ai-module-option-${module.id}`}
|
||||
disabled={!module.enabled}
|
||||
onClick={() => openModule(module.route)}
|
||||
aria-label={`${content.label}:${module.description}`}
|
||||
disabled={!enabled}
|
||||
aria-disabled={!enabled}
|
||||
onClick={() => openModule(module.route, enabled)}
|
||||
aria-label={`${content.label}:${module.description}${enabled ? '' : '(已关闭)'}`}
|
||||
className={cn(
|
||||
'module-option-card module-option-card-horizontal group motion-press flex w-full min-w-0 items-stretch rounded-lg border border-transparent bg-transparent p-0 text-left shadow-none disabled:cursor-not-allowed disabled:bg-transparent disabled:text-muted-foreground/70 disabled:opacity-75',
|
||||
!module.enabled && 'module-option-card-disabled',
|
||||
!enabled && 'module-option-card-disabled',
|
||||
)}
|
||||
>
|
||||
<span className="module-option-card-frame" aria-hidden="true" />
|
||||
@@ -90,14 +94,18 @@ export function ModuleSelection({ authRequired = true }: { authRequired?: boolea
|
||||
<img
|
||||
src={content.image}
|
||||
alt={content.imageAlt}
|
||||
className={cn('module-option-card-image-media h-full w-full object-cover', !module.enabled && 'grayscale')}
|
||||
className={cn('module-option-card-image-media h-full w-full object-cover', !enabled && 'grayscale')}
|
||||
draggable="false"
|
||||
/>
|
||||
</div>
|
||||
<div className="module-option-card-content relative min-h-0 flex-1">
|
||||
<p className="module-option-card-title font-medium tracking-[-0.02em]">{content.label}</p>
|
||||
<p className="module-option-card-description font-medium text-muted-foreground">{module.description}</p>
|
||||
{!module.enabled ? <p className="module-option-card-status font-semibold">暂未开放</p> : null}
|
||||
{!enabled ? (
|
||||
<p className="module-option-card-status font-semibold">
|
||||
{module.enabled ? '管理员已关闭' : '暂未开放'}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
<span className="module-option-card-hit-area" aria-hidden="true" />
|
||||
|
||||
Reference in New Issue
Block a user