Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ public interface IPageService extends IComponentUsageService {

PageDto getPage(String pageCode, String status);

PageDto getRootPage(String status, UserDetails user);

PageDto getRootPage(String status);

String getRootPageCode();

PageDto addPage(PageRequest pageRequest);

void removePage(String pageName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,44 @@ public PageDto getPage(String pageCode, String status) {
return pageDto;
}

@Override
public PageDto getRootPage(String status, UserDetails user) {
PageDto pageDto = this.getRootPage(status);
return this.loadVirtualChildren(pageDto, user);
}

@Override
public PageDto getRootPage(String status) {
IPage page;
switch (status) {
case STATUS_ONLINE:
page = this.getPageManager().getOnlineRoot();
break;
case STATUS_DRAFT:
default:
page = this.getPageManager().getDraftRoot();
break;
}
if (null == page) {
throw new RestServerError("Root page not found");
}
PageDto pageDto = this.getDtoBuilder().convert(page);
String token = this.getPageTokenManager().encrypt(page.getCode());
String urlToken = getUrlToken(token);
pageDto.setToken(urlToken);
pageDto.setReferences(this.getReferencesInfo(page));
return pageDto;
}

@Override
public String getRootPageCode() {
IPage root = this.getPageManager().getDraftRoot();
if (root == null) {
throw new ResourceNotFoundException(ERRCODE_PAGE_NOT_FOUND, "page", "RootPage");
}
return root.getCode();
}

private String getUrlToken(String token) {
try {
return URLEncoder.encode(token, "UTF-8");
Expand Down Expand Up @@ -377,6 +415,12 @@ public PageDto updatePageStatus(String pageCode, String status) {
this.getPageManager().setPageOnline(pageCode);
newPage = this.getPageManager().getOnlinePage(pageCode);
} else if (status.equals(STATUS_DRAFT)) {
IPage rootPage = this.getPageManager().getOnlineRoot();
if (rootPage != null && rootPage.getCode().equals(pageCode)) {
bindingResult.reject(PageValidator.ERRCODE_ROOT_PAGE,
new String[]{pageCode}, "page.status.root.unpublish");
throw new ValidationGenericException(bindingResult);
}
String[] childCodes = currentPage.getChildrenCodes();
for (String childCode : childCodes) {
IPage publicChild = this.getPageManager().getOnlinePage(childCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,18 @@ public void setAuthorizationService(IPageAuthorizationService authorizationServi
@RequestMapping(value = "/pages", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<RestResponse<List<PageDto>, Map<String, Object>>> getPages(
@RequestAttribute("user") UserDetails user,
@RequestParam(value = "parentCode", required = false, defaultValue = "homepage") String parentCode,
@RequestParam(value = "parentCode", required = false) String parentCode,
@RequestParam(value = "forLinkingToOwnerGroup", required = false) String forLinkingToOwnerGroup,
@RequestParam(value = "forLinkingToExtraGroups", required = false) String forLinkingToExtraGroups) {
String rootPageCode = this.getPageService().getRootPageCode();
if (parentCode == null || parentCode.isEmpty()) {
parentCode = rootPageCode;
}
logger.debug("getting page tree for parent {} ({}|{})", parentCode,
forLinkingToOwnerGroup, forLinkingToExtraGroups);

boolean editableParent = this.getAuthorizationService().canEdit(user, parentCode);
if (!editableParent && !parentCode.equals("homepage")) {
if (!editableParent && !parentCode.equals(rootPageCode)) {
throw new ResourcePermissionsException(user.getUsername(), parentCode);
}

Expand All @@ -145,7 +149,7 @@ public ResponseEntity<RestResponse<List<PageDto>, Map<String, Object>>> getPages
}

@RestAccessControl(permission = Permission.MANAGE_PAGES)
@RequestMapping(value = "/pages/search", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@RequestMapping(value = "/pages/utils/search", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PagedRestResponse<PageDto>> getPages(@RequestAttribute("user") UserDetails user, PageSearchRequest searchRequest) {
logger.debug("getting page list with request {}", searchRequest);
this.getPageValidator().validateRestListRequest(searchRequest, PageDto.class);
Expand All @@ -155,7 +159,7 @@ public ResponseEntity<PagedRestResponse<PageDto>> getPages(@RequestAttribute("us
}

@RestAccessControl(permission = Permission.MANAGE_PAGES)
@RequestMapping(value = "/pages/search/group/free", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@RequestMapping(value = "/pages/utils/search/group/free", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<PagedRestResponse<PageDto>> getFreeOnlinePages(@RequestAttribute("user") UserDetails user, RestListRequest restListRequest) {
logger.debug("getting free pages list with request {}", restListRequest);
this.getPageValidator().validateRestListRequest(restListRequest, PageDto.class);
Expand All @@ -164,14 +168,26 @@ public ResponseEntity<PagedRestResponse<PageDto>> getFreeOnlinePages(@RequestAtt
}

@RestAccessControl(permission = Permission.MANAGE_PAGES)
@RequestMapping(value = "/pages/viewpages", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@RequestMapping(value = "/pages/utils/viewpages", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SimpleRestResponse<List<PageDto>>> listViewPages() {
logger.debug("REST request - content type list view pages");

return ResponseEntity.ok(
new SimpleRestResponse<>(pageService.listViewPages()));
}

@RestAccessControl(permission = Permission.MANAGE_PAGES)
@RequestMapping(value = "/pages/utils/root", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<RestResponse<PageDto, Map<String, String>>> getRootPage(
@RequestAttribute("user") UserDetails user,
@RequestParam(value = "status", required = false, defaultValue = IPageService.STATUS_DRAFT) String status) {
logger.debug("getting root page");
PageDto page = this.getPageService().getRootPage(status, user);
Map<String, String> metadata = new HashMap<>();
metadata.put("status", status);
return new ResponseEntity<>(new RestResponse<>(page, metadata), HttpStatus.OK);
}

@RestAccessControl(permission = Permission.MANAGE_PAGES)
@RequestMapping(value = "/pages/{pageCode}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<RestResponse<PageDto, Map<String, String>>> getPage(@RequestAttribute("user") UserDetails user, @PathVariable String pageCode,
Expand Down Expand Up @@ -348,6 +364,10 @@ public ResponseEntity<SimpleRestResponse<?>> deletePage(
throw new ValidationGenericException(bindingResult);
}
//business validations
getPageValidator().validateRootPage(pageCode, bindingResult);
if (bindingResult.hasErrors()) {
throw new ValidationGenericException(bindingResult);
}
getPageValidator().validateOnlinePage(pageCode, bindingResult);
if (bindingResult.hasErrors()) {
throw new ValidationGenericException(bindingResult);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public class PageValidator extends AbstractPaginationValidator {
public static final String ERRCODE_PAGE_WITH_PUBLIC_CHILD = "8";
public static final String ERRCODE_PAGE_WITH_NO_PUBLIC_PARENT = "9";
public static final String ERRCODE_PAGE_INVALID_TITLE = "12";
public static final String ERRCODE_ROOT_PAGE = "13";

private final org.slf4j.Logger logger = EntLogFactory.getSanitizedLogger(getClass());

Expand Down Expand Up @@ -123,6 +124,13 @@ public void validateChildren(String pageCode, Errors errors) {
}
}

public void validateRootPage(String pageCode, Errors errors) {
IPage root = this.getPageManager().getDraftRoot();
if (root != null && root.getCode().equals(pageCode)) {
errors.reject(ERRCODE_ROOT_PAGE, new String[]{pageCode}, "page.delete.root");
}
}

public void validateChangePositionRequest(String pageCode, PagePositionRequest pageRequest, Errors errors) {
if (!StringUtils.equals(pageCode, pageRequest.getCode())) {
errors.rejectValue("code", ERRCODE_URINAME_MISMATCH, new String[]{pageCode, pageRequest.getCode()}, "page.code.mismatch");
Expand Down
2 changes: 2 additions & 0 deletions engine/src/main/resources/rest/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ page.status.invalid.draft.ref=draft page has references
page.status.parent.unpublished=The page ''{0}'' can''t be published because the parent page ''{1}'' is not public
page.status.publicChild=The page ''{0}'' can''t be unpublished because it has public children
page.widgetconfig.notoverridable=The widget configuration is not overridable
page.delete.root=The root page ''{0}'' cannot be deleted
page.status.root.unpublish=The root page ''{0}'' cannot be unpublished
page.title.notBlank=Page title for language ''{0}'' is required
invalidParameter.framedId=the URI parameter ''{0}'' is not valid

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ void testPageSearchByCode() throws Exception {
.build();
String accessToken = mockOAuthInterceptor(user);
ResultActions result = mockMvc
.perform(get("/pages/search")
.perform(get("/pages/utils/search")
.param("pageSize", "5")
.param("pageCodeToken", "pagin")
.header("Authorization", "Bearer " + accessToken));
Expand All @@ -220,7 +220,7 @@ void testPageSearchByTitle() throws Exception {
.build();
String accessToken = mockOAuthInterceptor(user);
ResultActions result = mockMvc
.perform(get("/pages/search")
.perform(get("/pages/utils/search")
.param("pageSize", "20")
.param("title", "errore")
.header("Authorization", "Bearer " + accessToken));
Expand All @@ -230,7 +230,7 @@ void testPageSearchByTitle() throws Exception {
result.andExpect(jsonPath("$.payload[0].code", is("errorpage")));

result = mockMvc
.perform(get("/pages/search")
.perform(get("/pages/utils/search")
.param("pageSize", "20")
.param("title", "iniziale")
.header("Authorization", "Bearer " + accessToken));
Expand All @@ -240,7 +240,7 @@ void testPageSearchByTitle() throws Exception {
result.andExpect(jsonPath("$.payload[0].code", is("homepage")));

result = mockMvc
.perform(get("/pages/search")
.perform(get("/pages/utils/search")
.param("pageSize", "20")
.param("title", "di")
.header("Authorization", "Bearer " + accessToken));
Expand All @@ -250,7 +250,7 @@ void testPageSearchByTitle() throws Exception {
result.andExpect(jsonPath("$.payload[0].code", is("errorpage")));

result = mockMvc
.perform(get("/pages/search")
.perform(get("/pages/utils/search")
.param("pageSize", "20")
.param("title", "start")
.header("Authorization", "Bearer " + accessToken));
Expand Down Expand Up @@ -421,7 +421,7 @@ void testPageSearchFreeOnlinePages() throws Exception {
.build();
String accessToken = mockOAuthInterceptor(user);
ResultActions result = mockMvc
.perform(get("/pages/search/group/free")
.perform(get("/pages/utils/search/group/free")
.param("pageSize", "50")
.header("Authorization", "Bearer " + accessToken));
result.andExpect(status().isOk());
Expand Down Expand Up @@ -1872,7 +1872,7 @@ void testCloneValidations() throws Exception {


private ResultActions performListViewPages(String accessToken) throws Exception {
return mockMvc.perform(get("/pages/viewpages")
return mockMvc.perform(get("/pages/utils/viewpages")
.header("Authorization", "Bearer " + accessToken));
}

Expand Down Expand Up @@ -2246,7 +2246,7 @@ void testRootIsVisibleAlsoToNonAdminUser() throws Exception {
.andExpect(status().isOk());

// search
mockMvc.perform(get("/pages/search")
mockMvc.perform(get("/pages/utils/search")
.param("sort", "code")
.param("direction", "ASC")
.param("pageCodeToken", "homepage")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.entando.entando.aps.system.services.page.IPageService;
import org.entando.entando.aps.system.services.page.PageAuthorizationService;
import org.entando.entando.aps.system.services.page.PageService;
import org.entando.entando.aps.system.services.page.model.PageDto;
Expand Down Expand Up @@ -219,6 +220,7 @@ void usersWithoutAdminOrFreeGroupAccessShouldSeeVirtualRoot() throws Exception {
List<PageDto> mockResult = List.of(page1);

Mockito.when(pageService.getPagesTree(eq("homepage"), any())).thenReturn(mockResult);
Mockito.when(pageService.getRootPageCode()).thenReturn("homepage");
Mockito.when(authorizationService.canEdit(any(UserDetails.class), eq("homepage"))).thenReturn(false);

ResultActions result = mockMvc.perform(
Expand Down Expand Up @@ -912,6 +914,7 @@ void shouldAllowRetrievingTreeFromUnauthorizedHomepage() throws Exception {
UserDetails user = new OAuth2TestUtils.UserBuilder("jack_bauer", "0x24").grantedToRoleAdmin().build();
String accessToken = mockOAuthInterceptor(user);

when(pageService.getRootPageCode()).thenReturn("homepage");
when(pageService.getPagesTree(eq("homepage"), any())).thenReturn(List.of());

mockMvc.perform(get("/pages")
Expand All @@ -928,6 +931,44 @@ private List<PageDto> createMetadataList(String json) throws IOException, JsonPa
return result;
}

@Test
void shouldGetRootPage() throws Exception {
UserDetails user = new OAuth2TestUtils.UserBuilder("jack_bauer", "0x24")
.withAuthorization(Group.FREE_GROUP_NAME, "managePages", Permission.MANAGE_PAGES)
.build();
String accessToken = mockOAuthInterceptor(user);

PageDto rootPageDto = new PageDto();
rootPageDto.setCode("home");

when(pageService.getRootPage(eq(IPageService.STATUS_DRAFT), any(UserDetails.class))).thenReturn(rootPageDto);

mockMvc.perform(get("/pages/utils/root")
.header("Authorization", "Bearer " + accessToken))
.andExpect(status().isOk())
.andExpect(jsonPath("$.payload.code", is("home")))
.andExpect(jsonPath("$.metaData.status", is("draft")));
}

@Test
void shouldValidateDeleteRootPage() throws Exception {
UserDetails user = new OAuth2TestUtils.UserBuilder("jack_bauer", "0x24").grantedToRoleAdmin().build();
String accessToken = mockOAuthInterceptor(user);

Page rootPage = new Page();
rootPage.setCode("homepage");
when(authorizationService.canEdit(any(UserDetails.class), any(String.class))).thenReturn(true);
when(this.controller.getPageValidator().getPageManager().getDraftRoot()).thenReturn(rootPage);

ResultActions result = mockMvc.perform(
delete("/pages/{pageCode}", "homepage")
.header("Authorization", "Bearer " + accessToken));

result.andExpect(status().isBadRequest());
result.andExpect(jsonPath("$.errors", hasSize(1)));
result.andExpect(jsonPath("$.errors[0].code", is(PageValidator.ERRCODE_ROOT_PAGE)));
}

private class PageM extends Page {

public PageM(boolean isOnline) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,28 @@ void validateMovePagePermissionsShouldReturnExceptionIfYouCannotWriteOldParent()
Assertions.assertTrue(errors.hasErrors());
}

@Test
void validateRootPageShouldRejectRootPageDeletion() {
IPage rootPage = Mockito.mock(IPage.class);
Mockito.when(rootPage.getCode()).thenReturn("homepage");
Mockito.when(pageManager.getDraftRoot()).thenReturn(rootPage);

BindingResult errors = (new DataBinder(new Object())).getBindingResult();
validator.validateRootPage("homepage", errors);
Assertions.assertTrue(errors.hasErrors());
}

@Test
void validateRootPageShouldAllowNonRootPageDeletion() {
IPage rootPage = Mockito.mock(IPage.class);
Mockito.when(rootPage.getCode()).thenReturn("homepage");
Mockito.when(pageManager.getDraftRoot()).thenReturn(rootPage);

BindingResult errors = (new DataBinder(new Object())).getBindingResult();
validator.validateRootPage("some_other_page", errors);
Assertions.assertFalse(errors.hasErrors());
}

private UserDetails getMockUser(){
User u = new User();
u.setUsername("mockUser");
Expand Down
Loading