fix: 修复博客菜单可见性
This commit is contained in:
parent
490632c7a1
commit
add0dc3a8c
@ -2,7 +2,6 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { In, Repository } from 'typeorm';
|
import { In, Repository } from 'typeorm';
|
||||||
import { toTree } from '@/common';
|
import { toTree } from '@/common';
|
||||||
import { WordpressService } from '@/wordpress/wordpress.service';
|
|
||||||
import { AdminUser } from '../user/admin-user.entity';
|
import { AdminUser } from '../user/admin-user.entity';
|
||||||
import { AdminMenu } from './admin-menu.entity';
|
import { AdminMenu } from './admin-menu.entity';
|
||||||
import type { AdminMenuInput, AdminMenuMeta } from '../admin.types';
|
import type { AdminMenuInput, AdminMenuMeta } from '../admin.types';
|
||||||
@ -12,20 +11,15 @@ export class AdminMenuService {
|
|||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(AdminMenu)
|
@InjectRepository(AdminMenu)
|
||||||
private readonly menuRepository: Repository<AdminMenu>,
|
private readonly menuRepository: Repository<AdminMenu>,
|
||||||
private readonly wordpressService: WordpressService,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async getAccessCodes(user: AdminUser) {
|
async getAccessCodes(user: AdminUser) {
|
||||||
const menus = this.filterUnavailableFeatureMenus(
|
const menus = await this.getAllowedMenus(user);
|
||||||
await this.getAllowedMenus(user),
|
|
||||||
);
|
|
||||||
return menus.map((menu) => menu.authCode).filter((authCode) => !!authCode);
|
return menus.map((menu) => menu.authCode).filter((authCode) => !!authCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRouteMenus(user: AdminUser) {
|
async getRouteMenus(user: AdminUser) {
|
||||||
const menus = this.filterUnavailableFeatureMenus(
|
const menus = await this.getAllowedMenus(user);
|
||||||
await this.getAllowedMenus(user),
|
|
||||||
);
|
|
||||||
return this.buildMenuTree(menus.filter((menu) => menu.type !== 'button'));
|
return this.buildMenuTree(menus.filter((menu) => menu.type !== 'button'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,22 +141,6 @@ export class AdminMenuService {
|
|||||||
return [...menuMap.values()];
|
return [...menuMap.values()];
|
||||||
}
|
}
|
||||||
|
|
||||||
private filterUnavailableFeatureMenus(menus: AdminMenu[]) {
|
|
||||||
if (!menus.some((menu) => this.isWordpressMenu(menu))) return menus;
|
|
||||||
if (this.wordpressService.isAdminIntegrationAvailable()) return menus;
|
|
||||||
|
|
||||||
// WordPress 是外部增强能力,远程不可用时不影响 Admin 主系统登录和系统管理菜单。
|
|
||||||
return menus.filter((menu) => !this.isWordpressMenu(menu));
|
|
||||||
}
|
|
||||||
|
|
||||||
private isWordpressMenu(menu: AdminMenu) {
|
|
||||||
return (
|
|
||||||
menu.name?.startsWith('Blog') ||
|
|
||||||
menu.path?.startsWith('/blog') ||
|
|
||||||
menu.authCode?.startsWith('Blog:')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private normalizeMenuInput(
|
private normalizeMenuInput(
|
||||||
data: AdminMenuInput,
|
data: AdminMenuInput,
|
||||||
includeEmptyMeta: boolean,
|
includeEmptyMeta: boolean,
|
||||||
|
|||||||
89
test/admin/admin-menu.service.spec.ts
Normal file
89
test/admin/admin-menu.service.spec.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import { AdminMenuService } from '../../src/admin/menu/admin-menu.service';
|
||||||
|
import type { AdminMenu } from '../../src/admin/menu/admin-menu.entity';
|
||||||
|
import type { AdminUser } from '../../src/admin/user/admin-user.entity';
|
||||||
|
|
||||||
|
describe('AdminMenuService', () => {
|
||||||
|
const blogMenus = [
|
||||||
|
createMenu({
|
||||||
|
id: '2041700000000100300',
|
||||||
|
meta: { title: '博客管理' },
|
||||||
|
name: 'Blog',
|
||||||
|
path: '/blog',
|
||||||
|
pid: '0',
|
||||||
|
type: 'catalog',
|
||||||
|
}),
|
||||||
|
createMenu({
|
||||||
|
authCode: 'Blog:Theme:List',
|
||||||
|
component: '/blog/theme/config',
|
||||||
|
id: '2041700000000100304',
|
||||||
|
meta: { title: '主题配置' },
|
||||||
|
name: 'BlogTheme',
|
||||||
|
path: '/blog/theme',
|
||||||
|
pid: '2041700000000100300',
|
||||||
|
type: 'menu',
|
||||||
|
}),
|
||||||
|
createMenu({
|
||||||
|
authCode: 'Blog:Theme:Import',
|
||||||
|
id: '2041700000000120332',
|
||||||
|
meta: { title: '导入 WordPress' },
|
||||||
|
name: 'BlogThemeImport',
|
||||||
|
pid: '2041700000000100304',
|
||||||
|
type: 'button',
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
it('keeps local Blog menus visible for super users', async () => {
|
||||||
|
const service = new AdminMenuService({
|
||||||
|
find: jest.fn(async () => blogMenus),
|
||||||
|
} as any);
|
||||||
|
const user = {
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
isDeleted: false,
|
||||||
|
roleCode: 'super',
|
||||||
|
status: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as AdminUser;
|
||||||
|
|
||||||
|
const routeMenus = await service.getRouteMenus(user);
|
||||||
|
const accessCodes = await service.getAccessCodes(user);
|
||||||
|
|
||||||
|
expect(routeMenus).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
children: [
|
||||||
|
expect.objectContaining({
|
||||||
|
name: 'BlogTheme',
|
||||||
|
path: '/blog/theme',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
name: 'Blog',
|
||||||
|
path: '/blog',
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
expect(accessCodes).toEqual(
|
||||||
|
expect.arrayContaining(['Blog:Theme:List', 'Blog:Theme:Import']),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function createMenu(menu: Partial<AdminMenu>): AdminMenu {
|
||||||
|
return {
|
||||||
|
authCode: null,
|
||||||
|
component: null,
|
||||||
|
createTime: new Date('2026-06-05T00:00:00Z'),
|
||||||
|
id: '',
|
||||||
|
isDeleted: false,
|
||||||
|
meta: {},
|
||||||
|
name: '',
|
||||||
|
path: null,
|
||||||
|
pid: '0',
|
||||||
|
redirect: null,
|
||||||
|
roles: [],
|
||||||
|
sort: 0,
|
||||||
|
status: 1,
|
||||||
|
type: 'menu',
|
||||||
|
updateTime: new Date('2026-06-05T00:00:00Z'),
|
||||||
|
...menu,
|
||||||
|
} as AdminMenu;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user