diff --git a/core/src/main/java/jenkins/model/NewViewLink.java b/core/src/main/java/jenkins/model/NewViewLink.java index fad3b0ca34..6c05f77b13 100644 --- a/core/src/main/java/jenkins/model/NewViewLink.java +++ b/core/src/main/java/jenkins/model/NewViewLink.java @@ -3,8 +3,10 @@ package jenkins.model; import com.google.common.annotations.VisibleForTesting; import hudson.Extension; import hudson.model.Action; +import hudson.model.ModifiableViewGroup; import hudson.model.TransientViewActionFactory; import hudson.model.View; +import hudson.model.ViewGroup; import java.util.Collections; import java.util.List; @@ -21,36 +23,46 @@ public class NewViewLink extends TransientViewActionFactory { public static final String URL_NAME = "newView"; @Override - public List createFor(View v) { - return Collections.singletonList(new Action() { + public List createFor(final View v) { + // do not show the action if the viewgroup is not modifiable + ViewGroup vg = v.getOwner(); + if (vg instanceof ModifiableViewGroup) { + return Collections.singletonList(new NewViewLinkAction((ModifiableViewGroup)vg)); + } + return Collections.emptyList(); + } - @Override - public String getIconFileName() { - if (!hasPermission(v)) { - return null; - } + private static class NewViewLinkAction implements Action { + private ModifiableViewGroup target; + + private NewViewLinkAction(ModifiableViewGroup target) { + this.target = target; + } + + @Override + public String getIconFileName() { + if (hasPermission()) { return ICON_FILE_NAME; } + return null; + } - @Override - public String getDisplayName() { - if (!hasPermission(v)) { - return null; - } + @Override + public String getDisplayName() { + return Messages.NewViewLink_NewView(); + } - return Messages.NewViewLink_NewView(); - } + @Override + public String getUrlName() { + // getUrl returns the path from the root (without the context and no leading slash) + // we need to add the slash so that this is not relative to the current URL but to the context + return "/" + target.getUrl() + URL_NAME; + } - @Override - public String getUrlName() { - return Jenkins.get().getRootUrl() + URL_NAME; - } + private boolean hasPermission() { + return target.hasPermission(View.CREATE); + } - private boolean hasPermission(View view) { - return view.hasPermission(View.CREATE); - } - - }); } } diff --git a/core/src/test/java/jenkins/model/NewViewLinkTest.java b/core/src/test/java/jenkins/model/NewViewLinkTest.java index badf7e3a92..dcf4e8d605 100644 --- a/core/src/test/java/jenkins/model/NewViewLinkTest.java +++ b/core/src/test/java/jenkins/model/NewViewLinkTest.java @@ -1,50 +1,39 @@ package jenkins.model; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import hudson.model.Action; +import hudson.model.ModifiableViewGroup; +import hudson.model.View; +import hudson.model.ViewGroup; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import hudson.model.Action; -import hudson.model.View; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({NewViewLink.class, Jenkins.class}) -@PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*"}) public class NewViewLinkTest { - @Mock - private Jenkins jenkins; - - @Mock - private final String rootUrl = "https://127.0.0.1:8080/"; - private NewViewLink newViewLink; private View view = mock(View.class); - + private ViewGroup group = mock(ModifiableViewGroup.class); + private final String viewGroupURL = "abc/"; + @Before public void initTests() throws Exception { - PowerMockito.mockStatic(Jenkins.class); - PowerMockito.when(Jenkins.get()).thenReturn(jenkins); - PowerMockito.when(jenkins.getRootUrl()).thenReturn(rootUrl); - newViewLink = new NewViewLink(); + when(view.getOwner()).thenReturn(group); + when(group.getUrl()).thenReturn(viewGroupURL); + + newViewLink = new NewViewLink(); } @Test public void getActionsHasPermission() throws Exception { - when(view.hasPermission(any())).thenReturn(true); + when(group.hasPermission(any())).thenReturn(true); final List actions = newViewLink.createFor(view); @@ -52,20 +41,29 @@ public class NewViewLinkTest { final Action action = actions.get(0); assertEquals(Messages.NewViewLink_NewView(), action.getDisplayName()); assertEquals(NewViewLink.ICON_FILE_NAME, action.getIconFileName()); - assertEquals(rootUrl + NewViewLink.URL_NAME, action.getUrlName()); + assertEquals("/" + viewGroupURL + NewViewLink.URL_NAME, action.getUrlName()); } @Test public void getActionsNoPermission() throws Exception { - when(view.hasPermission(any())).thenReturn(false); + when(group.hasPermission(any())).thenReturn(false); final List actions = newViewLink.createFor(view); assertEquals(1, actions.size()); final Action action = actions.get(0); - assertNull(action.getDisplayName()); assertNull(action.getIconFileName()); - assertEquals(rootUrl + NewViewLink.URL_NAME, action.getUrlName()); + assertEquals("/" + viewGroupURL + NewViewLink.URL_NAME, action.getUrlName()); + } + + @Test + public void getActionsNotModifiableOwner() throws Exception { + ViewGroup vg = mock(ViewGroup.class); + when(view.getOwner()).thenReturn(vg); + when(vg.hasPermission(any())).thenReturn(true); + + final List actions = newViewLink.createFor(view); + assertThat(actions, hasSize(0)); } } \ No newline at end of file diff --git a/pom.xml b/pom.xml index ffbd4b9085..7b1041096f 100644 --- a/pom.xml +++ b/pom.xml @@ -445,7 +445,7 @@ THE SOFTWARE. com.puppycrawl.tools checkstyle - 8.41 + 8.41.1