mirror of https://github.com/halo-dev/halo
* feat: #1119 * feat: #1119 * pref: allows multiple same menus. * feat: support create menu in batch. * feat: support delete menu in batch. * feat: #1119pull/1138/head
parent
ff734ed153
commit
c9ce7d29fd
|
@ -5,6 +5,7 @@ import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.web.SortDefault;
|
import org.springframework.data.web.SortDefault;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import run.halo.app.model.dto.MenuDTO;
|
import run.halo.app.model.dto.MenuDTO;
|
||||||
|
import run.halo.app.model.dto.base.InputConverter;
|
||||||
import run.halo.app.model.entity.Menu;
|
import run.halo.app.model.entity.Menu;
|
||||||
import run.halo.app.model.params.MenuParam;
|
import run.halo.app.model.params.MenuParam;
|
||||||
import run.halo.app.model.vo.MenuVO;
|
import run.halo.app.model.vo.MenuVO;
|
||||||
|
@ -12,6 +13,7 @@ import run.halo.app.service.MenuService;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.springframework.data.domain.Sort.Direction.ASC;
|
import static org.springframework.data.domain.Sort.Direction.ASC;
|
||||||
import static org.springframework.data.domain.Sort.Direction.DESC;
|
import static org.springframework.data.domain.Sort.Direction.DESC;
|
||||||
|
@ -40,11 +42,17 @@ public class MenuController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("tree_view")
|
@GetMapping("tree_view")
|
||||||
@ApiOperation("Lists categories as tree")
|
@ApiOperation("Lists menus as tree")
|
||||||
public List<MenuVO> listAsTree(@SortDefault(sort = "team", direction = DESC) Sort sort) {
|
public List<MenuVO> listAsTree(@SortDefault(sort = "team", direction = DESC) Sort sort) {
|
||||||
return menuService.listAsTree(sort.and(Sort.by(ASC, "priority")));
|
return menuService.listAsTree(sort.and(Sort.by(ASC, "priority")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("team/tree_view")
|
||||||
|
@ApiOperation("Lists menus as tree by team")
|
||||||
|
public List<MenuVO> listDefaultsAsTreeByTeam(@SortDefault(sort = "priority", direction = ASC) Sort sort, @RequestParam(name = "team") String team) {
|
||||||
|
return menuService.listByTeamAsTree(team, sort);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("{menuId:\\d+}")
|
@GetMapping("{menuId:\\d+}")
|
||||||
@ApiOperation("Gets menu detail by id")
|
@ApiOperation("Gets menu detail by id")
|
||||||
public MenuDTO getBy(@PathVariable("menuId") Integer menuId) {
|
public MenuDTO getBy(@PathVariable("menuId") Integer menuId) {
|
||||||
|
@ -57,10 +65,20 @@ public class MenuController {
|
||||||
return new MenuDTO().convertFrom(menuService.createBy(menuParam));
|
return new MenuDTO().convertFrom(menuService.createBy(menuParam));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/batch")
|
||||||
|
public List<MenuDTO> createBatchBy(@RequestBody @Valid List<MenuParam> menuParams) {
|
||||||
|
List<Menu> menus = menuParams
|
||||||
|
.stream()
|
||||||
|
.map(InputConverter::convertTo)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return menuService.createInBatch(menus).stream()
|
||||||
|
.map(menu -> (MenuDTO) new MenuDTO().convertFrom(menu))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
@PutMapping("{menuId:\\d+}")
|
@PutMapping("{menuId:\\d+}")
|
||||||
@ApiOperation("Updates a menu")
|
@ApiOperation("Updates a menu")
|
||||||
public MenuDTO updateBy(@PathVariable("menuId") Integer menuId,
|
public MenuDTO updateBy(@PathVariable("menuId") Integer menuId, @RequestBody @Valid MenuParam menuParam) {
|
||||||
@RequestBody @Valid MenuParam menuParam) {
|
|
||||||
// Get the menu
|
// Get the menu
|
||||||
Menu menu = menuService.getById(menuId);
|
Menu menu = menuService.getById(menuId);
|
||||||
|
|
||||||
|
@ -71,6 +89,17 @@ public class MenuController {
|
||||||
return new MenuDTO().convertFrom(menuService.update(menu));
|
return new MenuDTO().convertFrom(menuService.update(menu));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping("/batch")
|
||||||
|
public List<MenuDTO> updateBatchBy(@RequestBody @Valid List<MenuParam> menuParams) {
|
||||||
|
List<Menu> menus = menuParams
|
||||||
|
.stream()
|
||||||
|
.map(InputConverter::convertTo)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return menuService.updateInBatch(menus).stream()
|
||||||
|
.map(menu -> (MenuDTO) new MenuDTO().convertFrom(menu))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
@DeleteMapping("{menuId:\\d+}")
|
@DeleteMapping("{menuId:\\d+}")
|
||||||
@ApiOperation("Deletes a menu")
|
@ApiOperation("Deletes a menu")
|
||||||
public MenuDTO deleteBy(@PathVariable("menuId") Integer menuId) {
|
public MenuDTO deleteBy(@PathVariable("menuId") Integer menuId) {
|
||||||
|
@ -84,6 +113,15 @@ public class MenuController {
|
||||||
return new MenuDTO().convertFrom(menuService.removeById(menuId));
|
return new MenuDTO().convertFrom(menuService.removeById(menuId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/batch")
|
||||||
|
public List<MenuDTO> deleteBatchBy(@RequestBody List<Integer> menuIds) {
|
||||||
|
List<Menu> menus = menuService.listAllByIds(menuIds);
|
||||||
|
menuService.removeInBatch(menuIds);
|
||||||
|
return menus.stream()
|
||||||
|
.map(menu -> (MenuDTO) new MenuDTO().convertFrom(menu))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("teams")
|
@GetMapping("teams")
|
||||||
@ApiOperation("Lists all menu teams")
|
@ApiOperation("Lists all menu teams")
|
||||||
public List<String> teams() {
|
public List<String> teams() {
|
||||||
|
|
|
@ -4,8 +4,10 @@ import freemarker.core.Environment;
|
||||||
import freemarker.template.*;
|
import freemarker.template.*;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import run.halo.app.model.properties.PrimaryProperties;
|
||||||
import run.halo.app.model.support.HaloConst;
|
import run.halo.app.model.support.HaloConst;
|
||||||
import run.halo.app.service.MenuService;
|
import run.halo.app.service.MenuService;
|
||||||
|
import run.halo.app.service.OptionService;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -25,8 +27,11 @@ public class MenuTagDirective implements TemplateDirectiveModel {
|
||||||
|
|
||||||
private final MenuService menuService;
|
private final MenuService menuService;
|
||||||
|
|
||||||
public MenuTagDirective(Configuration configuration, MenuService menuService) {
|
private final OptionService optionService;
|
||||||
|
|
||||||
|
public MenuTagDirective(Configuration configuration, MenuService menuService, OptionService optionService) {
|
||||||
this.menuService = menuService;
|
this.menuService = menuService;
|
||||||
|
this.optionService = optionService;
|
||||||
configuration.setSharedVariable("menuTag", this);
|
configuration.setSharedVariable("menuTag", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,10 +43,12 @@ public class MenuTagDirective implements TemplateDirectiveModel {
|
||||||
String method = params.get(HaloConst.METHOD_KEY).toString();
|
String method = params.get(HaloConst.METHOD_KEY).toString();
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case "list":
|
case "list":
|
||||||
env.setVariable("menus", builder.build().wrap(menuService.listAll()));
|
String listTeam = optionService.getByPropertyOrDefault(PrimaryProperties.DEFAULT_MENU_TEAM, String.class, "");
|
||||||
|
env.setVariable("menus", builder.build().wrap(menuService.listByTeam(listTeam, Sort.by(DESC, "priority"))));
|
||||||
break;
|
break;
|
||||||
case "tree":
|
case "tree":
|
||||||
env.setVariable("menus", builder.build().wrap(menuService.listAsTree(Sort.by(DESC, "priority"))));
|
String treeTeam = optionService.getByPropertyOrDefault(PrimaryProperties.DEFAULT_MENU_TEAM, String.class, "");
|
||||||
|
env.setVariable("menus", builder.build().wrap(menuService.listByTeamAsTree(treeTeam, Sort.by(DESC, "priority"))));
|
||||||
break;
|
break;
|
||||||
case "listTeams":
|
case "listTeams":
|
||||||
env.setVariable("teams", builder.build().wrap(menuService.listTeamVos(Sort.by(DESC, "priority"))));
|
env.setVariable("teams", builder.build().wrap(menuService.listTeamVos(Sort.by(DESC, "priority"))));
|
||||||
|
@ -51,8 +58,8 @@ public class MenuTagDirective implements TemplateDirectiveModel {
|
||||||
env.setVariable("menus", builder.build().wrap(menuService.listByTeam(team, Sort.by(DESC, "priority"))));
|
env.setVariable("menus", builder.build().wrap(menuService.listByTeam(team, Sort.by(DESC, "priority"))));
|
||||||
break;
|
break;
|
||||||
case "treeByTeam":
|
case "treeByTeam":
|
||||||
String treeTeam = params.get("team").toString();
|
String treeTeamParam = params.get("team").toString();
|
||||||
env.setVariable("menus", builder.build().wrap(menuService.listByTeamAsTree(treeTeam, Sort.by(DESC, "priority"))));
|
env.setVariable("menus", builder.build().wrap(menuService.listByTeamAsTree(treeTeamParam, Sort.by(DESC, "priority"))));
|
||||||
break;
|
break;
|
||||||
case "count":
|
case "count":
|
||||||
env.setVariable("count", builder.build().wrap(menuService.count()));
|
env.setVariable("count", builder.build().wrap(menuService.count()));
|
||||||
|
|
|
@ -20,6 +20,8 @@ import javax.validation.constraints.Size;
|
||||||
@ToString
|
@ToString
|
||||||
public class MenuParam implements InputConverter<Menu> {
|
public class MenuParam implements InputConverter<Menu> {
|
||||||
|
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
@NotBlank(message = "菜单名称不能为空")
|
@NotBlank(message = "菜单名称不能为空")
|
||||||
@Size(max = 50, message = "菜单名称的字符长度不能超过 {max}")
|
@Size(max = 50, message = "菜单名称的字符长度不能超过 {max}")
|
||||||
private String name;
|
private String name;
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
package run.halo.app.model.properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Git static deploy properties.
|
|
||||||
*
|
|
||||||
* @author ryanwang
|
|
||||||
* @date 2019-12-26
|
|
||||||
*/
|
|
||||||
public enum GitStaticDeployProperties implements PropertyEnum {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Git static deploy domain.
|
|
||||||
*/
|
|
||||||
GIT_DOMAIN("git_static_deploy_domain", String.class, ""),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Git static deploy repository.
|
|
||||||
*/
|
|
||||||
GIT_REPOSITORY("git_static_deploy_repository", String.class, ""),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Git static deploy branch.
|
|
||||||
*/
|
|
||||||
GIT_BRANCH("git_static_deploy_branch", String.class, "master"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Git static deploy username.
|
|
||||||
*/
|
|
||||||
GIT_USERNAME("git_static_deploy_username", String.class, ""),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Git static deploy email.
|
|
||||||
*/
|
|
||||||
GIT_EMAIL("git_static_deploy_email", String.class, ""),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Git static deploy token.
|
|
||||||
*/
|
|
||||||
GIT_TOKEN("git_static_deploy_token", String.class, ""),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Git static deploy cname.
|
|
||||||
*/
|
|
||||||
GIT_CNAME("git_static_deploy_cname", String.class, "");
|
|
||||||
|
|
||||||
private final String value;
|
|
||||||
|
|
||||||
private final Class<?> type;
|
|
||||||
|
|
||||||
private final String defaultValue;
|
|
||||||
|
|
||||||
GitStaticDeployProperties(String value, Class<?> type, String defaultValue) {
|
|
||||||
this.defaultValue = defaultValue;
|
|
||||||
if (!PropertyEnum.isSupportedType(type)) {
|
|
||||||
throw new IllegalArgumentException("Unsupported blog property type: " + type);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.value = value;
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String defaultValue() {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
package run.halo.app.model.properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Netlify static deploy properties.
|
|
||||||
*
|
|
||||||
* @author ryanwang
|
|
||||||
* @date 2019-12-26
|
|
||||||
*/
|
|
||||||
public enum NetlifyStaticDeployProperties implements PropertyEnum {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Netlify static deploy domain.
|
|
||||||
*/
|
|
||||||
NETLIFY_DOMAIN("netlify_static_deploy_domain", String.class, ""),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Netlify static deploy site id.
|
|
||||||
*/
|
|
||||||
NETLIFY_SITE_ID("netlify_static_deploy_site_id", String.class, ""),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Netlify static deploy token.
|
|
||||||
*/
|
|
||||||
NETLIFY_TOKEN("netlify_static_deploy_token", String.class, "");
|
|
||||||
|
|
||||||
private final String value;
|
|
||||||
|
|
||||||
private final Class<?> type;
|
|
||||||
|
|
||||||
private final String defaultValue;
|
|
||||||
|
|
||||||
NetlifyStaticDeployProperties(String value, Class<?> type, String defaultValue) {
|
|
||||||
this.defaultValue = defaultValue;
|
|
||||||
if (!PropertyEnum.isSupportedType(type)) {
|
|
||||||
throw new IllegalArgumentException("Unsupported blog property type: " + type);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.value = value;
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String defaultValue() {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -28,7 +28,12 @@ public enum PrimaryProperties implements PropertyEnum {
|
||||||
/**
|
/**
|
||||||
* developer mode.
|
* developer mode.
|
||||||
*/
|
*/
|
||||||
DEV_MODE("developer_mode", Boolean.class, "false");
|
DEV_MODE("developer_mode", Boolean.class, "false"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default menu team name
|
||||||
|
*/
|
||||||
|
DEFAULT_MENU_TEAM("default_menu_team", String.class, "");
|
||||||
|
|
||||||
private final String value;
|
private final String value;
|
||||||
|
|
||||||
|
|
|
@ -158,9 +158,6 @@ public interface PropertyEnum extends ValueEnum<String> {
|
||||||
propertyEnumClasses.add(SeoProperties.class);
|
propertyEnumClasses.add(SeoProperties.class);
|
||||||
propertyEnumClasses.add(UpOssProperties.class);
|
propertyEnumClasses.add(UpOssProperties.class);
|
||||||
propertyEnumClasses.add(ApiProperties.class);
|
propertyEnumClasses.add(ApiProperties.class);
|
||||||
propertyEnumClasses.add(StaticDeployProperties.class);
|
|
||||||
propertyEnumClasses.add(GitStaticDeployProperties.class);
|
|
||||||
propertyEnumClasses.add(NetlifyStaticDeployProperties.class);
|
|
||||||
propertyEnumClasses.add(PermalinkProperties.class);
|
propertyEnumClasses.add(PermalinkProperties.class);
|
||||||
|
|
||||||
Map<String, PropertyEnum> result = new HashMap<>();
|
Map<String, PropertyEnum> result = new HashMap<>();
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
package run.halo.app.model.properties;
|
|
||||||
|
|
||||||
import run.halo.app.model.enums.StaticDeployType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static deploy properties.
|
|
||||||
*
|
|
||||||
* @author ryanwang
|
|
||||||
* @date 2019-12-26
|
|
||||||
*/
|
|
||||||
public enum StaticDeployProperties implements PropertyEnum {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* static deploy type
|
|
||||||
*/
|
|
||||||
DEPLOY_TYPE("static_deploy_type", StaticDeployType.class, StaticDeployType.GIT.name());
|
|
||||||
|
|
||||||
private final String value;
|
|
||||||
|
|
||||||
private final Class<?> type;
|
|
||||||
|
|
||||||
private final String defaultValue;
|
|
||||||
|
|
||||||
|
|
||||||
StaticDeployProperties(String value, Class<?> type, String defaultValue) {
|
|
||||||
this.value = value;
|
|
||||||
this.type = type;
|
|
||||||
this.defaultValue = defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String defaultValue() {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,6 +5,7 @@ import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import run.halo.app.model.dto.MenuDTO;
|
import run.halo.app.model.dto.MenuDTO;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,5 +17,5 @@ import java.util.List;
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class MenuVO extends MenuDTO {
|
public class MenuVO extends MenuDTO {
|
||||||
|
|
||||||
private List<MenuVO> children;
|
private List<MenuVO> children = new LinkedList<>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,15 +137,11 @@ public class MenuServiceImpl extends AbstractCrudService<Menu, Integer> implemen
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Menu create(@NotNull Menu menu) {
|
public @NotNull Menu create(@NotNull Menu menu) {
|
||||||
nameMustNotExist(menu);
|
|
||||||
|
|
||||||
return super.create(menu);
|
return super.create(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Menu update(@NotNull Menu menu) {
|
public @NotNull Menu update(@NotNull Menu menu) {
|
||||||
nameMustNotExist(menu);
|
|
||||||
|
|
||||||
return super.update(menu);
|
return super.update(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,6 +211,7 @@ public class MenuServiceImpl extends AbstractCrudService<Menu, Integer> implemen
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
private void nameMustNotExist(@NonNull Menu menu) {
|
private void nameMustNotExist(@NonNull Menu menu) {
|
||||||
Assert.notNull(menu, "Menu must not be null");
|
Assert.notNull(menu, "Menu must not be null");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue