From 86503c2508ce0247b900ad06654cac1454a967ff Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Mon, 28 Mar 2016 16:36:50 -0400 Subject: [PATCH] Moving DirectlyModifiableTopLevelItemGroup.canAdd check to a higher UI level, in ViewDescriptor.doAutoCompleteCopyNewItemFrom. --- .../model/AutoCompletionCandidates.java | 12 +-- .../java/hudson/model/ViewDescriptor.java | 26 +++++-- .../model/AutoCompletionCandidatesTest.java | 34 -------- .../java/hudson/model/ViewDescriptorTest.java | 78 +++++++++++++++++++ 4 files changed, 103 insertions(+), 47 deletions(-) create mode 100644 test/src/test/java/hudson/model/ViewDescriptorTest.java diff --git a/core/src/main/java/hudson/model/AutoCompletionCandidates.java b/core/src/main/java/hudson/model/AutoCompletionCandidates.java index 3c08103c15..0373b552bb 100644 --- a/core/src/main/java/hudson/model/AutoCompletionCandidates.java +++ b/core/src/main/java/hudson/model/AutoCompletionCandidates.java @@ -37,7 +37,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.annotation.CheckForNull; -import jenkins.model.DirectlyModifiableTopLevelItemGroup; /** * Data representation of the auto-completion candidates. @@ -107,7 +106,7 @@ public class AutoCompletionCandidates implements HttpResponse { * The nearby contextual {@link ItemGroup} to resolve relative job names from. * @since 1.553 */ - public static AutoCompletionCandidates ofJobNames(final Class type, final String value, final ItemGroup container) { + public static AutoCompletionCandidates ofJobNames(final Class type, final String value, ItemGroup container) { final AutoCompletionCandidates candidates = new AutoCompletionCandidates(); class Visitor extends ItemVisitor { String prefix; @@ -128,10 +127,8 @@ public class AutoCompletionCandidates implements HttpResponse { && i.hasPermission(Item.READ) // and read permission required ) { - if (type.isInstance(i) && n.startsWith(value) && - (!(container instanceof DirectlyModifiableTopLevelItemGroup) || !(i instanceof TopLevelItem) || ((DirectlyModifiableTopLevelItemGroup) container).canAdd((TopLevelItem) i))) { + if (type.isInstance(i) && n.startsWith(value)) candidates.add(n); - } // recurse String oldPrefix = prefix; @@ -156,10 +153,9 @@ public class AutoCompletionCandidates implements HttpResponse { if (value.startsWith("/")) new Visitor("/").onItemGroup(Jenkins.getInstance()); - ItemGroup parentContainer = container; for ( String p="../"; value.startsWith(p); p+="../") { - parentContainer = ((Item) parentContainer).getParent(); - new Visitor(p).onItemGroup(parentContainer); + container = ((Item)container).getParent(); + new Visitor(p).onItemGroup(container); } } diff --git a/core/src/main/java/hudson/model/ViewDescriptor.java b/core/src/main/java/hudson/model/ViewDescriptor.java index 2f304fa90f..f40ee0f59f 100644 --- a/core/src/main/java/hudson/model/ViewDescriptor.java +++ b/core/src/main/java/hudson/model/ViewDescriptor.java @@ -26,12 +26,14 @@ package hudson.model; import hudson.views.ListViewColumn; import hudson.views.ListViewColumnDescriptor; import hudson.views.ViewJobFilter; +import java.util.Iterator; +import java.util.List; +import jenkins.model.DirectlyModifiableTopLevelItemGroup; +import jenkins.model.Jenkins; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.DoNotUse; -import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.AncestorInPath; - -import java.util.List; +import org.kohsuke.stapler.QueryParameter; /** * {@link Descriptor} for {@link View}. @@ -76,8 +78,22 @@ public abstract class ViewDescriptor extends Descriptor { * Auto-completion for the "copy from" field in the new job page. */ @Restricted(DoNotUse.class) - public AutoCompletionCandidates doAutoCompleteCopyNewItemFrom(@QueryParameter final String value, @AncestorInPath ItemGroup container) { - return AutoCompletionCandidates.ofJobNames(TopLevelItem.class, value, container); + public AutoCompletionCandidates doAutoCompleteCopyNewItemFrom(@QueryParameter final String value, @AncestorInPath ItemGroup container) { + AutoCompletionCandidates candidates = AutoCompletionCandidates.ofJobNames(TopLevelItem.class, value, container); + if (container instanceof DirectlyModifiableTopLevelItemGroup) { + DirectlyModifiableTopLevelItemGroup modifiableContainer = (DirectlyModifiableTopLevelItemGroup) container; + Iterator it = candidates.getValues().iterator(); + while (it.hasNext()) { + TopLevelItem item = Jenkins.getInstance().getItem(it.next(), container, TopLevelItem.class); + if (item == null) { + continue; // ? + } + if (!modifiableContainer.canAdd(item)) { + it.remove(); + } + } + } + return candidates; } /** diff --git a/test/src/test/java/hudson/model/AutoCompletionCandidatesTest.java b/test/src/test/java/hudson/model/AutoCompletionCandidatesTest.java index 220d80a4c7..7f81ffc3d4 100644 --- a/test/src/test/java/hudson/model/AutoCompletionCandidatesTest.java +++ b/test/src/test/java/hudson/model/AutoCompletionCandidatesTest.java @@ -12,9 +12,6 @@ import org.jvnet.hudson.test.JenkinsRule; import java.util.Arrays; import java.util.TreeSet; -import jenkins.model.DirectlyModifiableTopLevelItemGroup; -import org.jvnet.hudson.test.MockFolder; -import org.jvnet.hudson.test.TestExtension; /** * @author Kohsuke Kawaguchi @@ -63,37 +60,6 @@ public class AutoCompletionCandidatesTest { assertContains(c, "../bar", "../foo"); } - /** Checks that {@link ViewDescriptor#doAutoCompleteCopyNewItemFrom} honors {@link DirectlyModifiableTopLevelItemGroup#canAdd}. */ - @Test - public void canAdd() throws Exception { - MockFolder d1 = j.createFolder("d1"); - d1.createProject(MockFolder.class, "sub"); - d1.createProject(FreeStyleProject.class, "prj"); - MockFolder d2 = j.jenkins.createProject(RestrictiveFolder.class, "d2"); - assertContains(AutoCompletionCandidates.ofJobNames(TopLevelItem.class, "../d1/", d2), "../d1/prj"); - } - - public static class RestrictiveFolder extends MockFolder { - - public RestrictiveFolder(ItemGroup parent, String name) { - super(parent, name); - } - - @Override - public boolean canAdd(TopLevelItem item) { - return item instanceof FreeStyleProject; - } - - @TestExtension("canAdd") public static class DescriptorImpl extends TopLevelItemDescriptor { - - @Override public TopLevelItem newInstance(ItemGroup parent, String name) { - return new RestrictiveFolder(parent, name); - } - - } - - } - private void assertContains(AutoCompletionCandidates c, String... values) { assertEquals(new TreeSet(Arrays.asList(values)), new TreeSet(c.getValues())); } diff --git a/test/src/test/java/hudson/model/ViewDescriptorTest.java b/test/src/test/java/hudson/model/ViewDescriptorTest.java new file mode 100644 index 0000000000..02be6a5f4b --- /dev/null +++ b/test/src/test/java/hudson/model/ViewDescriptorTest.java @@ -0,0 +1,78 @@ +/* + * The MIT License + * + * Copyright 2016 CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package hudson.model; + +import java.util.Arrays; +import java.util.TreeSet; +import jenkins.model.DirectlyModifiableTopLevelItemGroup; +import static org.junit.Assert.*; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.MockFolder; +import org.jvnet.hudson.test.TestExtension; + +public class ViewDescriptorTest { + + @Rule + public JenkinsRule r = new JenkinsRule(); + + /** Checks that {@link ViewDescriptor#doAutoCompleteCopyNewItemFrom} honors {@link DirectlyModifiableTopLevelItemGroup#canAdd}. */ + @Test + public void canAdd() throws Exception { + MockFolder d1 = r.createFolder("d1"); + d1.createProject(MockFolder.class, "sub"); + d1.createProject(FreeStyleProject.class, "prj"); + MockFolder d2 = r.jenkins.createProject(RestrictiveFolder.class, "d2"); + assertContains(r.jenkins.getDescriptorByType(AllView.DescriptorImpl.class).doAutoCompleteCopyNewItemFrom("../d1/", d2), "../d1/prj"); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) // the usual API mistakes + public static class RestrictiveFolder extends MockFolder { + + public RestrictiveFolder(ItemGroup parent, String name) { + super(parent, name); + } + + @Override + public boolean canAdd(TopLevelItem item) { + return item instanceof FreeStyleProject; + } + + @TestExtension("canAdd") public static class DescriptorImpl extends TopLevelItemDescriptor { + + @Override public TopLevelItem newInstance(ItemGroup parent, String name) { + return new RestrictiveFolder(parent, name); + } + + } + + } + + private void assertContains(AutoCompletionCandidates c, String... values) { + assertEquals(new TreeSet<>(Arrays.asList(values)), new TreeSet<>(c.getValues())); + } + +} -- GitLab